From a601ba6a76e8fb507e0c7d962214324662941057 Mon Sep 17 00:00:00 2001 From: dzaima Date: Wed, 11 May 2022 22:28:18 +0300 Subject: [PATCH] very unfinished FFI --- include/bqnffi.h | 89 ++++++ makefile | 55 ++-- src/builtins.h | 1 + src/builtins/sysfn.c | 5 +- src/ffi.c | 640 +++++++++++++++++++++++++++++++++++++++++++ src/ffi.h | 94 +++++++ src/h.h | 11 +- src/load.c | 3 +- src/opt/single.c | 1 + src/utils/talloc.h | 5 +- 10 files changed, 874 insertions(+), 30 deletions(-) create mode 100644 include/bqnffi.h create mode 100644 src/ffi.c create mode 100644 src/ffi.h diff --git a/include/bqnffi.h b/include/bqnffi.h new file mode 100644 index 00000000..f8b6736c --- /dev/null +++ b/include/bqnffi.h @@ -0,0 +1,89 @@ +#include +#include +#include + +typedef uint64_t BQNV; + +#ifdef __cplusplus +extern "C" { +#endif + +void bqn_free(BQNV v); + +double bqn_toF64 (BQNV v); // includes bqn_free(v) +uint32_t bqn_toChar(BQNV v); // includes bqn_free(v) +double bqn_readF64 (BQNV v); // doesn't include bqn_free(v) +uint32_t bqn_readChar(BQNV v); // doesn't include bqn_free(v) + +// invoke BQN function +BQNV bqn_call1(BQNV f, BQNV x); +BQNV bqn_call2(BQNV f, BQNV w, BQNV x); + +// evaluate BQN code in a fresh environment +BQNV bqn_eval(BQNV src); +BQNV bqn_evalCStr(char* str); // evaluates the null-terminated UTF8-encoded str; equal to `BQNV s = bqn_makeUTF8Str(str, strlen(str)); result = bqn_eval(s); bqn_free(s);` + + +// read array data +size_t bqn_bound(BQNV a); // aka product of shape, ×´≢a +size_t bqn_rank(BQNV a); +void bqn_shape(BQNV a, size_t* buf); // writes bqn_rank(a) items in buf +BQNV bqn_pick(BQNV a, size_t pos); + +// read all elements of `a` into the specified buffer +void bqn_readI8Arr (BQNV a, int8_t* buf); +void bqn_readI16Arr(BQNV a, int16_t* buf); +void bqn_readI32Arr(BQNV a, int32_t* buf); +void bqn_readF64Arr(BQNV a, double* buf); +void bqn_readC8Arr (BQNV a, uint8_t* buf); +void bqn_readC16Arr(BQNV a, uint16_t* buf); +void bqn_readC32Arr(BQNV a, uint32_t* buf); +void bqn_readObjArr(BQNV a, BQNV* buf); + + +// create objects +BQNV bqn_makeF64(double d); +BQNV bqn_makeChar(uint32_t c); +BQNV bqn_makeI8Arr (size_t rank, size_t* shape, int8_t* data); +BQNV bqn_makeI16Arr(size_t rank, size_t* shape, int16_t* data); +BQNV bqn_makeI32Arr(size_t rank, size_t* shape, int32_t* data); +BQNV bqn_makeF64Arr(size_t rank, size_t* shape, double* data); +BQNV bqn_makeC8Arr (size_t rank, size_t* shape, uint8_t* data); +BQNV bqn_makeC16Arr(size_t rank, size_t* shape, uint16_t* data); +BQNV bqn_makeC32Arr(size_t rank, size_t* shape, uint32_t* data); +BQNV bqn_makeObjArr(size_t rank, size_t* shape, BQNV* data); // frees the taken elements of data + +BQNV bqn_makeI8Vec (size_t len, int8_t* data); +BQNV bqn_makeI16Vec(size_t len, int16_t* data); +BQNV bqn_makeI32Vec(size_t len, int32_t* data); +BQNV bqn_makeF64Vec(size_t len, double* data); +BQNV bqn_makeC8Vec (size_t len, uint8_t* data); +BQNV bqn_makeC16Vec(size_t len, uint16_t* data); +BQNV bqn_makeC32Vec(size_t len, uint32_t* data); +BQNV bqn_makeObjVec(size_t len, BQNV* data); // frees the taken elements of data +BQNV bqn_makeUTF8Str(size_t len, char* str); + +typedef BQNV (*bqn_boundFn1)(BQNV obj, BQNV x); +typedef BQNV (*bqn_boundFn2)(BQNV obj, BQNV w, BQNV x); + +// when called, 1st arg to `f` will be `obj` +BQNV bqn_makeBoundFn1(bqn_boundFn1 f, BQNV obj); +BQNV bqn_makeBoundFn2(bqn_boundFn2 f, BQNV obj); + + +// direct (zero copy) array item access +typedef enum { elt_i8, elt_i16, elt_i32, elt_f64, elt_c8, elt_c16, elt_c32, elt_unk } BQNElType; +BQNElType bqn_directType(BQNV a); +// can only use the functions below if bqn_elType returns the corresponding type +// a valid implementation of bqn_elType would be to always return elt_unk, thus disallowing the use of direct access entirely +int8_t* bqn_directI8 (BQNV a); +int16_t* bqn_directI16(BQNV a); +int32_t* bqn_directI32(BQNV a); +double* bqn_directF64(BQNV a); +uint8_t* bqn_directC8 (BQNV a); +uint16_t* bqn_directC16(BQNV a); +uint32_t* bqn_directC32(BQNV a); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/makefile b/makefile index de697fa2..d5658ac5 100644 --- a/makefile +++ b/makefile @@ -37,32 +37,48 @@ c: @${MAKE} custom=1 run_incremental_0 # compiler setup -i_CC = clang -i_PIE = -no-pie -i_LD_LIBS = -lm -OUTPUT = BQN +i_CC := clang +i_PIE := -no-pie +i_LD_LIBS := -lm +i_FFI := 2 +i_singeli := 0 +OUTPUT := BQN ifeq ($(origin CC),command line) - i_CC = $(CC) - custom = 1 -endif -ifeq ($(origin PIE),command line) - i_PIE = $(PIE) - custom = 1 -endif -ifeq ($(origin LD_LIBS),command line) - i_LD_LIBS = $(LD_LIBS) + i_CC := $(CC) custom = 1 endif ifeq ($(origin singeli),command line) - i_singeli = $(singeli) + i_singeli := $(singeli) + custom = 1 +endif +ifeq ($(origin FFI),command line) + i_FFI := $(FFI) + custom = 1 +endif +ifneq ($(i_FFI),0) + i_LD_LIBS += -ldl -rdynamic +endif +ifeq ($(i_FFI),2) + i_LD_LIBS += -lffi +endif +ifeq ($(origin LD_LIBS),command line) + i_LD_LIBS := $(LD_LIBS) + custom = 1 +endif +ifeq ($(origin PIE),command line) + i_PIE := $(PIE) custom = 1 endif ifeq ($(origin f),command line) custom = 1 +else + f:= endif ifeq ($(origin lf),command line) custom = 1 +else + lf:= endif ifeq ($(origin CCFLAGS),command line) custom = 1 @@ -78,14 +94,7 @@ else NOWARN = -Wno-parentheses endif -ifeq (${i_singeli}, 1) - SINGELIFLAGS = '-DSINGELI' -else - i_singeli = 0 - SINGELIFLAGS = -endif - -ALL_CC_FLAGS = -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) $(f) $(i_f) $(SINGELIFLAGS) $(NOWARN) +ALL_CC_FLAGS = -std=gnu11 -Wall -Wno-unused-function -fms-extensions $(CCFLAGS) $(f) $(i_f) $(NOWARN) -DSINGELI=$(i_singeli) -DFFI=$(i_FFI) ALL_LD_FLAGS = $(LDFLAGS) $(lf) $(i_lf) $(i_PIE) $(i_LD_LIBS) ifneq (${manualJobs},1) @@ -152,7 +161,7 @@ ${bd}/%.o: src/core/%.c @echo $< | cut -c 5- @$(CC_INC) $@.d -o $@ -c $< -base: ${addprefix ${bd}/, load.o main.o rtwrap.o vm.o ns.o nfns.o} +base: ${addprefix ${bd}/, load.o main.o rtwrap.o vm.o ns.o nfns.o ffi.o} ${bd}/%.o: src/%.c @echo $< | cut -c 5- @$(CC_INC) $@.d -o $@ -c $< diff --git a/src/builtins.h b/src/builtins.h index 1e18ca0e..3b88e255 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -12,6 +12,7 @@ /* sysfn.c*/M(repr,"•Repr") M(fmt,"•Fmt") A(asrt,"!") A(casrt,"!") M(out,"•Out") M(show,"•Show") A(bqn,"•BQN") A(sh,"•SH") M(fromUtf8,"•FromUTF8") M(currentError,"•CurrentError") \ /* sysfn.c*/D(cmp,"•Cmp") A(hash,"•Hash") M(unixTime,"•UnixTime") M(monoTime,"•MonoTime") M(delay,"•Delay") M(makeRand,"•MakeRand") M(reBQN,"•ReBQN") M(exit,"•Exit") M(getLine,"•GetLine") \ /* sysfn.c*/M(fName,"•file.Name") \ +/* ffi.c*/D(loadffi,"•LoadFFI") \ /* sysfn.c*/M(tRawMode,"•term.RawMode") M(tFlush,"•term.Flush") M(tCharB,"•term.CharB") M(tCharN,"•term.CharN") M(tOutRaw,"•term.OutRaw") M(tErrRaw,"•term.ErrRaw") \ /* inverse.c*/M(setInvReg, "(SetInvReg)") M(setInvSwap, "(SetInvSwap)") M(nativeInvReg, "(NativeInvReg)") M(nativeInvSwap, "(NativeInvSwap)") \ /*internal.c*/M(itype,"•internal.Type") M(elType,"•internal.ElType") M(refc,"•internal.Refc") M(isPure,"•internal.IsPure") A(info,"•internal.Info") M(heapDump,"•internal.HeapDump") \ diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index 90450a12..b04a8a4d 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -239,7 +239,7 @@ B show_c1(B t, B x) { return x; } -static B vfyStr(B x, char* name, char* arg) { +B vfyStr(B x, char* name, char* arg) { if (isAtm(x) || rnk(x)!=1) thrF("%U: %U must be a character vector", name, arg); if (!elChr(TI(x,elType))) { usz ia = a(x)->ia; @@ -1141,6 +1141,9 @@ B sys_c1(B t, B x) { else if (eqStr(c, U"flines")) cr = m_nfn(fLinesDesc, inc(REQ_PATH)); else if (eqStr(c, U"import")) cr = m_nfn(importDesc, inc(REQ_PATH)); else if (eqStr(c, U"currenterror")) cr = inc(bi_currentError); + #if FFI + else if (eqStr(c, U"loadffi")) cr = inc(bi_loadffi); + #endif else if (eqStr(c, U"state")) { if (q_N(comp_currArgs)) thrM("No arguments present for •state"); cr = m_hVec3(inc(REQ_PATH), inc(REQ_NAME), inc(comp_currArgs)); diff --git a/src/ffi.c b/src/ffi.c new file mode 100644 index 00000000..f166b804 --- /dev/null +++ b/src/ffi.c @@ -0,0 +1,640 @@ +#include "core.h" + +#if FFI +#include "../include/bqnffi.h" +#include "utils/utf.h" +#include "utils/cstr.h" +#include "nfns.h" +#include + +// base interface defs for when GC stuff needs to be added in +static B getB(BQNV v) { + return b(v); +} +static BQNV makeX(B x) { + return x.u; +} +void bqn_free(BQNV v) { + dec(getB(v)); +} +static void freeTagged (BQNV v) { } +#define DIRECT_BQNV 1 + +double bqn_toF64 (BQNV v) { double r = o2fu(getB(v)); freeTagged(v); return r; } +uint32_t bqn_toChar(BQNV v) { uint32_t r = o2cu(getB(v)); freeTagged(v); return r; } +double bqn_readF64 (BQNV v) { return o2fu(getB(v)); } +uint32_t bqn_readChar(BQNV v) { return o2cu(getB(v)); } + +BQNV bqn_call1(BQNV f, BQNV x) { + return makeX(c1(getB(f), inc(getB(x)))); +} +BQNV bqn_call2(BQNV f, BQNV w, BQNV x) { + return makeX(c2(getB(f), inc(getB(w)), inc(getB(x)))); +} + +BQNV bqn_eval(BQNV src) { + return makeX(bqn_exec(inc(getB(src)), bi_N, bi_N)); +} +BQNV bqn_evalCStr(char* str) { + return makeX(bqn_exec(fromUTF8l(str), bi_N, bi_N)); +} + + +size_t bqn_bound(BQNV a) { return a(getB(a))->ia; } +size_t bqn_rank(BQNV a) { return rnk(getB(a)); } +void bqn_shape(BQNV a, size_t* buf) { B b = getB(a); + ur r = rnk(b); + usz* sh = a(b)->sh; + for (usz i = 0; i < r; i++) buf[i] = sh[i]; +} +BQNV bqn_pick(BQNV a, size_t pos) { + return makeX(IGet(getB(a),pos)); +} + +// TODO copy directly with some mut.h thing +void bqn_readI8Arr (BQNV a, i8* buf) { B c = toI8Any (inc(getB(a))); memcpy(buf, i8any_ptr (c), a(c)->ia * 1); dec(c); } +void bqn_readI16Arr(BQNV a, i16* buf) { B c = toI16Any(inc(getB(a))); memcpy(buf, i16any_ptr(c), a(c)->ia * 2); dec(c); } +void bqn_readI32Arr(BQNV a, i32* buf) { B c = toI32Any(inc(getB(a))); memcpy(buf, i32any_ptr(c), a(c)->ia * 4); dec(c); } +void bqn_readF64Arr(BQNV a, f64* buf) { B c = toF64Any(inc(getB(a))); memcpy(buf, f64any_ptr(c), a(c)->ia * 8); dec(c); } +void bqn_readC8Arr (BQNV a, u8* buf) { B c = toC8Any (inc(getB(a))); memcpy(buf, c8any_ptr (c), a(c)->ia * 1); dec(c); } +void bqn_readC16Arr(BQNV a, u16* buf) { B c = toC16Any(inc(getB(a))); memcpy(buf, c16any_ptr(c), a(c)->ia * 2); dec(c); } +void bqn_readC32Arr(BQNV a, u32* buf) { B c = toC32Any(inc(getB(a))); memcpy(buf, c32any_ptr(c), a(c)->ia * 4); dec(c); } +void bqn_readObjArr(BQNV a, BQNV* buf) { B b = getB(a); + usz ia = a(b)->ia; + B* p = arr_bptr(b); + if (p!=NULL) { + for (usz i = 0; i < ia; i++) buf[i] = makeX(inc(p[i])); + } else { + SGet(b) + for (usz i = 0; i < ia; i++) buf[i] = makeX(Get(b, i)); + } +} + + +BQNV bqn_makeF64(double d) { return makeX(m_f64(d)); } +BQNV bqn_makeChar(uint32_t c) { return makeX(m_c32(c)); } + + +static usz calcIA(size_t rank, size_t* shape) { + if (rank>UR_MAX) thrM("Rank too large"); + usz r = 1; + for (size_t i = 0; i < rank; i++) if (mulOn(r, shape[i])) thrM("Size too large"); + return r; +} +static void copyBData(B* r, BQNV* data, usz ia) { + for (size_t i = 0; i < ia; i++) { + BQNV c = data[i]; + #if DIRECT_BQNV + r[i] = getB(c); + #else + r[i] = inc(getB(c)); + bqn_free(c); + #endif + } +} +#define CPYSH(R) usz* sh = arr_shAlloc(R, r0); \ + if (sh) for (size_t i = 0; RARE(i < r0); i++) sh[i] = sh0[i]; + +BQNV bqn_makeI8Arr (size_t r0, size_t* sh0, i8* data) { usz ia=calcIA(r0,sh0); i8* rp; Arr* r = m_i8arrp (&rp,ia); CPYSH(r); memcpy(rp,data,ia*1); return makeX(taga(r)); } +BQNV bqn_makeI16Arr(size_t r0, size_t* sh0, i16* data) { usz ia=calcIA(r0,sh0); i16* rp; Arr* r = m_i16arrp(&rp,ia); CPYSH(r); memcpy(rp,data,ia*2); return makeX(taga(r)); } +BQNV bqn_makeI32Arr(size_t r0, size_t* sh0, i32* data) { usz ia=calcIA(r0,sh0); i32* rp; Arr* r = m_i32arrp(&rp,ia); CPYSH(r); memcpy(rp,data,ia*4); return makeX(taga(r)); } +BQNV bqn_makeF64Arr(size_t r0, size_t* sh0, f64* data) { usz ia=calcIA(r0,sh0); f64* rp; Arr* r = m_f64arrp(&rp,ia); CPYSH(r); memcpy(rp,data,ia*8); return makeX(taga(r)); } +BQNV bqn_makeC8Arr (size_t r0, size_t* sh0, u8* data) { usz ia=calcIA(r0,sh0); u8* rp; Arr* r = m_c8arrp (&rp,ia); CPYSH(r); memcpy(rp,data,ia*1); return makeX(taga(r)); } +BQNV bqn_makeC16Arr(size_t r0, size_t* sh0, u16* data) { usz ia=calcIA(r0,sh0); u16* rp; Arr* r = m_c16arrp(&rp,ia); CPYSH(r); memcpy(rp,data,ia*2); return makeX(taga(r)); } +BQNV bqn_makeC32Arr(size_t r0, size_t* sh0, u32* data) { usz ia=calcIA(r0,sh0); u32* rp; Arr* r = m_c32arrp(&rp,ia); CPYSH(r); memcpy(rp,data,ia*4); return makeX(taga(r)); } +BQNV bqn_makeObjArr(size_t r0, size_t* sh0, BQNV* data) { usz ia=calcIA(r0,sh0); HArr_p r = m_harrUp(ia); CPYSH((Arr*)r.c); copyBData(r.a,data,ia); return makeX(r.b); } + +BQNV bqn_makeI8Vec (size_t len, i8* data) { i8* rp; B r = m_i8arrv (&rp,len); memcpy(rp,data,len*1); return makeX(r); } +BQNV bqn_makeI16Vec(size_t len, i16* data) { i16* rp; B r = m_i16arrv(&rp,len); memcpy(rp,data,len*2); return makeX(r); } +BQNV bqn_makeI32Vec(size_t len, i32* data) { i32* rp; B r = m_i32arrv(&rp,len); memcpy(rp,data,len*4); return makeX(r); } +BQNV bqn_makeF64Vec(size_t len, f64* data) { f64* rp; B r = m_f64arrv(&rp,len); memcpy(rp,data,len*8); return makeX(r); } +BQNV bqn_makeC8Vec (size_t len, u8* data) { u8* rp; B r = m_c8arrv (&rp,len); memcpy(rp,data,len*1); return makeX(r); } +BQNV bqn_makeC16Vec(size_t len, u16* data) { u16* rp; B r = m_c16arrv(&rp,len); memcpy(rp,data,len*2); return makeX(r); } +BQNV bqn_makeC32Vec(size_t len, u32* data) { u32* rp; B r = m_c32arrv(&rp,len); memcpy(rp,data,len*4); return makeX(r); } +BQNV bqn_makeObjVec(size_t len, BQNV* data) { HArr_p r = m_harrUv(len); copyBData(r.a,data,len ); return makeX(r.b); } +BQNV bqn_makeUTF8Str(size_t len, char* str) { return makeX(fromUTF8(str, len)); } + +typedef struct BoundFn { + struct NFn; + void* w_c1; + void* w_c2; +} BoundFn; +NFnDesc* boundFnDesc; +NFnDesc* foreignFnDesc; + +B boundFn_c1(B t, B x) { BoundFn* c = c(BoundFn,t); return getB(((bqn_boundFn1)c->w_c1)(makeX(inc(c->obj)), makeX(x))); } +B boundFn_c2(B t, B w, B x) { BoundFn* c = c(BoundFn,t); return getB(((bqn_boundFn2)c->w_c2)(makeX(inc(c->obj)), makeX(w), makeX(x))); } + +typedef BQNV (*bqn_foreignFn1)(BQNV x); +typedef BQNV (*bqn_foreignFn2)(BQNV w, BQNV x); +B directFn_c1(B t, B x) { BoundFn* c = c(BoundFn,t); return getB(((bqn_foreignFn1)c->w_c1)( makeX(x))); } +B directFn_c2(B t, B w, B x) { BoundFn* c = c(BoundFn,t); return getB(((bqn_foreignFn2)c->w_c2)(makeX(w), makeX(x))); } + +static B m_ffiFn(NFnDesc* desc, B obj, BB2B c1, BBB2B c2, void* wc1, void* wc2) { + BoundFn* r = mm_alloc(sizeof(BoundFn), t_nfn); + nfn_lateInit((NFn*)r, desc); + r->obj = obj; + r->c1 = c1; + r->c2 = c2; + r->w_c1 = wc1; + r->w_c2 = wc2; + return tag(r, FUN_TAG); +} +BQNV bqn_makeBoundFn1(bqn_boundFn1 f, BQNV obj) { return makeX(m_ffiFn(boundFnDesc, inc(getB(obj)), boundFn_c1, c2_bad, f, NULL)); } +BQNV bqn_makeBoundFn2(bqn_boundFn2 f, BQNV obj) { return makeX(m_ffiFn(boundFnDesc, inc(getB(obj)), c1_bad, boundFn_c2, NULL, f)); } + +const static u8 typeMap[] = { + [el_bit] = elt_unk, + [el_B ] = elt_unk, + [el_i8 ] = elt_i8, [el_c8 ] = elt_c8, + [el_i16] = elt_i16, [el_c16] = elt_c16, + [el_i32] = elt_i32, [el_c32] = elt_c32, + [el_f64] = elt_f64, +}; +BQNElType bqn_directType(BQNV a) { + B b = getB(a); + if (!isArr(b)) return elt_unk; + return typeMap[TI(b,elType)]; +} +i8* bqn_directI8 (BQNV a) { return i8any_ptr (getB(a)); } +i16* bqn_directI16(BQNV a) { return i16any_ptr(getB(a)); } +i32* bqn_directI32(BQNV a) { return i32any_ptr(getB(a)); } +f64* bqn_directF64(BQNV a) { return f64any_ptr(getB(a)); } +u8* bqn_directC8 (BQNV a) { return c8any_ptr (getB(a)); } +u16* bqn_directC16(BQNV a) { return c16any_ptr(getB(a)); } +u32* bqn_directC32(BQNV a) { return c32any_ptr(getB(a)); } + +void ffiFn_visit(Value* v) { mm_visit(((BoundFn*)v)->obj); } +DEF_FREE(ffiFn) { dec(((BoundFn*)x)->obj); } + + + + + +#if FFI==2 + +#include +#include "utils/mut.h" +typedef struct BQNFFIEnt { + B o; + ffi_type t; + u8 extra; + u8 extra2; +} BQNFFIEnt; +typedef struct BQNFFIType { + struct Value; + u8 ty; + usz ia; + BQNFFIEnt a[]; +} BQNFFIType; + +enum ScalarTy { + sty_void, sty_a, + sty_u8, sty_u16, sty_u32, sty_u64, + sty_i8, sty_i16, sty_i32, sty_i64, + sty_f32, sty_f64 +}; +static const u8 sty_w[] = { + [sty_void]=0, [sty_a]=sizeof(BQNV), + [sty_u8]=1, [sty_u16]=2, [sty_u32]=4, [sty_u64]=8, + [sty_i8]=1, [sty_i16]=2, [sty_i32]=4, [sty_i64]=8, + [sty_f32]=4, [sty_f64]=8 +}; +static const char* sty_names[] = { + [sty_void]="void", [sty_a]="a", + [sty_u8]="u8", [sty_u16]="u16", [sty_u32]="u32", [sty_u64]="u64", + [sty_i8]="i8", [sty_i16]="i16", [sty_i32]="i32", [sty_i64]="i64", + [sty_f32]="f32", [sty_f64]="f64" +}; +enum CompoundTy { + cty_ptr, + cty_repr +}; + +static void printFFIType(FILE* f, B x) { + if (isC32(x)) fprintf(f, "%d", o2cu(x)); + else fprint(f, x); +} + +static B m_bqnFFIType(BQNFFIEnt** rp, u8 ty, usz ia) { + BQNFFIType* r = mm_alloc(fsizeof(BQNFFIType, a, BQNFFIEnt, ia), t_ffiType); + r->ty = ty; + r->ia = ia; + memset(r->a, 0, ia*sizeof(BQNFFIEnt)); + *rp = r->a; + return tag(r, OBJ_TAG); +} + +static u32 readUInt(u32** p) { + u32* c = *p; + u32 r = 0; + while (*c>='0' & *c<='9') { + if (r >= U32_MAX/10 - 10) thrM("FFI: number literal too large"); + r = r*10 + *c-'0'; + c++; + } + *p = c; + 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 + u32* c = *src; + u32 c0 = *c++; + ffi_type rt; + B ro; + bool parseRepr=false, subParseRepr=false, mut=false; + switch (c0) { + default: + thrM("FFI: Error parsing type"); + + case 'i': case 'u': case 'f':; + u32 n = readUInt(&c); + if (c0=='f') { + if (n==32) rt = ffi_type_float; + else if (n==64) rt = ffi_type_double; + else thrM("FFI: Bad float width"); + ro = m_c32(n==32? sty_f32 : sty_f64); + } else { + u32 scty; + if (n== 8) { scty = c0=='i'? sty_i8 : sty_u8; rt = c0=='i'? ffi_type_sint8 : ffi_type_uint8; } + else if (n==16) { scty = c0=='i'? sty_i16 : sty_u16; rt = c0=='i'? ffi_type_sint16 : ffi_type_uint16; } + else if (n==32) { scty = c0=='i'? sty_i32 : sty_u32; rt = c0=='i'? ffi_type_sint32 : ffi_type_uint32; } + else if (n==64) { scty = c0=='i'? sty_i64 : sty_u64; rt = c0=='i'? ffi_type_sint64 : ffi_type_uint64; } + else thrM("FFI: Bad integer width"); + ro = m_c32(scty); + } + parseRepr = !inPtr; + subParseRepr = inPtr; + break; + + case 'a': + ro = m_c32(sty_a); + rt = ffi_type_uint64; + break; + + case '*': case '&':; + if (c0=='&') mut = true; + BQNFFIEnt* rp; ro = m_bqnFFIType(&rp, cty_ptr, 1); + rp[0] = ffi_parseTypeStr(&c, true); + mut|= rp[0].extra2; + rp[0].extra = c0=='&'; + rt = ffi_type_pointer; + parseRepr = rp[0].extra; + break; + } + if (parseRepr && *c==':') { + c++; + u8 t = *c++; + u32 n = readUInt(&c); + if (t=='i' | t=='c') if (n!=8 & n!=16 & n!=32) { badW: thrF("Bad width in :%c%i", t, n); } + if (t=='u') if (n!=1 & n!=8 & n!=16 & n!=32) goto badW; + if (t=='f') if (n!=64) goto badW; + + B roP = ro; + BQNFFIEnt* rp; ro = m_bqnFFIType(&rp, cty_repr, 1); + rp[0] = (BQNFFIEnt){.o=roP, .t=rt, .extra=t, .extra2=63-CLZ(n)}; + } + *src = c; + return (BQNFFIEnt){.t=rt, .o=ro, .extra=subParseRepr, .extra2=mut}; +} + +B vfyStr(B x, char* name, char* arg); + +BQNFFIEnt ffi_parseType(B arg, bool forRes) { // doesn't consume; parse argument side & other global decorators; .extra=side, .extra2=contains mutation + vfyStr(arg, "FFI", "type"); + usz ia = a(arg)->ia; + if (ia==0) { + if (!forRes) thrM("FFI: Argument type empty"); + return (BQNFFIEnt){.t = ffi_type_void, .o=m_c32(sty_void)}; + } + MAKE_MUT(tmp, ia+1); mut_init(tmp, el_c32); MUTG_INIT(tmp); + mut_copyG(tmp, 0, arg, 0, ia); + mut_setG(tmp, ia, m_c32(0)); + u32* xp = tmp->ac32; + u32* xpN = xp + ia; + + u8 side; + if (*xp == U'𝕩') side = 2; + else if (*xp == U'𝕨') side = 1; + else side = 0; + if (forRes && side) thrM("FFI: Argument side cannot be specified for the result"); + if (side) xp++; + + BQNFFIEnt t = ffi_parseTypeStr(&xp, false); + // print(arg); printf(": "); printFFIType(stdout, t.o); printf("\n"); + if (xp!=xpN) thrM("FFI: Bad type descriptor"); + t.extra = side; + // keep extra2 as "contains mutation" + mut_pfree(tmp, 0); + return t; +} + +TAlloc* ffiTmpObj; +u8* ffiTmpS; +u8* ffiTmpC; +u8* ffiTmpE; +static NOINLINE usz ffiTmpX(usz n) { + usz psz = ffiTmpC-ffiTmpS; + TAlloc* na = mm_alloc(sizeof(TAlloc)+psz+n, t_temp); + memcpy(na->data, ffiTmpS, psz); + + ffiTmpS = na->data; + ffiTmpC = ffiTmpS + psz; + ffiTmpE = (u8*)na + mm_size((Value*) na); + if (ffiTmpObj) mm_free((Value*)ffiTmpObj); + ffiTmpObj = na; + return psz; +} +static NOINLINE usz ffiTmpAA(usz n) { + u64 align = _Alignof(max_align_t); + n = (n+align-1) & ~(align-1); + if (ffiTmpC+n > ffiTmpE) return ffiTmpX(n); + usz r = ffiTmpC-ffiTmpS; + ffiTmpC+= n; + return r; +} + +static B ffiObjs; + +static B toW(u8 tre, u8 wre, B x) { + switch(wre) { default: UD; + case 0: return taga(toBitArr(x)); break; + case 3: return tre=='c'? toC8Any(x) : toI8Any(x); break; + case 4: return tre=='c'? toC16Any(x) : toI16Any(x); break; + case 5: return tre=='c'? toC32Any(x) : toI32Any(x); break; + case 6: return toF64Any(x); break; + } +} + +usz genObj(BQNFFIEnt ent, B c, bool anyMut) { + // printFFIType(stdout,ent.o); printf(" = "); print(c); printf("\n"); + usz pos; + if (isC32(ent.o)) { // scalar + u32 t = o2cu(ent.o); + pos = ffiTmpAA(t==0? sizeof(BQNV) : 8); + void* ptr = ffiTmpS+pos; + f64 f = c.f; + switch(t) { default: thrF("FFI: Unimplemented scalar type %S", sty_names[t]); + case sty_a: *(BQNV*)ptr = makeX(inc(c)); break; + case sty_u8: *( u8*)ptr = f; break; + case sty_i8: *( i8*)ptr = f; break; + case sty_u16: *(u16*)ptr = f; break; + case sty_i16: *(i16*)ptr = f; break; + case sty_u32: *(u32*)ptr = f; break; + case sty_i32: *(i32*)ptr = f; break; + case sty_f32: *(float* )ptr = f; break; + case sty_f64: *(double*)ptr = f; break; + } + } else { + BQNFFIType* t = c(BQNFFIType, ent.o); + if (t->ty==cty_ptr) { // *any / &any + pos = ffiTmpAA(sizeof(void*)); + B e = t->a[0].o; + if (!isC32(e)) thrM("FFI: Nested pointers unimplemented"); + inc(c); + B cG; + if (!isArr(c)) thrF("FFI: Expected array corresponding to *%S", sty_names[o2cu(e)]); + usz ia = a(c)->ia; + bool mut = t->a[0].extra; + 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_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; ity==cty_repr) { // any:any + B o2 = t->a[0].o; + u8 tre = t->a[0].extra; + u8 wre = t->a[0].extra2; + if (isC32(o2)) { // scalar:any + pos = ffiTmpAA(8); + u8 et = o2cu(o2); + u8 etw = sty_w[et]*8; + // TODO if etw==1<ia != etw>>wre) thrM("FFI: Bad input array length"); + B cG = toW(tre, wre, inc(c)); + memcpy(ffiTmpS+pos, tyany_ptr(cG), 8); // may over-read, ¯\_(ツ)_/¯ + dec(cG); + } else { // *scalar:any / &scalar:any + pos = ffiTmpAA(sizeof(void*)); + 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 + inc(c); + B cG; + bool mut = t->a[0].extra; + if (mut) { + Arr* cGp; + switch(wre) { default: UD; + case 0: cGp = (Arr*) cpyBitArr(c); break; + case 3: cGp = tre=='c'? (Arr*) cpyC8Arr(c) : (Arr*) cpyI8Arr(c); break; + case 4: cGp = tre=='c'? (Arr*)cpyC16Arr(c) : (Arr*)cpyI16Arr(c); break; + case 5: cGp = tre=='c'? (Arr*)cpyC32Arr(c) : (Arr*)cpyI32Arr(c); break; + case 6: cGp = (Arr*) cpyF64Arr(c); break; + } + cG = taga(cGp); + } else cG = toW(tre, wre, c); + *(void**)(ffiTmpS+pos) = tyany_ptr(cG); + ffiObjs = vec_addN(ffiObjs, cG); + } + } else thrM("FFI: Unimplemented type"); + } + return pos; +} + +B buildObj(BQNFFIEnt ent, B c, bool anyMut, B* objs, usz* objPos) { + if (isC32(ent.o)) return m_f64(0); // scalar + BQNFFIType* t = c(BQNFFIType, ent.o); + if (t->ty==cty_ptr) { // *any / &any + B e = t->a[0].o; + B f = objs[(*objPos)++]; + bool mut = t->a[0].extra; + if (mut) { + usz ia = a(c)->ia; + switch(o2cu(e)) { default: UD; + 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; ity==cty_repr) { // any:any + B o2 = t->a[0].o; + if (isC32(o2)) return m_f64(0); // scalar:any + // *scalar:any / &scalar:any + B f = objs[(*objPos)++]; + bool mut = t->a[0].extra; + if (!mut) return m_f64(0); + return inc(f); + } else thrM("FFI: Unimplemented type"); +} + +B libffiFn_c2(B t, B w, B x) { + BoundFn* c = c(BoundFn,t); + B argObj = c(HArr,c->obj)->a[0]; + B cifObj = c(HArr,c->obj)->a[1]; + ffi_cif* cif = (void*) c(TAlloc,cifObj)->data; + void* sym = c->w_c2; + + usz argn = cif->nargs; + ffiTmpS = ffiTmpC = ffiTmpE = NULL; + ffiTmpObj = NULL; + ffiObjs = emptyHVec(); + ffiTmpX(128); + ffiTmpAA(argn * sizeof(u32)); + #define argOffs ((u32*)ffiTmpS) + + SGetU(x) + BQNFFIEnt* ents = c(BQNFFIType,argObj)->a; + usz mutArgs = 0; + for (usz i = 0; i < argn; i++) { + bool mut = ents[i+1].extra2; + argOffs[i] = genObj(ents[i+1], GetU(x,i), mut); + mutArgs+= mut; + } + + u32 resPos; + bool simpleRes = isC32(ents[0].o); + if (simpleRes) { + resPos = ffiTmpAA(o2cu(ents[0].o)==0? sizeof(BQNV) : sizeof(ffi_arg)>8? sizeof(ffi_arg) : 8); + } else thrM("FFI: Unimplemented result type"); + + 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]; + void* res = ffiTmpS + resPos; + + // for (usz i = 0; i < ffiTmpC-ffiTmpS; i++) { // simple hexdump of ffiTmp + // if (!(i&15)) printf("%s%p ", i?"\n":"", (void*)(ffiTmpS+i)); + // else if (!(i&3)) printf(" "); + // printf("%x%x ", ffiTmpS[i]>>4, ffiTmpS[i]&15); + // } + // printf("\n"); + + ffi_call(cif, sym, res, argPtrs); + + B r; + bool resVoid = false; + if (simpleRes) { + switch(o2cu(ents[0].o)) { default: thrM("FFI: Unimplemented type"); + case sty_void: r = m_c32(0); resVoid = true; break; + case sty_a: r = getB(*(BQNV*)res); break; + case sty_i8: r = m_i32(sizeof(ffi_arg )>sizeof( i8)? ( i8)*(ffi_arg *)res : *( i8*)res); break; + case sty_i16: r = m_i32(sizeof(ffi_arg )>sizeof(i16)? (i16)*(ffi_arg *)res : *(i16*)res); break; + case sty_i32: r = m_i32(sizeof(ffi_arg )>sizeof(i32)? (i32)*(ffi_arg *)res : *(i32*)res); break; + case sty_u8: r = m_i32(sizeof(ffi_sarg)>sizeof( u8)? ( u8)*(ffi_sarg*)res : *( u8*)res); break; + case sty_u16: r = m_i32(sizeof(ffi_sarg)>sizeof(u16)? (u16)*(ffi_sarg*)res : *(u16*)res); break; + case sty_u32: r = m_f64(sizeof(ffi_sarg)>sizeof(u32)? (u32)*(ffi_sarg*)res : *(u32*)res); break; + case sty_f32: r = m_f64(*(float* )res); break; + case sty_f64: r = m_f64(*(double*)res); break; + } + } else UD; + mm_free((Value*)ffiTmpObj); + + if (mutArgs) { + usz objPos = 0; + M_HARR(ra, mutArgs+(resVoid? 0 : 1)); + if (!resVoid) HARR_ADDA(ra, r); + for (usz i = 0; i < argn; i++) { + bool mut = ents[i+1].extra2; + B c = buildObj(ents[i+1], GetU(x,i), mut, harr_ptr(ffiObjs), &objPos); + if (mut) HARR_ADDA(ra, c); + } + r = HARR_FV(ra); + } + + dec(w); dec(x); dec(ffiObjs); + return r; +} +B libffiFn_c1(B t, B x) { return libffiFn_c2(t, bi_N, x); } + +#endif + + + + + +B loadffi_c2(B t, B w, B x) { + usz xia = a(x)->ia; + if (xia<2) thrM("FFI: Function specification must have at least two items"); + usz argn = xia-2; + SGetU(x) + B name = GetU(x,1); + vfyStr(name, "FFI", "type"); + + BQNFFIEnt tRes = ffi_parseType(GetU(x,0), true); + + BQNFFIEnt* args; B argObj = m_bqnFFIType(&args, 255, argn+1); + args[0] = tRes; + for (usz i = 0; i < argn; i++) args[i+1] = ffi_parseType(GetU(x,i+2), false); + + char* ws = toCStr(w); + void* dl = dlopen(ws, RTLD_NOW); + freeCStr(ws); + dec(w); + if (dl==NULL) thrF("Failed to load: %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 FFI==1 + return m_ffiFn(foreignFnDesc, bi_N, directFn_c1, directFn_c2, sym, sym); + #else + TAlloc* argsRaw = ARBOBJ(argn*sizeof(ffi_type*)); + ffi_type** argsRawArr = (ffi_type**)argsRaw->data; + for (usz i = 0; i < argn; i++) argsRawArr[i] = &args[i+1].t; + // for (usz i = 0; i < argn; i++) { + // ffi_type c = *argsRawArr[i]; + // printf("%zu %d %d %p\n", c.size, c.alignment, c.type, c.elements); + // } + TAlloc* cif = ARBOBJ(sizeof(ffi_cif)); + 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"); + // mm_free(argsRaw) + return m_ffiFn(foreignFnDesc, m_hVec3(argObj, tag(cif, OBJ_TAG), tag(argsRaw, OBJ_TAG)), libffiFn_c1, libffiFn_c2, NULL, sym); + #endif +} + +DEF_FREE(ffiType) { + usz ia = ((BQNFFIType*)x)->ia; + for (usz i = 0; i < ia; i++) dec(((BQNFFIType*)x)->a[i].o); +} +void ffiType_visit(Value* x) { + usz ia = ((BQNFFIType*)x)->ia; + for (usz i = 0; i < ia; i++) mm_visit(((BQNFFIType*)x)->a[i].o); +} +void ffiType_print(FILE* f, B x) { + BQNFFIType* t = c(BQNFFIType,x); + fprintf(f, "cty_%d⟨", t->ty); + for (usz i=0, ia=t->ia; ia[i].o); + } + fprintf(f, "⟩"); +} + +void ffi_init() { + boundFnDesc = registerNFn(m_str8l("(foreign function)"), boundFn_c1, boundFn_c2); + foreignFnDesc = registerNFn(m_str8l("(foreign function)"), directFn_c1, directFn_c2); + TIi(t_ffiType,freeO) = ffiType_freeO; + TIi(t_ffiType,freeF) = ffiType_freeF; + TIi(t_ffiType,visit) = ffiType_visit; + TIi(t_ffiType,print) = ffiType_print; +} + +#else +void ffi_init() { } +B loadffi_c2(B t, B w, B x) { thrM("CBQN was compiled without FFI"); } +#endif diff --git a/src/ffi.h b/src/ffi.h new file mode 100644 index 00000000..5e7d745d --- /dev/null +++ b/src/ffi.h @@ -0,0 +1,94 @@ +#include +#include +#include + +typedef uint64_t BQNV; + +// to define a native function, define one with one of the following signatures: +// BQNV yourName(BQNV x); +// BQNV yourName(BQNV w, BQNV x); +// and load it in BQN with something like `"path/to/compiled/file.so" •LoadNativeFnOrWhatever arity‿"yourName"` + +#ifdef __cplusplus +extern "C" { +#endif + +void bqn_free(BQNV v); + +double bqn_toF64 (BQNV v); // includes bqn_free(v) +uint32_t bqn_toChar(BQNV v); // includes bqn_free(v) +double bqn_readF64 (BQNV v); // doesn't include bqn_free(v) +uint32_t bqn_readChar(BQNV v); // doesn't include bqn_free(v) + +// invoke BQN function +BQNV bqn_call1(BQNV f, BQNV x); +BQNV bqn_call2(BQNV f, BQNV w, BQNV x); + +// evaluate BQN code in a fresh environment +BQNV bqn_eval(BQNV src); +BQNV bqn_evalCStr(char* str); // evaluates the null-terminated UTF8-encoded str; equal to `BQNV s = bqn_makeUTF8Str(str, strlen(str)); result = bqn_eval(s); bqn_free(s);` + + +// read array data +size_t bqn_bound(BQNV a); // aka product of shape, ×´≢a +size_t bqn_rank(BQNV a); +void bqn_shape(BQNV a, size_t* buf); // writes bqn_rank(a) items in buf +BQNV bqn_pick(BQNV a, size_t pos); + +// read all elements of `a` into the specified buffer +void bqn_readI8Arr (BQNV a, int8_t* buf); +void bqn_readI16Arr(BQNV a, int16_t* buf); +void bqn_readI32Arr(BQNV a, int32_t* buf); +void bqn_readF64Arr(BQNV a, double* buf); +void bqn_readC8Arr (BQNV a, uint8_t* buf); +void bqn_readC16Arr(BQNV a, uint16_t* buf); +void bqn_readC32Arr(BQNV a, uint32_t* buf); +void bqn_readObjArr(BQNV a, BQNV* buf); + + +// create objects +BQNV bqn_makeF64(double d); +BQNV bqn_makeChar(uint32_t c); +BQNV bqn_makeI8Arr (size_t rank, size_t* shape, int8_t* data); +BQNV bqn_makeI16Arr(size_t rank, size_t* shape, int16_t* data); +BQNV bqn_makeI32Arr(size_t rank, size_t* shape, int32_t* data); +BQNV bqn_makeF64Arr(size_t rank, size_t* shape, double* data); +BQNV bqn_makeC8Arr (size_t rank, size_t* shape, uint8_t* data); +BQNV bqn_makeC16Arr(size_t rank, size_t* shape, uint16_t* data); +BQNV bqn_makeC32Arr(size_t rank, size_t* shape, uint32_t* data); +BQNV bqn_makeObjArr(size_t rank, size_t* shape, BQNV* data); // frees the taken elements of data + +BQNV bqn_makeI8Vec (size_t len, int8_t* data); +BQNV bqn_makeI16Vec(size_t len, int16_t* data); +BQNV bqn_makeI32Vec(size_t len, int32_t* data); +BQNV bqn_makeF64Vec(size_t len, double* data); +BQNV bqn_makeC8Vec (size_t len, uint8_t* data); +BQNV bqn_makeC16Vec(size_t len, uint16_t* data); +BQNV bqn_makeC32Vec(size_t len, uint32_t* data); +BQNV bqn_makeObjVec(size_t len, BQNV* data); // frees the taken elements of data +BQNV bqn_makeUTF8Str(size_t len, char* str); + +typedef BQNV (*bqn_boundFn1)(BQNV obj, BQNV x); +typedef BQNV (*bqn_boundFn2)(BQNV obj, BQNV w, BQNV x); + +// when called, 1st arg to `f` will be `obj` +BQNV bqn_makeBoundFn1(bqn_boundFn1 f, BQNV obj); +BQNV bqn_makeBoundFn2(bqn_boundFn2 f, BQNV obj); + + +// direct (zero copy) array item access +typedef enum { elt_i8, elt_i16, elt_i32, elt_f64, elt_c8, elt_c16, elt_c32, elt_unk } BQNElType; +BQNElType bqn_directType(BQNV a); +// can only use the functions below if bqn_elType returns the corresponding type +// a valid implementation of bqn_elType would be to always return elt_unk, thus disallowing the use of direct access entirely +int8_t* bqn_directI8 (BQNV a); +int16_t* bqn_directI16(BQNV a); +int32_t* bqn_directI32(BQNV a); +double* bqn_directF64(BQNV a); +uint8_t* bqn_directC8 (BQNV a); +uint16_t* bqn_directC16(BQNV a); +uint32_t* bqn_directC32(BQNV a); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/h.h b/src/h.h index 425a6827..e29a3efb 100644 --- a/src/h.h +++ b/src/h.h @@ -39,6 +39,9 @@ #ifndef RANDSEED #define RANDSEED 0 // random seed used to make •rand (0 for using time) #endif +#ifndef FFI + #define FFI 2 +#endif // #define HEAP_VERIFY // enable usage of heapVerify() // #define ALLOC_STAT // store basic allocation statistics @@ -212,11 +215,11 @@ typedef union B { /*22*/ F(harr ) F(fillarr ) F(i8arr ) F(i16arr ) F(i32arr ) F(c8arr ) F(c16arr ) F(c32arr ) F(f64arr ) \ /*31*/ F(bitarr) \ \ - /*32*/ F(comp) F(block) F(body) F(scope) F(scopeExt) F(blBlocks) \ - /*38*/ F(ns) F(nsDesc) F(fldAlias) F(vfyObj) F(hashmap) F(temp) F(nfn) F(nfnDesc) \ - /*46*/ F(freed) F(harrPartial) F(customObj) F(mmapH) \ + /*32*/ F(comp) F(block) F(body) F(scope) F(scopeExt) F(blBlocks) F(arbObj) F(ffiType) \ + /*40*/ F(ns) F(nsDesc) F(fldAlias) F(vfyObj) F(hashmap) F(temp) F(nfn) F(nfnDesc) \ + /*48*/ F(freed) F(harrPartial) F(customObj) F(mmapH) \ \ - /*49*/ IF_WRAP(F(funWrap) F(md1Wrap) F(md2Wrap)) + /*51*/ IF_WRAP(F(funWrap) F(md1Wrap) F(md2Wrap)) enum Type { #define F(X) t_##X, diff --git a/src/load.c b/src/load.c index 3acbb5f3..a08cd117 100644 --- a/src/load.c +++ b/src/load.c @@ -5,7 +5,7 @@ #include "ns.h" #include "builtins.h" -#define FOR_INIT(F) F(base) F(harr) F(mutF) F(fillarr) F(tyarr) F(hash) F(sfns) F(fns) F(arith) F(md1) F(md2) F(derv) F(comp) F(rtWrap) F(ns) F(nfn) F(sysfn) F(inverse) F(load) F(sysfnPost) F(dervPost) F(mmap) +#define FOR_INIT(F) F(base) F(harr) F(mutF) F(fillarr) F(tyarr) F(hash) F(sfns) F(fns) F(arith) F(md1) F(md2) F(derv) F(comp) F(rtWrap) F(ns) F(nfn) F(sysfn) F(inverse) F(load) F(sysfnPost) F(dervPost) F(ffi) F(mmap) #define F(X) void X##_init(void); FOR_INIT(F) #undef F @@ -652,6 +652,7 @@ void base_init() { // very first init function TIi(t_customObj,freeO) = customObj_freeO; TIi(t_customObj,freeF) = customObj_freeF; TIi(t_customObj,visit) = customObj_visit; + TIi(t_arbObj,visit) = noop_visit; assert((MD1_TAG>>1) == (MD2_TAG>>1)); // just to be sure it isn't changed incorrectly, `isMd` depends on this diff --git a/src/opt/single.c b/src/opt/single.c index 96f01999..c1f81e04 100644 --- a/src/opt/single.c +++ b/src/opt/single.c @@ -29,5 +29,6 @@ #include "../ns.c" #include "../nfns.c" #include "../rtwrap.c" +#include "../ffi.c" #include "../jit/nvm.c" #include "../main.c" diff --git a/src/utils/talloc.h b/src/utils/talloc.h index e01d99bf..86a0c9b1 100644 --- a/src/utils/talloc.h +++ b/src/utils/talloc.h @@ -29,7 +29,10 @@ typedef struct TStack { #define TSFREE(N) mm_free((Value*)N##_o); #define TSUPD(N,AM) { N##_o = ts_e(N##_o, N##_e, AM); N = (void*)N##_o->data; } #define TSADD(N,X) { if (N##_o->size==N##_o->cap) TSUPD(N, 1); N[N##_o->size++] = X; } -#define TSADDA(N,P,AM) { u64 n=AM; if(N##_o->size+n>N##_o->cap) TSUPD(N, n); memcpy(N+N##_o->size,P,n*N##_e); N##_o->size+= n; } +#define TSADDA(N,P,AM) { u64 n_=(AM); if(N##_o->size+n_>N##_o->cap) TSUPD(N, n_); memcpy(N+N##_o->size,P,n_*N##_e); N##_o->size+= n_; } +#define TSADDAU(N,AM) { u64 n_=(AM); if(N##_o->size+n_>N##_o->cap) TSUPD(N, n_); N##_o->size+= n_; } #define TSFREEP(N) mm_free((void*)RFLD(N, TStack, data)); #define TSSIZE(N) (N##_o->size) TStack* ts_e(TStack* o, u32 elsz, u64 am); + +#define ARBOBJ(SZ) (TAlloc*)mm_alloc(sizeof(TAlloc)+(SZ), t_arbObj) \ No newline at end of file