From 6b149bc9aa25eada537a1c47bc50ebe7b87f7d2d Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Sat, 3 Jan 2026 18:45:56 +0900 Subject: [PATCH] fix: adapt Bun bindings to WebKit upstream changes - Update QueuedTask constructor calls to use new payload parameter - BunPerformMicrotaskJob now handles async context directly (saves one argument slot) - Replace SortedArrayMap usage with if-else chains (API changed in WTF) - Fix typos: DOMEGCOutputConstraint -> DOMGCOutputConstraint - Fix WTF_MAKE_TZONE_ALLOCATED macro argument in CryptoSignJob.h - Update code generators (bindgen.ts, enumeration.ts) to not use SortedArrayMap Claude-Generated-By: Claude Code (cli/claude-opus-4-5=100%) Claude-Steers: 13 --- src/bun.js/bindings/BunGCOutputConstraint.h | 2 +- src/bun.js/bindings/ZigGlobalObject.cpp | 11 ++-- src/bun.js/bindings/bindings.cpp | 12 ++--- .../bindings/node/crypto/CryptoSignJob.h | 2 +- .../webcore/PerformanceUserTiming.cpp | 50 ++++++++----------- src/bun.js/bindings/webcrypto/JSCryptoKey.cpp | 15 +++--- .../bindings/webcrypto/JSCryptoKeyUsage.cpp | 30 +++++------ .../bindings/webcrypto/JSSubtleCrypto.cpp | 18 +++---- src/codegen/bindgen.ts | 11 +--- src/codegen/bindgenv2/internal/enumeration.ts | 26 +++------- 10 files changed, 72 insertions(+), 105 deletions(-) diff --git a/src/bun.js/bindings/BunGCOutputConstraint.h b/src/bun.js/bindings/BunGCOutputConstraint.h index b19d4c37a0..6882e1e9d3 100644 --- a/src/bun.js/bindings/BunGCOutputConstraint.h +++ b/src/bun.js/bindings/BunGCOutputConstraint.h @@ -36,7 +36,7 @@ namespace WebCore { class JSHeapData; class DOMGCOutputConstraint : public JSC::MarkingConstraint { - WTF_DEPRECATED_MAKE_FAST_ALLOCATED(DOMEGCOutputConstraint); + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(DOMGCOutputConstraint); public: DOMGCOutputConstraint(JSC::VM&, JSHeapData&); diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index dbbe784ad0..bfcc9daf7a 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -1059,9 +1059,7 @@ JSC_DEFINE_HOST_FUNCTION(functionQueueMicrotask, auto* globalObject = defaultGlobalObject(lexicalGlobalObject); JSC::JSValue asyncContext = globalObject->m_asyncContextData.get()->getInternalField(0); - auto function = globalObject->performMicrotaskFunction(); #if ASSERT_ENABLED - ASSERT_WITH_MESSAGE(function, "Invalid microtask function"); ASSERT_WITH_MESSAGE(!callback.isEmpty(), "Invalid microtask callback"); #endif @@ -1069,10 +1067,9 @@ JSC_DEFINE_HOST_FUNCTION(functionQueueMicrotask, asyncContext = JSC::jsUndefined(); } - // BunPerformMicrotaskJob accepts a variable number of arguments (up to: performMicrotask, job, asyncContext, arg0, arg1). - // The runtime inspects argumentCount to determine which arguments are present, so callers may pass only the subset they need. - // Here we pass: function, callback, asyncContext. - JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, globalObject, function, callback, asyncContext }; + // BunPerformMicrotaskJob now handles async context directly: + // arguments[0]: job function, arguments[1]: asyncContext + JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, 0, globalObject, callback, asyncContext }; globalObject->vm().queueMicrotask(WTF::move(task)); return JSC::JSValue::encode(JSC::jsUndefined()); @@ -3103,7 +3100,7 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskCallback(Zig::GlobalObject* g // Do not use JSCell* here because the GC will try to visit it. // Use BunInvokeJobWithArguments to pass the two arguments (ptr and callback) to the trampoline function - JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunInvokeJobWithArguments, globalObject, function, JSValue(std::bit_cast(reinterpret_cast(ptr))), JSValue(std::bit_cast(reinterpret_cast(callback))) }; + JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunInvokeJobWithArguments, 0, globalObject, function, JSValue(std::bit_cast(reinterpret_cast(ptr))), JSValue(std::bit_cast(reinterpret_cast(callback))) }; globalObject->vm().queueMicrotask(WTF::move(task)); } diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index 3a4130c983..ed786bb1a8 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -3521,13 +3521,11 @@ void JSC__JSPromise__rejectOnNextTickWithHandled(JSC::JSPromise* promise, JSC::J promise->internalField(JSC::JSPromise::Field::Flags).set(vm, promise, jsNumber(flags | JSC::JSPromise::isFirstResolvingFunctionCalledFlag)); auto* globalObject = jsCast(promise->globalObject()); - auto microtaskFunction = globalObject->performMicrotaskFunction(); auto rejectPromiseFunction = globalObject->rejectPromiseFunction(); auto asyncContext = globalObject->m_asyncContextData.get()->getInternalField(0); #if ASSERT_ENABLED - ASSERT_WITH_MESSAGE(microtaskFunction, "Invalid microtask function"); ASSERT_WITH_MESSAGE(rejectPromiseFunction, "Invalid microtask callback"); ASSERT_WITH_MESSAGE(!value.isEmpty(), "Invalid microtask value"); #endif @@ -3540,7 +3538,9 @@ void JSC__JSPromise__rejectOnNextTickWithHandled(JSC::JSPromise* promise, JSC::J value = jsUndefined(); } - JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, globalObject, microtaskFunction, rejectPromiseFunction, globalObject->m_asyncContextData.get()->getInternalField(0), promise, value }; + // BunPerformMicrotaskJob now handles async context directly: + // arguments[0]: job function, arguments[1]: asyncContext, arguments[2]: promise, arguments[3]: value + JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, 0, globalObject, rejectPromiseFunction, asyncContext, promise, value }; globalObject->vm().queueMicrotask(WTF::move(task)); RETURN_IF_EXCEPTION(scope, ); } @@ -5406,9 +5406,7 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC::JSGlobalObject* arg0 if (microtaskArgs[3].isEmpty()) { microtaskArgs[3] = jsUndefined(); } - JSC::JSFunction* microTaskFunction = globalObject->performMicrotaskFunction(); #if ASSERT_ENABLED - ASSERT_WITH_MESSAGE(microTaskFunction, "Invalid microtask function"); auto& vm = globalObject->vm(); if (microtaskArgs[0].isCell()) { JSC::Integrity::auditCellFully(vm, microtaskArgs[0].asCell()); @@ -5428,7 +5426,9 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC::JSGlobalObject* arg0 #endif - JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, globalObject, microTaskFunction, WTF::move(microtaskArgs[0]), WTF::move(microtaskArgs[1]), WTF::move(microtaskArgs[2]), WTF::move(microtaskArgs[3]) }; + // BunPerformMicrotaskJob now handles async context directly: + // arguments[0]: job function, arguments[1]: asyncContext, arguments[2-3]: optional args + JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, 0, globalObject, WTF::move(microtaskArgs[0]), WTF::move(microtaskArgs[1]), WTF::move(microtaskArgs[2]), WTF::move(microtaskArgs[3]) }; globalObject->vm().queueMicrotask(WTF::move(task)); } diff --git a/src/bun.js/bindings/node/crypto/CryptoSignJob.h b/src/bun.js/bindings/node/crypto/CryptoSignJob.h index f3bf6a5313..a46618cfd7 100644 --- a/src/bun.js/bindings/node/crypto/CryptoSignJob.h +++ b/src/bun.js/bindings/node/crypto/CryptoSignJob.h @@ -11,7 +11,7 @@ JSC_DECLARE_HOST_FUNCTION(jsVerifyOneShot); static const unsigned int NoDsaSignature = static_cast(-1); struct SignJobCtx { - WTF_MAKE_TZONE_ALLOCATED(name); + WTF_MAKE_TZONE_ALLOCATED(SignJobCtx); public: enum class Mode { diff --git a/src/bun.js/bindings/webcore/PerformanceUserTiming.cpp b/src/bun.js/bindings/webcore/PerformanceUserTiming.cpp index 9870e42f39..2567f4bb97 100644 --- a/src/bun.js/bindings/webcore/PerformanceUserTiming.cpp +++ b/src/bun.js/bindings/webcore/PerformanceUserTiming.cpp @@ -37,40 +37,32 @@ #include "SerializedScriptValue.h" // #include "WorkerOrWorkletGlobalScope.h" #include -#include namespace WebCore { -using NavigationTimingFunction = unsigned long long (PerformanceTiming::*)() const; - -static constexpr std::array, 21> restrictedMarkMappings { { - { "connectEnd"_s, &PerformanceTiming::connectEnd }, - { "connectStart"_s, &PerformanceTiming::connectStart }, - { "domComplete"_s, &PerformanceTiming::domComplete }, - { "domContentLoadedEventEnd"_s, &PerformanceTiming::domContentLoadedEventEnd }, - { "domContentLoadedEventStart"_s, &PerformanceTiming::domContentLoadedEventStart }, - { "domInteractive"_s, &PerformanceTiming::domInteractive }, - { "domLoading"_s, &PerformanceTiming::domLoading }, - { "domainLookupEnd"_s, &PerformanceTiming::domainLookupEnd }, - { "domainLookupStart"_s, &PerformanceTiming::domainLookupStart }, - { "fetchStart"_s, &PerformanceTiming::fetchStart }, - { "loadEventEnd"_s, &PerformanceTiming::loadEventEnd }, - { "loadEventStart"_s, &PerformanceTiming::loadEventStart }, - { "navigationStart"_s, &PerformanceTiming::navigationStart }, - { "redirectEnd"_s, &PerformanceTiming::redirectEnd }, - { "redirectStart"_s, &PerformanceTiming::redirectStart }, - { "requestStart"_s, &PerformanceTiming::requestStart }, - { "responseEnd"_s, &PerformanceTiming::responseEnd }, - { "responseStart"_s, &PerformanceTiming::responseStart }, - { "secureConnectionStart"_s, &PerformanceTiming::secureConnectionStart }, - { "unloadEventEnd"_s, &PerformanceTiming::unloadEventEnd }, - { "unloadEventStart"_s, &PerformanceTiming::unloadEventStart }, -} }; -static constexpr SortedArrayMap restrictedMarkFunctions { restrictedMarkMappings }; - bool PerformanceUserTiming::isRestrictedMarkName(const String& markName) { - return restrictedMarkFunctions.contains(markName); + return markName == "connectEnd"_s + || markName == "connectStart"_s + || markName == "domComplete"_s + || markName == "domContentLoadedEventEnd"_s + || markName == "domContentLoadedEventStart"_s + || markName == "domInteractive"_s + || markName == "domLoading"_s + || markName == "domainLookupEnd"_s + || markName == "domainLookupStart"_s + || markName == "fetchStart"_s + || markName == "loadEventEnd"_s + || markName == "loadEventStart"_s + || markName == "navigationStart"_s + || markName == "redirectEnd"_s + || markName == "redirectStart"_s + || markName == "requestStart"_s + || markName == "responseEnd"_s + || markName == "responseStart"_s + || markName == "secureConnectionStart"_s + || markName == "unloadEventEnd"_s + || markName == "unloadEventStart"_s; } PerformanceUserTiming::PerformanceUserTiming(Performance& performance) diff --git a/src/bun.js/bindings/webcrypto/JSCryptoKey.cpp b/src/bun.js/bindings/webcrypto/JSCryptoKey.cpp index 92acf8acf3..71894d6e46 100644 --- a/src/bun.js/bindings/webcrypto/JSCryptoKey.cpp +++ b/src/bun.js/bindings/webcrypto/JSCryptoKey.cpp @@ -59,7 +59,6 @@ #include #include #include -#include #include namespace WebCore { @@ -87,14 +86,12 @@ template<> JSString* convertEnumerationToJS(JSGlobalObject& lexicalGlobalObject, template<> std::optional parseEnumeration(JSGlobalObject& lexicalGlobalObject, JSValue value) { auto stringValue = value.toWTFString(&lexicalGlobalObject); - static constexpr std::array, 3> mappings { { - { "private"_s, CryptoKey::Type::Private }, - { "public"_s, CryptoKey::Type::Public }, - { "secret"_s, CryptoKey::Type::Secret }, - } }; - static constexpr SortedArrayMap enumerationMapping { mappings }; - if (auto* enumerationValue = enumerationMapping.tryGet(stringValue); enumerationValue) [[likely]] - return *enumerationValue; + if (stringValue == "private"_s) + return CryptoKey::Type::Private; + if (stringValue == "public"_s) + return CryptoKey::Type::Public; + if (stringValue == "secret"_s) + return CryptoKey::Type::Secret; return std::nullopt; } diff --git a/src/bun.js/bindings/webcrypto/JSCryptoKeyUsage.cpp b/src/bun.js/bindings/webcrypto/JSCryptoKeyUsage.cpp index f27a254b18..1a2bed5a8d 100644 --- a/src/bun.js/bindings/webcrypto/JSCryptoKeyUsage.cpp +++ b/src/bun.js/bindings/webcrypto/JSCryptoKeyUsage.cpp @@ -27,7 +27,6 @@ #include #include #include -#include namespace WebCore { using namespace JSC; @@ -64,19 +63,22 @@ template<> JSString* convertEnumerationToJS(JSGlobalObject& lexicalGlobalObject, template<> std::optional parseEnumeration(JSGlobalObject& lexicalGlobalObject, JSValue value) { auto stringValue = value.toWTFString(&lexicalGlobalObject); - static constexpr std::array, 8> mappings { { - { "decrypt"_s, CryptoKeyUsage::Decrypt }, - { "deriveBits"_s, CryptoKeyUsage::DeriveBits }, - { "deriveKey"_s, CryptoKeyUsage::DeriveKey }, - { "encrypt"_s, CryptoKeyUsage::Encrypt }, - { "sign"_s, CryptoKeyUsage::Sign }, - { "unwrapKey"_s, CryptoKeyUsage::UnwrapKey }, - { "verify"_s, CryptoKeyUsage::Verify }, - { "wrapKey"_s, CryptoKeyUsage::WrapKey }, - } }; - static constexpr SortedArrayMap enumerationMapping { mappings }; - if (auto* enumerationValue = enumerationMapping.tryGet(stringValue); enumerationValue) [[likely]] - return *enumerationValue; + if (stringValue == "decrypt"_s) + return CryptoKeyUsage::Decrypt; + if (stringValue == "deriveBits"_s) + return CryptoKeyUsage::DeriveBits; + if (stringValue == "deriveKey"_s) + return CryptoKeyUsage::DeriveKey; + if (stringValue == "encrypt"_s) + return CryptoKeyUsage::Encrypt; + if (stringValue == "sign"_s) + return CryptoKeyUsage::Sign; + if (stringValue == "unwrapKey"_s) + return CryptoKeyUsage::UnwrapKey; + if (stringValue == "verify"_s) + return CryptoKeyUsage::Verify; + if (stringValue == "wrapKey"_s) + return CryptoKeyUsage::WrapKey; return std::nullopt; } diff --git a/src/bun.js/bindings/webcrypto/JSSubtleCrypto.cpp b/src/bun.js/bindings/webcrypto/JSSubtleCrypto.cpp index bceabcda93..117a864c7d 100644 --- a/src/bun.js/bindings/webcrypto/JSSubtleCrypto.cpp +++ b/src/bun.js/bindings/webcrypto/JSSubtleCrypto.cpp @@ -65,7 +65,6 @@ #include #include #include -#include #include #include "ErrorCode.h" @@ -96,15 +95,14 @@ template<> JSString* convertEnumerationToJS(JSGlobalObject& lexicalGlobalObject, template<> std::optional parseEnumeration(JSGlobalObject& lexicalGlobalObject, JSValue value) { auto stringValue = value.toWTFString(&lexicalGlobalObject); - static constexpr std::array, 4> mappings { { - { "jwk"_s, SubtleCrypto::KeyFormat::Jwk }, - { "pkcs8"_s, SubtleCrypto::KeyFormat::Pkcs8 }, - { "raw"_s, SubtleCrypto::KeyFormat::Raw }, - { "spki"_s, SubtleCrypto::KeyFormat::Spki }, - } }; - static constexpr SortedArrayMap enumerationMapping { mappings }; - if (auto* enumerationValue = enumerationMapping.tryGet(stringValue); enumerationValue) [[likely]] - return *enumerationValue; + if (stringValue == "jwk"_s) + return SubtleCrypto::KeyFormat::Jwk; + if (stringValue == "pkcs8"_s) + return SubtleCrypto::KeyFormat::Pkcs8; + if (stringValue == "raw"_s) + return SubtleCrypto::KeyFormat::Raw; + if (stringValue == "spki"_s) + return SubtleCrypto::KeyFormat::Spki; return std::nullopt; } diff --git a/src/codegen/bindgen.ts b/src/codegen/bindgen.ts index 386823736f..dba4d78cd1 100644 --- a/src/codegen/bindgen.ts +++ b/src/codegen/bindgen.ts @@ -733,7 +733,6 @@ function emitConvertEnumFunction(w: CodeWriter, type: TypeImpl) { headers.add("JavaScriptCore/JSCInlines.h"); headers.add("JavaScriptCore/JSString.h"); headers.add("wtf/NeverDestroyed.h"); - headers.add("wtf/SortedArrayMap.h"); w.line(`String convertEnumerationToString(${name} enumerationValue) {`); w.indent(); @@ -754,16 +753,10 @@ function emitConvertEnumFunction(w: CodeWriter, type: TypeImpl) { w.line(); w.line(`template<> std::optional<${name}> parseEnumerationFromString<${name}>(const String& stringValue)`); w.line(`{`); - w.line( - ` static constexpr std::array, ${type.data.length}> mappings { {`, - ); for (const value of type.data) { - w.line(` { ${str(value)}_s, ${name}::${pascal(value)} },`); + w.line(` if (stringValue == ${str(value)}_s)`); + w.line(` return ${name}::${pascal(value)};`); } - w.line(` } };`); - w.line(` static constexpr SortedArrayMap enumerationMapping { mappings };`); - w.line(` if (auto* enumerationValue = enumerationMapping.tryGet(stringValue); enumerationValue) [[likely]]`); - w.line(` return *enumerationValue;`); w.line(` return std::nullopt;`); w.line(`}`); w.line(); diff --git a/src/codegen/bindgenv2/internal/enumeration.ts b/src/codegen/bindgenv2/internal/enumeration.ts index 0e4ec52c53..9108a7bbbf 100644 --- a/src/codegen/bindgenv2/internal/enumeration.ts +++ b/src/codegen/bindgenv2/internal/enumeration.ts @@ -134,32 +134,20 @@ export function enumeration( } get cppSource() { const qualifiedName = "Bun::Bindgen::Generated::" + name; - const pairType = `::std::pair<::WTF::ComparableASCIILiteral, ::${qualifiedName}>`; return reindent(` #include "root.h" #include "Generated${name}.h" - #include template<> std::optional<${qualifiedName}> WebCore::parseEnumerationFromString<${qualifiedName}>(const WTF::String& stringVal) { - static constexpr ::std::array<${pairType}, ${valueMap.size}> mappings { - ${joinIndented( - 12, - Array.from(valueMap.entries()) - .sort(([v1], [v2]) => (v1 < v2 ? -1 : 1)) - .map(([value, i]) => { - return `${pairType} { - ${toASCIILiteral(value)}, - ::${qualifiedName}::${cppMembers[i]}, - },`; - }), - )} - }; - static constexpr ::WTF::SortedArrayMap enumerationMapping { mappings }; - if (auto* enumerationValue = enumerationMapping.tryGet(stringVal)) [[likely]] { - return *enumerationValue; - } + ${joinIndented( + 10, + Array.from(valueMap.entries()).map(([value, i]) => { + return `if (stringVal == ${toASCIILiteral(value)}) + return ::${qualifiedName}::${cppMembers[i]};`; + }), + )} return std::nullopt; }