• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/heap/finalization-registry-cleanup-task.h"
6 
7 #include "src/execution/frames.h"
8 #include "src/execution/interrupts-scope.h"
9 #include "src/execution/stack-guard.h"
10 #include "src/execution/v8threads.h"
11 #include "src/heap/heap-inl.h"
12 #include "src/objects/js-weak-refs-inl.h"
13 #include "src/tracing/trace-event.h"
14 
15 namespace v8 {
16 namespace internal {
17 
FinalizationRegistryCleanupTask(Heap * heap)18 FinalizationRegistryCleanupTask::FinalizationRegistryCleanupTask(Heap* heap)
19     : CancelableTask(heap->isolate()), heap_(heap) {}
20 
SlowAssertNoActiveJavaScript()21 void FinalizationRegistryCleanupTask::SlowAssertNoActiveJavaScript() {
22 #ifdef ENABLE_SLOW_DCHECKS
23   class NoActiveJavaScript : public ThreadVisitor {
24    public:
25     void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
26       for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
27         DCHECK(!it.frame()->is_java_script());
28       }
29     }
30   };
31   NoActiveJavaScript no_active_js_visitor;
32   Isolate* isolate = heap_->isolate();
33   no_active_js_visitor.VisitThread(isolate, isolate->thread_local_top());
34   isolate->thread_manager()->IterateArchivedThreads(&no_active_js_visitor);
35 #endif  // ENABLE_SLOW_DCHECKS
36 }
37 
RunInternal()38 void FinalizationRegistryCleanupTask::RunInternal() {
39   Isolate* isolate = heap_->isolate();
40   SlowAssertNoActiveJavaScript();
41 
42   TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8",
43                                 "V8.FinalizationRegistryCleanupTask");
44 
45   HandleScope handle_scope(isolate);
46   Handle<JSFinalizationRegistry> finalization_registry;
47   // There could be no dirty FinalizationRegistries. When a context is disposed
48   // by the embedder, its FinalizationRegistries are removed from the dirty
49   // list.
50   if (!heap_->DequeueDirtyJSFinalizationRegistry().ToHandle(
51           &finalization_registry)) {
52     return;
53   }
54   finalization_registry->set_scheduled_for_cleanup(false);
55 
56   // Since FinalizationRegistry cleanup callbacks are scheduled by V8, enter the
57   // FinalizationRegistry's context.
58   Handle<Context> context(
59       Context::cast(finalization_registry->native_context()), isolate);
60   Handle<Object> callback(finalization_registry->cleanup(), isolate);
61   v8::Context::Scope context_scope(v8::Utils::ToLocal(context));
62   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
63   v8::TryCatch catcher(v8_isolate);
64   catcher.SetVerbose(true);
65   std::unique_ptr<MicrotasksScope> microtasks_scope;
66   MicrotaskQueue* microtask_queue =
67       finalization_registry->native_context().microtask_queue();
68   if (!microtask_queue) microtask_queue = isolate->default_microtask_queue();
69   if (microtask_queue &&
70       microtask_queue->microtasks_policy() == v8::MicrotasksPolicy::kScoped) {
71     // InvokeFinalizationRegistryCleanupFromTask will call into V8 API methods,
72     // so we need a valid microtasks scope on the stack to avoid running into
73     // the CallDepthScope check.
74     microtasks_scope.reset(new v8::MicrotasksScope(
75         v8_isolate, microtask_queue, v8::MicrotasksScope::kDoNotRunMicrotasks));
76   }
77 
78   // Exceptions are reported via the message handler. This is ensured by the
79   // verbose TryCatch.
80   //
81   // Cleanup is interrupted if there is an exception. The HTML spec calls for a
82   // microtask checkpoint after each cleanup task, so the task should return
83   // after an exception so the host can perform a microtask checkpoint. In case
84   // of exception, check if the FinalizationRegistry still needs cleanup
85   // and should be requeued.
86   //
87   // TODO(syg): Implement better scheduling for finalizers.
88   InvokeFinalizationRegistryCleanupFromTask(context, finalization_registry,
89                                             callback);
90   if (finalization_registry->NeedsCleanup() &&
91       !finalization_registry->scheduled_for_cleanup()) {
92     auto nop = [](HeapObject, ObjectSlot, Object) {};
93     heap_->EnqueueDirtyJSFinalizationRegistry(*finalization_registry, nop);
94   }
95 
96   // Repost if there are remaining dirty FinalizationRegistries.
97   heap_->set_is_finalization_registry_cleanup_task_posted(false);
98   heap_->PostFinalizationRegistryCleanupTaskIfNeeded();
99 }
100 
101 }  // namespace internal
102 }  // namespace v8
103