-
Notifications
You must be signed in to change notification settings - Fork 5k
jsc: drain rejected-promise list in O(n) instead of O(n^2) #32554
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
8fa8c26
2b9af97
1930ad4
8aec644
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3278,18 +3278,35 @@ | |
|
|
||
| void GlobalObject::handleRejectedPromises() | ||
| { | ||
| if (m_aboutToBeNotifiedRejectedPromises.isEmpty()) [[likely]] | ||
| return; | ||
|
|
||
| JSC::VM& virtual_machine = vm(); | ||
| auto scope = DECLARE_TOP_EXCEPTION_SCOPE(virtual_machine); | ||
| while (auto* promise = m_aboutToBeNotifiedRejectedPromises.takeFirst(this)) { | ||
| if (promise->isHandled()) | ||
| continue; | ||
|
|
||
| Bun__handleRejectedPromise(this, promise); | ||
| if (auto ex = scope.exception()) { | ||
| (void)scope.tryClearException(); | ||
| this->reportUncaughtExceptionAtEventLoop(this, ex); | ||
| do { | ||
| // Move the whole list out under one cellLock, then iterate linearly. | ||
| // The previous takeFirst() loop did Vector::removeAt(0) + cellLock per | ||
| // element, which is O(n^2) for n queued rejections. JSC's | ||
| // VM::didExhaustMicrotaskQueue and WebCore's RejectedPromiseTracker | ||
| // both use the same move-out-then-iterate pattern. | ||
|
Check warning on line 3291 in src/jsc/bindings/ZigGlobalObject.cpp
|
||
|
claude[bot] marked this conversation as resolved.
Outdated
|
||
| JSC::MarkedArgumentBuffer promises; | ||
| m_aboutToBeNotifiedRejectedPromises.drainTo(this, promises); | ||
| RELEASE_ASSERT(!promises.hasOverflowed()); | ||
| for (size_t i = 0, size = promises.size(); i < size; ++i) { | ||
| auto* promise = static_cast<JSC::JSPromise*>(promises.at(i).asCell()); | ||
| if (promise->isHandled()) | ||
| continue; | ||
|
Check failure on line 3298 in src/jsc/bindings/ZigGlobalObject.cpp
|
||
|
claude[bot] marked this conversation as resolved.
|
||
|
|
||
| Bun__handleRejectedPromise(this, promise); | ||
| if (auto ex = scope.exception()) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if its a termination exception? tryClearException will return false and what we should do, in that case, is return out of this function.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @robobun can you resume this PR
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 8aec644: checks |
||
| (void)scope.tryClearException(); | ||
| this->reportUncaughtExceptionAtEventLoop(this, ex); | ||
| } | ||
| } | ||
| } | ||
| // An unhandledRejection handler may itself reject a promise; loop | ||
| // until the list stays empty (matches the original takeFirst loop's | ||
| // semantics, which re-read m_list each iteration). | ||
| } while (!m_aboutToBeNotifiedRejectedPromises.isEmpty()); | ||
| } | ||
|
|
||
| DEFINE_VISIT_CHILDREN(GlobalObject); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.