diff options
-rw-r--r-- | integration/bunjs-only-snippets/ffi.test.fixture.callback.c | 18 | ||||
-rw-r--r-- | integration/bunjs-only-snippets/ffi.test.fixture.receiver.c | 31 | ||||
-rw-r--r-- | integration/bunjs-only-snippets/ffi.test.js | 54 | ||||
-rw-r--r-- | src/javascript/jsc/api/FFI.h | 18 | ||||
-rw-r--r-- | src/javascript/jsc/api/bun.zig | 2 | ||||
-rw-r--r-- | src/javascript/jsc/api/ffi.zig | 2 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/JSFFIFunction.h | 5 |
7 files changed, 65 insertions, 65 deletions
diff --git a/integration/bunjs-only-snippets/ffi.test.fixture.callback.c b/integration/bunjs-only-snippets/ffi.test.fixture.callback.c index a428926ef..a0da35f62 100644 --- a/integration/bunjs-only-snippets/ffi.test.fixture.callback.c +++ b/integration/bunjs-only-snippets/ffi.test.fixture.callback.c @@ -100,6 +100,7 @@ typedef union EncodedJSValue { #endif void* asPtr; + double asDouble; } EncodedJSValue; EncodedJSValue ValueUndefined = { TagValueUndefined }; @@ -116,6 +117,7 @@ JSContext cachedJSContext; void* cachedCallbackFunction; #endif + static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__)); static EncodedJSValue DOUBLE_TO_JSVALUE(double val) __attribute__((__always_inline__)); static EncodedJSValue FLOAT_TO_JSVALUE(float val) __attribute__((__always_inline__)); @@ -149,19 +151,16 @@ static EncodedJSValue INT32_TO_JSVALUE(int32_t val) { return res; } + static EncodedJSValue DOUBLE_TO_JSVALUE(double val) { - EncodedJSValue res; -#ifdef USES_FLOAT - res.asInt64 = trunc(val) == val ? val : val - DoubleEncodeOffset; -#else -// should never get here - res.asInt64 = 0xa; -#endif + EncodedJSValue res; + res.asDouble = val; + res.asInt64 += DoubleEncodeOffset; return res; } static EncodedJSValue FLOAT_TO_JSVALUE(float val) { - return DOUBLE_TO_JSVALUE(val); + return DOUBLE_TO_JSVALUE((double)val); } static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) { @@ -172,7 +171,8 @@ static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) { static double JSVALUE_TO_DOUBLE(EncodedJSValue val) { - return val.asInt64 + DoubleEncodeOffset; + val.asInt64 -= DoubleEncodeOffset; + return val.asDouble; } static float JSVALUE_TO_FLOAT(EncodedJSValue val) { diff --git a/integration/bunjs-only-snippets/ffi.test.fixture.receiver.c b/integration/bunjs-only-snippets/ffi.test.fixture.receiver.c index 2107b684e..0f7047ab5 100644 --- a/integration/bunjs-only-snippets/ffi.test.fixture.receiver.c +++ b/integration/bunjs-only-snippets/ffi.test.fixture.receiver.c @@ -1,4 +1,4 @@ -#define HAS_ARGUMENTS +#define USES_FLOAT 1 // This file is part of Bun! // You can find the original source: // https://github.com/Jarred-Sumner/bun/blob/main/src/javascript/jsc/api/FFI.h#L2 @@ -100,6 +100,7 @@ typedef union EncodedJSValue { #endif void* asPtr; + double asDouble; } EncodedJSValue; EncodedJSValue ValueUndefined = { TagValueUndefined }; @@ -116,6 +117,7 @@ JSContext cachedJSContext; void* cachedCallbackFunction; #endif + static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__)); static EncodedJSValue DOUBLE_TO_JSVALUE(double val) __attribute__((__always_inline__)); static EncodedJSValue FLOAT_TO_JSVALUE(float val) __attribute__((__always_inline__)); @@ -149,19 +151,16 @@ static EncodedJSValue INT32_TO_JSVALUE(int32_t val) { return res; } + static EncodedJSValue DOUBLE_TO_JSVALUE(double val) { - EncodedJSValue res; -#ifdef USES_FLOAT - res.asInt64 = trunc(val) == val ? val : val - DoubleEncodeOffset; -#else -// should never get here - res.asInt64 = 0xa; -#endif + EncodedJSValue res; + res.asDouble = val; + res.asInt64 += DoubleEncodeOffset; return res; } static EncodedJSValue FLOAT_TO_JSVALUE(float val) { - return DOUBLE_TO_JSVALUE(val); + return DOUBLE_TO_JSVALUE((double)val); } static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) { @@ -172,7 +171,8 @@ static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) { static double JSVALUE_TO_DOUBLE(EncodedJSValue val) { - return val.asInt64 + DoubleEncodeOffset; + val.asInt64 -= DoubleEncodeOffset; + return val.asDouble; } static float JSVALUE_TO_FLOAT(EncodedJSValue val) { @@ -193,19 +193,14 @@ void* JSFunctionCall(void* globalObject, void* callFrame); // --- Generated Code --- /* --- The Function To Call */ -void callback(void* arg0); +float not_a_callback(); /* ---- Your Wrapper Function ---- */ void* JSFunctionCall(void* globalObject, void* callFrame) { #ifdef HAS_ARGUMENTS LOAD_ARGUMENTS_FROM_CALL_FRAME; #endif -#ifdef INJECT_BEFORE -//Bun_FFI_PointerOffsetToArgumentsList: 6 -//Bun_FFI_PointerOffsetToArgumentsCount: 0 -#endif - callback( JSVALUE_TO_PTR(arg(0))); - - return ValueUndefined.asPtr; + float return_value = not_a_callback(); + return FLOAT_TO_JSVALUE(return_value).asPtr; } diff --git a/integration/bunjs-only-snippets/ffi.test.js b/integration/bunjs-only-snippets/ffi.test.js index 14a38d6b2..597c0ef1f 100644 --- a/integration/bunjs-only-snippets/ffi.test.js +++ b/integration/bunjs-only-snippets/ffi.test.js @@ -27,9 +27,9 @@ it("ffi print", async () => { import.meta.dir + "/ffi.test.fixture.receiver.c", viewSource( { - callback: { - return_type: 13, - args: ["ptr"], + not_a_callback: { + return_type: "float", + args: [], }, }, false @@ -71,14 +71,14 @@ it("ffi run", () => { return_type: "char", args: [], }, - // returns_42_float: { - // return_type: "float", - // args: [], - // }, - // returns_42_double: { - // return_type: "double", - // args: [], - // }, + returns_42_float: { + return_type: "float", + args: [], + }, + returns_42_double: { + return_type: "double", + args: [], + }, returns_42_uint8_t: { return_type: "uint8_t", args: [], @@ -116,18 +116,18 @@ it("ffi run", () => { return_type: "char", args: ["char"], }, - // identity_float: { - // return_type: "float", - // args: ["float"], - // }, + identity_float: { + return_type: "float", + args: ["float"], + }, identity_bool: { return_type: "bool", args: ["bool"], }, - // identity_double: { - // return_type: "double", - // args: ["double"], - // }, + identity_double: { + return_type: "double", + args: ["double"], + }, identity_int8_t: { return_type: "int8_t", args: ["int8_t"], @@ -340,8 +340,10 @@ it("ffi run", () => { expect(returns_true()).toBe(true); expect(returns_false()).toBe(false); expect(returns_42_char()).toBe(42); - // expect(returns_42_float()).toBe(42); - // expect(returns_42_double()).toBe(42); + + expect(Math.fround(returns_42_float())).toBe(Math.fround(42.41999804973602)); + + expect(returns_42_double()).toBe(42.42); expect(returns_42_uint8_t()).toBe(42); expect(returns_neg_42_int8_t()).toBe(-42); expect(returns_42_uint16_t()).toBe(42); @@ -352,20 +354,20 @@ it("ffi run", () => { expect(identity_int32_t(10)).toBe(10); // expect(returns_neg_42_int64_t()).toBe(-42); expect(identity_char(10)).toBe(10); - // expect(identity_float(10.1)).toBe(10.1); + expect(identity_float(10.199999809265137)).toBe(10.199999809265137); expect(identity_bool(true)).toBe(true); expect(identity_bool(false)).toBe(false); - // expect(identity_double(10.1)).toBe(10.1); + expect(identity_double(10.100000000000364)).toBe(10.100000000000364); expect(identity_int8_t(10)).toBe(10); expect(identity_int16_t(10)).toBe(10); - + console.log("here"); // expect(identity_int64_t(10)).toBe(10); expect(identity_uint8_t(10)).toBe(10); expect(identity_uint16_t(10)).toBe(10); expect(identity_uint32_t(10)).toBe(10); expect(add_char(1, 1)).toBe(2); - // expect(add_float(1.1, 1.1)).toBe(2.2); - // expect(add_double(1.1, 1.1)).toBe(2.2); + expect(add_float(2.4, 2.8)).toBe(Math.fround(5.2)); + expect(add_double(4.2, 0.1)).toBe(4.3); expect(add_int8_t(1, 1)).toBe(2); expect(add_int16_t(1, 1)).toBe(2); expect(add_int32_t(1, 1)).toBe(2); diff --git a/src/javascript/jsc/api/FFI.h b/src/javascript/jsc/api/FFI.h index 096abcfd9..42bc03fc8 100644 --- a/src/javascript/jsc/api/FFI.h +++ b/src/javascript/jsc/api/FFI.h @@ -99,6 +99,7 @@ typedef union EncodedJSValue { #endif void* asPtr; + double asDouble; } EncodedJSValue; EncodedJSValue ValueUndefined = { TagValueUndefined }; @@ -115,6 +116,7 @@ JSContext cachedJSContext; void* cachedCallbackFunction; #endif + static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__)); static EncodedJSValue DOUBLE_TO_JSVALUE(double val) __attribute__((__always_inline__)); static EncodedJSValue FLOAT_TO_JSVALUE(float val) __attribute__((__always_inline__)); @@ -148,19 +150,16 @@ static EncodedJSValue INT32_TO_JSVALUE(int32_t val) { return res; } + static EncodedJSValue DOUBLE_TO_JSVALUE(double val) { - EncodedJSValue res; -#ifdef USES_FLOAT - res.asInt64 = trunc(val) == val ? val : val - DoubleEncodeOffset; -#else -// should never get here - res.asInt64 = 0xa; -#endif + EncodedJSValue res; + res.asDouble = val; + res.asInt64 += DoubleEncodeOffset; return res; } static EncodedJSValue FLOAT_TO_JSVALUE(float val) { - return DOUBLE_TO_JSVALUE(val); + return DOUBLE_TO_JSVALUE((double)val); } static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) { @@ -171,7 +170,8 @@ static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) { static double JSVALUE_TO_DOUBLE(EncodedJSValue val) { - return val.asInt64 + DoubleEncodeOffset; + val.asInt64 -= DoubleEncodeOffset; + return val.asDouble; } static float JSVALUE_TO_FLOAT(EncodedJSValue val) { diff --git a/src/javascript/jsc/api/bun.zig b/src/javascript/jsc/api/bun.zig index 79a0ae12f..632d85500 100644 --- a/src/javascript/jsc/api/bun.zig +++ b/src/javascript/jsc/api/bun.zig @@ -1477,7 +1477,7 @@ pub fn nanoseconds( _: JSC.C.ExceptionRef, ) JSC.C.JSValueRef { const ns = JSC.VirtualMachine.vm.origin_timer.read(); - JSC.JSValue.jsNumberFromUint64(ns).asObjectRef(); + return JSC.JSValue.jsNumberFromUint64(ns).asObjectRef(); } pub fn serve( diff --git a/src/javascript/jsc/api/ffi.zig b/src/javascript/jsc/api/ffi.zig index 7ae3b60dc..b3be0062f 100644 --- a/src/javascript/jsc/api/ffi.zig +++ b/src/javascript/jsc/api/ffi.zig @@ -740,7 +740,6 @@ pub const FFI = struct { } _ = TCC.tcc_set_output_type(state, TCC.TCC_OUTPUT_MEMORY); - CompilerRT.inject(state); const compilation_result = TCC.tcc_compile_string( state, @@ -763,6 +762,7 @@ pub const FFI = struct { _ = TCC.tcc_add_symbol(state, "bun_call", JSC.C.JSObjectCallAsFunction); _ = TCC.tcc_add_symbol(state, "cachedJSContext", js_context); _ = TCC.tcc_add_symbol(state, "cachedCallbackFunction", js_function); + CompilerRT.inject(state); var relocation_size = TCC.tcc_relocate(state, null); if (relocation_size == 0) return; diff --git a/src/javascript/jsc/bindings/JSFFIFunction.h b/src/javascript/jsc/bindings/JSFFIFunction.h index 8f65bf632..421adc3ff 100644 --- a/src/javascript/jsc/bindings/JSFFIFunction.h +++ b/src/javascript/jsc/bindings/JSFFIFunction.h @@ -34,7 +34,10 @@ using FFIFunction = JSC::EncodedJSValue (*)(JSC::JSGlobalObject* globalObject, J * * It was about 20% faster than using the JavaScriptCore C API for functions with 1 argument * - * Note: there is no wrapper function here + * There is no wrapper function. It does zero bounds checking on the arguments. + * It does not check for exceptions. It does not check for return value. + * It is the caller's responsibility to not buffer overflow the arguments + * For all those reasons, this shouldn't be used directly. */ class JSFFIFunction final : public JSC::JSFunction { public: |