| Index: src/global-handles.cc
|
| diff --git a/src/global-handles.cc b/src/global-handles.cc
|
| index aa6542baee922f8f4e517cd6764f8b8ed71290ee..4cd0a18ff8ece0cd658f744d19161269d5053de6 100644
|
| --- a/src/global-handles.cc
|
| +++ b/src/global-handles.cc
|
| @@ -495,6 +495,29 @@ class GlobalHandles::NodeIterator {
|
| DISALLOW_COPY_AND_ASSIGN(NodeIterator);
|
| };
|
|
|
| +class GlobalHandles::PendingPhantomCallbacksSecondPassTask : public v8::Task {
|
| + public:
|
| + // Takes ownership of the contents of pending_phantom_callbacks, leaving it in
|
| + // the same state it would be after a call to Clear().
|
| + PendingPhantomCallbacksSecondPassTask(
|
| + List<PendingPhantomCallback>* pending_phantom_callbacks, Isolate* isolate)
|
| + : isolate_(isolate) {
|
| + pending_phantom_callbacks_.Swap(pending_phantom_callbacks);
|
| + }
|
| +
|
| + ~PendingPhantomCallbacksSecondPassTask() override {}
|
| +
|
| + void Run() override {
|
| + InvokeSecondPassPhantomCallbacks(&pending_phantom_callbacks_, isolate_);
|
| + }
|
| +
|
| + private:
|
| + List<PendingPhantomCallback> pending_phantom_callbacks_;
|
| + Isolate* isolate_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PendingPhantomCallbacksSecondPassTask);
|
| +};
|
| +
|
|
|
| GlobalHandles::GlobalHandles(Isolate* isolate)
|
| : isolate_(isolate),
|
| @@ -709,6 +732,19 @@ bool GlobalHandles::IterateObjectGroups(ObjectVisitor* v,
|
| }
|
|
|
|
|
| +void GlobalHandles::InvokeSecondPassPhantomCallbacks(
|
| + List<PendingPhantomCallback>* callbacks, Isolate* isolate) {
|
| + while (callbacks->length() != 0) {
|
| + auto callback = callbacks->RemoveLast();
|
| + DCHECK(callback.node() == nullptr);
|
| + // No second pass callback required.
|
| + if (callback.callback() == nullptr) continue;
|
| + // Fire second pass callback
|
| + callback.Invoke(isolate);
|
| + }
|
| +}
|
| +
|
| +
|
| int GlobalHandles::PostScavengeProcessing(
|
| const int initial_post_gc_processing_count) {
|
| int freed_nodes = 0;
|
| @@ -791,7 +827,8 @@ void GlobalHandles::UpdateListOfNewSpaceNodes() {
|
| }
|
|
|
|
|
| -int GlobalHandles::DispatchPendingPhantomCallbacks() {
|
| +int GlobalHandles::DispatchPendingPhantomCallbacks(
|
| + bool synchronous_second_pass) {
|
| int freed_nodes = 0;
|
| {
|
| // The initial pass callbacks must simply clear the nodes.
|
| @@ -804,14 +841,15 @@ int GlobalHandles::DispatchPendingPhantomCallbacks() {
|
| freed_nodes++;
|
| }
|
| }
|
| - // The second pass empties the list.
|
| - while (pending_phantom_callbacks_.length() != 0) {
|
| - auto callback = pending_phantom_callbacks_.RemoveLast();
|
| - DCHECK(callback.node() == nullptr);
|
| - // No second pass callback required.
|
| - if (callback.callback() == nullptr) continue;
|
| - // Fire second pass callback.
|
| - callback.Invoke(isolate());
|
| + if (pending_phantom_callbacks_.length() > 0) {
|
| + if (synchronous_second_pass) {
|
| + InvokeSecondPassPhantomCallbacks(&pending_phantom_callbacks_, isolate());
|
| + } else {
|
| + auto* task = new PendingPhantomCallbacksSecondPassTask(
|
| + &pending_phantom_callbacks_, isolate());
|
| + V8::GetCurrentPlatform()->CallOnForegroundThread(
|
| + reinterpret_cast<v8::Isolate*>(isolate()), task);
|
| + }
|
| }
|
| pending_phantom_callbacks_.Clear();
|
| return freed_nodes;
|
| @@ -838,14 +876,17 @@ void GlobalHandles::PendingPhantomCallback::Invoke(Isolate* isolate) {
|
| }
|
|
|
|
|
| -int GlobalHandles::PostGarbageCollectionProcessing(GarbageCollector collector) {
|
| +int GlobalHandles::PostGarbageCollectionProcessing(
|
| + GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags) {
|
| // Process weak global handle callbacks. This must be done after the
|
| // GC is completely done, because the callbacks may invoke arbitrary
|
| // API functions.
|
| DCHECK(isolate_->heap()->gc_state() == Heap::NOT_IN_GC);
|
| const int initial_post_gc_processing_count = ++post_gc_processing_count_;
|
| int freed_nodes = 0;
|
| - freed_nodes += DispatchPendingPhantomCallbacks();
|
| + bool synchronous_second_pass =
|
| + (gc_callback_flags & kGCCallbackFlagForced) != 0;
|
| + freed_nodes += DispatchPendingPhantomCallbacks(synchronous_second_pass);
|
| if (initial_post_gc_processing_count != post_gc_processing_count_) {
|
| // If the callbacks caused a nested GC, then return. See comment in
|
| // PostScavengeProcessing.
|
|
|