diff --git a/src/ffi.c b/src/ffi.c index 3804a261..e25ca2a2 100644 --- a/src/ffi.c +++ b/src/ffi.c @@ -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); diff --git a/test/cases/ffi.bqn b/test/cases/ffi.bqn index fe310cc0..1d87732c 100644 --- a/test/cases/ffi.bqn +++ b/test/cases/ffi.bqn @@ -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 128⥊1 @@ -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 ¯4‿10000‿¯30000‿7e12 ⋄ s←-○{CpyA 0∾˜⋈˜𝕩}´ ⟨p.Field 2, p⟩ ⋄ Cpy ⟨p.Add 1, p, s⟩ ⋄ p.Read¨ ↕2}} %% ⟨¯4‿10000‿¯30000‿7e12, ¯4‿10000‿0‿0⟩ %USE Walloc {{𝕊al: p←"{i32,{i64,i64}}" Al 999 ⋄ {𝕩 p.Write ⟨𝕩×10,𝕩×20‿30⟩}¨ ↕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 raw‿raw‿0 }} %% ¯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 ≡ 1⊑F ⟨a, p.Cast"", 8⟩ ⋄ p.Read¨ ↕20}} %% ∾⟨↕10, ↕4, 6⥊0⟩ +%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, 6⥊0⟩ +%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 ≡ 1⊑F ⟨a, p.Cast"", 8⟩ ⋄ p.Read¨ ↕20}} %% ∾⟨↕10, ↕4, 6⥊0⟩ # !"FFI: Unimplemented result type" % @•FFI"*i32"‿"bqn_init" # !"FFI: Unimplemented result type" % @•FFI"&i32"‿"bqn_init"