initial struct support

This commit is contained in:
dzaima 2022-10-08 19:06:15 +03:00
parent 702d4e979d
commit 7e1c9b50cd
4 changed files with 277 additions and 69 deletions

282
src/ffi.c
View File

@ -203,18 +203,24 @@ DEF_FREE(ffiFn) { dec(((BoundFn*)x)->obj); }
typedef struct BQNFFIEnt { typedef struct BQNFFIEnt {
B o; union {
B o; // usual case
TAlloc* structData; // pointer stored in last element of cty_struct
};
#if FFI==2 #if FFI==2
ffi_type t; ffi_type t;
#endif #endif
// generic ffi_parseType ffi_parseTypeStr cty_ptr cty_repr // generic ffi_parseType ffi_parseTypeStr cty_ptr cty_repr
union { u8 extra; u8 onW; u8 canRetype; u8 mutPtr; u8 reType; }; union { u8 extra; u8 onW; u8 canRetype; u8 mutPtr; u8 reType; };
union { u8 extra2; u8 mutates; /*mutates*/ u8 reWidth; }; union { u8 extra2; u8 mutates; /*mutates*/ u8 reWidth; };
union { u8 extra3; u8 wholeArg; }; union {
union { u8 extra4; u8 resSingle; }; struct { u8 wholeArg; u8 resSingle; }; // ffi_parseType
u16 offset; // cty_struct
};
} BQNFFIEnt; } BQNFFIEnt;
typedef struct BQNFFIType { typedef struct BQNFFIType {
struct Value; struct Value;
union { u16 structSize; };
u8 ty; u8 ty;
usz ia; usz ia;
BQNFFIEnt a[]; BQNFFIEnt a[];
@ -248,7 +254,8 @@ static const char* sty_names[] = {
}; };
enum CompoundTy { enum CompoundTy {
cty_ptr, cty_ptr,
cty_repr cty_repr,
cty_struct,
}; };
static B m_bqnFFIType(BQNFFIEnt** rp, u8 ty, usz ia) { static B m_bqnFFIType(BQNFFIEnt** rp, u8 ty, usz ia) {
@ -279,10 +286,9 @@ BQNFFIEnt ffi_parseTypeStr(u32** src, bool inPtr) { // parse actual type
bool parseRepr=false, canRetype=false, mut=false; bool parseRepr=false, canRetype=false, mut=false;
u32 myWidth = 0; // used if parseRepr u32 myWidth = 0; // used if parseRepr
switch (c0) { switch (c0) {
default: default: thrM("FFI: Error parsing type");
thrM("FFI: Error parsing type");
case 'i': case 'u': case 'f':; case 'i': case 'u': case 'f': {
u32 n = readUInt(&c); u32 n = readUInt(&c);
if (c0=='f') { if (c0=='f') {
if (n==32) rt = ffi_type_float; if (n==32) rt = ffi_type_float;
@ -301,13 +307,16 @@ BQNFFIEnt ffi_parseTypeStr(u32** src, bool inPtr) { // parse actual type
parseRepr = !inPtr; myWidth = sty_w[o2cG(ro)]; parseRepr = !inPtr; myWidth = sty_w[o2cG(ro)];
canRetype = inPtr; canRetype = inPtr;
break; break;
}
case 'a': case 'a': {
ro = m_c32(sty_a); ro = m_c32(sty_a);
assert(sizeof(BQNV)==8); // ffi_type_uint64 must be the same as BQNV
rt = ffi_type_uint64; rt = ffi_type_uint64;
break; break;
}
case '*': case '&':; case '*': case '&': {
myWidth = sizeof(void*); myWidth = sizeof(void*);
if (c0=='*' && (0==*c || ':'==*c)) { if (c0=='*' && (0==*c || ':'==*c)) {
ro = m_c32(sty_ptr); ro = m_c32(sty_ptr);
@ -324,6 +333,38 @@ BQNFFIEnt ffi_parseTypeStr(u32** src, bool inPtr) { // parse actual type
} }
rt = ffi_type_pointer; rt = ffi_type_pointer;
break; break;
}
case '{': {
TSALLOC(BQNFFIEnt, es, 4);
while (true) {
BQNFFIEnt e = TSADD(es, ffi_parseTypeStr(&c, false));
if (e.mutates) thrM("FFI: Structs currently cannot contain mutable references");
u32 m = *c++;
if (m=='}') break;
if (m!=',') thrM("FFI: Invalid struct member");
}
usz n = TSSIZE(es);
BQNFFIEnt* rp; ro = m_bqnFFIType(&rp, cty_struct, n+1);
memcpy(rp, es, n*sizeof(BQNFFIEnt));
rp[n].structData = NULL;
TAlloc* ao = ARBOBJ(sizeof(ffi_type*) * (n+1));
rp[n].structData = ao;
ffi_type** els = rt.elements = (ffi_type**) ao->data;
for (usz i = 0; i < n; i++) els[i] = &rp[i].t;
els[n] = NULL;
TSFREE(es);
rt.type = FFI_TYPE_STRUCT;
TALLOC(size_t, offsets, n);
if (ffi_get_struct_offsets(FFI_DEFAULT_ABI, &rt, offsets) != FFI_OK) thrM("FFI: Failed getting struct offsets");
if (rt.size>=U16_MAX) thrM("FFI: Struct too large; limit is 65534 bytes");
for (usz i = 0; i < n; i++) rp[i].offset = offsets[i];
c(BQNFFIType, ro)->structSize = rt.size;
TFREE(offsets);
break;
}
} }
if (parseRepr && *c==':') { if (parseRepr && *c==':') {
c++; c++;
@ -436,13 +477,14 @@ static B makeRe(u8 reT, u8 reW/*log*/, u8* src, u32 elW/*bytes*/) {
FORCE_INLINE u64 i64abs(i64 x) { return x<0?-x:x; } FORCE_INLINE u64 i64abs(i64 x) { return x<0?-x:x; }
usz genObj(BQNFFIEnt ent, B c, bool anyMut) {
usz genObj(BQNFFIEnt ent, B c, bool anyMut, void* ptr) {
// printFFIType(stdout,ent.o); printf(" = "); print(c); printf("\n"); // printFFIType(stdout,ent.o); printf(" = "); print(c); printf("\n");
usz pos; usz pos;
#define ALLOC(N) if (ptr==NULL) { pos=ffiTmpAA(N); ptr=ffiTmpS+pos; } // TODO make top-level pos statically allocated so that there's no need for the conditionals
if (isC32(ent.o)) { // scalar if (isC32(ent.o)) { // scalar
u32 t = o2cG(ent.o); u32 t = o2cG(ent.o);
pos = ffiTmpAA(t==0? sizeof(BQNV) : 8); ALLOC(t==0? sizeof(BQNV) : 8);
void* ptr = ffiTmpS+pos;
f64 f = c.f; f64 f = c.f;
switch(t) { default: UD; // thrF("FFI: Unimplemented scalar type \"%S\"", sty_names[t]); switch(t) { default: UD; // thrF("FFI: Unimplemented scalar type \"%S\"", sty_names[t]);
case sty_a: *(BQNV*)ptr = makeX(inc(c)); break; case sty_a: *(BQNV*)ptr = makeX(inc(c)); break;
@ -461,42 +503,60 @@ usz genObj(BQNFFIEnt ent, B c, bool anyMut) {
} else { } else {
BQNFFIType* t = c(BQNFFIType, ent.o); BQNFFIType* t = c(BQNFFIType, ent.o);
if (t->ty==cty_ptr) { // *any / &any if (t->ty==cty_ptr) { // *any / &any
pos = ffiTmpAA(sizeof(void*)); ALLOC(sizeof(void*));
B e = t->a[0].o;
if (!isC32(e)) thrM("FFI: Complex pointer elements NYI");
inc(c);
B cG;
if (!isArr(c)) thrF("FFI: Expected array corresponding to \"*%S\"", sty_names[o2cG(e)]);
usz ia = IA(c);
bool mut = t->a[0].mutPtr;
switch(o2cG(e)) { default: thrF("FFI: \"*%S\" argument type NYI", sty_names[o2cG(e)]);
case sty_i8: cG = mut? taga(cpyI8Arr (c)) : toI8Any (c); break;
case sty_i16: cG = mut? taga(cpyI16Arr(c)) : toI16Any(c); break;
case sty_i32: cG = mut? taga(cpyI32Arr(c)) : toI32Any(c); break;
case sty_f64: cG = mut? taga(cpyF64Arr(c)) : toF64Any(c); break;
case sty_u8: { B t=toI16Any(c); i16* tp=i16any_ptr(t); i8* gp; cG= m_i8arrv(&gp, ia); u8* np=(u8* )gp; for (usz i=0; i<ia; i++) np[i]=tp[i]; dec(t); break; }
case sty_u16: { B t=toI32Any(c); i32* tp=i32any_ptr(t); i16* gp; cG=m_i16arrv(&gp, ia); u16* np=(u16* )gp; for (usz i=0; i<ia; i++) np[i]=tp[i]; dec(t); break; }
case sty_u32: { B t=toF64Any(c); f64* tp=f64any_ptr(t); i32* gp; cG=m_i32arrv(&gp, ia); u32* np=(u32* )gp; for (usz i=0; i<ia; i++) np[i]=tp[i]; dec(t); break; }
case sty_f32: { B t=toF64Any(c); f64* tp=f64any_ptr(t); i32* gp; cG=m_i32arrv(&gp, ia); float* np=(float*)gp; for (usz i=0; i<ia; i++) np[i]=tp[i]; dec(t); break; }
}
*(void**)(ffiTmpS+pos) = tyany_ptr(cG); B e = t->a[0].o;
ffiObjs = vec_addN(ffiObjs, cG); if (isC32(e)) { // *num / &num
inc(c);
B cG;
if (!isArr(c)) thrF("FFI: Expected array corresponding to \"*%S\"", sty_names[o2cG(e)]);
usz ia = IA(c);
bool mut = t->a[0].mutPtr;
switch(o2cG(e)) { default: thrF("FFI: \"*%S\" argument type NYI", sty_names[o2cG(e)]);
case sty_i8: cG = mut? taga(cpyI8Arr (c)) : toI8Any (c); break;
case sty_i16: cG = mut? taga(cpyI16Arr(c)) : toI16Any(c); break;
case sty_i32: cG = mut? taga(cpyI32Arr(c)) : toI32Any(c); break;
case sty_f64: cG = mut? taga(cpyF64Arr(c)) : toF64Any(c); break;
case sty_u8: { B t=toI16Any(c); i16* tp=i16any_ptr(t); i8* gp; cG= m_i8arrv(&gp, ia); u8* np=(u8* )gp; for (usz i=0; i<ia; i++) np[i]=tp[i]; dec(t); break; }
case sty_u16: { B t=toI32Any(c); i32* tp=i32any_ptr(t); i16* gp; cG=m_i16arrv(&gp, ia); u16* np=(u16* )gp; for (usz i=0; i<ia; i++) np[i]=tp[i]; dec(t); break; }
case sty_u32: { B t=toF64Any(c); f64* tp=f64any_ptr(t); i32* gp; cG=m_i32arrv(&gp, ia); u32* np=(u32* )gp; for (usz i=0; i<ia; i++) np[i]=tp[i]; dec(t); break; }
case sty_f32: { B t=toF64Any(c); f64* tp=f64any_ptr(t); i32* gp; cG=m_i32arrv(&gp, ia); float* np=(float*)gp; for (usz i=0; i<ia; i++) np[i]=tp[i]; dec(t); break; }
}
ffiObjs = vec_addN(ffiObjs, cG);
*(void**)ptr = tyany_ptr(cG);
} else {
BQNFFIType* t2 = c(BQNFFIType, e);
if (t2->ty != cty_struct) thrM("FFI: Unimplemented pointer element type");
if (!isArr(c)) thrM("FFI: Expected array corresponding to *{...}");
// *{...} / &{...}
usz ia = IA(c);
usz elSz = t2->structSize;
TALLOC(u8, dataAll, elSz*ia + sizeof(usz));
void* dataStruct = dataAll+sizeof(usz);
*((usz*)dataAll) = ia;
SGetU(c)
for (usz i = 0; i < ia; i++) genObj(t->a[0], GetU(c, i), anyMut, dataStruct + elSz*i);
*(void**)ptr = dataStruct;
ffiObjs = vec_addN(ffiObjs, tag(TOBJ(dataAll), OBJ_TAG));
}
} else if (t->ty==cty_repr) { // any:any } else if (t->ty==cty_repr) { // any:any
B o2 = t->a[0].o; B o2 = t->a[0].o;
u8 reT = t->a[0].reType; u8 reT = t->a[0].reType;
u8 reW = t->a[0].reWidth; u8 reW = t->a[0].reWidth;
if (isC32(o2)) { // scalar:any if (isC32(o2)) { // scalar:any
pos = ffiTmpAA(8); ALLOC(8);
u8 et = o2cG(o2); u8 et = o2cG(o2);
u8 etw = sty_w[et]*8; u8 etw = sty_w[et]*8;
if (!isArr(c)) thrF("FFI: Expected array corresponding to \"%S:%c%i\"", sty_names[et], reT, 1<<reW); if (!isArr(c)) thrF("FFI: Expected array corresponding to \"%S:%c%i\"", sty_names[et], reT, 1<<reW);
if (IA(c) != etw>>reW) thrM("FFI: Bad input array length"); if (IA(c) != etw>>reW) thrM("FFI: Bad input array length");
B cG = toW(reT, reW, inc(c)); B cG = toW(reT, reW, inc(c));
memcpy(ffiTmpS+pos, tyany_ptr(cG), 8); // may over-read, ¯\_(ツ)_/¯ memcpy(ptr, tyany_ptr(cG), 8); // may over-read, ¯\_(ツ)_/¯
dec(cG); dec(cG);
} else { // *scalar:any / &scalar:any } else { // *scalar:any / &scalar:any
pos = ffiTmpAA(sizeof(void*)); ALLOC(sizeof(void*));
if (!isArr(c)) thrM("FFI: Expected array corresponding to a pointer"); if (!isArr(c)) thrM("FFI: Expected array corresponding to a pointer");
BQNFFIType* t2 = c(BQNFFIType, o2); BQNFFIType* t2 = c(BQNFFIType, o2);
B ore = t2->a[0].o; B ore = t2->a[0].o;
@ -515,14 +575,74 @@ usz genObj(BQNFFIEnt ent, B c, bool anyMut) {
} }
cG = taga(cGp); cG = taga(cGp);
} else cG = toW(reT, reW, c); } else cG = toW(reT, reW, c);
*(void**)(ffiTmpS+pos) = tyany_ptr(cG); *(void**)ptr = tyany_ptr(cG);
ffiObjs = vec_addN(ffiObjs, cG); ffiObjs = vec_addN(ffiObjs, cG);
} }
} else if (t->ty==cty_struct) {
ALLOC(t->structSize);
if (!isArr(c)) thrM("FFI: Expected array corresponding to a struct");
if (IA(c)!=t->ia-1) thrM("FFI: Incorrect list length corresponding to a struct");
SGetU(c)
for (usz i = 0; i < t->ia-1; i++) {
BQNFFIEnt e = t->a[i];
genObj(e, GetU(c, i), anyMut, e.offset + (u8*)ptr);
}
} else thrM("FFI: Unimplemented type"); } else thrM("FFI: Unimplemented type");
} }
return pos; return pos;
} }
B readAny(BQNFFIEnt e, u8* ptr);
B readStruct(BQNFFIType* t, u8* ptr) {
usz ia = t->ia-1;
M_HARR(r, ia);
for (usz i = 0; i < ia; i++) {
void* c = ptr + t->a[i].offset;
HARR_ADD(r, i, readAny(t->a[i], c));
}
return HARR_FV(r);
}
B readSimple(u8 resCType, u8* ptr) {
B r;
switch(resCType) { default: UD; // thrM("FFI: Unimplemented type");
case sty_void: r = m_c32(0); break;
case sty_ptr: thrM("FFI: \"*\" unimplemented"); break;
case sty_a: r = getB(*(BQNV*)ptr); break;
case sty_i8: r = m_i32(*( i8*)ptr); break; case sty_u8: r = m_i32(*( u8*)ptr); break;
case sty_i16: r = m_i32(*(i16*)ptr); break; case sty_u16: r = m_i32(*(u16*)ptr); break;
case sty_i32: r = m_i32(*(i32*)ptr); break; case sty_u32: r = m_f64(*(u32*)ptr); break;
case sty_i64: { i64 v = *(i64*)ptr; if (i64abs(v)>=(1ULL<<53)) thrM("FFI: i64 result absolute value ≥ 2⋆53"); r = m_f64(v); break; }
case sty_u64: { u64 v = *(u64*)ptr; if ( v >=(1ULL<<53)) thrM("FFI: u64 result ≥ 2⋆53"); r = m_f64(v); break; }
case sty_f32: r = m_f64(*(float* )ptr); break;
case sty_f64: r = m_f64(*(double*)ptr); break;
}
return r;
}
B readRe(BQNFFIEnt e, u8* ptr) {
u8 et = o2cG(e.o);
u8 reT = e.reType;
u8 reW = e.reWidth;
u8 etw = sty_w[et];
return makeRe(reT, reW, ptr, etw);
}
B readAny(BQNFFIEnt e, u8* ptr) {
if (isC32(e.o)) {
return readSimple(o2cG(e.o), ptr);
} else {
BQNFFIType* t = c(BQNFFIType, e.o);
if (t->ty == cty_repr) { // cty_repr, scalar:x
return readRe(t->a[0], ptr);
} else if (t->ty == cty_struct) { // {...}
return readStruct(c(BQNFFIType, e.o), ptr);
}
}
thrM("FFI: Unimplemented struct field type for reading");
}
B buildObj(BQNFFIEnt ent, bool anyMut, B* objs, usz* objPos) { B buildObj(BQNFFIEnt ent, bool anyMut, B* objs, usz* objPos) {
if (isC32(ent.o)) return m_f64(0); // scalar if (isC32(ent.o)) return m_f64(0); // scalar
BQNFFIType* t = c(BQNFFIType, ent.o); BQNFFIType* t = c(BQNFFIType, ent.o);
@ -532,12 +652,26 @@ B buildObj(BQNFFIEnt ent, bool anyMut, B* objs, usz* objPos) {
bool mut = t->a[0].mutPtr; bool mut = t->a[0].mutPtr;
if (mut) { if (mut) {
usz ia = IA(f); usz ia = IA(f);
switch(o2cG(e)) { default: UD; if (isC32(e)) {
case sty_i8: case sty_i16: case sty_i32: case sty_f64: return inc(f); switch(o2cG(e)) { default: UD;
case sty_u8: { u8* tp=tyarr_ptr(f); i16* rp; B r=m_i16arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=tp[i]; return r; } case sty_i8: case sty_i16: case sty_i32: case sty_f64: return inc(f);
case sty_u16: { u16* tp=tyarr_ptr(f); i32* rp; B r=m_i32arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=tp[i]; return r; } case sty_u8: { u8* tp=tyarr_ptr(f); i16* rp; B r=m_i16arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=tp[i]; return r; }
case sty_u32: { u32* tp=tyarr_ptr(f); f64* rp; B r=m_f64arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=tp[i]; return r; } case sty_u16: { u16* tp=tyarr_ptr(f); i32* rp; B r=m_i32arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=tp[i]; return r; }
case sty_f32: { float*tp=tyarr_ptr(f); f64* rp; B r=m_f64arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=tp[i]; return r; } case sty_u32: { u32* tp=tyarr_ptr(f); f64* rp; B r=m_f64arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=tp[i]; return r; }
case sty_f32: { float*tp=tyarr_ptr(f); f64* rp; B r=m_f64arrv(&rp, ia); for (usz i=0; i<ia; i++) rp[i]=tp[i]; return r; }
}
} else {
BQNFFIType* t2 = c(BQNFFIType, e);
assert(t2->ty == cty_struct);
u8* dataAll = c(TAlloc,f)->data;
void* dataStruct = dataAll+sizeof(usz);
usz ia = *(usz*)dataAll;
usz elSz = t2->structSize;
M_HARR(r, ia);
for (usz i = 0; i < ia; i++) HARR_ADD(r, i, readStruct(t2, dataStruct + i*elSz));
return HARR_FV(r);
} }
} else return m_f64(0); } else return m_f64(0);
} else if (t->ty==cty_repr) { // any:any } else if (t->ty==cty_repr) { // any:any
@ -578,12 +712,12 @@ B libffiFn_c2(B t, B w, B x) {
for (usz i = 0; i < argn; i++) { for (usz i = 0; i < argn; i++) {
BQNFFIEnt e = ents[i+1]; BQNFFIEnt e = ents[i+1];
B o = e.wholeArg? (e.onW? w : x) : (e.onW? wf : xf)(e.onW?wa:xa, idxs[e.onW]++); B o = e.wholeArg? (e.onW? w : x) : (e.onW? wf : xf)(e.onW?wa:xa, idxs[e.onW]++);
argOffs[i] = genObj(e, o, e.extra2); argOffs[i] = genObj(e, o, e.extra2, NULL);
} }
u32 resPos;
bool simpleRes = isC32(ents[0].o); bool simpleRes = isC32(ents[0].o);
u32 resCType; u32 resCType;
usz resSize;
if (simpleRes) { if (simpleRes) {
resCType = o2cG(ents[0].o); resCType = o2cG(ents[0].o);
} else { } else {
@ -592,9 +726,18 @@ B libffiFn_c2(B t, B w, B x) {
B o2 = t->a[0].o; B o2 = t->a[0].o;
if (!isC32(o2)) thrM("FFI: Unimplemented result type"); if (!isC32(o2)) thrM("FFI: Unimplemented result type");
resCType = o2cG(o2); resCType = o2cG(o2);
} else thrM("FFI: Unimplemented result type"); } else if (t->ty == cty_struct) {
resSize = t->structSize;
goto resSize_alreadySet;
} else {
thrM("FFI: Unimplemented result type");
}
} }
resPos = ffiTmpAA(resCType==sty_a? sizeof(BQNV) : sizeof(ffi_arg)>8? sizeof(ffi_arg) : 8);
resSize = resCType==sty_a? sizeof(BQNV) : sizeof(ffi_arg)>8? sizeof(ffi_arg) : 8;
resSize_alreadySet:;
usz resPos = ffiTmpAA(resSize);
void** argPtrs = (void**) (ffiTmpS + ffiTmpAA(argn*sizeof(void*))); // must be the very last alloc to be able to store pointers void** argPtrs = (void**) (ffiTmpS + ffiTmpAA(argn*sizeof(void*))); // must be the very last alloc to be able to store pointers
for (usz i = 0; i < argn; i++) argPtrs[i] = ffiTmpS + argOffs[i]; for (usz i = 0; i < argn; i++) argPtrs[i] = ffiTmpS + argOffs[i];
@ -612,25 +755,15 @@ B libffiFn_c2(B t, B w, B x) {
B r; B r;
bool resVoid = false; bool resVoid = false;
if (simpleRes) { if (simpleRes) {
switch(resCType) { default: UD; // thrM("FFI: Unimplemented type"); r = readSimple(resCType, res);
case sty_void: r = m_c32(0); resVoid = true; break; resVoid = resCType==sty_void;
case sty_ptr: thrM("FFI: \"*\" unimplemented"); break; } else {
case sty_a: r = getB(*(BQNV*)res); break;
case sty_i8: r = m_i32(*( i8*)res); break; case sty_u8: r = m_i32(*( u8*)res); break;
case sty_i16: r = m_i32(*(i16*)res); break; case sty_u16: r = m_i32(*(u16*)res); break;
case sty_i32: r = m_i32(*(i32*)res); break; case sty_u32: r = m_f64(*(u32*)res); break;
case sty_i64: { i64 v = *(i64*)res; if (i64abs(v)>=(1ULL<<53)) thrM("FFI: i64 result absolute value ≥ 2⋆53"); r = m_f64(v); break; }
case sty_u64: { u64 v = *(u64*)res; if ( v >=(1ULL<<53)) thrM("FFI: u64 result ≥ 2⋆53"); r = m_f64(v); break; }
case sty_f32: r = m_f64(*(float* )res); break;
case sty_f64: r = m_f64(*(double*)res); break;
}
} else { // cty_repr, scalar:x
BQNFFIType* t = c(BQNFFIType, ents[0].o); BQNFFIType* t = c(BQNFFIType, ents[0].o);
u8 et = o2cG(t->a[0].o); if (t->ty == cty_repr) { // cty_repr, scalar:x
u8 reT = t->a[0].reType; r = readRe(t->a[0], res);
u8 reW = t->a[0].reWidth; } else { // {...}
u8 etw = sty_w[et]; r = readStruct(c(BQNFFIType, ents[0].o), res);
r = makeRe(reT, reW, res, etw); }
} }
mm_free((Value*)ffiTmpObj); mm_free((Value*)ffiTmpObj);
@ -742,18 +875,29 @@ B ffiload_c2(B t, B w, B x) {
#endif #endif
} }
#define FFI_TYPE_FLDS(OBJ, PTR) \
BQNFFIType* t = (BQNFFIType*) x; \
BQNFFIEnt* arr=t->a; usz ia=t->ia; \
if (t->ty == cty_struct) { \
ia--; \
if (arr[ia].structData!=NULL) { \
PTR(arr[ia].structData); \
} \
} \
for (usz i = 0; i < ia; i++) OBJ(arr[i].o);
DEF_FREE(ffiType) { DEF_FREE(ffiType) {
usz ia = PIA((BQNFFIType*)x); FFI_TYPE_FLDS(dec, ptr_dec);
for (usz i = 0; i < ia; i++) dec(((BQNFFIType*)x)->a[i].o);
} }
void ffiType_visit(Value* x) { void ffiType_visit(Value* x) {
usz ia = PIA((BQNFFIType*)x); FFI_TYPE_FLDS(mm_visit, mm_visitP);
for (usz i = 0; i < ia; i++) mm_visit(((BQNFFIType*)x)->a[i].o);
} }
void ffiType_print(FILE* f, B x) { void ffiType_print(FILE* f, B x) {
BQNFFIType* t = c(BQNFFIType,x); BQNFFIType* t = c(BQNFFIType,x);
fprintf(f, "cty_%d⟨", t->ty); fprintf(f, "cty_%d⟨", t->ty);
for (usz i=0, ia=PIA(t); i<ia; i++) { usz ia = t->ia;
if (t->ty==cty_struct) ia--;
for (usz i=0; i<ia; i++) {
if (i) fprintf(f, ", "); if (i) fprintf(f, ", ");
printFFIType(f, t->a[i].o); printFFIType(f, t->a[i].o);
} }

View File

@ -190,7 +190,43 @@ uint64_t pick_u64(uint64_t* arr, int idx) {
} }
typedef struct {
uint8_t u8v;
int32_t i32v;
int16_t u16v;
uint64_t u64v;
double f64v;
} S1;
int16_t thirdMember(S1 s) {
return s.u16v;
}
S1 incMembers(S1 s) {
s.u8v++;
s.u16v++;
s.i32v++;
s.u64v++;
s.f64v++;
return s;
}
typedef struct {
S1 a, b;
} S2;
S1 printAndInc(S1 s) {
s = incMembers(s);
printf("%u %d %d %lx %.17g\n", s.u8v, s.i32v, s.u16v, s.u64v, s.f64v);
return s;
}
void incMany(S2* list, uint64_t count) {
for (uint64_t i = 0; i < count; i++) {
list[i].a = printAndInc(list[i].a);
list[i].b = printAndInc(printAndInc(list[i].b));
}
}
int plusone(int x) { int plusone(int x) {
return x + 1; return x + 1;

View File

@ -72,6 +72,12 @@ f ↩ "lib.so" •FFI ⟨"u64:i8","pick_u64",">*u64:i8",">𝕨i32"⟩ ⋄ •Sho
f "lib.so" •FFI "u64:i8","pick_u64",">*u64:i8",">𝕨i32" •Show @+3 F "000000001234560011122100abacabad"-@ f "lib.so" •FFI "u64:i8","pick_u64",">*u64:i8",">𝕨i32" •Show @+3 F "000000001234560011122100abacabad"-@
f "lib.so" •FFI "u64", "pick_u64",">*u64:i8",">𝕨i32" •Show 1 F "000000001234560011122100"-'0' f "lib.so" •FFI "u64", "pick_u64",">*u64:i8",">𝕨i32" •Show 1 F "000000001234560011122100"-'0'
Section "# structs"
s1 "{u8,i32,i16,u64:u16,f64}" s2 "{"s1","s1"}"
f "lib.so" •FFI "i16", "thirdMember", ">"s1 •Show F 200, 2e9, ¯30000, 1234, 3.25
f "lib.so" •FFI s1, "incMembers", ">"s1 •Show F 200, 2e9, ¯30000, 1234, 3.25
f "lib.so" •FFI "&", "incMany", "&"s2, "u64" •Show¨ F 036+3<01+2<200, 2e9, ¯30000, 1234, 3.25, 3
Section "# self-ffi" Section "# self-ffi"
•term.Flush@ •term.Flush@
f @ •FFI "i32", "putchar", ">i32" F¨ 10˜"text"-@ f @ •FFI "i32", "putchar", ">i32" F¨ 10˜"text"-@

View File

@ -88,6 +88,28 @@ ff7fdfefefdf7bb4 ff7fdfefefdf7bb4 fefffdfff7ffbffb bffff7fffdfffeff
"abacabad" "abacabad"
6618611909121 6618611909121
# structs
¯30000
⟨ 201 2000000001 ¯29999 ⟨ 2 2 3 4 ⟩ 4.25 ⟩
201 2000000001 -29999 4000300020002 4.25
202 2000000002 -29998 5000400030003 5.25
203 2000000003 -29997 5000400030004 6.25
204 2000000004 -29996 7000600050005 7.25
205 2000000005 -29995 8000700060006 8.25
206 2000000006 -29994 8000700060007 9.25
207 2000000007 -29993 a000900080008 10.25
208 2000000008 -29992 b000a00090009 11.25
209 2000000009 -29991 b000a0009000a 12.25
┌─
· ⟨ 201 2000000001 ¯29999 ⟨ 2 2 3 4 ⟩ 4.25 ⟩ ⟨ 203 2000000003 ¯29997 ⟨ 4 3 4 5 ⟩ 6.25 ⟩
┌─
· ⟨ 204 2000000004 ¯29996 ⟨ 5 5 6 7 ⟩ 7.25 ⟩ ⟨ 206 2000000006 ¯29994 ⟨ 7 6 7 8 ⟩ 9.25 ⟩
┌─
· ⟨ 207 2000000007 ¯29993 ⟨ 8 8 9 10 ⟩ 10.25 ⟩ ⟨ 209 2000000009 ¯29991 ⟨ 10 9 10 11 ⟩ 12.25 ⟩
# self-ffi # self-ffi
text text
'𝕩' '𝕩'