From b96fe564a67936c9b946d4dfbeac0f2fa18eaeef Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Wed, 11 Feb 2026 19:17:17 +0900 Subject: [PATCH] perf: remove performMicrotaskFunction from BunPerformMicrotaskJob call sites MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion change to WebKit's maxMicrotaskArguments 5→4 reduction. - Remove performMicrotaskFunction from all QueuedTask construction sites (functionQueueMicrotask, JSC__JSPromise__reject_, queueMicrotaskJob) - Delete jsFunctionPerformMicrotask (now inlined in JSC's handler) - Remove m_performMicrotaskFunction LazyProperty and accessor sizeof(QueuedTask) drops from 56 to 48 bytes (-14%). --- src/bun.js/bindings/ZigGlobalObject.cpp | 70 +------------------------ src/bun.js/bindings/ZigGlobalObject.h | 2 - src/bun.js/bindings/bindings.cpp | 10 ++-- 3 files changed, 6 insertions(+), 76 deletions(-) diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 9cb9399815..f32ac3e832 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -1061,9 +1061,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 @@ -1071,10 +1069,8 @@ 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, 0, globalObject, function, callback, asyncContext }; + // BunPerformMicrotaskJob: callback, asyncContext + JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, 0, globalObject, callback, asyncContext }; globalObject->vm().queueMicrotask(WTF::move(task)); return JSC::JSValue::encode(JSC::jsUndefined()); @@ -1554,63 +1550,6 @@ extern "C" napi_env ZigGlobalObject__makeNapiEnvForFFI(Zig::GlobalObject* global return globalObject->makeNapiEnvForFFI(); } -JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotask, (JSGlobalObject * globalObject, CallFrame* callframe)) -{ - auto& vm = JSC::getVM(globalObject); - auto scope = DECLARE_TOP_EXCEPTION_SCOPE(vm); - - auto job = callframe->argument(0); - if (!job || job.isUndefinedOrNull()) [[unlikely]] { - return JSValue::encode(jsUndefined()); - } - - auto callData = JSC::getCallData(job); - MarkedArgumentBuffer arguments; - - if (callData.type == CallData::Type::None) [[unlikely]] { - return JSValue::encode(jsUndefined()); - } - - JSValue result; - WTF::NakedPtr exceptionPtr; - - JSValue restoreAsyncContext = {}; - InternalFieldTuple* asyncContextData = nullptr; - auto setAsyncContext = callframe->argument(1); - if (!setAsyncContext.isUndefined()) { - asyncContextData = globalObject->m_asyncContextData.get(); - restoreAsyncContext = asyncContextData->getInternalField(0); - asyncContextData->putInternalField(vm, 0, setAsyncContext); - } - - size_t argCount = callframe->argumentCount(); - switch (argCount) { - case 3: { - arguments.append(callframe->uncheckedArgument(2)); - break; - } - case 4: { - arguments.append(callframe->uncheckedArgument(2)); - arguments.append(callframe->uncheckedArgument(3)); - break; - } - default: - break; - } - - JSC::profiledCall(globalObject, ProfilingReason::API, job, callData, jsUndefined(), arguments, exceptionPtr); - - if (asyncContextData) { - asyncContextData->putInternalField(vm, 0, restoreAsyncContext); - } - - if (auto* exception = exceptionPtr.get()) { - Bun__reportUnhandledError(globalObject, JSValue::encode(exception)); - } - - return JSValue::encode(jsUndefined()); -} - JSC_DEFINE_HOST_FUNCTION(jsFunctionPerformMicrotaskVariadic, (JSGlobalObject * globalObject, CallFrame* callframe)) { auto& vm = JSC::getVM(globalObject); @@ -1940,11 +1879,6 @@ void GlobalObject::finishCreation(VM& vm) scope.assertNoExceptionExceptTermination(); init.set(subclassStructure); }); - m_performMicrotaskFunction.initLater( - [](const Initializer& init) { - init.set(JSFunction::create(init.vm, init.owner, 4, "performMicrotask"_s, jsFunctionPerformMicrotask, ImplementationVisibility::Public)); - }); - m_performMicrotaskVariadicFunction.initLater( [](const Initializer& init) { init.set(JSFunction::create(init.vm, init.owner, 4, "performMicrotaskVariadic"_s, jsFunctionPerformMicrotaskVariadic, ImplementationVisibility::Public)); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 5225b67ddd..dd3bf302e6 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -272,7 +272,6 @@ public: JSC::JSObject* performanceObject() const { return m_performanceObject.getInitializedOnMainThread(this); } - JSC::JSFunction* performMicrotaskFunction() const { return m_performMicrotaskFunction.getInitializedOnMainThread(this); } JSC::JSFunction* performMicrotaskVariadicFunction() const { return m_performMicrotaskVariadicFunction.getInitializedOnMainThread(this); } JSC::Structure* utilInspectOptionsStructure() const { return m_utilInspectOptionsStructure.getInitializedOnMainThread(this); } @@ -569,7 +568,6 @@ public: V(private, LazyPropertyOfGlobalObject, m_jsonlParseResultStructure) \ V(private, LazyPropertyOfGlobalObject, m_pathParsedObjectStructure) \ V(private, LazyPropertyOfGlobalObject, m_pendingVirtualModuleResultStructure) \ - V(private, LazyPropertyOfGlobalObject, m_performMicrotaskFunction) \ V(private, LazyPropertyOfGlobalObject, m_nativeMicrotaskTrampoline) \ V(private, LazyPropertyOfGlobalObject, m_performMicrotaskVariadicFunction) \ V(private, LazyPropertyOfGlobalObject, m_utilInspectFunction) \ diff --git a/src/bun.js/bindings/bindings.cpp b/src/bun.js/bindings/bindings.cpp index f3bf8d1f97..3bbf6fbcc9 100644 --- a/src/bun.js/bindings/bindings.cpp +++ b/src/bun.js/bindings/bindings.cpp @@ -3538,13 +3538,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 @@ -3557,7 +3555,8 @@ void JSC__JSPromise__rejectOnNextTickWithHandled(JSC::JSPromise* promise, JSC::J value = jsUndefined(); } - JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, 0, globalObject, microtaskFunction, rejectPromiseFunction, globalObject->m_asyncContextData.get()->getInternalField(0), promise, value }; + // BunPerformMicrotaskJob: rejectPromiseFunction, asyncContext, promise, value + JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, 0, globalObject, rejectPromiseFunction, globalObject->m_asyncContextData.get()->getInternalField(0), promise, value }; globalObject->vm().queueMicrotask(WTF::move(task)); RETURN_IF_EXCEPTION(scope, ); } @@ -5438,9 +5437,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()); @@ -5460,7 +5457,8 @@ extern "C" void JSC__JSGlobalObject__queueMicrotaskJob(JSC::JSGlobalObject* arg0 #endif - JSC::QueuedTask task { nullptr, JSC::InternalMicrotask::BunPerformMicrotaskJob, 0, globalObject, microTaskFunction, WTF::move(microtaskArgs[0]), WTF::move(microtaskArgs[1]), WTF::move(microtaskArgs[2]), WTF::move(microtaskArgs[3]) }; + // BunPerformMicrotaskJob: job, asyncContext, arg0, arg1 + 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)); }