aboutsummaryrefslogtreecommitdiff
path: root/integration/bunjs-only-snippets/ffi.test.fixture.receiver.c
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-05-02 20:26:18 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-05-02 20:26:18 -0700
commitc6d732eee2721cd6191672cbe2c57fb17c3fffe4 (patch)
treeda2716453ab256ea0b389b077ac7c98513abbfe7 /integration/bunjs-only-snippets/ffi.test.fixture.receiver.c
parent21ab47d9fe1085b7a1a959df810386367ebd5c23 (diff)
downloadbun-c6d732eee2721cd6191672cbe2c57fb17c3fffe4.tar.gz
bun-c6d732eee2721cd6191672cbe2c57fb17c3fffe4.tar.zst
bun-c6d732eee2721cd6191672cbe2c57fb17c3fffe4.zip
[bun:ffi] Improve `uint64_t` and `int64_t` performance
Diffstat (limited to 'integration/bunjs-only-snippets/ffi.test.fixture.receiver.c')
-rw-r--r--integration/bunjs-only-snippets/ffi.test.fixture.receiver.c125
1 files changed, 105 insertions, 20 deletions
diff --git a/integration/bunjs-only-snippets/ffi.test.fixture.receiver.c b/integration/bunjs-only-snippets/ffi.test.fixture.receiver.c
index 121f2d3a0..07d44c3a6 100644
--- a/integration/bunjs-only-snippets/ffi.test.fixture.receiver.c
+++ b/integration/bunjs-only-snippets/ffi.test.fixture.receiver.c
@@ -1,3 +1,4 @@
+#define HAS_ARGUMENTS
#define USES_FLOAT 1
// This file is part of Bun!
// You can find the original source:
@@ -8,20 +9,15 @@
// It must be kept in sync with JSCJSValue.h
// https://github.com/Jarred-Sumner/WebKit/blob/72c2052b781cbfd4af867ae79ac9de460e392fba/Source/JavaScriptCore/runtime/JSCJSValue.h#L455-L458
#ifdef IS_CALLBACK
-// #define INJECT_BEFORE printf("bun_call %p cachedJSContext %p cachedCallbackFunction %p\n", &bun_call, cachedJSContext, cachedCallbackFunction);
+#define INJECT_BEFORE int c = 500; // This is a callback, so we need to inject code before the call
#endif
#define IS_BIG_ENDIAN 0
#define USE_JSVALUE64 1
#define USE_JSVALUE32_64 0
-// #include <stdint.h>
-#ifdef INJECT_BEFORE
-// #include <stdio.h>
-#endif
-// #include <tcclib.h>
-// // /* 7.18.1.1 Exact-width integer types */
+// /* 7.18.1.1 Exact-width integer types */
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef short int16_t;
@@ -30,7 +26,7 @@ typedef int int32_t;
typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
-typedef uint64_t size_t;
+typedef unsigned long long size_t;
typedef long intptr_t;
typedef uint64_t uintptr_t;
typedef _Bool bool;
@@ -39,6 +35,13 @@ typedef _Bool bool;
#define false 0
+#ifdef INJECT_BEFORE
+// #include <stdint.h>
+#endif
+// #include <tcclib.h>
+
+
+
// This value is 2^49, used to encode doubles such that the encoded value will
// begin with a 15-bit pattern within the range 0x0002..0xFFFC.
#define DoubleEncodeOffsetBit 49
@@ -50,6 +53,10 @@ typedef _Bool bool;
#define TagValueTrue (OtherTag | BoolTag | true)
#define TagValueUndefined (OtherTag | UndefinedTag)
#define TagValueNull (OtherTag)
+#define NotCellMask NumberTag | OtherTag
+
+#define MAX_INT32 2147483648
+#define MAX_INT52 9007199254740991
// If all bits in the mask are set, this indicates an integer number,
// if any but not all are set this value is a double precision number.
@@ -59,8 +66,8 @@ typedef void* JSCell;
typedef union EncodedJSValue {
int64_t asInt64;
-#if USE_JSVALUE32_64
-#elif USE_JSVALUE64
+
+#if USE_JSVALUE64
JSCell *ptr;
#endif
@@ -85,7 +92,13 @@ EncodedJSValue ValueTrue = { TagValueTrue };
typedef void* JSContext;
-#define LOAD_ARGUMENTS_FROM_CALL_FRAME EncodedJSValue* args = (EncodedJSValue*)((size_t*)callFrame + Bun_FFI_PointerOffsetToArgumentsList);
+// Bun_FFI_PointerOffsetToArgumentsList is injected into the build
+// The value is generated in `make sizegen`
+// The value is 6.
+// On ARM64_32, the value is something else but it really doesn't matter for our case
+// However, I don't want this to subtly break amidst future upgrades to JavaScriptCore
+#define LOAD_ARGUMENTS_FROM_CALL_FRAME \
+ int64_t *argsPtr = (int64_t*)((size_t*)callFrame + Bun_FFI_PointerOffsetToArgumentsList)
#ifdef IS_CALLBACK
@@ -94,11 +107,20 @@ JSContext cachedJSContext;
void* cachedCallbackFunction;
#endif
-uint64_t JSVALUE_TO_UINT64(void* globalObject, EncodedJSValue value);
-int64_t JSVALUE_TO_INT64(EncodedJSValue value);
+static bool JSVALUE_IS_CELL(EncodedJSValue val) __attribute__((__always_inline__));
+static bool JSVALUE_IS_INT32(EncodedJSValue val) __attribute__((__always_inline__));
+static bool JSVALUE_IS_NUMBER(EncodedJSValue val) __attribute__((__always_inline__));
+
+static uint64_t JSVALUE_TO_UINT64(void* globalObject, EncodedJSValue value) __attribute__((__always_inline__));
+static int64_t JSVALUE_TO_INT64(EncodedJSValue value) __attribute__((__always_inline__));
+uint64_t JSVALUE_TO_UINT64_SLOW(void* globalObject, 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(void* globalObject, uint64_t val);
-EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val);
static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__));
static EncodedJSValue DOUBLE_TO_JSVALUE(double val) __attribute__((__always_inline__));
@@ -112,6 +134,19 @@ static float JSVALUE_TO_FLOAT(EncodedJSValue val) __attribute__((__always_inline
static double JSVALUE_TO_DOUBLE(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_TO_BOOL(EncodedJSValue val) __attribute__((__always_inline__));
+static bool JSVALUE_IS_CELL(EncodedJSValue val) {
+ return !(val.asInt64 & NotCellMask);
+}
+
+static bool JSVALUE_IS_INT32(EncodedJSValue val) {
+ return (val.asInt64 & NumberTag) == NumberTag;
+}
+
+static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
+ return val.asInt64 & NumberTag;
+}
+
+
static void* JSVALUE_TO_PTR(EncodedJSValue val) {
// must be a double
return (void*)(val.asInt64 - DoubleEncodeOffset);
@@ -165,22 +200,72 @@ static bool JSVALUE_TO_BOOL(EncodedJSValue val) {
return val.asInt64 == TagValueTrue;
}
-#define arg(i) ((EncodedJSValue*)args)[i]
+
+static uint64_t JSVALUE_TO_UINT64(void* globalObject, EncodedJSValue value) {
+ if (JSVALUE_IS_INT32(value)) {
+ return (uint64_t)JSVALUE_TO_INT32(value);
+ }
+
+ if (JSVALUE_IS_NUMBER(value)) {
+ return (uint64_t)JSVALUE_TO_DOUBLE(value);
+ }
+
+ return JSVALUE_TO_UINT64_SLOW(globalObject, value);
+}
+static int64_t JSVALUE_TO_INT64(EncodedJSValue value) {
+ if (JSVALUE_IS_INT32(value)) {
+ return (int64_t)JSVALUE_TO_INT32(value);
+ }
+
+ if (JSVALUE_IS_NUMBER(value)) {
+ return (int64_t)JSVALUE_TO_DOUBLE(value);
+ }
+
+ return JSVALUE_TO_INT64_SLOW(value);
+}
+
+static EncodedJSValue UINT64_TO_JSVALUE(void* globalObject, uint64_t val) {
+ if (val < MAX_INT32) {
+ return INT32_TO_JSVALUE((int32_t)val);
+ }
+
+ if (val < MAX_INT52) {
+ return DOUBLE_TO_JSVALUE((double)val);
+ }
+
+ return UINT64_TO_JSVALUE_SLOW(globalObject, val);
+}
+
+static EncodedJSValue INT64_TO_JSVALUE(void* globalObject, int64_t val) {
+ if (val >= -MAX_INT32 && val <= MAX_INT32) {
+ return INT32_TO_JSVALUE((int32_t)val);
+ }
+
+ if (val >= -MAX_INT52 && val <= MAX_INT52) {
+ return DOUBLE_TO_JSVALUE((double)val);
+ }
+
+ return INT64_TO_JSVALUE_SLOW(globalObject, val);
+}
+
#ifndef IS_CALLBACK
void* JSFunctionCall(void* globalObject, void* callFrame);
+
#endif
// --- Generated Code ---
/* --- The Function To Call */
-float not_a_callback();
+float not_a_callback(float arg0);
+
/* ---- Your Wrapper Function ---- */
void* JSFunctionCall(void* globalObject, void* callFrame) {
-#ifdef HAS_ARGUMENTS
LOAD_ARGUMENTS_FROM_CALL_FRAME;
-#endif
- float return_value = not_a_callback();
+ EncodedJSValue arg0;
+ arg0.asInt64 = *argsPtr;
+ float return_value = not_a_callback( JSVALUE_TO_FLOAT(arg0));
+
return FLOAT_TO_JSVALUE(return_value).asPtr;
}