mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
FFI: provide napi_env explicitly (#15431)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
This commit is contained in:
@@ -60,8 +60,9 @@ typedef enum {
|
||||
napi_detachable_arraybuffer_expected,
|
||||
napi_would_deadlock // unused
|
||||
} napi_status;
|
||||
void* NapiHandleScope__open(void* jsGlobalObject, bool detached);
|
||||
void NapiHandleScope__close(void* jsGlobalObject, void* handleScope);
|
||||
void* NapiHandleScope__open(void* napi_env, bool detached);
|
||||
void NapiHandleScope__close(void* napi_env, void* handleScope);
|
||||
extern struct napi_env__ Bun__thisFFIModuleNapiEnv;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -444,6 +444,13 @@ pub const FFI = struct {
|
||||
return error.DeferredErrors;
|
||||
}
|
||||
|
||||
for (this.symbols.map.values()) |*symbol| {
|
||||
if (symbol.needsNapiEnv()) {
|
||||
_ = TCC.tcc_add_symbol(state, "Bun__thisFFIModuleNapiEnv", globalThis);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (this.define.items) |define| {
|
||||
TCC.tcc_define_symbol(state, define[0], define[1]);
|
||||
|
||||
@@ -801,7 +808,7 @@ pub const FFI = struct {
|
||||
const function_name = function.base_name.?;
|
||||
const allocator = bun.default_allocator;
|
||||
|
||||
function.compile(allocator) catch |err| {
|
||||
function.compile(allocator, globalThis) catch |err| {
|
||||
if (!globalThis.hasException()) {
|
||||
const ret = JSC.toInvalidArguments("{s} when translating symbol \"{s}\"", .{
|
||||
@errorName(err),
|
||||
@@ -1141,7 +1148,7 @@ pub const FFI = struct {
|
||||
function.symbol_from_dynamic_library = resolved_symbol;
|
||||
}
|
||||
|
||||
function.compile(allocator) catch |err| {
|
||||
function.compile(allocator, global) catch |err| {
|
||||
const ret = JSC.toInvalidArguments("{s} when compiling symbol \"{s}\" in \"{s}\"", .{
|
||||
bun.asByteSlice(@errorName(err)),
|
||||
bun.asByteSlice(function_name),
|
||||
@@ -1246,7 +1253,7 @@ pub const FFI = struct {
|
||||
return ret;
|
||||
}
|
||||
|
||||
function.compile(allocator) catch |err| {
|
||||
function.compile(allocator, global) catch |err| {
|
||||
const ret = JSC.toInvalidArguments("{s} when compiling symbol \"{s}\"", .{
|
||||
bun.asByteSlice(@errorName(err)),
|
||||
bun.asByteSlice(function_name),
|
||||
@@ -1555,6 +1562,7 @@ pub const FFI = struct {
|
||||
pub fn compile(
|
||||
this: *Function,
|
||||
allocator: std.mem.Allocator,
|
||||
globalObject: *JSC.JSGlobalObject,
|
||||
) !void {
|
||||
var source_code = std.ArrayList(u8).init(allocator);
|
||||
var source_code_writer = source_code.writer();
|
||||
@@ -1577,6 +1585,8 @@ pub const FFI = struct {
|
||||
|
||||
_ = TCC.tcc_set_output_type(state, TCC.TCC_OUTPUT_MEMORY);
|
||||
|
||||
_ = TCC.tcc_add_symbol(state, "Bun__thisFFIModuleNapiEnv", globalObject);
|
||||
|
||||
CompilerRT.define(state);
|
||||
|
||||
// TCC.tcc_define_symbol(
|
||||
@@ -1684,6 +1694,8 @@ pub const FFI = struct {
|
||||
|
||||
_ = TCC.tcc_set_output_type(state, TCC.TCC_OUTPUT_MEMORY);
|
||||
|
||||
_ = TCC.tcc_add_symbol(state, "Bun__thisFFIModuleNapiEnv", js_context);
|
||||
|
||||
CompilerRT.define(state);
|
||||
|
||||
const compilation_result = TCC.tcc_compile_string(
|
||||
@@ -1811,7 +1823,7 @@ pub const FFI = struct {
|
||||
|
||||
if (this.needsHandleScope()) {
|
||||
try writer.writeAll(
|
||||
\\ void* handleScope = NapiHandleScope__open(JS_GLOBAL_OBJECT, false);
|
||||
\\ void* handleScope = NapiHandleScope__open(&Bun__thisFFIModuleNapiEnv, false);
|
||||
\\
|
||||
);
|
||||
}
|
||||
@@ -1824,7 +1836,7 @@ pub const FFI = struct {
|
||||
for (this.arg_types.items, 0..) |arg, i| {
|
||||
if (arg == .napi_env) {
|
||||
try writer.print(
|
||||
\\ napi_env arg{d} = (napi_env)JS_GLOBAL_OBJECT;
|
||||
\\ napi_env arg{d} = (napi_env)&Bun__thisFFIModuleNapiEnv;
|
||||
\\ argsPtr++;
|
||||
\\
|
||||
,
|
||||
@@ -1924,7 +1936,7 @@ pub const FFI = struct {
|
||||
|
||||
if (this.needsHandleScope()) {
|
||||
try writer.writeAll(
|
||||
\\ NapiHandleScope__close(JS_GLOBAL_OBJECT, handleScope);
|
||||
\\ NapiHandleScope__close(&Bun__thisFFIModuleNapiEnv, handleScope);
|
||||
\\
|
||||
);
|
||||
}
|
||||
@@ -2056,6 +2068,16 @@ pub const FFI = struct {
|
||||
|
||||
try writer.writeAll(";\n}\n\n");
|
||||
}
|
||||
|
||||
fn needsNapiEnv(this: *const FFI.Function) bool {
|
||||
for (this.arg_types.items) |arg| {
|
||||
if (arg == .napi_env or arg == .napi_value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Must be kept in sync with JSFFIFunction.h version
|
||||
@@ -2240,7 +2262,7 @@ pub const FFI = struct {
|
||||
try writer.writeAll("JSVALUE_TO_FLOAT(");
|
||||
},
|
||||
.napi_env => {
|
||||
try writer.writeAll("(napi_env)JS_GLOBAL_OBJECT");
|
||||
try writer.writeAll("((napi_env)&Bun__thisFFIModuleNapiEnv)");
|
||||
return;
|
||||
},
|
||||
.napi_value => {
|
||||
@@ -2301,7 +2323,7 @@ pub const FFI = struct {
|
||||
try writer.print("FLOAT_TO_JSVALUE({s})", .{self.symbol});
|
||||
},
|
||||
.napi_env => {
|
||||
try writer.writeAll("JS_GLOBAL_OBJECT");
|
||||
try writer.writeAll("((napi_env)&Bun__thisFFIModuleNapiEnv)");
|
||||
},
|
||||
.napi_value => {
|
||||
try writer.print("((EncodedJSValue) {{.asNapiValue = {s} }} )", .{self.symbol});
|
||||
|
||||
@@ -2,8 +2,8 @@ import { expect, it } from "bun:test";
|
||||
import { bunEnv, bunExe, isWindows } from "harness";
|
||||
import path from "path";
|
||||
|
||||
// TODO: we need to install build-essential and apple SDK in CI.
|
||||
// it can't find includes. It can on machiens with that enabled.
|
||||
// TODO: we need to install build-essential and Apple SDK in CI.
|
||||
// It can't find includes. It can on machines with that enabled.
|
||||
it.todoIf(isWindows)("can run a .c file", () => {
|
||||
const result = Bun.spawnSync({
|
||||
cmd: [bunExe(), path.join(__dirname, "cc-fixture.js")],
|
||||
|
||||
@@ -35,6 +35,38 @@ typedef _Bool bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#ifndef SRC_JS_NATIVE_API_TYPES_H_
|
||||
typedef struct napi_env__ *napi_env;
|
||||
typedef int64_t napi_value;
|
||||
typedef enum {
|
||||
napi_ok,
|
||||
napi_invalid_arg,
|
||||
napi_object_expected,
|
||||
napi_string_expected,
|
||||
napi_name_expected,
|
||||
napi_function_expected,
|
||||
napi_number_expected,
|
||||
napi_boolean_expected,
|
||||
napi_array_expected,
|
||||
napi_generic_failure,
|
||||
napi_pending_exception,
|
||||
napi_cancelled,
|
||||
napi_escape_called_twice,
|
||||
napi_handle_scope_mismatch,
|
||||
napi_callback_scope_mismatch,
|
||||
napi_queue_full,
|
||||
napi_closing,
|
||||
napi_bigint_expected,
|
||||
napi_date_expected,
|
||||
napi_arraybuffer_expected,
|
||||
napi_detachable_arraybuffer_expected,
|
||||
napi_would_deadlock // unused
|
||||
} napi_status;
|
||||
void* NapiHandleScope__open(void* napi_env, bool detached);
|
||||
void NapiHandleScope__close(void* napi_env, void* handleScope);
|
||||
extern struct napi_env__ Bun__thisFFIModuleNapiEnv;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef INJECT_BEFORE
|
||||
// #include <stdint.h>
|
||||
@@ -45,14 +77,14 @@ typedef _Bool bool;
|
||||
// begin with a 15-bit pattern within the range 0x0002..0xFFFC.
|
||||
#define DoubleEncodeOffsetBit 49
|
||||
#define DoubleEncodeOffset (1ll << DoubleEncodeOffsetBit)
|
||||
#define OtherTag 0x2
|
||||
#define BoolTag 0x4
|
||||
#define UndefinedTag 0x8
|
||||
#define OtherTag 0x2ll
|
||||
#define BoolTag 0x4ll
|
||||
#define UndefinedTag 0x8ll
|
||||
#define TagValueFalse (OtherTag | BoolTag | false)
|
||||
#define TagValueTrue (OtherTag | BoolTag | true)
|
||||
#define TagValueUndefined (OtherTag | UndefinedTag)
|
||||
#define TagValueNull (OtherTag)
|
||||
#define NotCellMask NumberTag | OtherTag
|
||||
#define NotCellMask (int64_t)(NumberTag | OtherTag)
|
||||
|
||||
#define MAX_INT32 2147483648
|
||||
#define MAX_INT52 9007199254740991
|
||||
@@ -70,6 +102,8 @@ typedef union EncodedJSValue {
|
||||
JSCell *ptr;
|
||||
#endif
|
||||
|
||||
napi_value asNapiValue;
|
||||
|
||||
#if IS_BIG_ENDIAN
|
||||
struct {
|
||||
int32_t tag;
|
||||
@@ -140,6 +174,11 @@ static int32_t JSVALUE_TO_INT32(EncodedJSValue val) __attribute__((__always_inli
|
||||
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 uint8_t GET_JSTYPE(EncodedJSValue val) __attribute__((__always_inline__));
|
||||
static bool JSTYPE_IS_TYPED_ARRAY(uint8_t type) __attribute__((__always_inline__));
|
||||
static bool JSCELL_IS_TYPED_ARRAY(EncodedJSValue val) __attribute__((__always_inline__));
|
||||
static void* JSVALUE_TO_TYPED_ARRAY_VECTOR(EncodedJSValue val) __attribute__((__always_inline__));
|
||||
static uint64_t JSVALUE_TO_TYPED_ARRAY_LENGTH(EncodedJSValue val) __attribute__((__always_inline__));
|
||||
|
||||
static bool JSVALUE_IS_CELL(EncodedJSValue val) {
|
||||
return !(val.asInt64 & NotCellMask);
|
||||
@@ -153,6 +192,25 @@ static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
|
||||
return val.asInt64 & NumberTag;
|
||||
}
|
||||
|
||||
static uint8_t GET_JSTYPE(EncodedJSValue val) {
|
||||
return *(uint8_t*)((uint8_t*)val.asPtr + JSCell__offsetOfType);
|
||||
}
|
||||
|
||||
static bool JSTYPE_IS_TYPED_ARRAY(uint8_t type) {
|
||||
return type >= JSTypeArrayBufferViewMin && type <= JSTypeArrayBufferViewMax;
|
||||
}
|
||||
|
||||
static bool JSCELL_IS_TYPED_ARRAY(EncodedJSValue val) {
|
||||
return JSVALUE_IS_CELL(val) && JSTYPE_IS_TYPED_ARRAY(GET_JSTYPE(val));
|
||||
}
|
||||
|
||||
static void* JSVALUE_TO_TYPED_ARRAY_VECTOR(EncodedJSValue val) {
|
||||
return *(void**)((char*)val.asPtr + JSArrayBufferView__offsetOfVector);
|
||||
}
|
||||
|
||||
static uint64_t JSVALUE_TO_TYPED_ARRAY_LENGTH(EncodedJSValue val) {
|
||||
return *(uint64_t*)((char*)val.asPtr + JSArrayBufferView__offsetOfLength);
|
||||
}
|
||||
|
||||
// JSValue numbers-as-pointers are represented as a 52-bit integer
|
||||
// Previously, the pointer was stored at the end of the 64-bit value
|
||||
@@ -162,6 +220,11 @@ static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
|
||||
static void* JSVALUE_TO_PTR(EncodedJSValue val) {
|
||||
if (val.asInt64 == TagValueNull)
|
||||
return 0;
|
||||
|
||||
if (JSCELL_IS_TYPED_ARRAY(val)) {
|
||||
return JSVALUE_TO_TYPED_ARRAY_VECTOR(val);
|
||||
}
|
||||
|
||||
val.asInt64 -= DoubleEncodeOffset;
|
||||
size_t ptr = (size_t)val.asDouble;
|
||||
return (void*)ptr;
|
||||
@@ -244,6 +307,10 @@ static uint64_t JSVALUE_TO_UINT64(EncodedJSValue value) {
|
||||
return (uint64_t)JSVALUE_TO_DOUBLE(value);
|
||||
}
|
||||
|
||||
if (JSCELL_IS_TYPED_ARRAY(value)) {
|
||||
return (uint64_t)JSVALUE_TO_TYPED_ARRAY_LENGTH(value);
|
||||
}
|
||||
|
||||
return JSVALUE_TO_UINT64_SLOW(value);
|
||||
}
|
||||
static int64_t JSVALUE_TO_INT64(EncodedJSValue value) {
|
||||
@@ -293,6 +360,9 @@ ZIG_REPR_TYPE JSFunctionCall(void* jsGlobalObject, void* callFrame);
|
||||
|
||||
/* --- The Callback Function */
|
||||
bool my_callback_function(void* arg0) {
|
||||
#ifdef INJECT_BEFORE
|
||||
INJECT_BEFORE;
|
||||
#endif
|
||||
ZIG_REPR_TYPE arguments[1];
|
||||
arguments[0] = PTR_TO_JSVALUE(arg0).asZigRepr;
|
||||
return (bool)JSVALUE_TO_BOOL(_FFI_Callback_call((void*)0x0000000000000000ULL, 1, arguments));
|
||||
|
||||
@@ -35,6 +35,38 @@ typedef _Bool bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
#ifndef SRC_JS_NATIVE_API_TYPES_H_
|
||||
typedef struct napi_env__ *napi_env;
|
||||
typedef int64_t napi_value;
|
||||
typedef enum {
|
||||
napi_ok,
|
||||
napi_invalid_arg,
|
||||
napi_object_expected,
|
||||
napi_string_expected,
|
||||
napi_name_expected,
|
||||
napi_function_expected,
|
||||
napi_number_expected,
|
||||
napi_boolean_expected,
|
||||
napi_array_expected,
|
||||
napi_generic_failure,
|
||||
napi_pending_exception,
|
||||
napi_cancelled,
|
||||
napi_escape_called_twice,
|
||||
napi_handle_scope_mismatch,
|
||||
napi_callback_scope_mismatch,
|
||||
napi_queue_full,
|
||||
napi_closing,
|
||||
napi_bigint_expected,
|
||||
napi_date_expected,
|
||||
napi_arraybuffer_expected,
|
||||
napi_detachable_arraybuffer_expected,
|
||||
napi_would_deadlock // unused
|
||||
} napi_status;
|
||||
void* NapiHandleScope__open(void* napi_env, bool detached);
|
||||
void NapiHandleScope__close(void* napi_env, void* handleScope);
|
||||
extern struct napi_env__ Bun__thisFFIModuleNapiEnv;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef INJECT_BEFORE
|
||||
// #include <stdint.h>
|
||||
@@ -45,14 +77,14 @@ typedef _Bool bool;
|
||||
// begin with a 15-bit pattern within the range 0x0002..0xFFFC.
|
||||
#define DoubleEncodeOffsetBit 49
|
||||
#define DoubleEncodeOffset (1ll << DoubleEncodeOffsetBit)
|
||||
#define OtherTag 0x2
|
||||
#define BoolTag 0x4
|
||||
#define UndefinedTag 0x8
|
||||
#define OtherTag 0x2ll
|
||||
#define BoolTag 0x4ll
|
||||
#define UndefinedTag 0x8ll
|
||||
#define TagValueFalse (OtherTag | BoolTag | false)
|
||||
#define TagValueTrue (OtherTag | BoolTag | true)
|
||||
#define TagValueUndefined (OtherTag | UndefinedTag)
|
||||
#define TagValueNull (OtherTag)
|
||||
#define NotCellMask NumberTag | OtherTag
|
||||
#define NotCellMask (int64_t)(NumberTag | OtherTag)
|
||||
|
||||
#define MAX_INT32 2147483648
|
||||
#define MAX_INT52 9007199254740991
|
||||
@@ -70,6 +102,8 @@ typedef union EncodedJSValue {
|
||||
JSCell *ptr;
|
||||
#endif
|
||||
|
||||
napi_value asNapiValue;
|
||||
|
||||
#if IS_BIG_ENDIAN
|
||||
struct {
|
||||
int32_t tag;
|
||||
@@ -140,6 +174,11 @@ static int32_t JSVALUE_TO_INT32(EncodedJSValue val) __attribute__((__always_inli
|
||||
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 uint8_t GET_JSTYPE(EncodedJSValue val) __attribute__((__always_inline__));
|
||||
static bool JSTYPE_IS_TYPED_ARRAY(uint8_t type) __attribute__((__always_inline__));
|
||||
static bool JSCELL_IS_TYPED_ARRAY(EncodedJSValue val) __attribute__((__always_inline__));
|
||||
static void* JSVALUE_TO_TYPED_ARRAY_VECTOR(EncodedJSValue val) __attribute__((__always_inline__));
|
||||
static uint64_t JSVALUE_TO_TYPED_ARRAY_LENGTH(EncodedJSValue val) __attribute__((__always_inline__));
|
||||
|
||||
static bool JSVALUE_IS_CELL(EncodedJSValue val) {
|
||||
return !(val.asInt64 & NotCellMask);
|
||||
@@ -153,6 +192,25 @@ static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
|
||||
return val.asInt64 & NumberTag;
|
||||
}
|
||||
|
||||
static uint8_t GET_JSTYPE(EncodedJSValue val) {
|
||||
return *(uint8_t*)((uint8_t*)val.asPtr + JSCell__offsetOfType);
|
||||
}
|
||||
|
||||
static bool JSTYPE_IS_TYPED_ARRAY(uint8_t type) {
|
||||
return type >= JSTypeArrayBufferViewMin && type <= JSTypeArrayBufferViewMax;
|
||||
}
|
||||
|
||||
static bool JSCELL_IS_TYPED_ARRAY(EncodedJSValue val) {
|
||||
return JSVALUE_IS_CELL(val) && JSTYPE_IS_TYPED_ARRAY(GET_JSTYPE(val));
|
||||
}
|
||||
|
||||
static void* JSVALUE_TO_TYPED_ARRAY_VECTOR(EncodedJSValue val) {
|
||||
return *(void**)((char*)val.asPtr + JSArrayBufferView__offsetOfVector);
|
||||
}
|
||||
|
||||
static uint64_t JSVALUE_TO_TYPED_ARRAY_LENGTH(EncodedJSValue val) {
|
||||
return *(uint64_t*)((char*)val.asPtr + JSArrayBufferView__offsetOfLength);
|
||||
}
|
||||
|
||||
// JSValue numbers-as-pointers are represented as a 52-bit integer
|
||||
// Previously, the pointer was stored at the end of the 64-bit value
|
||||
@@ -162,6 +220,11 @@ static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
|
||||
static void* JSVALUE_TO_PTR(EncodedJSValue val) {
|
||||
if (val.asInt64 == TagValueNull)
|
||||
return 0;
|
||||
|
||||
if (JSCELL_IS_TYPED_ARRAY(val)) {
|
||||
return JSVALUE_TO_TYPED_ARRAY_VECTOR(val);
|
||||
}
|
||||
|
||||
val.asInt64 -= DoubleEncodeOffset;
|
||||
size_t ptr = (size_t)val.asDouble;
|
||||
return (void*)ptr;
|
||||
@@ -244,6 +307,10 @@ static uint64_t JSVALUE_TO_UINT64(EncodedJSValue value) {
|
||||
return (uint64_t)JSVALUE_TO_DOUBLE(value);
|
||||
}
|
||||
|
||||
if (JSCELL_IS_TYPED_ARRAY(value)) {
|
||||
return (uint64_t)JSVALUE_TO_TYPED_ARRAY_LENGTH(value);
|
||||
}
|
||||
|
||||
return JSVALUE_TO_UINT64_SLOW(value);
|
||||
}
|
||||
static int64_t JSVALUE_TO_INT64(EncodedJSValue value) {
|
||||
|
||||
Reference in New Issue
Block a user