Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
[JSC] Optimize async/await and microtask queue part 1
https://bugs.webkit.org/show_bug.cgi?id=244165 Reviewed by Ross Kirsling. This patch improves our async await performance, including microtask queue implementation in JSC side. 1. Promise reaction now delivers |context| value additionally. It is passed as a second argument to the fulfill / reject handlers if it exists. In async function code, we need to have generator reference in the promise handlers, and we end up allocating a closure for them capturing |generator|. But (1) this kind of case is common and (2) allocating closure is costly. In this patch, we additionally pass context parameter so that handlers can get |generator| tied to this handler registration. This removes closure allocations and improve async / await performance. Currently this context parameter is usable only when using resolveWithoutPromise APIs. Keep in mind that we could attempt to optimize the current implementation by making promiseOrCapability field to promiseOrCapabilityOrContext. So if users would like to use it, not passing a promise as a context for the future refactoring, it could be broken. 2. We found that MicrotaskQueue can get *super* large. And current heap-allocated JSMicrotask and Strong<> implementation is too costly for these cases. In this patch, we redesign MicrotaskQueue in JSC VM: QueuedTask holds JSValues directly, and JSC GC scans this queue to keep them alive. We also make QueuedTask non heap-allocated structure so MicrotaskQueue enqueue/dequeue and scanning (for GC) is super fast. We also introduce optimization to reduce scanning cost in GC by maintaining scanning cursor so that we do not take much time in GC scanning. Currently these optimization is only applied to JSC VM's MicrotaskQueue: WebCore has different implementation, so this is not applied to WebContent use case. But we first would like to apply it to JavaScriptCore.framework use case, and then, we will apply this optimization / redesign current WebCore MicrotaskQueue mechanism to be faster one later. This offers 4% improvement in JetStream2/async-fs since it is using async / await. * LayoutTests/inspector/canvas/recording-bitmaprenderer-frameCount-expected.txt: * LayoutTests/inspector/canvas/recording-bitmaprenderer-full-expected.txt: * LayoutTests/inspector/canvas/recording-bitmaprenderer-memoryLimit-expected.txt: * Source/JavaScriptCore/builtins/AsyncFromSyncIteratorPrototype.js: (linkTimeConstant.asyncFromSyncIteratorOnRejected): (linkTimeConstant.asyncFromSyncIteratorOnFulfilledContinue): (linkTimeConstant.asyncFromSyncIteratorOnFulfilledDone): (return): (throw): (next.try): Deleted. (next): Deleted. (return.try): Deleted. (throw.try): Deleted. * Source/JavaScriptCore/builtins/AsyncFunctionPrototype.js: (linkTimeConstant.asyncFunctionResumeOnFulfilled): (linkTimeConstant.asyncFunctionResumeOnRejected): (linkTimeConstant.asyncFunctionResume): * Source/JavaScriptCore/builtins/AsyncGeneratorPrototype.js: (linkTimeConstant.asyncGeneratorYieldAwaited): (linkTimeConstant.asyncGeneratorYieldOnRejected): (linkTimeConstant.asyncGeneratorYield): (linkTimeConstant.awaitValue): (linkTimeConstant.doAsyncGeneratorBodyCallOnFulfilledNormal): (linkTimeConstant.doAsyncGeneratorBodyCallOnFulfilledReturn): (linkTimeConstant.doAsyncGeneratorBodyCall): (linkTimeConstant.asyncGeneratorResumeNextOnFulfilled): (linkTimeConstant.asyncGeneratorResumeNextOnRejected): (linkTimeConstant.asyncGeneratorResumeNext): (asyncGeneratorYieldAwaited): Deleted. (onRejected): Deleted. (onFulfilled): Deleted. * Source/JavaScriptCore/builtins/BuiltinNames.h: * Source/JavaScriptCore/builtins/InternalPromiseConstructor.js: (internalAll): * Source/JavaScriptCore/builtins/PromiseOperations.js: (linkTimeConstant.pushNewPromiseReaction): (linkTimeConstant.triggerPromiseReactions): (linkTimeConstant.promiseReactionJobWithoutPromise): (linkTimeConstant.resolveWithoutPromise): (linkTimeConstant.rejectWithoutPromise): (linkTimeConstant.fulfillWithoutPromise): (linkTimeConstant.resolveWithoutPromiseForAsyncAwait): (linkTimeConstant.createResolvingFunctionsWithoutPromise): (linkTimeConstant.promiseReactionJob): (linkTimeConstant.promiseResolveThenableJobFast): (linkTimeConstant.promiseResolveThenableJobWithoutPromiseFast): (linkTimeConstant.promiseResolveThenableJobWithDerivedPromise): (linkTimeConstant.performPromiseThen): * Source/JavaScriptCore/builtins/PromisePrototype.js: (then): * Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.cpp: (JSC::BytecodeIntrinsicRegistry::BytecodeIntrinsicRegistry): * Source/JavaScriptCore/bytecode/BytecodeIntrinsicRegistry.h: * Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp: (JSC::BytecodeGenerator::BytecodeGenerator): * Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp: (JSC::generatorInternalFieldIndex): (JSC::FunctionNode::emitBytecode): * Source/JavaScriptCore/debugger/Debugger.cpp: (JSC::Debugger::didQueueMicrotask): (JSC::Debugger::willRunMicrotask): (JSC::Debugger::didRunMicrotask): * Source/JavaScriptCore/debugger/Debugger.h: (JSC::Debugger::Observer::didQueueMicrotask): (JSC::Debugger::Observer::willRunMicrotask): (JSC::Debugger::Observer::didRunMicrotask): * Source/JavaScriptCore/heap/Heap.cpp: (JSC::Heap::beginMarking): (JSC::Heap::addCoreConstraints): * Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.cpp: (Inspector::InspectorDebuggerAgent::asyncCallIdentifier): (Inspector::InspectorDebuggerAgent::didScheduleAsyncCall): (Inspector::InspectorDebuggerAgent::didCancelAsyncCall): (Inspector::InspectorDebuggerAgent::willDispatchAsyncCall): (Inspector::InspectorDebuggerAgent::didDispatchAsyncCall): (Inspector::InspectorDebuggerAgent::didQueueMicrotask): (Inspector::InspectorDebuggerAgent::willRunMicrotask): (Inspector::InspectorDebuggerAgent::didRunMicrotask): (Inspector::InspectorDebuggerAgent::didClearAsyncStackTraceData): * Source/JavaScriptCore/inspector/agents/InspectorDebuggerAgent.h: * Source/JavaScriptCore/runtime/JSGenerator.h: * Source/JavaScriptCore/runtime/JSGlobalObject.cpp: (JSC::JSC_DEFINE_HOST_FUNCTION): (JSC::JSGlobalObject::queueMicrotask): * Source/JavaScriptCore/runtime/JSGlobalObject.h: * Source/JavaScriptCore/runtime/JSMicrotask.cpp: (JSC::runJSMicrotask): (JSC::JSMicrotask::run): * Source/JavaScriptCore/runtime/JSMicrotask.h: * Source/JavaScriptCore/runtime/JSPromise.cpp: (JSC::JSPromise::performPromiseThen): * Source/JavaScriptCore/runtime/Microtask.h: (JSC::Microtask::Microtask): (JSC::Microtask::identifier const): * Source/JavaScriptCore/runtime/VM.cpp: (JSC::VM::queueMicrotask): (JSC::VM::drainMicrotasks): (JSC::VM::beginMarking): (JSC::VM::visitAggregateImpl): (JSC::QueuedTask::run): (JSC::MicrotaskQueue::visitAggregateImpl): * Source/JavaScriptCore/runtime/VM.h: (JSC::QueuedTask::QueuedTask): (JSC::QueuedTask::identifier const): (JSC::MicrotaskQueue::dequeue): (JSC::MicrotaskQueue::enqueue): (JSC::MicrotaskQueue::isEmpty const): (JSC::MicrotaskQueue::clear): (JSC::MicrotaskQueue::beginMarking): * Source/WTF/wtf/Deque.h: (WTF::DequeIterator::operator+=): (WTF::DequeIterator::operator+ const): (WTF::DequeConstIterator::operator+=): (WTF::DequeConstIterator::operator+ const): (WTF::inlineCapacity>::increment): * Source/WebCore/bindings/js/JSDOMMicrotask.cpp: (WebCore::JSDOMMicrotask::run): Canonical link: https://commits.webkit.org/253651@main
- Loading branch information