diff options
Diffstat (limited to 'test')
| -rw-r--r-- | test/bun.js/ffi.test.fixture.callback.c | 39 | ||||
| -rw-r--r-- | test/bun.js/ffi.test.fixture.receiver.c | 33 | ||||
| -rw-r--r-- | test/bun.js/ffi.test.js | 164 |
3 files changed, 109 insertions, 127 deletions
diff --git a/test/bun.js/ffi.test.fixture.callback.c b/test/bun.js/ffi.test.fixture.callback.c index cb38eebe8..58e6c482e 100644 --- a/test/bun.js/ffi.test.fixture.callback.c +++ b/test/bun.js/ffi.test.fixture.callback.c @@ -1,3 +1,4 @@ +#define JS_GLOBAL_OBJECT (void*)0x0UL #define IS_CALLBACK 1 // This file is part of Bun! // You can find the original source: @@ -102,9 +103,16 @@ typedef void* JSContext; #ifdef IS_CALLBACK -extern int64_t bun_call(JSContext, void* func, void* thisValue, size_t len, const EncodedJSValue args[], void* exception); -JSContext cachedJSContext; -void* cachedCallbackFunction; +ZIG_REPR_TYPE FFI_Callback_call(void* ctx, size_t argCount, ZIG_REPR_TYPE* args); +// We wrap +static EncodedJSValue _FFI_Callback_call(void* ctx, size_t argCount, ZIG_REPR_TYPE* args) __attribute__((__always_inline__)); +static EncodedJSValue _FFI_Callback_call(void* ctx, size_t argCount, ZIG_REPR_TYPE* args) { + EncodedJSValue return_value; + return_value.asZigRepr = FFI_Callback_call(ctx, argCount, args); + return return_value; +} +static ZIG_REPR_TYPE arguments[100]; + #endif static bool JSVALUE_IS_CELL(EncodedJSValue val) __attribute__((__always_inline__)); @@ -116,10 +124,10 @@ static int64_t JSVALUE_TO_INT64(EncodedJSValue value) __attribute__((__always_i uint64_t JSVALUE_TO_UINT64_SLOW(EncodedJSValue value); int64_t JSVALUE_TO_INT64_SLOW(EncodedJSValue value); -EncodedJSValue UINT64_TO_JSVALUE_SLOW(void* globalObject, uint64_t val); -EncodedJSValue INT64_TO_JSVALUE_SLOW(void* globalObject, int64_t val); -static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) __attribute__((__always_inline__)); -static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) __attribute__((__always_inline__)); +EncodedJSValue UINT64_TO_JSVALUE_SLOW(void* jsGlobalObject, uint64_t val); +EncodedJSValue INT64_TO_JSVALUE_SLOW(void* jsGlobalObject, int64_t val); +static EncodedJSValue UINT64_TO_JSVALUE(void* jsGlobalObject, uint64_t val) __attribute__((__always_inline__)); +static EncodedJSValue INT64_TO_JSVALUE(void* jsGlobalObject, int64_t val) __attribute__((__always_inline__)); static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__)); @@ -241,7 +249,7 @@ static int64_t JSVALUE_TO_INT64(EncodedJSValue value) { return JSVALUE_TO_INT64_SLOW(value); } -static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) { +static EncodedJSValue UINT64_TO_JSVALUE(void* jsGlobalObject, uint64_t val) { if (val < MAX_INT32) { return INT32_TO_JSVALUE((int32_t)val); } @@ -250,10 +258,10 @@ static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) { return DOUBLE_TO_JSVALUE((double)val); } - return UINT64_TO_JSVALUE_SLOW(globalObject, val); + return UINT64_TO_JSVALUE_SLOW(jsGlobalObject, val); } -static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) { +static EncodedJSValue INT64_TO_JSVALUE(void* jsGlobalObject, int64_t val) { if (val >= -MAX_INT32 && val <= MAX_INT32) { return INT32_TO_JSVALUE((int32_t)val); } @@ -262,11 +270,11 @@ static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) { return DOUBLE_TO_JSVALUE((double)val); } - return INT64_TO_JSVALUE_SLOW(globalObject, val); + return INT64_TO_JSVALUE_SLOW(jsGlobalObject, val); } #ifndef IS_CALLBACK -ZIG_REPR_TYPE JSFunctionCall(void* globalObject, void* callFrame); +ZIG_REPR_TYPE JSFunctionCall(void* jsGlobalObject, void* callFrame); #endif @@ -282,10 +290,7 @@ bool my_callback_function(void* arg0) { #ifdef INJECT_BEFORE INJECT_BEFORE; #endif - EncodedJSValue arguments[1] = { - PTR_TO_JSVALUE(arg0) - }; - EncodedJSValue return_value = {bun_call(cachedJSContext, cachedCallbackFunction, (void*)0, 1, &arguments[0], (void*)0)}; - return JSVALUE_TO_BOOL(return_value); +arguments[0] = PTR_TO_JSVALUE(arg0).asZigRepr; + return (bool)JSVALUE_TO_BOOL(_FFI_Callback_call((void*)0x0UL, 1, arguments)); } diff --git a/test/bun.js/ffi.test.fixture.receiver.c b/test/bun.js/ffi.test.fixture.receiver.c index f8417805d..c972c2df1 100644 --- a/test/bun.js/ffi.test.fixture.receiver.c +++ b/test/bun.js/ffi.test.fixture.receiver.c @@ -103,9 +103,16 @@ typedef void* JSContext; #ifdef IS_CALLBACK -extern int64_t bun_call(JSContext, void* func, void* thisValue, size_t len, const EncodedJSValue args[], void* exception); -JSContext cachedJSContext; -void* cachedCallbackFunction; +ZIG_REPR_TYPE FFI_Callback_call(void* ctx, size_t argCount, ZIG_REPR_TYPE* args); +// We wrap +static EncodedJSValue _FFI_Callback_call(void* ctx, size_t argCount, ZIG_REPR_TYPE* args) __attribute__((__always_inline__)); +static EncodedJSValue _FFI_Callback_call(void* ctx, size_t argCount, ZIG_REPR_TYPE* args) { + EncodedJSValue return_value; + return_value.asZigRepr = FFI_Callback_call(ctx, argCount, args); + return return_value; +} +static ZIG_REPR_TYPE arguments[100]; + #endif static bool JSVALUE_IS_CELL(EncodedJSValue val) __attribute__((__always_inline__)); @@ -117,10 +124,10 @@ static int64_t JSVALUE_TO_INT64(EncodedJSValue value) __attribute__((__always_i uint64_t JSVALUE_TO_UINT64_SLOW(EncodedJSValue value); int64_t JSVALUE_TO_INT64_SLOW(EncodedJSValue value); -EncodedJSValue UINT64_TO_JSVALUE_SLOW(void* globalObject, uint64_t val); -EncodedJSValue INT64_TO_JSVALUE_SLOW(void* globalObject, int64_t val); -static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) __attribute__((__always_inline__)); -static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) __attribute__((__always_inline__)); +EncodedJSValue UINT64_TO_JSVALUE_SLOW(void* jsGlobalObject, uint64_t val); +EncodedJSValue INT64_TO_JSVALUE_SLOW(void* jsGlobalObject, int64_t val); +static EncodedJSValue UINT64_TO_JSVALUE(void* jsGlobalObject, uint64_t val) __attribute__((__always_inline__)); +static EncodedJSValue INT64_TO_JSVALUE(void* jsGlobalObject, int64_t val) __attribute__((__always_inline__)); static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__)); @@ -242,7 +249,7 @@ static int64_t JSVALUE_TO_INT64(EncodedJSValue value) { return JSVALUE_TO_INT64_SLOW(value); } -static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) { +static EncodedJSValue UINT64_TO_JSVALUE(void* jsGlobalObject, uint64_t val) { if (val < MAX_INT32) { return INT32_TO_JSVALUE((int32_t)val); } @@ -251,10 +258,10 @@ static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) { return DOUBLE_TO_JSVALUE((double)val); } - return UINT64_TO_JSVALUE_SLOW(globalObject, val); + return UINT64_TO_JSVALUE_SLOW(jsGlobalObject, val); } -static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) { +static EncodedJSValue INT64_TO_JSVALUE(void* jsGlobalObject, int64_t val) { if (val >= -MAX_INT32 && val <= MAX_INT32) { return INT32_TO_JSVALUE((int32_t)val); } @@ -263,11 +270,11 @@ static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) { return DOUBLE_TO_JSVALUE((double)val); } - return INT64_TO_JSVALUE_SLOW(globalObject, val); + return INT64_TO_JSVALUE_SLOW(jsGlobalObject, val); } #ifndef IS_CALLBACK -ZIG_REPR_TYPE JSFunctionCall(void* globalObject, void* callFrame); +ZIG_REPR_TYPE JSFunctionCall(void* jsGlobalObject, void* callFrame); #endif @@ -278,7 +285,7 @@ float not_a_callback(float arg0); /* ---- Your Wrapper Function ---- */ -ZIG_REPR_TYPE JSFunctionCall(void* globalObject, void* callFrame) { +ZIG_REPR_TYPE JSFunctionCall(void* JS_GLOBAL_OBJECT, void* callFrame) { LOAD_ARGUMENTS_FROM_CALL_FRAME; EncodedJSValue arg0; arg0.asInt64 = *argsPtr; diff --git a/test/bun.js/ffi.test.js b/test/bun.js/ffi.test.js index 536e6d7aa..6433f0161 100644 --- a/test/bun.js/ffi.test.js +++ b/test/bun.js/ffi.test.js @@ -4,6 +4,7 @@ import { CFunction, CString, dlopen as _dlopen, + JSCallback, ptr, read, toArrayBuffer, @@ -372,6 +373,7 @@ function ffiRunner(fast) { }, close, } = dlopen("/tmp/bun-ffi-test.dylib", types); + Bun.gc(true); expect(returns_true()).toBe(true); Bun.gc(true); @@ -407,6 +409,7 @@ function ffiRunner(fast) { expect(identity_int8_t(10)).toBe(10); expect(identity_int16_t(10)).toBe(10); + if (fast) expect(identity_int64_t(10)).toBe(10); else expect(identity_int64_t(10)).toBe(10n); expect(identity_uint8_t(10)).toBe(10); @@ -486,6 +489,70 @@ function ffiRunner(fast) { }); expect(myCFunction()).toBe(true); + { + const typeMap = { + int8_t: -8, + int16_t: -16, + int32_t: -32, + int64_t: -64n, + uint8_t: 8, + uint16_t: 16, + uint32_t: 32, + uint64_t: 64n, + float: 32.5, + double: 64.5, + ptr: 0xdeadbeef, + "void*": null, + }; + + // Return types, 1 argument + for (let [returnName, returnValue] of Object.entries(typeMap)) { + var roundtripFunction = new CFunction({ + ptr: new JSCallback( + { + returns: returnName, + args: [returnName], + }, + (input) => { + return input; + } + ).ptr, + returns: returnName, + args: [returnName], + }); + expect(roundtripFunction(returnValue)).toBe(returnValue); + } + + { + var toClose = new JSCallback( + { + returns: "bool", + args: ["bool"], + }, + (input) => { + return input; + } + ); + expect(toClose.ptr > 0).toBe(true); + toClose.close(); + expect(toClose.ptr === null).toBe(true); + } + + // Return types, no args + for (let [name, value] of Object.entries(typeMap)) { + var roundtripFunction = new CFunction({ + ptr: new JSCallback( + { + returns: name, + }, + () => value + ).ptr, + returns: name, + }); + expect(roundtripFunction()).toBe(value); + } + } + // check deallocator is called // for (let constructor of [toArrayBuffer, toBuffer]) { @@ -506,103 +573,6 @@ function ffiRunner(fast) { // Bun.gc(true); // } close(); - /* - --- - This style of callback is not implemented yet - */ - // function identityBool() { - // return true; - // } - // globalThis.identityBool = identityBool; - - // const first = native.callback( - // { - // returns: "bool", - // }, - // identityBool - // ); - // expect( - // cb_identity_true() - // ).toBe(true); - - // expect(cb_identity_true(first)).toBe(true); - - // expect( - // cb_identity_false( - // callback( - // { - // returns: "bool", - // }, - // () => false - // ) - // ) - // ).toBe(false); - - // expect( - // cb_identity_42_char( - // callback( - // { - // returns: "char", - // }, - // () => 42 - // ) - // ) - // ).toBe(42); - // expect( - // cb_identity_42_uint8_t( - // callback( - // { - // returns: "uint8_t", - // }, - // () => 42 - // ) - // ) - // ).toBe(42); - - // cb_identity_neg_42_int8_t( - // callback( - // { - // returns: "int8_t", - // }, - // () => -42 - // ) - // ).toBe(-42); - - // cb_identity_42_uint16_t( - // callback( - // { - // returns: "uint16_t", - // }, - // () => 42 - // ) - // ).toBe(42); - - // cb_identity_42_uint32_t( - // callback( - // { - // returns: "uint32_t", - // }, - // () => 42 - // ) - // ).toBe(42); - - // cb_identity_neg_42_int16_t( - // callback( - // { - // returns: "int16_t", - // }, - // () => -42 - // ) - // ).toBe(-42); - - // cb_identity_neg_42_int32_t( - // callback( - // { - // returns: "int32_t", - // }, - // () => -42 - // ) - // ).toBe(-42); } // TODO: There is a crash when dlopen() two times the same library in quick succession |
