support passing pointer objects to typed arguments

This commit is contained in:
dzaima 2024-02-05 01:19:46 +02:00
parent a4c0424931
commit 102874c43f
2 changed files with 27 additions and 8 deletions

View File

@ -682,6 +682,14 @@ static NOINLINE B ty_fmt(B o) {
STATIC_GLOBAL B ffiObjsGlobal;
static void genObj_ptr(void* res, B c, B expEl) {
B h = ptrobj_checkget(c);
#if FFI_CHECKS
if (!ptrty_equal(ptrh_type(h), expEl)) thrF("FFI: Pointer object type isn't compatible with argument type");
#endif
ffiObjsGlobal = vec_addN(ffiObjsGlobal, incG(c));
*(void**)res = ptrh_ptr(h);
}
void genObj(B o, B c, bool anyMut, void* ptr) { // doesn't consume
// printFFIType(stdout,o); printf(" = "); printI(c); printf("\n");
if (isC32(o)) { // scalar
@ -706,6 +714,7 @@ void genObj(B o, B c, bool anyMut, void* ptr) { // doesn't consume
if (t->ty==cty_ptr || t->ty==cty_tlarr) { // *any / &any
B e = t->a[0].o;
if (isAtm(c)) {
if (isNsp(c)) { genObj_ptr(ptr, c, e); return; }
thrF("FFI: Expected array or pointer object corresponding to %R", ty_fmt(o));
}
usz ia = IA(c);
@ -744,23 +753,27 @@ void genObj(B o, B c, bool anyMut, void* ptr) { // doesn't consume
B o2 = t->a[0].o;
u8 reT = t->a[0].reType;
u8 reW = t->a[0].reWidth;
if (isC32(o2)) { // scalar:any
if (isC32(o2)) { // scalar:any (incl. *:any)
u8 et = o2cG(o2);
bool eptr = et==sty_ptr;
u8 mul = (sty_w[et]*8) >> reW;
if (!isArr(c)) thrF("FFI: Expected array corresponding to %R", ty_fmt(o));
if (IA(c) != mul) thrF("FFI: Bad array corresponding to %R: expected %s elements, got %s", ty_fmt(o), (usz)mul, IA(c));
if (eptr && isNsp(c)) { genObj_ptr(ptr, c, o2); return; }
if (eptr) ffiObjsGlobal = vec_addN(ffiObjsGlobal, m_i32(0));
if (isAtm(c)) thrF("FFI: Expected array%S corresponding to %R", eptr?" or pointer object":"", ty_fmt(o));
if (IA(c) != mul) thrF("FFI: Bad array%S corresponding to %R: expected %s elements, got %s", eptr?" or pointer object":"", ty_fmt(o), (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
BQNFFIType* t2 = c(BQNFFIType, o2);
B ore = t2->a[0].o;
if (isNsp(c)) { genObj_ptr(ptr, c, ore); return; }
assert(t2->ty==cty_ptr && isC32(ore)); // we shouldn't be generating anything else
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 %R", ty_fmt(o));
if (!isArr(c)) thrF("FFI: Expected array or pointer object corresponding to %R", ty_fmt(o));
if (mul && (IA(c) & (mul-1)) != 0) thrF("FFI: Bad array corresponding to %R: expected a multiple of %s elements, got %s", ty_fmt(o), (usz)mul, IA(c));
incG(c); B cG;
@ -852,7 +865,7 @@ B buildObj(BQNFFIEnt ent, bool anyMut, B* objs, usz* objPos) {
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);
case sty_i8: case sty_i16: case sty_i32: case sty_f64: return inc(f);
case sty_u8: return readU8Bits(f);
case sty_u16: return readU16Bits(f);
case sty_u32: return readU32Bits(f);
@ -874,7 +887,7 @@ B buildObj(BQNFFIEnt ent, bool anyMut, B* objs, usz* objPos) {
} else return m_f64(0);
} else if (t->ty==cty_repr) { // any:any
B o2 = t->a[0].o;
if (isC32(o2)) return m_f64(0); // scalar:any
if (isC32(o2)) return o2cG(o2)==sty_ptr? objs[(*objPos)++] : m_f64(0); // scalar:any
BQNFFIType* t2 = c(BQNFFIType,o2); // *scalar:any / &scalar:any
assert(t2->ty == cty_ptr);

View File

@ -146,7 +146,7 @@
# 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: Expected array or pointer object 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
@ -154,7 +154,7 @@
!"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: Expected array or pointer object 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
@ -193,6 +193,7 @@
%USE Walloc {{𝕊al: p"{i16,i16,i16,i64}" Al 99 p.Write ¯410000¯300007e12 s-{CpyA 0˜˜𝕩}´ p.Field 2, p Cpy p.Add 1, p, s p.Read¨ 2}} %% ¯410000¯300007e12, ¯41000000
%USE Walloc {{𝕊al: p"{i32,{i64,i64}}" Al 999 {𝕩 p.Write 𝕩×10,𝕩×2030}¨ 4 ((p.Field 1).Field 0).Read¨ 4 }} %% 20×4
!"Cannot get a field of a pointer to a scalar" % %USE WallocE {{𝕊al: ("i32" Al 99).Field 0}}
%USE Walloc {{𝕊al: p"i16" Al 99 raw Cpy 0˜˜p.Add 3 cpy2@•FFI"*i16""memcpy""*:i8""*:i8"size_t p.Sub Cpy2 rawraw0 }} %% ¯3
# garbage arguments
!"Expected integer, got character" % %USE WallocE {{𝕊al: p"i8" Al 1 p.Add '!'}}
@ -257,6 +258,11 @@
0 %USE TyEq "*{*}", "*{i8}"
0 %USE TyEq "*{i8}", "*{*}"
# passing pointer objects as arguments
!"FFI: Pointer object type isn't compatible with argument type" % %USE WallocE {{𝕊al: f @•FFI"""bqn_init"">*i8" p"i16" Al 10 F p}}
%USE Walloc {{𝕊al: p "i16" Al 99 p.Write¨˜ 10 a (p.Add 10).Cast"i16:c8" f@•FFI"*:i8""memcpy""&i16:c8""*i16:c8"size_t ! a 1F a, p.Cast"", 8 p.Read¨ 20}} %% 10, 4, 60
%USE Walloc {{𝕊al: p "i16" Al 99 p.Write¨˜ 10 Cpy (p.Add 10).Cast"i16:c8", p.Cast"", 8 p.Read¨ 20}} %% 10, 4, 60
%USE Walloc {{𝕊al: p "i16" Al 99 p.Write¨˜ 10 a (p.Add 10).Cast"i16:c8" f@•FFI"*:i8""memcpy""&i16" "*:i8" size_t ! a 1F a, p.Cast"", 8 p.Read¨ 20}} %% 10, 4, 60
# !"FFI: Unimplemented result type" % @•FFI"*i32"‿"bqn_init"
# !"FFI: Unimplemented result type" % @•FFI"&i32"‿"bqn_init"