From 60faa8696fda76336c1f9792ddfdf0d242ecdc38 Mon Sep 17 00:00:00 2001 From: pfg Date: Mon, 21 Jul 2025 16:26:07 -0700 Subject: [PATCH] Auto cpp->zig bindings (#20881) Co-authored-by: pfgithub <6010774+pfgithub@users.noreply.github.com> Co-authored-by: Ben Grant Co-authored-by: Claude --- CONTRIBUTING.md | 1 + build.zig | 7 + bun.lock | 10 + cmake/sources/JavaScriptCodegenSources.txt | 2 + cmake/targets/BuildBun.cmake | 31 +- cmake/tools/SetupZig.cmake | 2 +- package.json | 2 + src/ast/Expr.zig | 4 +- src/bun.js/bindings/BunString.cpp | 38 +- src/bun.js/bindings/CustomGetterSetter.zig | 8 +- src/bun.js/bindings/DOMURL.zig | 6 +- src/bun.js/bindings/DoubleFormatter.cpp | 4 +- .../bindings/ExposeNodeModuleGlobals.cpp | 2 +- src/bun.js/bindings/HTTPServerAgent.zig | 9 +- src/bun.js/bindings/IPC.cpp | 14 +- .../bindings/InspectorHTTPServerAgent.cpp | 11 +- src/bun.js/bindings/JSMap.zig | 12 +- src/bun.js/bindings/JSPromise.zig | 21 +- src/bun.js/bindings/JSValue.zig | 71 +- src/bun.js/bindings/SourceProvider.zig | 6 +- src/bun.js/bindings/VM.zig | 11 +- src/bun.js/bindings/ZigGlobalObject.cpp | 2 +- src/bun.js/bindings/bindings.cpp | 158 ++-- src/bun.js/bindings/c-bindings.cpp | 2 +- src/bun.js/bindings/headers.h | 2 - src/bun.js/bindings/root.h | 3 + src/bun.js/bindings/wtf-bindings.cpp | 4 +- src/bun.js/ipc.zig | 8 +- src/bun.zig | 12 +- src/bun_js.zig | 8 +- src/codegen/cppbind.ts | 694 ++++++++++++++++++ src/codegen/shared-types.ts | 60 ++ src/fmt.zig | 6 +- src/string.zig | 52 +- src/string/WTFStringImpl.zig | 16 +- 35 files changed, 1026 insertions(+), 273 deletions(-) create mode 100644 src/codegen/cppbind.ts create mode 100644 src/codegen/shared-types.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9799ba4ea..19266abfdc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -160,6 +160,7 @@ In particular, these are: - `./src/codegen/generate-jssink.ts` -- Generates `build/debug/codegen/JSSink.cpp`, `build/debug/codegen/JSSink.h` which implement various classes for interfacing with `ReadableStream`. This is internally how `FileSink`, `ArrayBufferSink`, `"type": "direct"` streams and other code related to streams works. - `./src/codegen/generate-classes.ts` -- Generates `build/debug/codegen/ZigGeneratedClasses*`, which generates Zig & C++ bindings for JavaScriptCore classes implemented in Zig. In `**/*.classes.ts` files, we define the interfaces for various classes, methods, prototypes, getters/setters etc which the code generator reads to generate boilerplate code implementing the JavaScript objects in C++ and wiring them up to Zig +- `./src/codegen/cppbind.ts` -- Generates automatic Zig bindings for C++ functions marked with `[[ZIG_EXPORT]]` attributes. - `./src/codegen/bundle-modules.ts` -- Bundles built-in modules like `node:fs`, `bun:ffi` into files we can include in the final binary. In development, these can be reloaded without rebuilding Zig (you still need to run `bun run build`, but it re-reads the transpiled files from disk afterwards). In release builds, these are embedded into the binary. - `./src/codegen/bundle-functions.ts` -- Bundles globally-accessible functions implemented in JavaScript/TypeScript like `ReadableStream`, `WritableStream`, and a handful more. These are used similarly to the builtin modules, but the output more closely aligns with what WebKit/Safari does for Safari's built-in functions so that we can copy-paste the implementations from WebKit as a starting point. diff --git a/build.zig b/build.zig index 82a7294249..4bc45fcdea 100644 --- a/build.zig +++ b/build.zig @@ -752,6 +752,13 @@ fn addInternalImports(b: *Build, mod: *Module, opts: *BunBuildOptions) void { }); } } + { + const cppImport = b.createModule(.{ + .root_source_file = (std.Build.LazyPath{ .cwd_relative = opts.codegen_path }).path(b, "cpp.zig"), + }); + mod.addImport("cpp", cppImport); + cppImport.addImport("bun", mod); + } inline for (.{ .{ .import = "completions-bash", .file = b.path("completions/bun.bash") }, .{ .import = "completions-zsh", .file = b.path("completions/bun.zsh") }, diff --git a/bun.lock b/bun.lock index 345e3a7b9b..8bb29562bf 100644 --- a/bun.lock +++ b/bun.lock @@ -4,6 +4,8 @@ "": { "name": "bun", "devDependencies": { + "@lezer/common": "^1.2.3", + "@lezer/cpp": "^1.1.3", "esbuild": "^0.21.4", "mitata": "^0.1.11", "peechy": "0.4.34", @@ -87,6 +89,14 @@ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], + "@lezer/common": ["@lezer/common@1.2.3", "", {}, "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA=="], + + "@lezer/cpp": ["@lezer/cpp@1.1.3", "", { "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }, "sha512-ykYvuFQKGsRi6IcE+/hCSGUhb/I4WPjd3ELhEblm2wS2cOznDFzO+ubK2c+ioysOnlZ3EduV+MVQFCPzAIoY3w=="], + + "@lezer/highlight": ["@lezer/highlight@1.2.1", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA=="], + + "@lezer/lr": ["@lezer/lr@1.4.2", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA=="], + "@types/bun": ["@types/bun@workspace:packages/@types/bun"], "@types/node": ["@types/node@22.15.18", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-v1DKRfUdyW+jJhZNEI1PYy29S2YRxMV5AOO/x/SjKmW0acCIOqmbj6Haf9eHAhsPmrhlHSxEhv/1WszcLWV4cg=="], diff --git a/cmake/sources/JavaScriptCodegenSources.txt b/cmake/sources/JavaScriptCodegenSources.txt index 2eec797d85..2c97f0a153 100644 --- a/cmake/sources/JavaScriptCodegenSources.txt +++ b/cmake/sources/JavaScriptCodegenSources.txt @@ -8,6 +8,7 @@ src/codegen/bundle-functions.ts src/codegen/bundle-modules.ts src/codegen/class-definitions.ts src/codegen/client-js.ts +src/codegen/cppbind.ts src/codegen/create-hash-table.ts src/codegen/generate-classes.ts src/codegen/generate-compact-string-table.ts @@ -17,3 +18,4 @@ src/codegen/generate-node-errors.ts src/codegen/helpers.ts src/codegen/internal-module-registry-scanner.ts src/codegen/replacements.ts +src/codegen/shared-types.ts diff --git a/cmake/targets/BuildBun.cmake b/cmake/targets/BuildBun.cmake index f3f74f9fc4..95fddc9c12 100644 --- a/cmake/targets/BuildBun.cmake +++ b/cmake/targets/BuildBun.cmake @@ -255,6 +255,10 @@ set(BUN_ZIG_GENERATED_CLASSES_SCRIPT ${CWD}/src/codegen/generate-classes.ts) absolute_sources(BUN_ZIG_GENERATED_CLASSES_SOURCES ${CWD}/cmake/sources/ZigGeneratedClassesSources.txt) +# hand written cpp source files. Full list of "source" code (including codegen) is in BUN_CPP_SOURCES +absolute_sources(BUN_CXX_SOURCES ${CWD}/cmake/sources/CxxSources.txt) +absolute_sources(BUN_C_SOURCES ${CWD}/cmake/sources/CSources.txt) + set(BUN_ZIG_GENERATED_CLASSES_OUTPUTS ${CODEGEN_PATH}/ZigGeneratedClasses.h ${CODEGEN_PATH}/ZigGeneratedClasses.cpp @@ -308,6 +312,27 @@ set(BUN_JAVASCRIPT_OUTPUTS ${CWD}/src/bun.js/bindings/GeneratedJS2Native.zig ) +set(BUN_CPP_OUTPUTS + ${CODEGEN_PATH}/cpp.zig +) + +register_command( + TARGET + bun-cppbind + COMMENT + "Generating C++ --> Zig bindings" + COMMAND + ${BUN_EXECUTABLE} + ${CWD}/src/codegen/cppbind.ts + ${CWD}/src + ${CODEGEN_PATH} + SOURCES + ${BUN_JAVASCRIPT_CODEGEN_SOURCES} + ${BUN_CXX_SOURCES} + OUTPUTS + ${BUN_CPP_OUTPUTS} +) + register_command( TARGET bun-js-modules @@ -537,6 +562,7 @@ set(BUN_ZIG_GENERATED_SOURCES ${BUN_ERROR_CODE_OUTPUTS} ${BUN_ZIG_GENERATED_CLASSES_OUTPUTS} ${BUN_JAVASCRIPT_OUTPUTS} + ${BUN_CPP_OUTPUTS} ) # In debug builds, these are not embedded, but rather referenced at runtime. @@ -606,6 +632,7 @@ register_command( TARGETS clone-zig clone-zstd + bun-cppbind SOURCES ${BUN_ZIG_SOURCES} ${BUN_ZIG_GENERATED_SOURCES} @@ -618,10 +645,6 @@ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "build.zig") set(BUN_USOCKETS_SOURCE ${CWD}/packages/bun-usockets) -# hand written cpp source files. Full list of "source" code (including codegen) is in BUN_CPP_SOURCES -absolute_sources(BUN_CXX_SOURCES ${CWD}/cmake/sources/CxxSources.txt) -absolute_sources(BUN_C_SOURCES ${CWD}/cmake/sources/CSources.txt) - if(WIN32) list(APPEND BUN_CXX_SOURCES ${CWD}/src/bun.js/bindings/windows/rescle.cpp) list(APPEND BUN_CXX_SOURCES ${CWD}/src/bun.js/bindings/windows/rescle-binding.cpp) diff --git a/cmake/tools/SetupZig.cmake b/cmake/tools/SetupZig.cmake index 5515015e59..607e43c2e8 100644 --- a/cmake/tools/SetupZig.cmake +++ b/cmake/tools/SetupZig.cmake @@ -20,7 +20,7 @@ else() unsupported(CMAKE_SYSTEM_NAME) endif() -set(ZIG_COMMIT "0a0120fa92cd7f6ab244865688b351df634f0707") +set(ZIG_COMMIT "edc6229b1fafb1701a25fb4e17114cc756991546") optionx(ZIG_TARGET STRING "The zig target to use" DEFAULT ${DEFAULT_ZIG_TARGET}) if(CMAKE_BUILD_TYPE STREQUAL "Release") diff --git a/package.json b/package.json index 3c2f0084b6..57784c79e3 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "./packages/@types/bun" ], "devDependencies": { + "@lezer/common": "^1.2.3", + "@lezer/cpp": "^1.1.3", "esbuild": "^0.21.4", "mitata": "^0.1.11", "peechy": "0.4.34", diff --git a/src/ast/Expr.zig b/src/ast/Expr.zig index 64534d21fc..9382990da1 100644 --- a/src/ast/Expr.zig +++ b/src/ast/Expr.zig @@ -3201,14 +3201,12 @@ pub fn StoredData(tag: Tag) type { }; } -extern fn JSC__jsToNumber(latin1_ptr: [*]const u8, len: usize) f64; - fn stringToEquivalentNumberValue(str: []const u8) f64 { // +"" -> 0 if (str.len == 0) return 0; if (!bun.strings.isAllASCII(str)) return std.math.nan(f64); - return JSC__jsToNumber(str.ptr, str.len); + return bun.cpp.JSC__jsToNumber(str.ptr, str.len); } const JSPrinter = @import("../js_printer.zig"); diff --git a/src/bun.js/bindings/BunString.cpp b/src/bun.js/bindings/BunString.cpp index 6f1bece04f..e35e456dc0 100644 --- a/src/bun.js/bindings/BunString.cpp +++ b/src/bun.js/bindings/BunString.cpp @@ -44,35 +44,35 @@ extern "C" void mi_free(void* ptr); using namespace JSC; extern "C" BunString BunString__fromBytes(const char* bytes, size_t length); -extern "C" bool Bun__WTFStringImpl__hasPrefix(const WTF::StringImpl* impl, const char* bytes, size_t length) +extern "C" [[ZIG_EXPORT(nothrow)]] bool Bun__WTFStringImpl__hasPrefix(const WTF::StringImpl* impl, const char* bytes, size_t length) { return impl->startsWith({ bytes, length }); } -extern "C" void Bun__WTFStringImpl__deref(WTF::StringImpl* impl) +extern "C" [[ZIG_EXPORT(nothrow)]] void Bun__WTFStringImpl__deref(WTF::StringImpl* impl) { impl->deref(); } -extern "C" void Bun__WTFStringImpl__ref(WTF::StringImpl* impl) +extern "C" [[ZIG_EXPORT(nothrow)]] void Bun__WTFStringImpl__ref(WTF::StringImpl* impl) { impl->ref(); } -extern "C" bool BunString__fromJS(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue encodedValue, BunString* bunString) +extern "C" [[ZIG_EXPORT(nothrow)]] bool BunString__fromJS(JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue encodedValue, BunString* bunString) { JSC::JSValue value = JSC::JSValue::decode(encodedValue); *bunString = Bun::toString(globalObject, value); return bunString->tag != BunStringTag::Dead; } -extern "C" BunString BunString__createAtom(const char* bytes, size_t length) +extern "C" [[ZIG_EXPORT(nothrow)]] BunString BunString__createAtom(const char* bytes, size_t length) { ASSERT(simdutf::validate_ascii(bytes, length)); auto atom = tryMakeAtomString(String(StringImpl::createWithoutCopying({ bytes, length }))); return { BunStringTag::WTFStringImpl, { .wtf = atom.releaseImpl().leakRef() } }; } -extern "C" BunString BunString__tryCreateAtom(const char* bytes, size_t length) +extern "C" [[ZIG_EXPORT(nothrow)]] BunString BunString__tryCreateAtom(const char* bytes, size_t length) { if (simdutf::validate_ascii(bytes, length)) { auto atom = tryMakeAtomString(String(StringImpl::createWithoutCopying({ bytes, length }))); @@ -84,7 +84,7 @@ extern "C" BunString BunString__tryCreateAtom(const char* bytes, size_t length) return { BunStringTag::Dead, {} }; } -extern "C" JSC::EncodedJSValue BunString__createUTF8ForJS(JSC::JSGlobalObject* globalObject, const char* ptr, size_t length) +extern "C" [[ZIG_EXPORT(zero_is_throw)]] JSC::EncodedJSValue BunString__createUTF8ForJS(JSC::JSGlobalObject* globalObject, const char* ptr, size_t length) { auto& vm = JSC::getVM(globalObject); auto scope = DECLARE_THROW_SCOPE(vm); @@ -134,7 +134,7 @@ extern "C" JSC::EncodedJSValue BunString__transferToJS(BunString* bunString, JSC } // int64_t max to say "not a number" -extern "C" int64_t BunString__toInt32(BunString* bunString) +extern "C" [[ZIG_EXPORT(nothrow)]] int64_t BunString__toInt32(const BunString* bunString) { if (bunString->tag == BunStringTag::Empty || bunString->tag == BunStringTag::Dead) { return std::numeric_limits::max(); @@ -191,7 +191,7 @@ BunString fromJS(JSC::JSGlobalObject* globalObject, JSValue value) return { BunStringTag::WTFStringImpl, { .wtf = impl.leakRef() } }; } -extern "C" void BunString__toThreadSafe(BunString* str) +extern "C" [[ZIG_EXPORT(nothrow)]] void BunString__toThreadSafe(BunString* str) { if (str->tag == BunStringTag::WTFStringImpl) { auto impl = str->impl.wtf->isolatedCopy(); @@ -286,7 +286,7 @@ extern "C" JSC::EncodedJSValue BunString__toJS(JSC::JSGlobalObject* globalObject return JSValue::encode(Bun::toJS(globalObject, *bunString)); } -extern "C" BunString BunString__fromUTF16Unitialized(size_t length) +extern "C" [[ZIG_EXPORT(nothrow)]] BunString BunString__fromUTF16Unitialized(size_t length) { ASSERT(length > 0); std::span ptr; @@ -297,7 +297,7 @@ extern "C" BunString BunString__fromUTF16Unitialized(size_t length) return { BunStringTag::WTFStringImpl, { .wtf = impl.leakRef() } }; } -extern "C" BunString BunString__fromLatin1Unitialized(size_t length) +extern "C" [[ZIG_EXPORT(nothrow)]] BunString BunString__fromLatin1Unitialized(size_t length) { ASSERT(length > 0); std::span ptr; @@ -330,7 +330,7 @@ extern "C" BunString BunString__fromUTF8(const char* bytes, size_t length) return Bun::toString(impl.leakRef()); } -extern "C" BunString BunString__fromLatin1(const char* bytes, size_t length) +extern "C" [[ZIG_EXPORT(nothrow)]] BunString BunString__fromLatin1(const char* bytes, size_t length) { ASSERT(length > 0); std::span ptr; @@ -343,7 +343,7 @@ extern "C" BunString BunString__fromLatin1(const char* bytes, size_t length) return { BunStringTag::WTFStringImpl, { .wtf = impl.leakRef() } }; } -extern "C" BunString BunString__fromUTF16ToLatin1(const char16_t* bytes, size_t length) +extern "C" [[ZIG_EXPORT(nothrow)]] BunString BunString__fromUTF16ToLatin1(const char16_t* bytes, size_t length) { ASSERT(length > 0); ASSERT_WITH_MESSAGE(simdutf::validate_utf16le(bytes, length), "This function only accepts ascii UTF16 strings"); @@ -359,7 +359,7 @@ extern "C" BunString BunString__fromUTF16ToLatin1(const char16_t* bytes, size_t return { BunStringTag::WTFStringImpl, { .wtf = impl.leakRef() } }; } -extern "C" BunString BunString__fromUTF16(const char16_t* bytes, size_t length) +extern "C" [[ZIG_EXPORT(nothrow)]] BunString BunString__fromUTF16(const char16_t* bytes, size_t length) { ASSERT(length > 0); std::span ptr; @@ -371,7 +371,7 @@ extern "C" BunString BunString__fromUTF16(const char16_t* bytes, size_t length) return { BunStringTag::WTFStringImpl, { .wtf = impl.leakRef() } }; } -extern "C" BunString BunString__fromBytes(const char* bytes, size_t length) +extern "C" [[ZIG_EXPORT(nothrow)]] BunString BunString__fromBytes(const char* bytes, size_t length) { ASSERT(length > 0); if (simdutf::validate_ascii(bytes, length)) { @@ -399,7 +399,7 @@ extern "C" BunString BunString__createExternal(const char* bytes, size_t length, return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } }; } -extern "C" JSC::EncodedJSValue BunString__toJSON( +extern "C" [[ZIG_EXPORT(zero_is_throw)]] JSC::EncodedJSValue BunString__toJSON( JSC::JSGlobalObject* globalObject, BunString* bunString) { @@ -438,7 +438,7 @@ extern "C" JSC::EncodedJSValue BunString__createArray( return JSValue::encode(array); } -extern "C" void BunString__toWTFString(BunString* bunString) +extern "C" [[ZIG_EXPORT(nothrow)]] void BunString__toWTFString(BunString* bunString) { WTF::String str; if (bunString->tag == BunStringTag::ZigString) { @@ -730,7 +730,7 @@ extern "C" BunString BunString__createExternalGloballyAllocatedUTF16( return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } }; } -extern "C" bool WTFStringImpl__isThreadSafe( +extern "C" [[ZIG_EXPORT(nothrow)]] bool WTFStringImpl__isThreadSafe( const WTF::StringImpl* wtf) { if (wtf->bufferOwnership() != StringImpl::BufferOwnership::BufferInternal) @@ -739,7 +739,7 @@ extern "C" bool WTFStringImpl__isThreadSafe( return !(wtf->isSymbol() || wtf->isAtom()); } -extern "C" void Bun__WTFStringImpl__ensureHash(WTF::StringImpl* str) +extern "C" [[ZIG_EXPORT(nothrow)]] void Bun__WTFStringImpl__ensureHash(WTF::StringImpl* str) { str->hash(); } diff --git a/src/bun.js/bindings/CustomGetterSetter.zig b/src/bun.js/bindings/CustomGetterSetter.zig index a93e22df42..783d7602e5 100644 --- a/src/bun.js/bindings/CustomGetterSetter.zig +++ b/src/bun.js/bindings/CustomGetterSetter.zig @@ -1,11 +1,11 @@ +const bun = @import("bun"); + pub const CustomGetterSetter = opaque { pub fn isGetterNull(this: *CustomGetterSetter) bool { - return JSC__CustomGetterSetter__isGetterNull(this); + return bun.cpp.JSC__CustomGetterSetter__isGetterNull(this); } pub fn isSetterNull(this: *CustomGetterSetter) bool { - return JSC__CustomGetterSetter__isSetterNull(this); + return bun.cpp.JSC__CustomGetterSetter__isSetterNull(this); } - extern fn JSC__CustomGetterSetter__isGetterNull(this: *CustomGetterSetter) bool; - extern fn JSC__CustomGetterSetter__isSetterNull(this: *CustomGetterSetter) bool; }; diff --git a/src/bun.js/bindings/DOMURL.zig b/src/bun.js/bindings/DOMURL.zig index b4ca3bdd01..1c8d9f80d8 100644 --- a/src/bun.js/bindings/DOMURL.zig +++ b/src/bun.js/bindings/DOMURL.zig @@ -1,7 +1,5 @@ pub const DOMURL = opaque { pub extern fn WebCore__DOMURL__cast_(JSValue0: JSValue, arg1: *VM) ?*DOMURL; - pub extern fn WebCore__DOMURL__href_(arg0: ?*DOMURL, arg1: *ZigString) void; - pub extern fn WebCore__DOMURL__pathname_(arg0: ?*DOMURL, arg1: *ZigString) void; pub fn cast_(value: JSValue, vm: *VM) ?*DOMURL { return WebCore__DOMURL__cast_(value, vm); @@ -12,7 +10,7 @@ pub const DOMURL = opaque { } pub fn href_(this: *DOMURL, out: *ZigString) void { - return WebCore__DOMURL__href_(this, out); + return bun.cpp.WebCore__DOMURL__href_(this, out); } pub fn href(this: *DOMURL) ZigString { @@ -41,7 +39,7 @@ pub const DOMURL = opaque { } pub fn pathname_(this: *DOMURL, out: *ZigString) void { - return WebCore__DOMURL__pathname_(this, out); + return bun.cpp.WebCore__DOMURL__pathname_(this, out); } pub fn pathname(this: *DOMURL) ZigString { diff --git a/src/bun.js/bindings/DoubleFormatter.cpp b/src/bun.js/bindings/DoubleFormatter.cpp index 82266076a2..a0e096d859 100644 --- a/src/bun.js/bindings/DoubleFormatter.cpp +++ b/src/bun.js/bindings/DoubleFormatter.cpp @@ -8,7 +8,7 @@ using namespace WTF; /// Must be called with a buffer of exactly 124 /// Find the length by scanning for the 0 -extern "C" size_t WTF__dtoa(char* buf_124_bytes, double number) +extern "C" [[ZIG_EXPORT(nothrow)]] size_t WTF__dtoa(char* buf_124_bytes, double number) { NumberToStringBuffer& buf = *reinterpret_cast(buf_124_bytes); return WTF::numberToStringAndSize(number, buf).size(); @@ -17,7 +17,7 @@ extern "C" size_t WTF__dtoa(char* buf_124_bytes, double number) /// This is the equivalent of the unary '+' operator on a JS string /// See https://262.ecma-international.org/14.0/#sec-stringtonumber /// Grammar: https://262.ecma-international.org/14.0/#prod-StringNumericLiteral -extern "C" double JSC__jsToNumber(char* latin1_ptr, size_t len) +extern "C" [[ZIG_EXPORT(nothrow)]] double JSC__jsToNumber(const char* latin1_ptr, size_t len) { return JSC::jsToNumber(WTF::StringView(latin1_ptr, len, true)); } diff --git a/src/bun.js/bindings/ExposeNodeModuleGlobals.cpp b/src/bun.js/bindings/ExposeNodeModuleGlobals.cpp index 95a24b19fe..f236aff00f 100644 --- a/src/bun.js/bindings/ExposeNodeModuleGlobals.cpp +++ b/src/bun.js/bindings/ExposeNodeModuleGlobals.cpp @@ -67,7 +67,7 @@ FOREACH_EXPOSED_BUILTIN_IMR(DECL_GETTER) } // namespace ExposeNodeModuleGlobalGetters -extern "C" void Bun__ExposeNodeModuleGlobals(Zig::GlobalObject* globalObject) +extern "C" [[ZIG_EXPORT(nothrow)]] void Bun__ExposeNodeModuleGlobals(Zig::GlobalObject* globalObject) { auto& vm = JSC::getVM(globalObject); diff --git a/src/bun.js/bindings/HTTPServerAgent.zig b/src/bun.js/bindings/HTTPServerAgent.zig index 27b94cfd57..88352b4019 100644 --- a/src/bun.js/bindings/HTTPServerAgent.zig +++ b/src/bun.js/bindings/HTTPServerAgent.zig @@ -134,9 +134,6 @@ pub const Route = extern struct { //#region C++ agent reference type for Zig pub const InspectorHTTPServerAgent = opaque { - extern fn Bun__HTTPServerAgent__notifyServerStarted(agent: *InspectorHTTPServerAgent, serverId: ServerId, hotReloadId: HotReloadId, address: *const BunString, startTime: f64, serverInstance: *anyopaque) void; - extern fn Bun__HTTPServerAgent__notifyServerStopped(agent: *InspectorHTTPServerAgent, serverId: ServerId, timestamp: f64) void; - extern fn Bun__HTTPServerAgent__notifyServerRoutesUpdated(agent: *InspectorHTTPServerAgent, serverId: ServerId, hotReloadId: HotReloadId, routes: [*]Route, routesCount: usize) void; extern fn Bun__HTTPServerAgent__notifyRequestWillBeSent(agent: *InspectorHTTPServerAgent, requestId: RequestId, serverId: ServerId, routeId: RouteId, url: *const BunString, fullUrl: *const BunString, method: HTTPMethod, headersJson: *const BunString, paramsJson: *const BunString, hasBody: bool, timestamp: f64) void; extern fn Bun__HTTPServerAgent__notifyResponseReceived(agent: *InspectorHTTPServerAgent, requestId: RequestId, serverId: ServerId, statusCode: i32, statusText: *const BunString, headersJson: *const BunString, hasBody: bool, timestamp: f64) void; extern fn Bun__HTTPServerAgent__notifyBodyChunkReceived(agent: *InspectorHTTPServerAgent, requestId: RequestId, serverId: ServerId, flags: i32, chunk: *const BunString, timestamp: f64) void; @@ -144,15 +141,15 @@ pub const InspectorHTTPServerAgent = opaque { extern fn Bun__HTTPServerAgent__notifyRequestHandlerException(agent: *InspectorHTTPServerAgent, requestId: RequestId, serverId: ServerId, message: *const BunString, url: *const BunString, line: i32, timestamp: f64) void; pub fn notifyServerStarted(agent: *InspectorHTTPServerAgent, serverId: ServerId, hotReloadId: HotReloadId, address: *const BunString, startTime: f64, serverInstance: *anyopaque) void { - Bun__HTTPServerAgent__notifyServerStarted(agent, serverId, hotReloadId, address, startTime, serverInstance); + bun.cpp.Bun__HTTPServerAgent__notifyServerStarted(agent, serverId, hotReloadId, address, startTime, serverInstance); } pub fn notifyServerStopped(agent: *InspectorHTTPServerAgent, serverId: ServerId, timestamp: f64) void { - Bun__HTTPServerAgent__notifyServerStopped(agent, serverId, timestamp); + bun.cpp.Bun__HTTPServerAgent__notifyServerStopped(agent, serverId, timestamp); } pub fn notifyServerRoutesUpdated(agent: *InspectorHTTPServerAgent, serverId: ServerId, hotReloadId: HotReloadId, routes: []Route) void { - Bun__HTTPServerAgent__notifyServerRoutesUpdated(agent, serverId, hotReloadId, routes.ptr, routes.len); + bun.cpp.Bun__HTTPServerAgent__notifyServerRoutesUpdated(agent, serverId, hotReloadId, routes.ptr, routes.len); } }; diff --git a/src/bun.js/bindings/IPC.cpp b/src/bun.js/bindings/IPC.cpp index 24ef361934..d5641de572 100644 --- a/src/bun.js/bindings/IPC.cpp +++ b/src/bun.js/bindings/IPC.cpp @@ -3,7 +3,7 @@ #include "BunBuiltinNames.h" #include "WebCoreJSBuiltins.h" -extern "C" JSC::EncodedJSValue IPCSerialize(JSC::JSGlobalObject* global, JSC::JSValue message, JSC::JSValue handle) +extern "C" [[ZIG_EXPORT(zero_is_throw)]] JSC::EncodedJSValue IPCSerialize(JSC::JSGlobalObject* global, JSC::EncodedJSValue message, JSC::EncodedJSValue handle) { auto& vm = JSC::getVM(global); auto scope = DECLARE_THROW_SCOPE(vm); @@ -11,15 +11,15 @@ extern "C" JSC::EncodedJSValue IPCSerialize(JSC::JSGlobalObject* global, JSC::JS JSC::CallData callData = JSC::getCallData(serializeFunction); JSC::MarkedArgumentBuffer args; - args.append(message); - args.append(handle); + args.append(JSC::JSValue::decode(message)); + args.append(JSC::JSValue::decode(handle)); auto result = JSC::call(global, serializeFunction, callData, JSC::jsUndefined(), args); RETURN_IF_EXCEPTION(scope, {}); return JSC::JSValue::encode(result); } -extern "C" JSC::EncodedJSValue IPCParse(JSC::JSGlobalObject* global, JSC::JSValue target, JSC::JSValue serialized, JSC::JSValue fd) +extern "C" [[ZIG_EXPORT(zero_is_throw)]] JSC::EncodedJSValue IPCParse(JSC::JSGlobalObject* global, JSC::EncodedJSValue target, JSC::EncodedJSValue serialized, JSC::EncodedJSValue fd) { auto& vm = JSC::getVM(global); auto scope = DECLARE_THROW_SCOPE(vm); @@ -27,9 +27,9 @@ extern "C" JSC::EncodedJSValue IPCParse(JSC::JSGlobalObject* global, JSC::JSValu JSC::CallData callData = JSC::getCallData(parseFunction); JSC::MarkedArgumentBuffer args; - args.append(target); - args.append(serialized); - args.append(fd); + args.append(JSC::JSValue::decode(target)); + args.append(JSC::JSValue::decode(serialized)); + args.append(JSC::JSValue::decode(fd)); auto result = JSC::call(global, parseFunction, callData, JSC::jsUndefined(), args); RETURN_IF_EXCEPTION(scope, {}); diff --git a/src/bun.js/bindings/InspectorHTTPServerAgent.cpp b/src/bun.js/bindings/InspectorHTTPServerAgent.cpp index 58fc7329b1..9d40ff74ba 100644 --- a/src/bun.js/bindings/InspectorHTTPServerAgent.cpp +++ b/src/bun.js/bindings/InspectorHTTPServerAgent.cpp @@ -182,13 +182,18 @@ extern "C" { // Functions for Zig to call to notify about HTTP server events -void Bun__HTTPServerAgent__notifyServerStarted(Inspector::InspectorHTTPServerAgent* agent, int serverId, int hotReloadId, BunString* address, double startTime, void* serverInstance) +typedef int ServerId; +typedef int HotReloadId; +typedef int RouteId; +typedef int RequestId; + +[[ZIG_EXPORT(nothrow)]] void Bun__HTTPServerAgent__notifyServerStarted(Inspector::InspectorHTTPServerAgent* agent, ServerId serverId, HotReloadId hotReloadId, const BunString* address, double startTime, void* serverInstance) { agent->serverStarted(serverId, address->toWTFString(), startTime, serverInstance); } -void Bun__HTTPServerAgent__notifyServerStopped(Inspector::InspectorHTTPServerAgent* agent, int serverId, double timestamp) +[[ZIG_EXPORT(nothrow)]] void Bun__HTTPServerAgent__notifyServerStopped(Inspector::InspectorHTTPServerAgent* agent, ServerId serverId, double timestamp) { agent->serverStopped(serverId, timestamp); @@ -214,7 +219,7 @@ struct Route { BunString script_url; }; -void Bun__HTTPServerAgent__notifyServerRoutesUpdated(Inspector::InspectorHTTPServerAgent* agent, int serverId, int hotReloadId, +[[ZIG_EXPORT(nothrow)]] void Bun__HTTPServerAgent__notifyServerRoutesUpdated(Inspector::InspectorHTTPServerAgent* agent, ServerId serverId, HotReloadId hotReloadId, Route* routes_ptr, size_t routes_len) { diff --git a/src/bun.js/bindings/JSMap.zig b/src/bun.js/bindings/JSMap.zig index 65626c5434..ea05be9815 100644 --- a/src/bun.js/bindings/JSMap.zig +++ b/src/bun.js/bindings/JSMap.zig @@ -1,20 +1,16 @@ pub const JSMap = opaque { extern fn JSC__JSMap__create(*JSGlobalObject) JSValue; - extern fn JSC__JSMap__get_(?*JSMap, *JSGlobalObject, JSValue) JSValue; - extern fn JSC__JSMap__has(arg0: ?*JSMap, arg1: *JSGlobalObject, JSValue2: JSValue) bool; - extern fn JSC__JSMap__remove(arg0: ?*JSMap, arg1: *JSGlobalObject, JSValue2: JSValue) bool; - extern fn JSC__JSMap__set(arg0: ?*JSMap, arg1: *JSGlobalObject, JSValue2: JSValue, JSValue3: JSValue) void; pub fn create(globalObject: *JSGlobalObject) JSValue { return JSC__JSMap__create(globalObject); } pub fn set(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue, value: JSValue) void { - return JSC__JSMap__set(this, globalObject, key, value); + return bun.cpp.JSC__JSMap__set(this, globalObject, key, value); } pub fn get_(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue) JSValue { - return JSC__JSMap__get_(this, globalObject, key); + return bun.cpp.JSC__JSMap__get_(this, globalObject, key); } pub fn get(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue) ?JSValue { @@ -26,11 +22,11 @@ pub const JSMap = opaque { } pub fn has(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue) bool { - return JSC__JSMap__has(this, globalObject, key); + return bun.cpp.JSC__JSMap__has(this, globalObject, key); } pub fn remove(this: *JSMap, globalObject: *JSGlobalObject, key: JSValue) bool { - return JSC__JSMap__remove(this, globalObject, key); + return bun.cpp.JSC__JSMap__remove(this, globalObject, key); } pub fn fromJS(value: JSValue) ?*JSMap { diff --git a/src/bun.js/bindings/JSPromise.zig b/src/bun.js/bindings/JSPromise.zig index 74bbb0067f..fcf011dec8 100644 --- a/src/bun.js/bindings/JSPromise.zig +++ b/src/bun.js/bindings/JSPromise.zig @@ -6,19 +6,12 @@ pub const JSPromise = opaque { }; extern fn JSC__JSPromise__create(arg0: *JSGlobalObject) *JSPromise; - extern fn JSC__JSPromise__isHandled(arg0: *const JSPromise, arg1: *VM) bool; - extern fn JSC__JSPromise__reject(arg0: *JSPromise, arg1: *JSGlobalObject, JSValue2: JSValue) void; - extern fn JSC__JSPromise__rejectAsHandled(arg0: *JSPromise, arg1: *JSGlobalObject, JSValue2: JSValue) void; extern fn JSC__JSPromise__rejectedPromise(arg0: *JSGlobalObject, JSValue1: JSValue) *JSPromise; /// **DEPRECATED** This function does not notify the VM about the rejection, /// meaning it will not trigger unhandled rejection handling. Use JSC__JSPromise__rejectedPromise instead. extern fn JSC__JSPromise__rejectedPromiseValue(arg0: *JSGlobalObject, JSValue1: JSValue) JSValue; - extern fn JSC__JSPromise__resolve(arg0: *JSPromise, arg1: *JSGlobalObject, JSValue2: JSValue) void; extern fn JSC__JSPromise__resolvedPromise(arg0: *JSGlobalObject, JSValue1: JSValue) *JSPromise; extern fn JSC__JSPromise__resolvedPromiseValue(arg0: *JSGlobalObject, JSValue1: JSValue) JSValue; - extern fn JSC__JSPromise__result(arg0: *JSPromise, arg1: *VM) JSValue; - extern fn JSC__JSPromise__setHandled(arg0: *JSPromise, arg1: *VM) void; - extern fn JSC__JSPromise__status(arg0: *const JSPromise, arg1: *VM) JSPromise.Status; extern fn JSC__JSPromise__wrap(*JSC.JSGlobalObject, *anyopaque, *const fn (*anyopaque, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue) JSC.JSValue; pub fn Weak(comptime T: type) type { @@ -212,19 +205,19 @@ pub const JSPromise = opaque { } pub fn status(this: *const JSPromise, vm: *VM) Status { - return JSC__JSPromise__status(this, vm); + return @enumFromInt(bun.cpp.JSC__JSPromise__status(this, vm)); } pub fn result(this: *JSPromise, vm: *VM) JSValue { - return JSC__JSPromise__result(this, vm); + return bun.cpp.JSC__JSPromise__result(this, vm); } pub fn isHandled(this: *const JSPromise, vm: *VM) bool { - return JSC__JSPromise__isHandled(this, vm); + return bun.cpp.JSC__JSPromise__isHandled(this, vm); } pub fn setHandled(this: *JSPromise, vm: *VM) void { - JSC__JSPromise__setHandled(this, vm); + bun.cpp.JSC__JSPromise__setHandled(this, vm); } pub fn resolvedPromise(globalThis: *JSGlobalObject, value: JSValue) *JSPromise { @@ -261,7 +254,7 @@ pub const JSPromise = opaque { } } - return bun.jsc.fromJSHostCallGeneric(globalThis, @src(), JSC__JSPromise__resolve, .{ this, globalThis, value }) catch return bun.debugAssert(false); // TODO: properly propagate exception upwards + bun.cpp.JSC__JSPromise__resolve(this, globalThis, value) catch return bun.debugAssert(false); // TODO: properly propagate exception upwards } pub fn reject(this: *JSPromise, globalThis: *JSGlobalObject, value: JSError!JSValue) void { @@ -275,11 +268,11 @@ pub const JSPromise = opaque { const err = value catch |err| globalThis.takeException(err); - return bun.jsc.fromJSHostCallGeneric(globalThis, @src(), JSC__JSPromise__reject, .{ this, globalThis, err }) catch return bun.debugAssert(false); // TODO: properly propagate exception upwards + bun.cpp.JSC__JSPromise__reject(this, globalThis, err) catch return bun.debugAssert(false); // TODO: properly propagate exception upwards } pub fn rejectAsHandled(this: *JSPromise, globalThis: *JSGlobalObject, value: JSValue) void { - return bun.jsc.fromJSHostCallGeneric(globalThis, @src(), JSC__JSPromise__rejectAsHandled, .{ this, globalThis, value }) catch return bun.debugAssert(false); // TODO: properly propagate exception upwards + bun.cpp.JSC__JSPromise__rejectAsHandled(this, globalThis, value) catch return bun.debugAssert(false); // TODO: properly propagate exception upwards } pub fn create(globalThis: *JSGlobalObject) *JSPromise { diff --git a/src/bun.js/bindings/JSValue.zig b/src/bun.js/bindings/JSValue.zig index cc65081aac..c06cd3051c 100644 --- a/src/bun.js/bindings/JSValue.zig +++ b/src/bun.js/bindings/JSValue.zig @@ -29,14 +29,12 @@ pub const JSValue = enum(i64) { return @as(JSValue, @enumFromInt(@as(i64, @bitCast(@intFromPtr(ptr))))); } - extern fn JSC__JSValue__coerceToInt32(this: JSValue, globalThis: *JSC.JSGlobalObject) i32; pub fn coerceToInt32(this: JSValue, globalThis: *JSC.JSGlobalObject) bun.JSError!i32 { - return bun.jsc.fromJSHostCallGeneric(globalThis, @src(), JSC__JSValue__coerceToInt32, .{ this, globalThis }); + return bun.cpp.JSC__JSValue__coerceToInt32(this, globalThis); } - extern fn JSC__JSValue__coerceToInt64(this: JSValue, globalThis: *JSC.JSGlobalObject) i64; pub fn coerceToInt64(this: JSValue, globalThis: *JSC.JSGlobalObject) bun.JSError!i64 { - return bun.jsc.fromJSHostCallGeneric(globalThis, @src(), JSC__JSValue__coerceToInt64, .{ this, globalThis }); + return bun.cpp.JSC__JSValue__coerceToInt64(this, globalThis); } pub fn getIndex(this: JSValue, globalThis: *JSGlobalObject, i: u32) JSError!JSValue { @@ -627,16 +625,15 @@ pub const JSValue = enum(i64) { return null; } - extern fn JSC__JSValue__jsBoolean(i: bool) JSValue; pub inline fn jsBoolean(i: bool) JSValue { - return JSC__JSValue__jsBoolean(i); + return switch (i) { + false => .false, + true => .true, + }; } - extern fn JSC__JSValue__jsDoubleNumber(i: f64) JSValue; - - extern fn JSC__JSValue__jsEmptyString(globalThis: *JSGlobalObject) JSValue; pub inline fn jsEmptyString(globalThis: *JSGlobalObject) JSValue { - return JSC__JSValue__jsEmptyString(globalThis); + return bun.cpp.JSC__JSValue__jsEmptyString(globalThis); } pub inline fn jsNull() JSValue { @@ -647,9 +644,8 @@ pub const JSValue = enum(i64) { return jsNumberWithType(@TypeOf(number), number); } - extern fn JSC__JSValue__jsTDZValue() JSValue; pub inline fn jsTDZValue() JSValue { - return JSC__JSValue__jsTDZValue(); + return bun.cpp.JSC__JSValue__jsTDZValue(); } pub fn className(this: JSValue, globalThis: *JSGlobalObject) bun.JSError!ZigString { @@ -748,13 +744,11 @@ pub const JSValue = enum(i64) { pub fn jsDoubleNumber(i: f64) JSValue { return FFI.DOUBLE_TO_JSVALUE(i).asJSValue; } - extern fn JSC__JSValue__jsNumberFromChar(i: u8) JSValue; pub fn jsNumberFromChar(i: u8) JSValue { - return JSC__JSValue__jsNumberFromChar(i); + return bun.cpp.JSC__JSValue__jsNumberFromChar(i); } - extern fn JSC__JSValue__jsNumberFromU16(i: u16) JSValue; pub fn jsNumberFromU16(i: u16) JSValue { - return JSC__JSValue__jsNumberFromU16(i); + return bun.cpp.JSC__JSValue__jsNumberFromU16(i); } pub fn jsNumberFromInt32(i: i32) JSValue { return FFI.INT32_TO_JSVALUE(i).asJSValue; @@ -808,8 +802,6 @@ pub const JSValue = enum(i64) { return coerceJSValueDoubleTruncatingT(i64, this.asNumber()); } - extern fn JSC__JSValue__toInt64(this: JSValue) i64; - /// Decimal values are truncated without rounding. /// `-Infinity` and `NaN` coerce to -minInt(64) /// `Infinity` coerces to maxInt(64) @@ -822,7 +814,7 @@ pub const JSValue = enum(i64) { return this.coerceDoubleTruncatingIntoInt64(); } - return JSC__JSValue__toInt64(this); + return bun.cpp.JSC__JSValue__toInt64(this); } pub const ComparisonResult = enum(u8) { @@ -862,13 +854,11 @@ pub const JSValue = enum(i64) { pub fn isBoolean(this: JSValue) bool { return this == .true or this == .false; } - extern fn JSC__JSValue__isAnyInt(this: JSValue) bool; pub fn isAnyInt(this: JSValue) bool { - return JSC__JSValue__isAnyInt(this); + return bun.cpp.JSC__JSValue__isAnyInt(this); } - extern fn JSC__JSValue__isUInt32AsAnyInt(this: JSValue) bool; pub fn isUInt32AsAnyInt(this: JSValue) bool { - return JSC__JSValue__isUInt32AsAnyInt(this); + return bun.cpp.JSC__JSValue__isUInt32AsAnyInt(this); } pub fn asEncoded(this: JSValue) FFI.EncodedJSValue { @@ -883,9 +873,8 @@ pub const JSValue = enum(i64) { return FFI.JSVALUE_IS_INT32(.{ .asJSValue = this }); } - extern fn JSC__JSValue__isInt32AsAnyInt(this: JSValue) bool; pub fn isInt32AsAnyInt(this: JSValue) bool { - return JSC__JSValue__isInt32AsAnyInt(this); + return bun.cpp.JSC__JSValue__isInt32AsAnyInt(this); } pub fn isNumber(this: JSValue) bool { @@ -963,33 +952,26 @@ pub const JSValue = enum(i64) { return jsType(this).isStringObjectLike(); } - extern fn JSC__JSValue__isBigInt(this: JSValue) bool; pub fn isBigInt(this: JSValue) bool { - return JSC__JSValue__isBigInt(this); + return bun.cpp.JSC__JSValue__isBigInt(this); } - extern fn JSC__JSValue__isHeapBigInt(this: JSValue) bool; pub fn isHeapBigInt(this: JSValue) bool { - return JSC__JSValue__isHeapBigInt(this); + return bun.cpp.JSC__JSValue__isHeapBigInt(this); } - extern fn JSC__JSValue__isBigInt32(this: JSValue) bool; pub fn isBigInt32(this: JSValue) bool { - return JSC__JSValue__isBigInt32(this); + return bun.cpp.JSC__JSValue__isBigInt32(this); } - extern fn JSC__JSValue__isSymbol(this: JSValue) bool; pub fn isSymbol(this: JSValue) bool { - return JSC__JSValue__isSymbol(this); + return bun.cpp.JSC__JSValue__isSymbol(this); } - extern fn JSC__JSValue__isPrimitive(this: JSValue) bool; pub fn isPrimitive(this: JSValue) bool { - return JSC__JSValue__isPrimitive(this); + return bun.cpp.JSC__JSValue__isPrimitive(this); } - extern fn JSC__JSValue__isGetterSetter(this: JSValue) bool; pub fn isGetterSetter(this: JSValue) bool { - return JSC__JSValue__isGetterSetter(this); + return bun.cpp.JSC__JSValue__isGetterSetter(this); } - extern fn JSC__JSValue__isCustomGetterSetter(this: JSValue) bool; pub fn isCustomGetterSetter(this: JSValue) bool { - return JSC__JSValue__isCustomGetterSetter(this); + return bun.cpp.JSC__JSValue__isCustomGetterSetter(this); } pub inline fn isObject(this: JSValue) bool { return this.isCell() and this.jsType().isObject(); @@ -1016,10 +998,9 @@ pub const JSValue = enum(i64) { return JSC__JSValue__isClass(this, global); } - extern fn JSC__JSValue__isConstructor(this: JSValue) bool; pub fn isConstructor(this: JSValue) bool { if (!this.isCell()) return false; - return JSC__JSValue__isConstructor(this); + return bun.cpp.JSC__JSValue__isConstructor(this); } extern fn JSC__JSValue__getNameProperty(this: JSValue, global: *JSGlobalObject, ret: *ZigString) void; @@ -1060,9 +1041,8 @@ pub const JSValue = enum(i64) { return JSC__JSValue__asCell(this); } - extern fn JSC__JSValue__isCallable(this: JSValue) bool; pub fn isCallable(this: JSValue) bool { - return JSC__JSValue__isCallable(this); + return bun.cpp.JSC__JSValue__isCallable(this); } /// Statically cast a value to a cell. Returns `null` for non-cells. @@ -1088,9 +1068,8 @@ pub const JSValue = enum(i64) { return JSC__JSValue__isTerminationException(this); } - extern fn JSC__JSValue__toZigException(this: JSValue, global: *JSGlobalObject, exception: *ZigException) void; pub fn toZigException(this: JSValue, global: *JSGlobalObject, exception: *ZigException) void { - return bun.jsc.fromJSHostCallGeneric(global, @src(), JSC__JSValue__toZigException, .{ this, global, exception }) catch return; // TODO: properly propagate termination + return bun.cpp.JSC__JSValue__toZigException(this, global, exception) catch return; // TODO: properly propagate termination } extern fn JSC__JSValue__toZigString(this: JSValue, out: *ZigString, global: *JSGlobalObject) void; @@ -2357,7 +2336,7 @@ pub const JSValue = enum(i64) { }; pub const exposed_to_ffi = struct { - pub const JSVALUE_TO_INT64 = JSValue.JSC__JSValue__toInt64; + pub const JSVALUE_TO_INT64 = bun.cpp.JSC__JSValue__toInt64; pub const JSVALUE_TO_UINT64 = JSValue.JSC__JSValue__toUInt64NoTruncate; pub const INT64_TO_JSVALUE = JSValue.JSC__JSValue__fromInt64NoTruncate; pub const UINT64_TO_JSVALUE = JSValue.JSC__JSValue__fromUInt64NoTruncate; diff --git a/src/bun.js/bindings/SourceProvider.zig b/src/bun.js/bindings/SourceProvider.zig index 60aeeddd3b..13f974cd67 100644 --- a/src/bun.js/bindings/SourceProvider.zig +++ b/src/bun.js/bindings/SourceProvider.zig @@ -1,8 +1,8 @@ +const bun = @import("bun"); + /// Opaque representation of a JavaScript source provider pub const SourceProvider = opaque { - extern fn JSC__SourceProvider__deref(*SourceProvider) void; - pub fn deref(provider: *SourceProvider) void { - JSC__SourceProvider__deref(provider); + bun.cpp.JSC__SourceProvider__deref(provider); } }; diff --git a/src/bun.js/bindings/VM.zig b/src/bun.js/bindings/VM.zig index 5b29c2ac99..5858e7e26d 100644 --- a/src/bun.js/bindings/VM.zig +++ b/src/bun.js/bindings/VM.zig @@ -19,9 +19,8 @@ pub const VM = opaque { return JSC__VM__setControlFlowProfiler(vm, enabled); } - extern fn JSC__VM__isJITEnabled() bool; pub fn isJITEnabled() bool { - return JSC__VM__isJITEnabled(); + return bun.cpp.JSC__VM__isJITEnabled(); } extern fn JSC__VM__hasExecutionTimeLimit(vm: *VM) bool; @@ -70,14 +69,6 @@ pub const VM = opaque { return JSC__VM__deleteAllCode(vm, global_object); } - extern fn JSC__VM__whenIdle(vm: *VM, callback: *const fn (...) callconv(.C) void) void; - pub fn whenIdle( - vm: *VM, - callback: *const fn (...) callconv(.C) void, - ) void { - return JSC__VM__whenIdle(vm, callback); - } - extern fn JSC__VM__shrinkFootprint(vm: *VM) void; pub fn shrinkFootprint( vm: *VM, diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 4a0c86d947..5d566de68a 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -3877,7 +3877,7 @@ JSC_DEFINE_HOST_FUNCTION(functionJsGc, return JSValue::encode(jsUndefined()); } -extern "C" void JSC__JSGlobalObject__addGc(JSC::JSGlobalObject* globalObject) +extern "C" [[ZIG_EXPORT(nothrow)]] void JSC__JSGlobalObject__addGc(JSC::JSGlobalObject* globalObject) { auto& vm = JSC::getVM(globalObject); globalObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, "gc"_s), 0, functionJsGc, ImplementationVisibility::Public, JSC::NoIntrinsic, PropertyAttribute::DontEnum | 0); diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 03ce32e398..afa0178816 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -2056,12 +2056,12 @@ WebCore::DOMURL* WebCore__DOMURL__cast_(JSC::EncodedJSValue JSValue0, JSC::VM* v return WebCoreCast(JSValue0); } -void WebCore__DOMURL__href_(WebCore::DOMURL* domURL, ZigString* arg1) +[[ZIG_EXPORT(nothrow)]] void WebCore__DOMURL__href_(WebCore::DOMURL* domURL, ZigString* arg1) { const WTF::URL& href = domURL->href(); *arg1 = Zig::toZigString(href.string()); } -void WebCore__DOMURL__pathname_(WebCore::DOMURL* domURL, ZigString* arg1) +[[ZIG_EXPORT(nothrow)]] void WebCore__DOMURL__pathname_(WebCore::DOMURL* domURL, ZigString* arg1) { const WTF::URL& href = domURL->href(); const WTF::StringView& pathname = href.path(); @@ -3333,7 +3333,7 @@ JSC::EncodedJSValue JSC__JSPromise__wrap(JSC::JSGlobalObject* globalObject, void RELEASE_AND_RETURN(scope, JSValue::encode(JSC::JSPromise::resolvedPromise(globalObject, result))); } -void JSC__JSPromise__reject(JSC::JSPromise* arg0, JSC::JSGlobalObject* globalObject, +[[ZIG_EXPORT(check_slow)]] void JSC__JSPromise__reject(JSC::JSPromise* arg0, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue JSValue2) { JSValue value = JSC::JSValue::decode(JSValue2); @@ -3351,7 +3351,7 @@ void JSC__JSPromise__reject(JSC::JSPromise* arg0, JSC::JSGlobalObject* globalObj arg0->reject(globalObject, exception); } -void JSC__JSPromise__rejectAsHandled(JSC::JSPromise* arg0, JSC::JSGlobalObject* arg1, +[[ZIG_EXPORT(check_slow)]] void JSC__JSPromise__rejectAsHandled(JSC::JSPromise* arg0, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2) { ASSERT_WITH_MESSAGE(arg0->inherits(), "Argument is not a promise"); @@ -3365,7 +3365,7 @@ JSC::JSPromise* JSC__JSPromise__rejectedPromise(JSC::JSGlobalObject* arg0, JSC:: return JSC::JSPromise::rejectedPromise(arg0, JSC::JSValue::decode(JSValue1)); } -void JSC__JSPromise__resolve(JSC::JSPromise* arg0, JSC::JSGlobalObject* arg1, +[[ZIG_EXPORT(check_slow)]] void JSC__JSPromise__resolve(JSC::JSPromise* arg0, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2) { JSValue target = JSValue::decode(JSValue2); @@ -3435,7 +3435,7 @@ JSC::JSPromise* JSC__JSPromise__resolvedPromise(JSC::JSGlobalObject* globalObjec return promise; } -JSC::EncodedJSValue JSC__JSPromise__result(JSC::JSPromise* promise, JSC::VM* arg1) +[[ZIG_EXPORT(nothrow)]] JSC::EncodedJSValue JSC__JSPromise__result(JSC::JSPromise* promise, JSC::VM* arg1) { auto& vm = *arg1; @@ -3457,9 +3457,9 @@ JSC::EncodedJSValue JSC__JSPromise__result(JSC::JSPromise* promise, JSC::VM* arg } } -uint32_t JSC__JSPromise__status(const JSC::JSPromise* arg0, JSC::VM* arg1) +[[ZIG_EXPORT(nothrow)]] uint32_t JSC__JSPromise__status(const JSC::JSPromise* arg0, JSC::VM* arg1) { - switch (arg0->status(reinterpret_cast(arg1))) { + switch (arg0->status(*arg1)) { case JSC::JSPromise::Status::Pending: return 0; case JSC::JSPromise::Status::Fulfilled: @@ -3470,11 +3470,11 @@ uint32_t JSC__JSPromise__status(const JSC::JSPromise* arg0, JSC::VM* arg1) return 255; } } -bool JSC__JSPromise__isHandled(const JSC::JSPromise* arg0, JSC::VM* arg1) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSPromise__isHandled(const JSC::JSPromise* arg0, JSC::VM* arg1) { - return arg0->isHandled(reinterpret_cast(arg1)); + return arg0->isHandled(*arg1); } -void JSC__JSPromise__setHandled(JSC::JSPromise* promise, JSC::VM* arg1) +[[ZIG_EXPORT(nothrow)]] void JSC__JSPromise__setHandled(JSC::JSPromise* promise, JSC::VM* arg1) { auto& vm = *arg1; auto flags = promise->internalField(JSC::JSPromise::Field::Flags).get().asUInt32(); @@ -3537,11 +3537,11 @@ JSC::JSInternalPromise* JSC__JSInternalPromise__resolvedPromise(JSC::JSGlobalObj JSC::EncodedJSValue JSC__JSInternalPromise__result(const JSC::JSInternalPromise* arg0, JSC::VM* arg1) { - return JSC::JSValue::encode(arg0->result(reinterpret_cast(arg1))); + return JSC::JSValue::encode(arg0->result(*arg1)); } uint32_t JSC__JSInternalPromise__status(const JSC::JSInternalPromise* arg0, JSC::VM* arg1) { - switch (arg0->status(reinterpret_cast(arg1))) { + switch (arg0->status(*arg1)) { case JSC::JSInternalPromise::Status::Pending: return 0; case JSC::JSInternalPromise::Status::Fulfilled: @@ -3554,7 +3554,7 @@ uint32_t JSC__JSInternalPromise__status(const JSC::JSInternalPromise* arg0, JSC: } bool JSC__JSInternalPromise__isHandled(const JSC::JSInternalPromise* arg0, JSC::VM* arg1) { - return arg0->isHandled(reinterpret_cast(arg1)); + return arg0->isHandled(*arg1); } void JSC__JSInternalPromise__setHandled(JSC::JSInternalPromise* promise, JSC::VM* arg1) { @@ -3620,15 +3620,15 @@ bool JSC__JSValue__isException(JSC::EncodedJSValue JSValue0, JSC::VM* arg1) { return JSC::jsDynamicCast(JSC::JSValue::decode(JSValue0)) != nullptr; } -bool JSC__JSValue__isAnyInt(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isAnyInt(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isAnyInt(); } -bool JSC__JSValue__isBigInt(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isBigInt(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isBigInt(); } -bool JSC__JSValue__isBigInt32(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isBigInt32(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isBigInt32(); } @@ -3682,8 +3682,8 @@ bool JSC__JSValue__isClass(JSC::EncodedJSValue JSValue0, JSC::JSGlobalObject* ar } return false; } -bool JSC__JSValue__isCell(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isCell(); } -bool JSC__JSValue__isCustomGetterSetter(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isCell(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isCell(); } +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isCustomGetterSetter(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isCustomGetterSetter(); } @@ -3721,62 +3721,57 @@ void JSC__JSValue__forEach(JSC::EncodedJSValue JSValue0, JSC::JSGlobalObject* ar }); } -bool JSC__JSValue__isCallable(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isCallable(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isCallable(); } -bool JSC__JSValue__isGetterSetter(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isGetterSetter(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isGetterSetter(); } -bool JSC__JSValue__isHeapBigInt(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isHeapBigInt(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isHeapBigInt(); } -bool JSC__JSValue__isInt32(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isInt32(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isInt32(); } -bool JSC__JSValue__isInt32AsAnyInt(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isInt32AsAnyInt(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isInt32AsAnyInt(); } -bool JSC__JSValue__isNull(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isNull(); } -bool JSC__JSValue__isNumber(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isNull(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isNull(); } +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isNumber(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isNumber(); } -bool JSC__JSValue__isObject(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isObject(JSC::EncodedJSValue JSValue0) { return JSValue0 != 0 && JSC::JSValue::decode(JSValue0).isObject(); } -bool JSC__JSValue__isPrimitive(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isPrimitive(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isPrimitive(); } -bool JSC__JSValue__isSymbol(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isSymbol(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isSymbol(); } -bool JSC__JSValue__isUInt32AsAnyInt(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isUInt32AsAnyInt(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isUInt32AsAnyInt(); } -bool JSC__JSValue__isUndefined(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isUndefined(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isUndefined(); } -bool JSC__JSValue__isUndefinedOrNull(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isUndefinedOrNull(JSC::EncodedJSValue JSValue0) { return JSC::JSValue::decode(JSValue0).isUndefinedOrNull(); } -JSC::EncodedJSValue JSC__JSValue__jsBoolean(bool arg0) -{ - return JSC::JSValue::encode(JSC::jsBoolean(arg0)); -} - -JSC::EncodedJSValue JSC__JSValue__jsEmptyString(JSC::JSGlobalObject* arg0) +[[ZIG_EXPORT(nothrow)]] JSC::EncodedJSValue JSC__JSValue__jsEmptyString(JSC::JSGlobalObject* arg0) { return JSC::JSValue::encode(JSC::jsEmptyString(arg0->vm())); } @@ -3784,7 +3779,7 @@ JSC::EncodedJSValue JSC__JSValue__jsNull() { return JSC::JSValue::encode(JSC::jsNull()); } -JSC::EncodedJSValue JSC__JSValue__jsNumberFromChar(unsigned char arg0) +[[ZIG_EXPORT(nothrow)]] JSC::EncodedJSValue JSC__JSValue__jsNumberFromChar(unsigned char arg0) { return JSC::JSValue::encode(JSC::jsNumber(arg0)); } @@ -3800,7 +3795,7 @@ JSC::EncodedJSValue JSC__JSValue__jsNumberFromInt64(int64_t arg0) { return JSC::JSValue::encode(JSC::jsNumber(arg0)); } -JSC::EncodedJSValue JSC__JSValue__jsNumberFromU16(uint16_t arg0) +[[ZIG_EXPORT(nothrow)]] JSC::EncodedJSValue JSC__JSValue__jsNumberFromU16(uint16_t arg0) { return JSC::JSValue::encode(JSC::jsNumber(arg0)); } @@ -3809,7 +3804,7 @@ JSC::EncodedJSValue JSC__JSValue__jsNumberFromUint64(uint64_t arg0) return JSC::JSValue::encode(JSC::jsNumber(arg0)); } -int64_t JSC__JSValue__toInt64(JSC::EncodedJSValue val) +[[ZIG_EXPORT(nothrow)]] int64_t JSC__JSValue__toInt64(JSC::EncodedJSValue val) { JSC::JSValue value = JSC::JSValue::decode(val); ASSERT(value.isHeapBigInt() || value.isNumber()); @@ -4243,7 +4238,7 @@ CPP_DECL double Bun__JSValue__toNumber(JSC::EncodedJSValue JSValue0, JSC::JSGlob } // truncates values larger than int32 -int32_t JSC__JSValue__coerceToInt32(JSC::EncodedJSValue JSValue0, JSC::JSGlobalObject* arg1) +[[ZIG_EXPORT(check_slow)]] int32_t JSC__JSValue__coerceToInt32(JSC::EncodedJSValue JSValue0, JSC::JSGlobalObject* arg1) { JSC::JSValue value = JSC::JSValue::decode(JSValue0); if (value.isCell() && value.isHeapBigInt()) { @@ -4252,7 +4247,7 @@ int32_t JSC__JSValue__coerceToInt32(JSC::EncodedJSValue JSValue0, JSC::JSGlobalO return value.toInt32(arg1); } -int64_t JSC__JSValue__coerceToInt64(JSC::EncodedJSValue JSValue0, JSC::JSGlobalObject* arg1) +[[ZIG_EXPORT(check_slow)]] int64_t JSC__JSValue__coerceToInt64(JSC::EncodedJSValue JSValue0, JSC::JSGlobalObject* arg1) { JSValue value = JSValue::decode(JSValue0); if (value.isCell() && value.isHeapBigInt()) { @@ -4277,7 +4272,7 @@ JSC::EncodedJSValue JSC__JSValue__getErrorsProperty(JSC::EncodedJSValue JSValue0 return JSC::JSValue::encode(obj->getDirect(global->vm(), global->vm().propertyNames->errors)); } -JSC::EncodedJSValue JSC__JSValue__jsTDZValue() { return JSC::JSValue::encode(JSC::jsTDZValue()); }; +[[ZIG_EXPORT(nothrow)]] JSC::EncodedJSValue JSC__JSValue__jsTDZValue() { return JSC::JSValue::encode(JSC::jsTDZValue()); }; JSC::EncodedJSValue JSC__JSValue__jsUndefined() { return JSC::JSValue::encode(JSC::jsUndefined()); }; JSC::JSObject* JSC__JSValue__toObject(JSC::EncodedJSValue JSValue0, JSC::JSGlobalObject* arg1) { @@ -5189,7 +5184,7 @@ JSC::EncodedJSValue JSC__JSValue__toError_(JSC::EncodedJSValue JSValue0) return {}; } -void JSC__JSValue__toZigException(JSC::EncodedJSValue jsException, JSC::JSGlobalObject* global, ZigException* exception) +extern "C" [[ZIG_EXPORT(check_slow)]] void JSC__JSValue__toZigException(JSC::EncodedJSValue jsException, JSC::JSGlobalObject* global, ZigException* exception) { JSC::JSValue value = JSC::JSValue::decode(jsException); if (value == JSC::JSValue {}) { @@ -5288,7 +5283,10 @@ size_t JSC__VM__runGC(JSC::VM* vm, bool sync) return vm->heap.sizeAfterLastFullCollection(); } -bool JSC__VM__isJITEnabled() { return JSC::Options::useJIT(); } +[[ZIG_EXPORT(nothrow)]] bool JSC__VM__isJITEnabled() +{ + return JSC::Options::useJIT(); +} void JSC__VM__clearExecutionTimeLimit(JSC::VM* vm) { @@ -5317,8 +5315,10 @@ extern "C" void JSC__Exception__getStackTrace(JSC::Exception* arg0, JSC::JSGloba populateStackTrace(arg0->vm(), arg0->stack(), trace, global, PopulateStackTraceFlags::OnlyPosition); } -void JSC__VM__shrinkFootprint(JSC::VM* arg0) { arg0->shrinkFootprintWhenIdle(); }; -void JSC__VM__whenIdle(JSC::VM* arg0, void (*ArgFn1)()) { arg0->whenIdle(ArgFn1); }; +void JSC__VM__shrinkFootprint(JSC::VM* arg0) +{ + arg0->shrinkFootprintWhenIdle(); +}; void JSC__VM__holdAPILock(JSC::VM* arg0, void* ctx, void (*callback)(void* arg0)) { @@ -5369,13 +5369,25 @@ void JSC__VM__reportExtraMemory(JSC::VM* arg0, size_t arg1) } void JSC__VM__deinit(JSC::VM* arg1, JSC::JSGlobalObject* globalObject) {} -void JSC__VM__drainMicrotasks(JSC::VM* arg0) { arg0->drainMicrotasks(); } +void JSC__VM__drainMicrotasks(JSC::VM* arg0) +{ + arg0->drainMicrotasks(); +} -bool JSC__VM__executionForbidden(JSC::VM* arg0) { return (*arg0).executionForbidden(); } +bool JSC__VM__executionForbidden(JSC::VM* arg0) +{ + return (*arg0).executionForbidden(); +} -bool JSC__VM__isEntered(JSC::VM* arg0) { return (*arg0).isEntered(); } +bool JSC__VM__isEntered(JSC::VM* arg0) +{ + return (*arg0).isEntered(); +} -void JSC__VM__setExecutionForbidden(JSC::VM* arg0, bool arg1) { (*arg0).setExecutionForbidden(); } +void JSC__VM__setExecutionForbidden(JSC::VM* arg0, bool arg1) +{ + (*arg0).setExecutionForbidden(); +} // These may be called concurrently from another thread. void JSC__VM__notifyNeedTermination(JSC::VM* arg0) @@ -5388,9 +5400,18 @@ void JSC__VM__notifyNeedTermination(JSC::VM* arg0) if (didEnter) vm.apiLock().lock(); } -void JSC__VM__notifyNeedDebuggerBreak(JSC::VM* arg0) { (*arg0).notifyNeedDebuggerBreak(); } -void JSC__VM__notifyNeedShellTimeoutCheck(JSC::VM* arg0) { (*arg0).notifyNeedShellTimeoutCheck(); } -void JSC__VM__notifyNeedWatchdogCheck(JSC::VM* arg0) { (*arg0).notifyNeedWatchdogCheck(); } +void JSC__VM__notifyNeedDebuggerBreak(JSC::VM* arg0) +{ + (*arg0).notifyNeedDebuggerBreak(); +} +void JSC__VM__notifyNeedShellTimeoutCheck(JSC::VM* arg0) +{ + (*arg0).notifyNeedShellTimeoutCheck(); +} +void JSC__VM__notifyNeedWatchdogCheck(JSC::VM* arg0) +{ + (*arg0).notifyNeedWatchdogCheck(); +} void JSC__VM__throwError(JSC::VM* vm_, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue encodedValue) { @@ -5942,7 +5963,7 @@ void JSC__JSValue__forEachPropertyOrdered(JSC::EncodedJSValue JSValue0, JSC::JSG properties.releaseData(); } -bool JSC__JSValue__isConstructor(JSC::EncodedJSValue JSValue0) +[[ZIG_EXPORT(nothrow)]] bool JSC__JSValue__isConstructor(JSC::EncodedJSValue JSValue0) { JSValue value = JSValue::decode(JSValue0); return value.isConstructor(); @@ -6172,7 +6193,7 @@ extern "C" JSC::EncodedJSValue JSC__JSValue__getOwnByValue(JSC::EncodedJSValue v } } -extern "C" double Bun__parseDate(JSC::JSGlobalObject* globalObject, BunString* str) +extern "C" [[ZIG_EXPORT(check_slow)]] double Bun__parseDate(JSC::JSGlobalObject* globalObject, BunString* str) { auto& vm = JSC::getVM(globalObject); return vm.dateCache.parseDate(globalObject, vm, str->toWTFString()); @@ -6297,23 +6318,23 @@ CPP_DECL JSC::EncodedJSValue JSC__JSMap__create(JSC::JSGlobalObject* arg0) JSC::JSMap* map = JSC::JSMap::create(arg0->vm(), arg0->mapStructure()); return JSC::JSValue::encode(map); } -CPP_DECL JSC::EncodedJSValue JSC__JSMap__get_(JSC::JSMap* map, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2) +CPP_DECL [[ZIG_EXPORT(nothrow)]] JSC::EncodedJSValue JSC__JSMap__get_(JSC::JSMap* map, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2) { JSC::JSValue value = JSC::JSValue::decode(JSValue2); return JSC::JSValue::encode(map->get(arg1, value)); } -CPP_DECL bool JSC__JSMap__has(JSC::JSMap* map, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2) +CPP_DECL [[ZIG_EXPORT(nothrow)]] bool JSC__JSMap__has(JSC::JSMap* map, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2) { JSC::JSValue value = JSC::JSValue::decode(JSValue2); return map->has(arg1, value); } -CPP_DECL bool JSC__JSMap__remove(JSC::JSMap* map, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2) +CPP_DECL [[ZIG_EXPORT(nothrow)]] bool JSC__JSMap__remove(JSC::JSMap* map, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2) { JSC::JSValue value = JSC::JSValue::decode(JSValue2); return map->remove(arg1, value); } -CPP_DECL void JSC__JSMap__set(JSC::JSMap* map, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2, JSC::EncodedJSValue JSValue3) +CPP_DECL [[ZIG_EXPORT(nothrow)]] void JSC__JSMap__set(JSC::JSMap* map, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2, JSC::EncodedJSValue JSValue3) { map->set(arg1, JSC::JSValue::decode(JSValue2), JSC::JSValue::decode(JSValue3)); } @@ -6439,12 +6460,12 @@ CPP_DECL bool JSC__GetterSetter__isSetterNull(JSC::GetterSetter* gettersetter) return gettersetter->isSetterNull(); } -CPP_DECL bool JSC__CustomGetterSetter__isGetterNull(JSC::CustomGetterSetter* gettersetter) +CPP_DECL [[ZIG_EXPORT(nothrow)]] bool JSC__CustomGetterSetter__isGetterNull(JSC::CustomGetterSetter* gettersetter) { return gettersetter->getter() == nullptr; } -CPP_DECL bool JSC__CustomGetterSetter__isSetterNull(JSC::CustomGetterSetter* gettersetter) +CPP_DECL [[ZIG_EXPORT(nothrow)]] bool JSC__CustomGetterSetter__isSetterNull(JSC::CustomGetterSetter* gettersetter) { return gettersetter->setter() == nullptr; } @@ -6454,7 +6475,7 @@ CPP_DECL JSC::EncodedJSValue Bun__ProxyObject__getInternalField(JSC::EncodedJSVa return JSValue::encode(jsCast(JSValue::decode(value))->internalField((ProxyObject::Field)id).get()); } -CPP_DECL void JSC__SourceProvider__deref(JSC::SourceProvider* provider) +CPP_DECL [[ZIG_EXPORT(nothrow)]] void JSC__SourceProvider__deref(JSC::SourceProvider* provider) { provider->deref(); } @@ -6574,6 +6595,15 @@ extern "C" double Bun__JSC__operationMathPow(double x, double y) return operationMathPow(x, y); } +#if !ENABLE(EXCEPTION_SCOPE_VERIFICATION) +extern "C" [[ZIG_EXPORT(nothrow)]] bool Bun__RETURN_IF_EXCEPTION(JSC::JSGlobalObject* globalObject) +{ + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + RETURN_IF_EXCEPTION(scope, true); + return false; +} +#endif + CPP_DECL unsigned int Bun__CallFrame__getLineNumber(JSC::CallFrame* callFrame, JSC::JSGlobalObject* globalObject) { auto& vm = JSC::getVM(globalObject); diff --git a/src/bun.js/bindings/c-bindings.cpp b/src/bun.js/bindings/c-bindings.cpp index 3f7c50467a..4d91a42850 100644 --- a/src/bun.js/bindings/c-bindings.cpp +++ b/src/bun.js/bindings/c-bindings.cpp @@ -615,7 +615,7 @@ extern "C" int32_t open_as_nonblocking_tty(int32_t fd, int32_t mode) #endif -extern "C" size_t Bun__ramSize() +extern "C" [[ZIG_EXPORT(nothrow)]] size_t Bun__ramSize() { // This value is cached internally. return WTF::ramSize(); diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h index 9b3cde8af6..db641387cc 100644 --- a/src/bun.js/bindings/headers.h +++ b/src/bun.js/bindings/headers.h @@ -261,7 +261,6 @@ CPP_DECL bool JSC__JSValue__isUInt32AsAnyInt(JSC::EncodedJSValue JSValue0); CPP_DECL bool JSC__JSValue__jestDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2); CPP_DECL bool JSC__JSValue__jestDeepMatch(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2, bool arg3); CPP_DECL bool JSC__JSValue__jestStrictDeepEquals(JSC::EncodedJSValue JSValue0, JSC::EncodedJSValue JSValue1, JSC::JSGlobalObject* arg2); -CPP_DECL JSC::EncodedJSValue JSC__JSValue__jsBoolean(bool arg0); CPP_DECL JSC::EncodedJSValue JSC__JSValue__jsDoubleNumber(double arg0); CPP_DECL JSC::EncodedJSValue JSC__JSValue__jsNull(); CPP_DECL JSC::EncodedJSValue JSC__JSValue__jsNumberFromChar(unsigned char arg0); @@ -322,7 +321,6 @@ CPP_DECL void JSC__VM__setExecutionTimeLimit(JSC::VM* arg0, double arg1); CPP_DECL void JSC__VM__shrinkFootprint(JSC::VM* arg0); CPP_DECL void JSC__VM__throwError(JSC::VM* arg0, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2); CPP_DECL void JSC__VM__throwError(JSC::VM* arg0, JSC::JSGlobalObject* arg1, JSC::EncodedJSValue JSValue2); -CPP_DECL void JSC__VM__whenIdle(JSC::VM* arg0, void(* ArgFn1)()); CPP_DECL void FFI__ptr__put(JSC::JSGlobalObject* arg0, JSC::EncodedJSValue JSValue1); diff --git a/src/bun.js/bindings/root.h b/src/bun.js/bindings/root.h index 182264805b..8894cfe38a 100644 --- a/src/bun.js/bindings/root.h +++ b/src/bun.js/bindings/root.h @@ -98,4 +98,7 @@ #define BUN_DEFINE_HOST_FUNCTION(name, args) extern "C" JSC_DEFINE_HOST_FUNCTION(name, args) #endif +// can be nothrow | zero_is_throw | check_slow +#define ZIG_EXPORT(...) + #endif diff --git a/src/bun.js/bindings/wtf-bindings.cpp b/src/bun.js/bindings/wtf-bindings.cpp index c81b7e0024..0e5bfd5cc4 100644 --- a/src/bun.js/bindings/wtf-bindings.cpp +++ b/src/bun.js/bindings/wtf-bindings.cpp @@ -235,12 +235,12 @@ size_t toISOString(JSC::VM& vm, double date, char in[64]) static thread_local WTF::StackBounds stackBoundsForCurrentThread = WTF::StackBounds::emptyBounds(); -extern "C" void Bun__StackCheck__initialize() +extern "C" [[ZIG_EXPORT(nothrow)]] void Bun__StackCheck__initialize() { stackBoundsForCurrentThread = WTF::StackBounds::currentThreadStackBounds(); } -extern "C" void* Bun__StackCheck__getMaxStack() +extern "C" [[ZIG_EXPORT(nothrow)]] void* Bun__StackCheck__getMaxStack() { return stackBoundsForCurrentThread.end(); } diff --git a/src/bun.js/ipc.zig b/src/bun.js/ipc.zig index 714d658b7e..0206ca2091 100644 --- a/src/bun.js/ipc.zig +++ b/src/bun.js/ipc.zig @@ -1358,16 +1358,12 @@ pub const IPCHandlers = struct { }; }; -extern "C" fn IPCSerialize(globalObject: *JSC.JSGlobalObject, message: JSC.JSValue, handle: JSC.JSValue) JSC.JSValue; - pub fn ipcSerialize(globalObject: *JSC.JSGlobalObject, message: JSC.JSValue, handle: JSC.JSValue) bun.JSError!JSC.JSValue { - return bun.jsc.fromJSHostCall(globalObject, @src(), IPCSerialize, .{ globalObject, message, handle }); + return bun.cpp.IPCSerialize(globalObject, message, handle); } -extern "C" fn IPCParse(globalObject: *JSC.JSGlobalObject, target: JSC.JSValue, serialized: JSC.JSValue, fd: JSC.JSValue) JSC.JSValue; - pub fn ipcParse(globalObject: *JSC.JSGlobalObject, target: JSC.JSValue, serialized: JSC.JSValue, fd: JSC.JSValue) bun.JSError!JSC.JSValue { - return bun.jsc.fromJSHostCall(globalObject, @src(), IPCParse, .{ globalObject, target, serialized, fd }); + return bun.cpp.IPCParse(globalObject, target, serialized, fd); } const node_cluster_binding = @import("./node/node_cluster_binding.zig"); diff --git a/src/bun.zig b/src/bun.zig index b273caaba0..cd080b870b 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -1944,6 +1944,7 @@ pub const MutableString = _string.MutableString; pub const WTF = struct { /// The String type from WebKit's WTF library. pub const StringImpl = _string.WTFStringImpl; + pub const _StringImplStruct = _string.WTFStringImplStruct; }; pub const Wyhash11 = @import("./wyhash.zig").Wyhash11; @@ -3410,9 +3411,8 @@ pub fn tagName(comptime Enum: type, value: Enum) ?[:0]const u8 { if (@intFromEnum(value) == f.value) break f.name; } else null; } -extern "c" fn Bun__ramSize() usize; pub fn getTotalMemorySize() usize { - return Bun__ramSize(); + return cpp.Bun__ramSize(); } pub const DebugThreadLock = if (Environment.isDebug) @@ -3700,14 +3700,12 @@ pub const Maybe = bun.JSC.Node.Maybe; pub const StackCheck = struct { cached_stack_end: usize = 0, - extern fn Bun__StackCheck__initialize() void; pub fn configureThread() void { - Bun__StackCheck__initialize(); + cpp.Bun__StackCheck__initialize(); } - extern "c" fn Bun__StackCheck__getMaxStack() usize; fn getStackEnd() usize { - return Bun__StackCheck__getMaxStack(); + return @intFromPtr(cpp.Bun__StackCheck__getMaxStack()); } pub fn init() StackCheck { @@ -3755,6 +3753,8 @@ pub const MemoryReportingAllocator = @import("./allocators/MemoryReportingAlloca pub const mach_port = if (Environment.isMac) std.c.mach_port_t else u32; +pub const cpp = @import("cpp").bindings; + pub fn contains(item: anytype, list: *const std.ArrayListUnmanaged(@TypeOf(item))) bool { const T = @TypeOf(item); return switch (T) { diff --git a/src/bun_js.zig b/src/bun_js.zig index 4b8429df44..66a0d0d453 100644 --- a/src/bun_js.zig +++ b/src/bun_js.zig @@ -466,19 +466,15 @@ pub const Run = struct { vm.globalExit(); } - extern fn Bun__ExposeNodeModuleGlobals(*JSC.JSGlobalObject) void; - /// add `gc()` to `globalThis`. - extern fn JSC__JSGlobalObject__addGc(*JSC.JSGlobalObject) void; - fn addConditionalGlobals(this: *Run) void { const vm = this.vm; const runtime_options: *const Command.RuntimeOptions = &this.ctx.runtime_options; if (runtime_options.eval.script.len > 0) { - Bun__ExposeNodeModuleGlobals(vm.global); + bun.cpp.Bun__ExposeNodeModuleGlobals(vm.global); } if (runtime_options.expose_gc) { - JSC__JSGlobalObject__addGc(vm.global); + bun.cpp.JSC__JSGlobalObject__addGc(vm.global); } } }; diff --git a/src/codegen/cppbind.ts b/src/codegen/cppbind.ts new file mode 100644 index 0000000000..91237006b4 --- /dev/null +++ b/src/codegen/cppbind.ts @@ -0,0 +1,694 @@ +import { SyntaxNode } from "@lezer/common"; +import { parser as cppParser } from "@lezer/cpp"; +import { mkdir } from "fs/promises"; +import { join, relative } from "path"; +import { bannedTypes, sharedTypes, typeDeclarations } from "./shared-types"; + +type Point = { + line: number; + column: number; +}; +type Srcloc = { + file: string; + start: Point; + end: Point; +}; +type CppFn = { + name: string; + returnType: CppType; + parameters: CppParameter[]; + position: Srcloc; + tag: ExportTag; +}; +type CppParameter = { + type: CppType; + name: string; +}; +type CppType = + | { + type: "pointer"; + child: CppType; + position: Srcloc; + isConst: boolean; + isMany: boolean; + } + | { + type: "named"; + name: string; + position: Srcloc; + }; + +type PositionedError = { + position: Srcloc; + message: string; + notes: { position: Srcloc; message: string }[]; +}; +const errors: PositionedError[] = []; +function appendError(position: Srcloc, message: string): PositionedError { + const error: PositionedError = { position, message, notes: [] }; + errors.push(error); + return error; +} +function appendErrorFromCatch(error: unknown, position: Srcloc): PositionedError { + if (error instanceof PositionedErrorClass) { + errors.push(error); + return error; + } + if (error instanceof Error) { + return appendError(position, error.message); + } + return appendError(position, "unknown error: " + JSON.stringify(error)); +} +function throwError(position: Srcloc, message: string): never { + throw new PositionedErrorClass(position, message); +} +class PositionedErrorClass extends Error { + notes: { position: Srcloc; message: string }[] = []; + constructor( + public position: Srcloc, + message: string, + ) { + super(message); + } +} + +// Lezer works with offsets, but our errors need line/column. This utility handles the conversion. +class LineInfo { + private lineStarts: number[]; + constructor(private source: string) { + this.lineStarts = [0]; + for (let i = 0; i < source.length; i++) { + if (source[i] === "\n") { + this.lineStarts.push(i + 1); + } + } + } + + get(offset: number): Point { + // A binary search would be faster, but this is fine for files of this size. + let line = 1; + let lineStart = 0; + for (let i = this.lineStarts.length - 1; i >= 0; i--) { + if (this.lineStarts[i] <= offset) { + line = i + 1; + lineStart = this.lineStarts[i]; + break; + } + } + const column = offset - lineStart + 1; + return { line, column }; + } +} + +// A context object to pass around file-specific parsing information. +type ParseContext = { + file: string; + sourceCode: string; + lineInfo: LineInfo; +}; + +function nodePosition(node: SyntaxNode, ctx: ParseContext): Srcloc { + return { + file: ctx.file, + start: ctx.lineInfo.get(node.from), + end: ctx.lineInfo.get(node.to), + }; +} +const text = (node: SyntaxNode, ctx: ParseContext) => ctx.sourceCode.slice(node.from, node.to); + +function assertNever(value: never): never { + throw new Error("assertNever"); +} + +export function prettyPrintLezerNode(node: SyntaxNode, sourceCode: string): string { + const lines: string[] = []; + const printRecursive = (currentNode: SyntaxNode, prefix: string, isLast: boolean) => { + // Determine the connector shape + const connector = isLast ? "└─ " : "├─ "; + const linePrefix = prefix + connector; + + // Get the node's text, escape newlines, and truncate for readability + const nodeText = sourceCode.slice(currentNode.from, currentNode.to); + let truncatedText = nodeText.replace(/\n/g, "\\n"); + if (truncatedText.length > 50) { + truncatedText = truncatedText.slice(0, 50) + "..."; + } + + // Format and add the current node's line + lines.push(`${linePrefix}${currentNode.name} [${currentNode.from}..${currentNode.to}] "${truncatedText}"`); + if (currentNode.name === "CompoundStatement") { + lines.push(prefix + " └─ ..."); + return; + } + + // Prepare the prefix for the children + const childPrefix = prefix + (isLast ? " " : "│ "); + + // Recurse for children + const children: SyntaxNode[] = []; + const cursor = currentNode.cursor(); + if (cursor.firstChild()) { + do { + children.push(cursor.node); + } while (cursor.nextSibling()); + } + + children.forEach((child, index) => { + printRecursive(child, childPrefix, index === children.length - 1); + }); + }; + + // Start the process for the root node without any prefix/connector + const rootText = sourceCode.slice(node.from, node.to).replace(/\n/g, "\\n").slice(0, 50); + lines.push(`${node.name} [${node.from}..${node.to}] "${rootText}${rootText.length === 50 ? "..." : ""}"`); + + const children: SyntaxNode[] = []; + const cursor = node.cursor(); + if (cursor.firstChild()) { + do { + children.push(cursor.node); + } while (cursor.nextSibling()); + } + + children.forEach((child, index) => { + printRecursive(child, "", index === children.length - 1); + }); + + return lines.join("\n"); +} + +function getChildren(node: SyntaxNode): SyntaxNode[] { + const children: SyntaxNode[] = []; + let child = node.firstChild; + while (child) { + children.push(child); + child = child.nextSibling; + } + return children; +} + +const allowedLezerTypes = new Set(["PrimitiveType", "ScopedTypeIdentifier", "TypeIdentifier", "SizedTypeSpecifier"]); +function processRootmostType(ctx: ParseContext, node: SyntaxNode): CppType { + const children = getChildren(node); + for (const child of children) { + if (allowedLezerTypes.has(child.type.name)) { + return { type: "named", name: text(child, ctx), position: nodePosition(child, ctx) }; + } + } + throwError(nodePosition(node, ctx), "no valid type found:\n" + prettyPrintLezerNode(node, ctx.sourceCode)); +} + +function processDeclarator( + ctx: ParseContext, + node: SyntaxNode, // Initially a FunctionDefinition/ParameterDeclaration, then recursively a Declarator variant + rootmostType?: CppType, +): { type: CppType; final: SyntaxNode } { + // Initial entry point with a definition/declaration, find the top-level declarator + if (node.name === "FunctionDefinition" || node.name === "ParameterDeclaration") { + rootmostType ??= processRootmostType(ctx, node); + } else { + if (!rootmostType) + throwError( + nodePosition(node, ctx), + "no rootmost type provided to declarator:\n" + prettyPrintLezerNode(node, ctx.sourceCode), + ); + } + + const children = getChildren(node); + const declarators = children.filter(child => child.name.endsWith("Declarator") || child.name === "Identifier"); + if (declarators.length !== 1) { + throwError( + nodePosition(node, ctx), + "no or multiple declarators found:\n" + prettyPrintLezerNode(node, ctx.sourceCode), + ); + } + const declarator = declarators[0]!; + + // Recursively peel off pointers + if (declarator?.name === "PointerDeclarator") { + if (!rootmostType) throwError(nodePosition(declarator, ctx), "no rootmost type provided to PointerDeclarator"); + const isConst = !!declarator.parent?.getChild("const"); + + return processDeclarator(ctx, declarator, { + type: "pointer", + child: rootmostType, + position: nodePosition(declarator, ctx), + isConst, + isMany: false, + }); + } + + return { type: rootmostType, final: declarator }; +} + +function processFunction(ctx: ParseContext, node: SyntaxNode, tag: ExportTag): CppFn { + // `node` is a FunctionDefinition + const declarator = processDeclarator(ctx, node); + const final = declarator.final; + + if (final.name !== "FunctionDeclarator") { + throwError(nodePosition(final, ctx), "not a function_declarator: " + final.name); + } + const nameNode = final.getChild("Identifier"); + if (!nameNode) throwError(nodePosition(final, ctx), "no name found:\n" + prettyPrintLezerNode(final, ctx.sourceCode)); + + const parameterList = final.getChild("ParameterList"); + if (!parameterList) throwError(nodePosition(final, ctx), "no parameter list found"); + + const parameters: CppParameter[] = []; + for (const parameter of parameterList.getChildren("ParameterDeclaration")) { + const paramDeclarator = processDeclarator(ctx, parameter); + const name = paramDeclarator.final; + + if (name.name === "ReferenceDeclarator") { + throwError(nodePosition(name, ctx), "references are not allowed"); + } + if (name.name !== "Identifier") { + throwError(nodePosition(name, ctx), "parameter name is not an identifier: " + name.name); + } + + parameters.push({ type: paramDeclarator.type, name: text(name, ctx) }); + } + + for (let i = 0; i < parameters.length; i++) { + const param = parameters[i]; + const next = parameters[i + 1]; + if (param.type.type === "pointer" && next?.type.type === "named" && next.type.name === "size_t") { + param.type.isMany = true; + i++; + } + } + + return { + returnType: declarator.type, + name: text(nameNode, ctx), + parameters, + position: nodePosition(nameNode, ctx), + tag, + }; +} + +type ExportTag = "check_slow" | "zero_is_throw" | "false_is_throw" | "nothrow"; + +const sharedTypesText = await Bun.file("src/codegen/shared-types.ts").text(); +const sharedTypesLines = sharedTypesText.split("\n"); +let sharedTypesLine = 0; +let sharedTypesColumn = 0; +let sharedTypesColumnEnd = 0; +for (const line of sharedTypesLines) { + sharedTypesLine++; + if (line.includes("export const sharedTypes")) { + sharedTypesColumn = line.indexOf("sharedTypes") + 1; + sharedTypesColumnEnd = sharedTypesColumn + "sharedTypes".length; + break; + } +} + +const errorsForTypes: Map = new Map(); +function generateZigType(type: CppType, subLevel?: boolean) { + if (type.type === "pointer") { + if (type.isMany && type.isConst) return `?[*]const ${generateZigType(type.child, true)}`; + if (type.isMany) return `?[*]${generateZigType(type.child, true)}`; + if (type.isConst) return `?*const ${generateZigType(type.child, true)}`; + return `?*${generateZigType(type.child, true)}`; + } + if (type.type === "named" && type.name === "void") { + if (subLevel) return "anyopaque"; + return "void"; + } + if (type.type === "named") { + const bannedType = bannedTypes[type.name]; + if (bannedType) { + appendError(type.position, bannedType); + return "anyopaque"; + } + const sharedType = sharedTypes[type.name]; + if (sharedType) return sharedType; + const error = errorsForTypes.has(type.name) + ? errorsForTypes.get(type.name)! + : appendError( + { + file: "src/codegen/shared-types.ts", + start: { line: sharedTypesLine, column: sharedTypesColumn }, + end: { line: sharedTypesLine, column: sharedTypesColumnEnd }, + }, + "sharedTypes is missing type: " + JSON.stringify(type.name), + ); + errorsForTypes.set(type.name, error); + error.notes.push({ position: type.position, message: "used in exported function here" }); + return "anyopaque"; + } + assertNever(type); +} +function formatZigName(name: string): string { + if (name.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) return name; + return "@" + JSON.stringify(name); +} +function generateZigParameterList(parameters: CppParameter[], globalThisArg?: CppParameter): string { + return parameters + .map(p => { + if (p === globalThisArg) { + return `${formatZigName(p.name)}: *jsc.JSGlobalObject`; + } else { + return `${formatZigName(p.name)}: ${generateZigType(p.type, false)}`; + } + }) + .join(", "); +} +function generateZigSourceComment(cfg: Cfg, resultSourceLinks: string[], fn: CppFn): string { + const fileName = relative(cfg.dstDir, fn.position.file); + resultSourceLinks.push(`${fn.name}:${fileName}:${fn.position.start.line}:${fn.position.start.column}`); + return ` /// Source: ${fn.name}`; +} + +function closest(node: SyntaxNode | null, type: string): SyntaxNode | null { + while (node) { + if (node.name === type) return node; + node = node.parent; + } + return null; +} + +type CppParser = typeof cppParser; + +async function processFile(parser: CppParser, file: string, allFunctions: CppFn[]) { + const sourceCode = await Bun.file(file).text(); + if (!sourceCode.includes("[[ZIG_EXPORT(")) return; + + const sourceCodeLines = sourceCode.split("\n"); + const manualFindLines = new Set(); + for (let i = 0; i < sourceCodeLines.length; i++) { + if (sourceCodeLines[i].includes("[[ZIG_EXPORT(")) { + manualFindLines.add(i + 1); + } + } + + const tree = parser.parse(sourceCode); + const lineInfo = new LineInfo(sourceCode); + const ctx: ParseContext = { file, sourceCode, lineInfo }; + + if (!tree) { + appendError({ file, start: { line: 0, column: 0 }, end: { line: 0, column: 0 } }, "no tree found"); + for (const lineNumber of manualFindLines) { + const lineContent = sourceCodeLines[lineNumber - 1]; + const column = lineContent.indexOf("[[ZIG_EXPORT(") + 3; + appendError( + { + file, + start: { line: lineNumber, column }, + end: { line: lineNumber, column: column + "ZIG_EXPORT(".length }, + }, + "ZIG_EXPORT found, but Lezer failed to parse the file.", + ); + } + return; + } + + const queryFoundLines = new Set(); + + tree.iterate({ + enter: nodeRef => { + if (nodeRef.name !== "FunctionDefinition") { + return true; // Continue traversal + } + // console.log( + // `\n--- Found ZIG_EXPORT on function in ${file} at line ${lineInfo.get(nodeRef.node.from).line} ---\n`, + // ); + // // Use the new pretty-printer to log the tree structure of the matched function + // console.log(prettyPrintLezerNode(nodeRef.node, ctx.sourceCode)); + // console.log(`-------------------------------------------------------------------\n`); + + const fnNode = nodeRef.node; + let zigExportAttr: SyntaxNode | null = null; + let tagIdentifier: SyntaxNode | null = null; + + for (const attr of fnNode.getChildren("Attribute")) { + const attrNameNode = attr.getChild("AttributeName"); + if (attrNameNode && text(attrNameNode, ctx) === "ZIG_EXPORT") { + zigExportAttr = attr; + const args = attr.getChild("AttributeArgs"); + if (args) { + tagIdentifier = args.getChild("Identifier"); + } + break; + } + } + + if (!zigExportAttr || !tagIdentifier) { + return false; // Not an exported function, prune search + } + + queryFoundLines.add(lineInfo.get(zigExportAttr.from).line); + + // disabled because lezer parses (extern "C") seperately to the function definition / block + /* const linkage = closest(fnNode, "LinkageSpecification"); + const linkageString = linkage?.getChild("String"); + if (!linkage || !linkageString || text(linkageString, ctx) !== '"C"') { + appendError( + nodePosition(fnNode, ctx), + 'exported function must be extern "C":\n' + + (linkage ? prettyPrintLezerNode(linkage, ctx.sourceCode) : "no linkage"), + ); + } */ + + const tagStr = text(tagIdentifier, ctx); + let tag: ExportTag | undefined; + if ( + tagStr === "nothrow" || + tagStr === "zero_is_throw" || + tagStr === "check_slow" || + tagStr === "false_is_throw" + ) { + tag = tagStr; + } else if (tagStr === "print") { + console.log(prettyPrintLezerNode(fnNode, ctx.sourceCode)); + appendError(nodePosition(tagIdentifier, ctx), "'print' tags are only for debugging cppbind"); + tag = "nothrow"; + } else { + appendError( + nodePosition(tagIdentifier, ctx), + "tag must be nothrow, zero_is_throw, check_slow, or false_is_throw: " + tagStr, + ); + tag = "nothrow"; + } + + try { + const result = processFunction(ctx, fnNode, tag); + allFunctions.push(result); + } catch (e) { + appendErrorFromCatch(e, nodePosition(fnNode, ctx)); + } + + return false; // Don't descend into function body + }, + }); + + for (const lineNumber of manualFindLines) { + if (!queryFoundLines.has(lineNumber)) { + const lineContent = sourceCodeLines[lineNumber - 1]; + const column = lineContent.indexOf("[[ZIG_EXPORT(") + 3; + const position: Srcloc = { + file, + start: { line: lineNumber, column }, + end: { line: lineNumber, column: column + "ZIG_EXPORT(".length }, + }; + appendError( + position, + "ZIG_EXPORT was found on this line, but the Lezer parser did not find a valid C++ attribute on a function definition. Ensure it's in the form `[[ZIG_EXPORT(tag)]]` before a function definition.", + ); + } + } +} + +async function renderError(position: Srcloc, message: string, label: string, color: string) { + const fileContent = await Bun.file(position.file).text(); + const lines = fileContent.split("\n"); + const line = lines[position.start.line - 1]; + if (line === undefined) return; + + console.error( + `\x1b[m${position.file}:${position.start.line}:${position.start.column}: ${color}\x1b[1m${label}:\x1b[m ${message}`, + ); + const before = `${position.start.line} | ${line.substring(0, position.start.column - 1)}`; + const after = line.substring(position.start.column - 1); + console.error(`\x1b[90m${before}${after}\x1b[m`); + let length = position.start.line === position.end.line ? position.end.column - position.start.column : 1; + console.error(`\x1b[m${" ".repeat(Bun.stringWidth(before))}${color}^${"~".repeat(Math.max(length - 1, 0))}\x1b[m`); +} + +type Cfg = { + dstDir: string; +}; +function generateZigFn( + fn: CppFn, + resultRaw: string[], + resultBindings: string[], + resultSourceLinks: string[], + cfg: Cfg, +): void { + const returnType = generateZigType(fn.returnType); + if (resultBindings.length) resultBindings.push(""); + resultBindings.push(generateZigSourceComment(cfg, resultSourceLinks, fn)); + if (fn.tag === "nothrow") { + resultBindings.push( + ` pub extern fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters)}) ${returnType};`, + ); + return; + } + + resultRaw.push(` extern fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters)}) ${returnType};`); + let globalThisArg: CppParameter | undefined; + for (const param of fn.parameters) { + const type = generateZigType(param.type); + if (type === "?*jsc.JSGlobalObject") { + globalThisArg = param; + break; + } + } + if (!globalThisArg) throwError(fn.position, "no globalThis argument found (required for " + fn.tag + ")"); + if (fn.tag === "check_slow") { + if (returnType === "jsc.JSValue") { + appendError( + fn.position, + "Use ZIG_EXPORT(zero_is_throw) instead of ZIG_EXPORT(check_slow) for functions that return JSValue", + ); + } + resultBindings.push( + ` pub inline fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) bun.JSError!${returnType} {`, + ` if (comptime Environment.ci_assert) {`, + ` var scope: jsc.CatchScope = undefined;`, + ` scope.init(${formatZigName(globalThisArg.name)}, @src());`, + ` defer scope.deinit();`, + ``, + ` const result = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, + ` try scope.returnIfException();`, + ` return result;`, + ` } else {`, + ` const result = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, + ` if (Bun__RETURN_IF_EXCEPTION(${formatZigName(globalThisArg.name)})) return error.JSError;`, + ` return result;`, + ` }`, + ` }`, + ); + return; + } + + let equalsValue: string; + if (fn.tag === "zero_is_throw") { + equalsValue = ".zero"; + if (returnType !== "jsc.JSValue") { + appendError(fn.position, "ZIG_EXPORT(zero_is_throw) is only allowed for functions that return JSValue"); + } + } else if (fn.tag === "false_is_throw") { + equalsValue = "false"; + if (returnType !== "bool") { + appendError(fn.position, "ZIG_EXPORT(false_is_throw) is only allowed for functions that return bool"); + } + } else assertNever(fn.tag); + resultBindings.push( + ` pub inline fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) bun.JSError!${returnType} {`, + ` if (comptime Environment.ci_assert) {`, + ` var scope: jsc.ExceptionValidationScope = undefined;`, + ` scope.init(${formatZigName(globalThisArg.name)}, @src());`, + ` defer scope.deinit();`, + ``, + ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, + ` scope.assertExceptionPresenceMatches(value == ${equalsValue});`, + ` return if (value == ${equalsValue}) error.JSError else value;`, + ` } else {`, + ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, + ` if (value == ${equalsValue}) return error.JSError;`, + ` return value;`, + ` }`, + ` }`, + ); + return; +} + +async function readFileOrEmpty(file: string): Promise { + try { + const fileContents = await Bun.file(file).text(); + return fileContents; + } catch (e) { + return ""; + } +} + +async function main() { + const args = process.argv.slice(2); + const rootDir = args[0]; + const dstDir = args[1]; + if (!rootDir || !dstDir) { + console.error("Usage: bun src/codegen/cppbind "); + process.exit(1); + } + await mkdir(dstDir, { recursive: true }); + + const parser = cppParser; + + const allCppFiles = (await Bun.file("cmake/sources/CxxSources.txt").text()) + .trim() + .split("\n") + .map(q => q.trim()) + .filter(q => !!q) + .filter(q => !q.startsWith("#")); + + const allFunctions: CppFn[] = []; + for (const file of allCppFiles) { + await processFile(parser, file, allFunctions); + } + + const resultRaw: string[] = []; + const resultBindings: string[] = []; + const resultSourceLinks: string[] = []; + for (const fn of allFunctions) { + try { + generateZigFn(fn, resultRaw, resultBindings, resultSourceLinks, { dstDir }); + } catch (e) { + appendErrorFromCatch(e, fn.position); + } + } + + for (const message of errors) { + await renderError(message.position, message.message, "error", "\x1b[31m"); + for (const note of message.notes) { + await renderError(note.position, note.message, "note", "\x1b[36m"); + } + console.error(); + } + + const resultFilePath = join(dstDir, "cpp.zig"); + const resultContents = + typeDeclarations + + "\nconst raw = struct {\n" + + resultRaw.join("\n") + + "\n};\n\npub const bindings = struct {\n" + + resultBindings.join("\n") + + "\n};\n"; + if ((await readFileOrEmpty(resultFilePath)) !== resultContents) { + await Bun.write(resultFilePath, resultContents); + } + + const resultSourceLinksFilePath = join(dstDir, "cpp.source-links"); + const resultSourceLinksContents = resultSourceLinks.join("\n"); + if ((await readFileOrEmpty(resultSourceLinksFilePath)) !== resultSourceLinksContents) { + await Bun.write(resultSourceLinksFilePath, resultSourceLinksContents); + } + + const now = Date.now(); + const sin = Math.round(((Math.sin((now / 1000) * 1) + 1) / 2) * 24); + + console.log( + " ".repeat(sin) + + (errors.length > 0 ? "✗" : "✓") + + " cppbind.ts generated bindings to " + + resultFilePath + + (errors.length > 0 ? " with errors" : ""), + ); + if (errors.length > 0) { + process.exit(1); + } +} + +// Run the main function +await main(); diff --git a/src/codegen/shared-types.ts b/src/codegen/shared-types.ts new file mode 100644 index 0000000000..efdb213787 --- /dev/null +++ b/src/codegen/shared-types.ts @@ -0,0 +1,60 @@ +export const typeDeclarations = `// generated by cppbind.ts from functions marked with [[ZIG_EXPORT(mode)]] + +const bun = @import("bun"); +const jsc = bun.jsc; +const HTTPServerAgent = bun.jsc.Debugger.HTTPServerAgent; +const Environment = bun.Environment; +`; + +export const sharedTypes: Record = { + // Basic types + "bool": "bool", + "char": "u8", + "unsigned char": "u8", + "signed char": "i8", + "char16_t": "u16", + "short": "c_short", + "unsigned short": "c_ushort", + "int": "c_int", + "unsigned": "c_uint", + "unsigned int": "c_uint", + "long": "c_long", + "unsigned long": "c_ulong", + "long long": "c_longlong", + "unsigned long long": "c_ulonglong", + "float": "f32", + "double": "f64", + "size_t": "usize", + "ssize_t": "isize", + "int8_t": "i8", + "uint8_t": "u8", + "int16_t": "i16", + "uint16_t": "u16", + "int32_t": "i32", + "uint32_t": "u32", + "int64_t": "i64", + "uint64_t": "u64", + + // Common Bun types + "BunString": "bun.String", + "JSC::EncodedJSValue": "jsc.JSValue", + "JSC::JSGlobalObject": "jsc.JSGlobalObject", + "ZigException": "jsc.ZigException", + "Inspector::InspectorHTTPServerAgent": "HTTPServerAgent.InspectorHTTPServerAgent", + "HotReloadId": "HTTPServerAgent.HotReloadId", + "ServerId": "HTTPServerAgent.ServerId", + "Route": "HTTPServerAgent.Route", + "Zig::GlobalObject": "jsc.JSGlobalObject", + "JSC::VM": "jsc.VM", + "WTF::StringImpl": "bun.WTF._StringImplStruct", + "WebCore::DOMURL": "bun.DOMURL", + "ZigString": "bun.JSC.ZigString", + "JSC::JSPromise": "bun.JSC.JSPromise", + "JSC::JSMap": "bun.JSC.JSMap", + "JSC::CustomGetterSetter": "bun.JSC.CustomGetterSetter", + "JSC::SourceProvider": "bun.JSC.SourceProvider", +}; + +export const bannedTypes: Record = { + "JSC::JSValue": "Not allowed, use JSC::EncodedJSValue instead", +}; diff --git a/src/fmt.zig b/src/fmt.zig index 6caa40b7b1..ec84395921 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -1682,10 +1682,8 @@ pub fn double(number: f64) FormatDouble { pub const FormatDouble = struct { number: f64, - extern fn WTF__dtoa(buf_124_bytes: *[124]u8, number: f64) usize; - pub fn dtoa(buf: *[124]u8, number: f64) []const u8 { - const len = WTF__dtoa(buf, number); + const len = bun.cpp.WTF__dtoa(&buf.ptr[0], number); return buf[0..len]; } @@ -1694,7 +1692,7 @@ pub const FormatDouble = struct { return "-0"; } - const len = WTF__dtoa(buf, number); + const len = bun.cpp.WTF__dtoa(&buf.ptr[0], number); return buf[0..len]; } diff --git a/src/string.zig b/src/string.zig index 995be0aeff..16fab4c729 100644 --- a/src/string.zig +++ b/src/string.zig @@ -47,15 +47,8 @@ pub const String = extern struct { pub const dead = String{ .tag = .Dead, .value = .{ .Dead = {} } }; pub const StringImplAllocator = @import("./string/WTFStringImpl.zig").StringImplAllocator; - extern fn BunString__fromLatin1(bytes: [*]const u8, len: usize) String; - extern fn BunString__fromBytes(bytes: [*]const u8, len: usize) String; - extern fn BunString__fromUTF16(bytes: [*]const u16, len: usize) String; - extern fn BunString__fromUTF16ToLatin1(bytes: [*]const u16, len: usize) String; - extern fn BunString__fromLatin1Unitialized(len: usize) String; - extern fn BunString__fromUTF16Unitialized(len: usize) String; - extern fn BunString__toInt32(this: String) i64; - pub fn toInt32(this: String) ?i32 { - const val = BunString__toInt32(this); + pub fn toInt32(this: *const String) ?i32 { + const val = bun.cpp.BunString__toInt32(this); if (val > std.math.maxInt(i32)) return null; return @intCast(val); } @@ -113,7 +106,7 @@ pub const String = extern struct { fn createUninitializedLatin1(len: usize) struct { String, []u8 } { bun.assert(len > 0); - const string = BunString__fromLatin1Unitialized(len); + const string = bun.cpp.BunString__fromLatin1Unitialized(len); _ = validateRefCount(string); const wtf = string.value.WTFStringImpl; return .{ @@ -124,7 +117,7 @@ pub const String = extern struct { fn createUninitializedUTF16(len: usize) struct { String, []u16 } { bun.assert(len > 0); - const string = BunString__fromUTF16Unitialized(len); + const string = bun.cpp.BunString__fromUTF16Unitialized(len); _ = validateRefCount(string); const wtf = string.value.WTFStringImpl; return .{ @@ -166,7 +159,7 @@ pub const String = extern struct { pub fn cloneLatin1(bytes: []const u8) String { JSC.markBinding(@src()); if (bytes.len == 0) return String.empty; - return validateRefCount(BunString__fromLatin1(bytes.ptr, bytes.len)); + return validateRefCount(bun.cpp.BunString__fromLatin1(bytes.ptr, bytes.len)); } pub inline fn validateRefCount(this: String) String { @@ -188,9 +181,9 @@ pub const String = extern struct { pub fn cloneUTF16(bytes: []const u16) String { if (bytes.len == 0) return String.empty; if (bun.strings.firstNonASCII16([]const u16, bytes) == null) { - return validateRefCount(BunString__fromUTF16ToLatin1(bytes.ptr, bytes.len)); + return validateRefCount(bun.cpp.BunString__fromUTF16ToLatin1(bytes.ptr, bytes.len)); } - return validateRefCount(BunString__fromUTF16(bytes.ptr, bytes.len)); + return validateRefCount(bun.cpp.BunString__fromUTF16(bytes.ptr, bytes.len)); } pub fn createFormat(comptime fmt: [:0]const u8, args: anytype) OOM!String { @@ -242,17 +235,14 @@ pub const String = extern struct { return cloneUTF8(this.byteSlice()); } - extern fn BunString__createAtom(bytes: [*]const u8, len: usize) String; - extern fn BunString__tryCreateAtom(bytes: [*]const u8, len: usize) String; - /// Must be given ascii input pub fn createAtomASCII(bytes: []const u8) String { - return BunString__createAtom(bytes.ptr, bytes.len); + return bun.cpp.BunString__createAtom(bytes.ptr, bytes.len); } /// Will return null if the input is non-ascii or too long pub fn tryCreateAtom(bytes: []const u8) ?String { - const atom = BunString__tryCreateAtom(bytes.ptr, bytes.len); + const atom = bun.cpp.BunString__tryCreateAtom(bytes.ptr, bytes.len); return if (atom.tag == .Dead) null else atom; } @@ -509,7 +499,7 @@ pub const String = extern struct { scope.init(globalObject, @src()); defer scope.deinit(); var out: String = String.dead; - const ok = BunString__fromJS(globalObject, value, &out); + const ok = bun.cpp.BunString__fromJS(globalObject, value, &out); // If there is a pending exception, but stringifying succeeds, we don't return JSError. // We do need to always call hasException() to satisfy the need for an exception check. @@ -561,7 +551,7 @@ pub const String = extern struct { pub fn toWTF(this: *String) void { JSC.markBinding(@src()); - BunString__toWTFString(this); + bun.cpp.BunString__toWTFString(this); } pub inline fn length(this: String) usize { @@ -657,10 +647,8 @@ pub const String = extern struct { return false; } - extern fn BunString__toJSON(globalObject: *bun.JSC.JSGlobalObject, this: *String) JSC.JSValue; - pub fn toJSByParseJSON(self: *String, globalObject: *JSC.JSGlobalObject) bun.JSError!JSC.JSValue { - return bun.jsc.fromJSHostCall(globalObject, @src(), BunString__toJSON, .{ globalObject, self }); + return bun.cpp.BunString__toJSON(globalObject, self); } pub fn encodeInto(self: String, out: []u8, comptime enc: JSC.Node.Encoding) !usize { @@ -824,17 +812,13 @@ pub const String = extern struct { return this.toSlice(allocator); } - extern fn BunString__fromJS(globalObject: *JSC.JSGlobalObject, value: bun.JSC.JSValue, out: *String) bool; extern fn BunString__toJS(globalObject: *JSC.JSGlobalObject, in: *const String) JSC.JSValue; extern fn BunString__toJSWithLength(globalObject: *JSC.JSGlobalObject, in: *const String, usize) JSC.JSValue; extern fn BunString__toJSDOMURL(globalObject: *JSC.JSGlobalObject, in: *String) JSC.JSValue; - extern fn Bun__parseDate(*JSC.JSGlobalObject, *String) f64; - extern fn BunString__toWTFString(this: *String) void; - extern fn BunString__createUTF8ForJS(globalObject: *JSC.JSGlobalObject, ptr: [*]const u8, len: usize) JSC.JSValue; pub fn createUTF8ForJS(globalObject: *JSC.JSGlobalObject, utf8_slice: []const u8) bun.JSError!JSC.JSValue { JSC.markBinding(@src()); - return bun.jsc.fromJSHostCall(globalObject, @src(), BunString__createUTF8ForJS, .{ globalObject, utf8_slice.ptr, utf8_slice.len }); + return bun.cpp.BunString__createUTF8ForJS(globalObject, utf8_slice.ptr, utf8_slice.len); } pub fn createFormatForJS(globalObject: *JSC.JSGlobalObject, comptime fmt: [:0]const u8, args: anytype) bun.JSError!JSC.JSValue { @@ -842,12 +826,12 @@ pub const String = extern struct { var builder = std.ArrayList(u8).init(bun.default_allocator); defer builder.deinit(); builder.writer().print(fmt, args) catch bun.outOfMemory(); - return bun.jsc.fromJSHostCall(globalObject, @src(), BunString__createUTF8ForJS, .{ globalObject, builder.items.ptr, builder.items.len }); + return bun.cpp.BunString__createUTF8ForJS(globalObject, builder.items.ptr, builder.items.len); } pub fn parseDate(this: *String, globalObject: *JSC.JSGlobalObject) bun.JSError!f64 { JSC.markBinding(@src()); - return bun.jsc.fromJSHostCallGeneric(globalObject, @src(), Bun__parseDate, .{ globalObject, this }); + return bun.cpp.Bun__parseDate(globalObject, this); } pub fn ref(this: String) void { @@ -1043,14 +1027,12 @@ pub const String = extern struct { return bun.strings.eqlLong(this.byteSlice(), value, true); } - extern fn BunString__toThreadSafe(this: *String) void; - /// Does not increment the reference count unless the StringImpl is cloned. pub fn toThreadSafe(this: *String) void { JSC.markBinding(@src()); if (this.tag == .WTFStringImpl) { - BunString__toThreadSafe(this); + bun.cpp.BunString__toThreadSafe(this); } } @@ -1062,7 +1044,7 @@ pub const String = extern struct { if (this.tag == .WTFStringImpl) { const orig = this.value.WTFStringImpl; - BunString__toThreadSafe(this); + bun.cpp.BunString__toThreadSafe(this); if (this.value.WTFStringImpl == orig) { orig.ref(); } diff --git a/src/string/WTFStringImpl.zig b/src/string/WTFStringImpl.zig index 27e27a7864..90595a6ac6 100644 --- a/src/string/WTFStringImpl.zig +++ b/src/string/WTFStringImpl.zig @@ -45,9 +45,8 @@ pub const WTFStringImplStruct = extern struct { return if (this.is8Bit()) this.m_length else this.m_length * 2; } - extern fn WTFStringImpl__isThreadSafe(WTFStringImpl) bool; pub fn isThreadSafe(this: WTFStringImpl) bool { - return WTFStringImpl__isThreadSafe(this); + return bun.cpp.WTFStringImpl__isThreadSafe(this); } pub fn byteSlice(this: WTFStringImpl) []const u8 { @@ -91,7 +90,7 @@ pub const WTFStringImplStruct = extern struct { JSC.markBinding(@src()); const current_count = self.refCount(); bun.assert(self.hasAtLeastOneRef()); // do not use current_count, it breaks for static strings - Bun__WTFStringImpl__deref(self); + bun.cpp.Bun__WTFStringImpl__deref(self); if (comptime bun.Environment.allow_assert) { if (current_count > 1) { bun.assert(self.refCount() < current_count or self.isStatic()); @@ -103,7 +102,7 @@ pub const WTFStringImplStruct = extern struct { JSC.markBinding(@src()); const current_count = self.refCount(); bun.assert(self.hasAtLeastOneRef()); // do not use current_count, it breaks for static strings - Bun__WTFStringImpl__ref(self); + bun.cpp.Bun__WTFStringImpl__ref(self); bun.assert(self.refCount() > current_count or self.isStatic()); } @@ -117,11 +116,10 @@ pub const WTFStringImplStruct = extern struct { return ZigString.Slice.init(this.refCountAllocator(), this.latin1Slice()); } - extern fn Bun__WTFStringImpl__ensureHash(this: WTFStringImpl) void; /// Compute the hash() if necessary pub fn ensureHash(this: WTFStringImpl) void { JSC.markBinding(@src()); - Bun__WTFStringImpl__ensureHash(this); + bun.cpp.Bun__WTFStringImpl__ensureHash(this); } pub fn toUTF8(this: WTFStringImpl, allocator: std.mem.Allocator) ZigString.Slice { @@ -217,12 +215,8 @@ pub const WTFStringImplStruct = extern struct { } pub fn hasPrefix(self: WTFStringImpl, text: []const u8) bool { - return Bun__WTFStringImpl__hasPrefix(self, text.ptr, text.len); + return bun.cpp.Bun__WTFStringImpl__hasPrefix(self, text.ptr, text.len); } - - extern fn Bun__WTFStringImpl__deref(self: WTFStringImpl) void; - extern fn Bun__WTFStringImpl__ref(self: WTFStringImpl) void; - extern fn Bun__WTFStringImpl__hasPrefix(self: *const WTFStringImplStruct, offset: [*]const u8, length: usize) bool; }; pub const StringImplAllocator = struct {