result & argument position selection

This commit is contained in:
dzaima 2022-05-21 23:42:06 +03:00
parent af3c6b7857
commit 1a8ee67d41

133
src/ffi.c
View File

@ -122,6 +122,9 @@ typedef struct BoundFn {
struct NFn; struct NFn;
void* w_c1; void* w_c1;
void* w_c2; void* w_c2;
#if FFI==2
i32 mutCount;
#endif
} BoundFn; } BoundFn;
NFnDesc* boundFnDesc; NFnDesc* boundFnDesc;
NFnDesc* foreignFnDesc; NFnDesc* foreignFnDesc;
@ -178,8 +181,11 @@ typedef struct BQNFFIEnt {
#if FFI==2 #if FFI==2
ffi_type t; ffi_type t;
#endif #endif
u8 extra; // generic ffi_parseType ffi_parseTypeStr cty_ptr
u8 extra2; union { u8 extra; u8 onW; u8 canRetype; u8 mutPtr; };
union { u8 extra2; u8 mutates; /*mutates*/ };
union { u8 extra3; u8 wholeArg; };
union { u8 extra4; u8 resSingle; };
} BQNFFIEnt; } BQNFFIEnt;
typedef struct BQNFFIType { typedef struct BQNFFIType {
struct Value; struct Value;
@ -239,12 +245,12 @@ static u32 readUInt(u32** p) {
*p = c; *p = c;
return r; return r;
} }
BQNFFIEnt ffi_parseTypeStr(u32** src, bool inPtr) { // parse actual type; res.extra: whether should parse a :abc; res.extra2: whether has any mutation BQNFFIEnt ffi_parseTypeStr(u32** src, bool inPtr) { // parse actual type
u32* c = *src; u32* c = *src;
u32 c0 = *c++; u32 c0 = *c++;
ffi_type rt; ffi_type rt;
B ro; B ro;
bool parseRepr=false, subParseRepr=false, mut=false; bool parseRepr=false, canRetype=false, mut=false;
switch (c0) { switch (c0) {
default: default:
thrM("FFI: Error parsing type"); thrM("FFI: Error parsing type");
@ -266,7 +272,7 @@ BQNFFIEnt ffi_parseTypeStr(u32** src, bool inPtr) { // parse actual type; res.ex
ro = m_c32(scty); ro = m_c32(scty);
} }
parseRepr = !inPtr; parseRepr = !inPtr;
subParseRepr = inPtr; canRetype = inPtr;
break; break;
case 'a': case 'a':
@ -278,10 +284,10 @@ BQNFFIEnt ffi_parseTypeStr(u32** src, bool inPtr) { // parse actual type; res.ex
if (c0=='&') mut = true; if (c0=='&') mut = true;
BQNFFIEnt* rp; ro = m_bqnFFIType(&rp, cty_ptr, 1); BQNFFIEnt* rp; ro = m_bqnFFIType(&rp, cty_ptr, 1);
rp[0] = ffi_parseTypeStr(&c, true); rp[0] = ffi_parseTypeStr(&c, true);
mut|= rp[0].extra2; mut|= rp[0].mutates;
parseRepr = rp[0].extra; parseRepr = rp[0].canRetype;
rp[0].extra = c0=='&'; rp[0].mutPtr = c0=='&';
rt = ffi_type_pointer; rt = ffi_type_pointer;
break; break;
} }
@ -298,34 +304,48 @@ BQNFFIEnt ffi_parseTypeStr(u32** src, bool inPtr) { // parse actual type; res.ex
rp[0] = (BQNFFIEnt){.o=roP, .t=rt, .extra=t, .extra2=63-CLZ(n)}; rp[0] = (BQNFFIEnt){.o=roP, .t=rt, .extra=t, .extra2=63-CLZ(n)};
} }
*src = c; *src = c;
return (BQNFFIEnt){.t=rt, .o=ro, .extra=subParseRepr, .extra2=mut}; return (BQNFFIEnt){.t=rt, .o=ro, .canRetype=canRetype, .extra2=mut};
} }
BQNFFIEnt ffi_parseType(B arg, bool forRes) { // doesn't consume; parse argument side & other global decorators; .extra=side, .extra2=contains mutation BQNFFIEnt ffi_parseType(B arg, bool forRes) { // doesn't consume; parse argument side & other global decorators
vfyStr(arg, "FFI", "type"); vfyStr(arg, "FFI", "type");
usz ia = a(arg)->ia; usz ia = a(arg)->ia;
if (ia==0) { if (ia==0) {
if (!forRes) thrM("FFI: Argument type empty"); if (!forRes) thrM("FFI: Argument type empty");
return (BQNFFIEnt){.t = ffi_type_void, .o=m_c32(sty_void)}; return (BQNFFIEnt){.t = ffi_type_void, .o=m_c32(sty_void), .resSingle=false};
} }
MAKE_MUT(tmp, ia+1); mut_init(tmp, el_c32); MUTG_INIT(tmp); MAKE_MUT(tmp, ia+1); mut_init(tmp, el_c32); MUTG_INIT(tmp);
mut_copyG(tmp, 0, arg, 0, ia); mut_copyG(tmp, 0, arg, 0, ia);
mut_setG(tmp, ia, m_c32(0)); mut_setG(tmp, ia, m_c32(0));
u32* xp = tmp->ac32; u32* xp = tmp->ac32;
u32* xpN = xp + ia; u32* xpN = xp + ia;
u8 side; BQNFFIEnt t;
if (*xp == U'𝕩') side = 2; if (xp[0]=='&' && xp[1]=='\0') {
else if (*xp == U'𝕨') side = 1; t = (BQNFFIEnt){.t = ffi_type_void, .o=m_c32(sty_void), .resSingle=true};
else side = 0; } else {
if (forRes && side) thrM("FFI: Argument side cannot be specified for the result"); u8 side = 0;
if (side) xp++; bool whole = false;
while (true) {
if (*xp == U'𝕩') { if (side) thrM("FFI: Multiple occurrences of argument side specified"); side = 1; }
else if (*xp == U'𝕨') { if (side) thrM("FFI: Multiple occurrences of argument side specified"); side = 2; }
else if (*xp == U'>') { if (whole) thrM("FFI: Multiple occurrences of '>'"); whole = true; }
else break;
xp++;
}
if (forRes && side) thrM("FFI: Argument side cannot be specified for the result");
if (side) side--;
else side = 0;
BQNFFIEnt t = ffi_parseTypeStr(&xp, false); t = ffi_parseTypeStr(&xp, false);
// print(arg); printf(": "); printFFIType(stdout, t.o); printf("\n"); // print(arg); printf(": "); printFFIType(stdout, t.o); printf("\n");
if (xp!=xpN) thrM("FFI: Bad type descriptor"); if (xp!=xpN) thrM("FFI: Bad type descriptor");
t.extra = side; t.onW = side;
// keep extra2 as "contains mutation" // keep .mutates
t.wholeArg = whole;
t.resSingle = false;
}
mut_pfree(tmp, 0); mut_pfree(tmp, 0);
return t; return t;
} }
@ -396,7 +416,7 @@ usz genObj(BQNFFIEnt ent, B c, bool anyMut) {
B cG; B cG;
if (!isArr(c)) thrF("FFI: Expected array corresponding to *%S", sty_names[o2cu(e)]); if (!isArr(c)) thrF("FFI: Expected array corresponding to *%S", sty_names[o2cu(e)]);
usz ia = a(c)->ia; usz ia = a(c)->ia;
bool mut = t->a[0].extra; bool mut = t->a[0].mutPtr;
switch(o2cu(e)) { default: thrF("FFI: Unimplemented pointer to %S", sty_names[o2cu(e)]); switch(o2cu(e)) { default: thrF("FFI: Unimplemented pointer to %S", sty_names[o2cu(e)]);
case sty_i8: cG = mut? taga(cpyI8Arr (c)) : toI8Any (c); break; case sty_i8: cG = mut? taga(cpyI8Arr (c)) : toI8Any (c); break;
case sty_i16: cG = mut? taga(cpyI16Arr(c)) : toI16Any(c); break; case sty_i16: cG = mut? taga(cpyI16Arr(c)) : toI16Any(c); break;
@ -433,7 +453,7 @@ usz genObj(BQNFFIEnt ent, B c, bool anyMut) {
assert(t2->ty==cty_ptr && isC32(ore)); // we shouldn't be generating anything else assert(t2->ty==cty_ptr && isC32(ore)); // we shouldn't be generating anything else
inc(c); inc(c);
B cG; B cG;
bool mut = t->a[0].extra; bool mut = t->a[0].mutPtr;
if (mut) { if (mut) {
Arr* cGp; Arr* cGp;
switch(wre) { default: UD; switch(wre) { default: UD;
@ -453,15 +473,15 @@ usz genObj(BQNFFIEnt ent, B c, bool anyMut) {
return pos; return pos;
} }
B buildObj(BQNFFIEnt ent, B c, 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);
if (t->ty==cty_ptr) { // *any / &any if (t->ty==cty_ptr) { // *any / &any
B e = t->a[0].o; B e = t->a[0].o;
B f = objs[(*objPos)++]; B f = objs[(*objPos)++];
bool mut = t->a[0].extra; bool mut = t->a[0].mutPtr;
if (mut) { if (mut) {
usz ia = a(c)->ia; usz ia = a(f)->ia;
switch(o2cu(e)) { default: UD; switch(o2cu(e)) { default: UD;
case sty_i8: case sty_i16: case sty_i32: case sty_f64: return inc(f); case sty_i8: case sty_i16: case sty_i32: case sty_f64: return inc(f);
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_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; }
@ -475,7 +495,7 @@ B buildObj(BQNFFIEnt ent, B c, bool anyMut, B* objs, usz* objPos) {
if (isC32(o2)) return m_f64(0); // scalar:any if (isC32(o2)) return m_f64(0); // scalar:any
// *scalar:any / &scalar:any // *scalar:any / &scalar:any
B f = objs[(*objPos)++]; B f = objs[(*objPos)++];
bool mut = t->a[0].extra; bool mut = t->a[0].mutPtr;
if (!mut) return m_f64(0); if (!mut) return m_f64(0);
return inc(f); return inc(f);
} else thrM("FFI: Unimplemented type"); } else thrM("FFI: Unimplemented type");
@ -496,13 +516,19 @@ B libffiFn_c2(B t, B w, B x) {
ffiTmpAA(argn * sizeof(u32)); ffiTmpAA(argn * sizeof(u32));
#define argOffs ((u32*)ffiTmpS) #define argOffs ((u32*)ffiTmpS)
SGetU(x) u32 flags = (u64)c->w_c1;
Arr* wa; AS2B wf;
Arr* xa; AS2B xf;
if (flags&1) { wa=a(w); wf=TIv(wa,getU); }
if (flags&2) { xa=a(x); xf=TIv(xa,getU); }
i32 idxs[2] = {0,0};
BQNFFIEnt* ents = c(BQNFFIType,argObj)->a; BQNFFIEnt* ents = c(BQNFFIType,argObj)->a;
usz mutArgs = 0;
for (usz i = 0; i < argn; i++) { for (usz i = 0; i < argn; i++) {
bool mut = ents[i+1].extra2; BQNFFIEnt e = ents[i+1];
argOffs[i] = genObj(ents[i+1], GetU(x,i), mut); B o = e.wholeArg? (e.onW? w : x) : (e.onW? wf : xf)(e.onW?wa:xa, idxs[e.onW]++);
mutArgs+= mut; argOffs[i] = genObj(e, o, e.extra2);
} }
u32 resPos; u32 resPos;
@ -542,16 +568,26 @@ B libffiFn_c2(B t, B w, B x) {
} else UD; } else UD;
mm_free((Value*)ffiTmpObj); mm_free((Value*)ffiTmpObj);
i32 mutArgs = c->mutCount;
if (mutArgs) { if (mutArgs) {
usz objPos = 0; usz objPos = 0;
M_HARR(ra, mutArgs+(resVoid? 0 : 1)); bool resSingle = flags&4;
if (!resVoid) HARR_ADDA(ra, r); if (resSingle) {
for (usz i = 0; i < argn; i++) { for (usz i = 0; i < argn; i++) {
bool mut = ents[i+1].extra2; BQNFFIEnt e = ents[i+1];
B c = buildObj(ents[i+1], GetU(x,i), mut, harr_ptr(ffiObjs), &objPos); B c = buildObj(e, e.mutates, harr_ptr(ffiObjs), &objPos);
if (mut) HARR_ADDA(ra, c); if (e.mutates) r = c;
}
} else {
M_HARR(ra, mutArgs+(resVoid? 0 : 1));
if (!resVoid) HARR_ADDA(ra, r);
for (usz i = 0; i < argn; i++) {
BQNFFIEnt e = ents[i+1];
B c = buildObj(e, e.mutates, harr_ptr(ffiObjs), &objPos);
if (e.mutates) HARR_ADDA(ra, c);
}
r = HARR_FV(ra);
} }
r = HARR_FV(ra);
} }
dec(w); dec(x); dec(ffiObjs); dec(w); dec(x); dec(ffiObjs);
@ -583,11 +619,21 @@ B ffiload_c2(B t, B w, B x) {
#if FFI==2 #if FFI==2
BQNFFIEnt* args; B argObj = m_bqnFFIType(&args, 255, argn+1); BQNFFIEnt* args; B argObj = m_bqnFFIType(&args, 255, argn+1);
args[0] = tRes; args[0] = tRes;
for (usz i = 0; i < argn; i++) args[i+1] = ffi_parseType(GetU(x,i+2), false); bool one [2]={0,0};
bool many[2]={0,0};
i32 mutCount = 0;
for (usz i = 0; i < argn; i++) {
BQNFFIEnt e = args[i+1] = ffi_parseType(GetU(x,i+2), false);
(e.wholeArg? one : many)[e.extra] = true;
if (e.mutates) mutCount++;
}
if (one[0] && many[0]) thrM("FFI: Multiple arguments for 𝕩 specified, but one has '>'");
if (one[1] && many[1]) thrM("FFI: Multiple arguments for 𝕨 specified, but one has '>'");
#else #else
for (usz i = 0; i < argn; i++) ffi_parseType(GetU(x,i+2), false); for (usz i = 0; i < argn; i++) ffi_parseType(GetU(x,i+2), false);
(void)tRes; (void)tRes;
#endif #endif
if (tRes.resSingle && mutCount!=1) thrF("FFI: Return was \"&\", but found %i mutated variables", mutCount);
char* ws = toCStr(w); char* ws = toCStr(w);
void* dl = dlopen(ws, RTLD_NOW); void* dl = dlopen(ws, RTLD_NOW);
@ -618,7 +664,10 @@ B ffiload_c2(B t, B w, B x) {
ffi_status s = ffi_prep_cif((ffi_cif*)cif->data, FFI_DEFAULT_ABI, argn, &args[0].t, argsRawArr); ffi_status s = ffi_prep_cif((ffi_cif*)cif->data, FFI_DEFAULT_ABI, argn, &args[0].t, argsRawArr);
if (s!=FFI_OK) thrM("FFI: Error preparing call interface"); if (s!=FFI_OK) thrM("FFI: Error preparing call interface");
// mm_free(argsRaw) // mm_free(argsRaw)
return m_ffiFn(foreignFnDesc, m_hVec3(argObj, tag(cif, OBJ_TAG), tag(argsRaw, OBJ_TAG)), libffiFn_c1, libffiFn_c2, NULL, sym); u32 flags = many[1] | many[0]<<1 | tRes.resSingle<<2;
B r = m_ffiFn(foreignFnDesc, m_hVec3(argObj, tag(cif, OBJ_TAG), tag(argsRaw, OBJ_TAG)), libffiFn_c1, libffiFn_c2, (void*)(u64)flags, sym);
c(BoundFn,r)->mutCount = mutCount;
return r;
#endif #endif
} }