more FFI error checking, plus bugfixes

This commit is contained in:
dzaima 2023-07-28 14:43:17 +03:00
parent 1bc96f5557
commit 627a7e0771
4 changed files with 139 additions and 112 deletions

157
src/ffi.c
View File

@ -265,6 +265,50 @@ static void printFFIType(FILE* f, B x) {
#if FFI==2
#if FFI_CHECKS
static char* typeDesc(i32 typeNum) {
switch(typeNum) {
default: return "(unknown)";
case 0: return "an array";
case 1: return "a number";
case 2: return "a character";
case 3: return "a function";
case 4: return "a 1-modifier";
case 5: return "a 2-modifier";
case 6: return "a namespace";
}
}
static NOINLINE i32 nonNumber(B x) { // returns -1 if x is all numeric, otherwise •Type of the offending element
if (elNum(TI(x,elType))) return -1;
usz ia = IA(x); SGetU(x)
i32 r = -1;
for (ux i = 0; i < ia; i++) {
B c = GetU(x,i);
if (!isNum(c)) { r = typeInt(c); break; }
}
return r;
}
static NOINLINE void ffi_checkRange(B x, i32 mode, char* desc, i64 min, i64 max) { // doesn't consume; assumes non-array has already been checked for; if min==max, doesn't check range
if (IA(x)==0) return;
char* ref = mode==1? "&" : mode==0? "*" : ":";
i32 nonNum = nonNumber(x);
if (nonNum!=-1) thrF("FFI: Array provided for %S%S contained %S", ref, desc, typeDesc(nonNum));
if (min==max) return;
incG(x); x = elNum(TI(x,elType))? x : taga(cpyF64Arr(x));
i64 buf[2];
if (!getRange_fns[TI(x,elType)](tyany_ptr(x), buf, IA(x))) thrF("FFI: Array provided for %S%S contained non-integer", ref, desc);
if (buf[0]<min) thrF("FFI: Array provided for %S%S contained %l", ref, desc, buf[0]);
if (buf[1]>max) thrF("FFI: Array provided for %S%S contained %l", ref, desc, buf[1]);
decG(x);
}
#else
static void ffi_checkRange(B x, i32 mode, char* desc, i64 min, i64 max) { }
#endif
enum ScalarTy {
sty_void, sty_a, sty_ptr,
sty_u8, sty_u16, sty_u32, sty_u64,
@ -444,9 +488,13 @@ BQNFFIEnt ffi_parseTypeStr(u32** src, bool inPtr, bool top) { // parse actual ty
c++;
u8 t = *c++;
u32 n = readUInt(&c);
if (t=='i' | t=='c') if (n!=8 & n!=16 & n!=32) { badW: thrF("Unsupported width in :%c%i", (u32)t, n); }
if (t=='u') if (n!=1) goto badW;
if (t=='f') if (n!=64) goto badW;
if (t=='i' || t=='c') {
if (n!=8 & n!=16 & n!=32) { badW: thrF("FFI: Unsupported width in :%c%i", (u32)t, n); }
} else if (t=='u') {
if (n!=1) goto badW;
} else if (t=='f') {
if (n!=64) goto badW;
} else thrM("FFI: Unexpected character after \":\"");
if (isC32(ro) && n > myWidth*8) thrF("FFI: Representation wider than the value for \"%S:%c%i\"", sty_names[o2cG(ro)], (u32)t, n);
// TODO figure out what to do with i32:i32 etc
@ -512,13 +560,13 @@ static usz ffiTmpAlign(usz n) {
static B ffiObjs;
static B toW(u8 reT, u8 reW, B x) {
static NOINLINE B toW(u8 reT, u8 reW, B x) {
switch(reW) { default: UD;
case 0: return taga(toBitArr(x)); break;
case 3: return reT=='c'? toC8Any(x) : toI8Any(x); break;
case 4: return reT=='c'? toC16Any(x) : toI16Any(x); break;
case 5: return reT=='c'? toC32Any(x) : toI32Any(x); break;
case 6: return toF64Any(x); break;
case 0: ffi_checkRange(x, 2, "u1", 0, 1); return taga(toBitArr(x)); break;
case 3: if (reT=='i') ffi_checkRange(x, 2, "i8", I8_MIN, I8_MAX); return reT=='c'? toC8Any(x) : toI8Any(x); break;
case 4: if (reT=='i') ffi_checkRange(x, 2, "i16", I16_MIN, I16_MAX); return reT=='c'? toC16Any(x) : toI16Any(x); break;
case 5: if (reT=='i') ffi_checkRange(x, 2, "i32", I32_MIN, I32_MAX); return reT=='c'? toC32Any(x) : toI32Any(x); break;
case 6: ffi_checkRange(x, 2, "f64", 0, 0); return toF64Any(x); break;
}
}
static u8 reTyMapC[] = { [3]=t_c8arr, [4]=t_c16arr, [5]=t_c32arr };
@ -534,49 +582,6 @@ static B makeRe(u8 reT, u8 reW/*log*/, u8* src, u32 elW/*bytes*/) {
FORCE_INLINE u64 i64abs(i64 x) { return x<0?-x:x; }
#if FFI_CHECKS
static char* typeDesc(i32 typeNum) {
switch(typeNum) {
default: return "(unknown)";
case 0: return "an array";
case 1: return "a number";
case 2: return "a character";
case 3: return "a function";
case 4: return "a 1-modifier";
case 5: return "a 2-modifier";
case 6: return "a namespace";
}
}
static NOINLINE i32 nonNumber(B x) { // returns -1 if x is all numeric, otherwise •Type of the offending element
if (elNum(TI(x,elType))) return -1;
usz ia = IA(x); SGetU(x)
i32 r = -1;
for (ux i = 0; i < ia; i++) {
B c = GetU(x,i);
if (!isNum(c)) { r = typeInt(c); break; }
}
return r;
}
static NOINLINE void ffi_checkRange(B x, bool mut, char* desc, i64 min, i64 max) { // doesn't consume; assumes non-array has already been checked for; if min==max, doesn't check range
if (IA(x)==0) return;
char ref = mut? '&' : '*';
i32 nonNum = nonNumber(x);
if (nonNum!=-1) thrF("FFI: Array provided for %c%S contained %S", ref, desc, typeDesc(nonNum));
if (min==max) return;
incG(x); x = elNum(TI(x,elType))? x : taga(cpyF64Arr(x));
i64 buf[2];
if (!getRange_fns[TI(x,elType)](tyany_ptr(x), buf, IA(x))) thrF("Array provided for %c%S contained non-integer", ref, desc);
if (buf[0]<min) thrF("FFI: Array provided for %c%S contained %l", ref, desc, buf[0]);
if (buf[1]>max) thrF("FFI: Array provided for %c%S contained %l", ref, desc, buf[1]);
decG(x);
}
#else
static void ffi_checkRange(B x, bool mut, char* desc, i64 min, i64 max) { }
#endif
#define CPY_UNSIGNED(REL, UEL, DIRECT, WIDEN, WEL) \
if (TI(x,elType)<=el_##REL) return taga(DIRECT(x)); \
usz ia = IA(x); \
@ -605,10 +610,10 @@ static B toU16Bits(B x) { return TI(x,elType)==el_i16? x : cpyU16Bits(x); }
static B toU8Bits(B x) { return TI(x,elType)==el_i8? x : cpyU8Bits(x); }
// read x as the specified type (assuming a container of the respective width signed integer array); consumes x
NOINLINE B readU8Bits(B x) { usz ia=IA(x); u8* xp=tyarr_ptr(x); i16* rp; B r=m_i16arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=xp[i]; return num_squeeze(r); }
NOINLINE B readU16Bits(B x) { usz ia=IA(x); u16* xp=tyarr_ptr(x); i32* rp; B r=m_i32arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=xp[i]; return num_squeeze(r); }
NOINLINE B readU32Bits(B x) { usz ia=IA(x); u32* xp=tyarr_ptr(x); f64* rp; B r=m_f64arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=xp[i]; return num_squeeze(r); }
NOINLINE B readF32Bits(B x) { usz ia=IA(x); float*xp=tyarr_ptr(x); f64* rp; B r=m_f64arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=xp[i]; return r; }
NOINLINE B readU8Bits(B x) { usz ia=IA(x); u8* xp=tyarr_ptr(x); i16* rp; B r=m_i16arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=xp[i]; return num_squeeze(r); }
NOINLINE B readU16Bits(B x) { usz ia=IA(x); u16* xp=tyarr_ptr(x); i32* rp; B r=m_i32arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=xp[i]; return num_squeeze(r); }
NOINLINE B readU32Bits(B x) { usz ia=IA(x); u32* xp=tyarr_ptr(x); f64* rp; B r=m_f64arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=xp[i]; return num_squeeze(r); }
NOINLINE B readF32Bits(B x) { usz ia=IA(x); f32* xp=tyarr_ptr(x); f64* rp; B r=m_f64arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=xp[i]; return r; }
void genObj(B o, B c, bool anyMut, void* ptr) {
// printFFIType(stdout,o); printf(" = "); printI(c); printf("\n");
@ -677,28 +682,32 @@ void genObj(B o, B c, bool anyMut, void* ptr) {
u8 reW = t->a[0].reWidth;
if (isC32(o2)) { // scalar:any
u8 et = o2cG(o2);
u8 etw = sty_w[et]*8;
u8 mul = (sty_w[et]*8) >> reW;
if (!isArr(c)) thrF("FFI: Expected array corresponding to \"%S:%c%i\"", sty_names[et], (u32)reT, 1<<reW);
if (IA(c) != etw>>reW) thrF("FFI: Bad array corresponding to \"%S:%c%i\": expected %s elements, got %s", sty_names[et], (u32)reT, 1<<reW, (usz)(etw>>reW), IA(c));
if (IA(c) != mul) thrF("FFI: Bad array corresponding to \"%S:%c%i\": expected %s elements, got %s", sty_names[et], (u32)reT, 1<<reW, (usz)mul, IA(c));
B cG = toW(reT, reW, incG(c));
memcpy(ptr, tyany_ptr(cG), 8); // may over-read, ¯\_(ツ)_/¯
dec(cG);
} else { // *scalar:any / &scalar:any
if (!isArr(c)) thrM("FFI: Expected array corresponding to a pointer");
BQNFFIType* t2 = c(BQNFFIType, o2);
B ore = t2->a[0].o;
assert(t2->ty==cty_ptr && isC32(ore)); // we shouldn't be generating anything else
incG(c);
B cG;
bool mut = t->a[0].mutPtr;
bool mut = t2->a[0].mutPtr;
u8 et = o2cG(ore);
u8 mul = (sty_w[et]*8) >> reW;
if (!isArr(c)) thrF("FFI: Expected array corresponding to \"%S%S:%c%i\"", mut?"&":"*", sty_names[et], (u32)reT, 1<<reW);
if (mul && (IA(c) & (mul-1)) != 0) thrF("FFI: Bad array corresponding to \"%S%S:%c%i\": expected a multiple of %s elements, got %s", mut?"&":"*", sty_names[et], (u32)reT, 1<<reW, (usz)mul, IA(c));
incG(c); B cG;
if (mut) {
Arr* cGp;
switch(reW) { default: UD;
case 0: cGp = (Arr*) cpyBitArr(c); break;
case 3: cGp = reT=='c'? (Arr*) cpyC8Arr(c) : (Arr*) cpyI8Arr(c); break;
case 4: cGp = reT=='c'? (Arr*)cpyC16Arr(c) : (Arr*)cpyI16Arr(c); break;
case 5: cGp = reT=='c'? (Arr*)cpyC32Arr(c) : (Arr*)cpyI32Arr(c); break;
case 6: cGp = (Arr*) cpyF64Arr(c); break;
case 0: ffi_checkRange(c, 2, "u1", 0, 1); cGp = (Arr*) cpyBitArr(c); break;
case 3: if (reT=='i') ffi_checkRange(c, 2, "i8", I8_MIN, I8_MAX); cGp = reT=='c'? (Arr*) cpyC8Arr(c) : (Arr*) cpyI8Arr(c); break;
case 4: if (reT=='i') ffi_checkRange(c, 2, "i16", I16_MIN, I16_MAX); cGp = reT=='c'? (Arr*)cpyC16Arr(c) : (Arr*)cpyI16Arr(c); break;
case 5: if (reT=='i') ffi_checkRange(c, 2, "i32", I32_MIN, I32_MAX); cGp = reT=='c'? (Arr*)cpyC32Arr(c) : (Arr*)cpyI32Arr(c); break;
case 6: ffi_checkRange(c, 2, "f64", 0, 0); cGp = (Arr*) cpyF64Arr(c); break;
}
cG = taga(cGp);
} else cG = toW(reT, reW, c);
@ -774,8 +783,7 @@ B buildObj(BQNFFIEnt ent, bool anyMut, B* objs, usz* objPos) {
if (t->ty==cty_ptr) { // *any / &any
B e = t->a[0].o;
B f = objs[(*objPos)++];
bool mut = t->a[0].mutPtr;
if (mut) {
if (t->a[0].mutPtr) {
if (isC32(e)) {
switch(o2cG(e)) { default: UD;
case sty_i8: case sty_i16: case sty_i32: case sty_f64: return incG(f);
@ -801,10 +809,11 @@ B buildObj(BQNFFIEnt ent, bool anyMut, B* objs, usz* objPos) {
} else if (t->ty==cty_repr) { // any:any
B o2 = t->a[0].o;
if (isC32(o2)) return m_f64(0); // scalar:any
// *scalar:any / &scalar:any
BQNFFIType* t2 = c(BQNFFIType,o2); // *scalar:any / &scalar:any
assert(t2->ty == cty_ptr);
B f = objs[(*objPos)++];
bool mut = t->a[0].mutPtr;
if (!mut) return m_f64(0);
if (!t2->a[0].mutPtr) return m_f64(0);
return inc(f);
} else thrM("FFI: Unimplemented type (buildObj)");
}
@ -1007,14 +1016,14 @@ B ffiload_c2(B t, B w, B x) {
if (ws) freeCStr(ws);
dec(w);
if (dl==NULL) thrF("Failed to load: %S", dlerror());
if (dl==NULL) thrF("FFI: Failed to load library: %S", dlerror());
char* nameStr = toCStr(name);
void* sym = dlsym(dl, nameStr);
freeCStr(nameStr);
dec(x);
if (sym==NULL) thrF("Failed to find symbol: %S", dlerror());
if (sym==NULL) thrF("FFI: Failed to find symbol: %S", dlerror());
#if FFI==1
return m_ffiFn(foreignFnDesc, bi_N, directFn_c1, directFn_c2, sym, sym);
#else

View File

@ -1,11 +1,12 @@
%DEF var V•internal.Variation LV•internal.ListVariations CLR•internal.ClearRefs
%DEF tvar %USE var _tvar {F _𝕣 x: (CLR@) {F 𝕩 V x}¨ LV 𝕩; w F _𝕣 x: (CLR@) (LV 𝕨) {(𝕨 V w) F 𝕩 V x} LV 𝕩}
%DEF defs size_t "u64"
%DEF defs size_t "u64" size_tw 64
# bad •FFI invocation
# generally weird
@ •FFI9 """bqn_this symbol doesn't exist" %% 9
"file that doesn't exist" •FFI'e' """abort" %% 'e'
@ •FFI'e' """bqn_this symbol doesn't exist" %% 'e'
!"FFI: Type must be a string" % @•FFI "hello"
!"FFI: Error parsing type: Unexpected character '?'" % @•FFI"""bqn_init""?"
!"FFI: Bad array type" % @•FFI"""bqn_init""["
@ -50,12 +51,13 @@
!"FFI: Structs currently cannot contain mutable references" % @•FFI"""bqn_init""{&i32}"
# :
!"FFI: Garbage at end of type" % @•FFI"""bqn_init""i32:"
!"Unsupported width in :i0" % @•FFI"""bqn_init""i32:i"
!"Unsupported width in :i9" % @•FFI"""bqn_init""i32:i9"
!"Unsupported width in :u16" % @•FFI"""bqn_init""i32:u16"
!"Unsupported width in :i64" % @•FFI"i32:i64""bqn_init"
!"Unsupported width in :f32" % @•FFI"""bqn_init""i32:f32"
!"FFI: Unexpected character after "":""" % @•FFI"""bqn_init""i32:"
!"FFI: Unexpected character after "":""" % f@•FFI"""bqn_init"">*u64:q8"
!"FFI: Unsupported width in :i0" % @•FFI"""bqn_init""i32:i"
!"FFI: Unsupported width in :i9" % @•FFI"""bqn_init""i32:i9"
!"FFI: Unsupported width in :u16" % @•FFI"""bqn_init""i32:u16"
!"FFI: Unsupported width in :i64" % @•FFI"i32:i64""bqn_init"
!"FFI: Unsupported width in :f32" % @•FFI"""bqn_init""i32:f32"
!"FFI: number literal too large" % @•FFI"""bqn_init""i32:u9999999999999999"
!"FFI: Representation wider than the value for ""i32:f64""" % @•FFI"""bqn_init""i32:f64"
!"FFI: Garbage at end of type" % @•FFI"""bqn_init""i32 hello world"
@ -77,6 +79,9 @@
%USE defs f@•FFI"&""memcpy""&i16""*i8"size_t G{F𝕩,0,0} G ¯3276832767 %% ¯3276832767
%USE defs f@•FFI"&""memcpy""&{i16}""*i8"size_t G{F𝕩,0,0} G ¨¯3276832767 %% ¨¯3276832767
%USE defs f@•FFI"&""memcpy""&f32""*i8"size_t G{F𝕩,0,0} G ,¯∞,÷10÷˜10 %% ,¯∞,÷00.100000001490116120.200000002980232240.300000011920928960.40000000596046450.50.60000002384185790.6999999880790710.8000000119209290.8999999761581421
%USE defs f@•FFI"&""memcpy""&i32""*i16:u1"size_t F 5, 321, 4 %% ¯1
%USE defs f@•FFI"&","memcpy","&i8","*i8",size_t":u1" F ¯100+10, 10, size_tw001 %% (4)4¯100+10
%USE defs f@•FFI"&""memcpy""&i16""*i16:i32"size_t F ¯100+10, 123+456×216, ¯2, 8 %% 123456¯2¯14¯100+10
@ -90,13 +95,6 @@
!"FFI: Array provided for &u16 contained ¯1" % f@•FFI"&""bqn_init"">&u16" F ¯1
!"FFI: Array provided for &u32 contained ¯1" % f@•FFI"&""bqn_init"">&u32" F ¯1
!"FFI: Array provided for &i16 contained 32768" % f@•FFI"&""bqn_init"">&i16" F ¯3276832768
!"FFI: Array provided for &i16 contained ¯32769" % f@•FFI"&""bqn_init"">&i16" F ¯32768¯32769
!"FFI: Array provided for &u8 contained an array" % f@•FFI"&""bqn_init"">&u8" F 300
!"FFI: Array provided for &i16 contained a character" % f@•FFI"&""bqn_init"">&i16" F "hi"
!"FFI: Array provided for &f64 contained a namespace" % f@•FFI"&""bqn_init"">&f64" F 12{}
# bad scalars
!"FFI: u8 argument not exact" % f@•FFI"""bqn_init"">u8" F 256
!"FFI: u16 argument not exact" % f@•FFI"""bqn_init"">u16" F ¯1
@ -120,11 +118,6 @@
# wrong argument internal structure
!"FFI: Expected array corresponding to ""i32:i8""" % f@•FFI"""bqn_init"">i32:i8" F @
!"FFI: Bad array corresponding to ""i32:i8"": expected 4 elements, got 10" % f@•FFI"""bqn_init"">i32:i8" F 10
!"FFI: Expected array corresponding to a pointer" % f@•FFI"""bqn_init"">*i32:i8" F @
!"FFI: Expected array corresponding to *{...}" % f@•FFI"""bqn_init"">*{i32}" F @
!"FFI: Expected array corresponding to a struct" % f@•FFI"""bqn_init"">{i32}" F @
!"FFI: Expected array corresponding to a struct" % f@•FFI"""bqn_init"">*{i32}" F @
@ -133,6 +126,31 @@
!"FFI: Incorrect list length corresponding to an array: expected 2, got 0" % f@•FFI"""bqn_init"">*[2]i32" F
!"FFI: Incorrect list length corresponding to an array: expected 2, got 3" % f@•FFI"""bqn_init"">*[2]i32" F 123
# bad :
!"FFI: Expected array corresponding to ""i32:i8""" % f@•FFI"""bqn_init"">i32:i8" F @
!"FFI: Expected array corresponding to ""*i32:i8""" % f@•FFI"""bqn_init"">*i32:i8" F @
!"FFI: Bad array corresponding to ""i32:i8"": expected 4 elements, got 10" % f@•FFI"""bqn_init"">i32:i8" F 10
!"FFI: Bad array corresponding to ""u64:u1"": expected 64 elements, got 128" % f@•FFI"""bqn_init"">u64:u1" F 1281
!"FFI: Array provided for :u1 contained 63" % f@•FFI"""bqn_init"">u64:u1" F 64
!"FFI: Bad array corresponding to ""u64:i8"": expected 8 elements, got 64" % f@•FFI"""bqn_init"">u64:i8" F 64
!"FFI: Expected array corresponding to ""*u64:i8""" % f@•FFI"""bqn_init"">*u64:i8" F @
!"FFI: Array provided for :i8 contained 199" % f@•FFI"""bqn_init"">*u64:i8" F 200
!"FFI: Array provided for :i8 contained 199" % f@•FFI"""bqn_init"">&u64:i8" F 200
!"FFI: Array provided for :u1 contained 63" % f@•FFI"""bqn_init"">&u64:u1" F 64
!"FFI: Bad array corresponding to ""*u64:i8"": expected a multiple of 8 elements, got 2" % f@•FFI"""bqn_init"">*u64:i8" F 2
!"FFI: Bad array corresponding to ""*u32:i16"": expected a multiple of 2 elements, got 1" % f@•FFI"""bqn_init"">*u32:i16" F 1
!"FFI: Bad array corresponding to ""&u64:u1"": expected a multiple of 64 elements, got 32" % f@•FFI"""bqn_init"">&u64:u1" F 320
!"FFI: Array provided for &i16 contained 32768" % f@•FFI"&""bqn_init"">&i16" F ¯3276832768
!"FFI: Array provided for &i16 contained ¯32769" % f@•FFI"&""bqn_init"">&i16" F ¯32768¯32769
!"FFI: Array provided for &u8 contained an array" % f@•FFI"&""bqn_init"">&u8" F 300
!"FFI: Array provided for &i16 contained a character" % f@•FFI"&""bqn_init"">&i16" F "hi"
!"FFI: Array provided for &f64 contained a namespace" % f@•FFI"&""bqn_init"">&f64" F 12{}
# unimplemented stuff

View File

@ -39,16 +39,16 @@ f ↩ "lib.so" •FFI "f32"‿"sumF32Arr"‿"*f32:i32"‿"i32" ⋄ •Show F ⟨
Section "# mutate i32*"
f "lib.so" •FFI "","incI32s","&u32", "i32" •Show F 1e8×20+10 10
f "lib.so" •FFI "","incI32s","&i32:u1", "i32" •Show F 1010101001010011011000010101001000100010001110111111001100100100, 2
f "lib.so" •FFI "","incI32s","&i32:c8", "i32" •Show F "helloworld", 2
f "lib.so" •FFI "","incI32s",">𝕨&i32:c8",">i32" •Show "helloworld" F 2
f "lib.so" •FFI "","incI32s","&i32:c8", "i32" •Show F "hello, world", 2
f "lib.so" •FFI "","incI32s",">𝕨&i32:c8",">i32" •Show "hello, world" F 2
f "lib.so" •FFI "", "incI32s", "&i32:c8", "i32" •Show F "helloworld", 2
f "lib.so" •FFI "", "incI32s", "&i32:c8", "𝕨i32" •Show 2 F "helloworld"
f "lib.so" •FFI "", "incI32s", "&i32:c8",">𝕨i32" •Show 2 F "helloworld"
f "lib.so" •FFI "", "incI32s", ">&i32:c8",">𝕨i32" •Show 2 F "helloworld"
f "lib.so" •FFI "", "incI32s",">𝕨&i32:c8", ">i32" •Show "helloworld" F 2
f "lib.so" •FFI "", "incI32s", "&i32:c8", "i32" •Show F "helloworld", 2
f "lib.so" •FFI "&","incI32s", "&i32:c8", "i32" •Show F "helloworld", 2
f "lib.so" •FFI "", "incI32s", "&i32:c8", "i32" •Show F "hello, world", 2
f "lib.so" •FFI "", "incI32s", "&i32:c8", "𝕨i32" •Show 2 F "hello, world"
f "lib.so" •FFI "", "incI32s", "&i32:c8",">𝕨i32" •Show 2 F "hello, world"
f "lib.so" •FFI "", "incI32s", ">&i32:c8",">𝕨i32" •Show 2 F "hello, world"
f "lib.so" •FFI "", "incI32s",">𝕨&i32:c8", ">i32" •Show "hello, world" F 2
f "lib.so" •FFI "", "incI32s", "&i32:c8", "i32" •Show F "hello, world", 2
f "lib.so" •FFI "&","incI32s", "&i32:c8", "i32" •Show F "hello, world", 2
Section "# mutate i32*, i16*, i8*"
f "lib.so" •FFI "","incInts","&i32", "&i16","&i8" •Show F ¨ 102030

View File

@ -54,15 +54,15 @@ ff7fdfefefdf7bb4 ff7fdfefefdf7bb4 fefffdfff7ffbffb bffff7fffdfffeff
# mutate i32*
⟨ ⟨ 2000000001 2100000001 2200000001 2300000001 2400000001 2500000001 2600000001 2700000001 2800000001 2900000001 ⟩ ⟩
⟨ 0 1 1 0 1 0 1 0 0 1 0 1 0 0 1 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 1 0 1 0 1 0 0 0 1 0 0 0 1 1 1 0 1 1 1 1 1 1 0 0 1 1 0 0 1 0 0 1 0 0 ⟩
"iellpworld"
"iellpworld"
"iellpworld"
"iellpworld"
"iellpworld"
"iellpworld"
"iellpworld"
⟨ "iellpworld" ⟩
"iellpworld"
"iellp, world"
"iellp, world"
"iellp, world"
"iellp, world"
"iellp, world"
"iellp, world"
"iellp, world"
⟨ "iellp, world" ⟩
"iellp, world"
# mutate i32*, i16*, i8*
10 20 30