[weakrefs] Call Isolate::ClearKeptObjects() as part of microtask checkpoint
In the spec, WeakRefs that are dereferenced are kept alive until there's no JS on the stack, and then the host is expected to call ClearKeptObjects to clear those strong references [1]. HTML calls ClearKeptObjects at the end of a PerformMicrotaskCheckpoint [2]. In V8, leaving this up to the embedder is error prone in the same way the deprecated FinalizationGroup callback APIs were error prone: it depends on the embedder doing the right thing. This CL moves the call to ClearKeptObjects to be after running of microtasks within V8. However, the Isolate::ClearKeptObjects API should not be removed or deprecated in case an embedder uses an entirely custom MicrotaskQueue implementation and invokes MicrotaskQueue::PerformCheckpoint manually. [1] https://tc39.es/proposal-weakrefs/#sec-clear-kept-objects [2] https://github.com/whatwg/html/pull/4571 Bug: v8:8179 Change-Id: Ie243804157b56241ca69ed8fad300e839a0c9f75 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2055967 Commit-Queue: Shu-yu Guo <syg@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#66327}
This commit is contained in:
parent
27b41b54ab
commit
9f0f2cb7f0
31
include/v8.h
31
include/v8.h
@ -7282,10 +7282,10 @@ typedef void (*MicrotasksCompletedCallback)(Isolate*);
|
||||
typedef void (*MicrotasksCompletedCallbackWithData)(Isolate*, void*);
|
||||
typedef void (*MicrotaskCallback)(void* data);
|
||||
|
||||
|
||||
/**
|
||||
* Policy for running microtasks:
|
||||
* - explicit: microtasks are invoked with Isolate::RunMicrotasks() method;
|
||||
* - explicit: microtasks are invoked with the
|
||||
* Isolate::PerformMicrotaskCheckpoint() method;
|
||||
* - scoped: microtasks invocation is controlled by MicrotasksScope objects;
|
||||
* - auto: microtasks are invoked when the script call depth decrements
|
||||
* to zero.
|
||||
@ -7376,7 +7376,7 @@ class V8_EXPORT MicrotaskQueue {
|
||||
};
|
||||
|
||||
/**
|
||||
* This scope is used to control microtasks when kScopeMicrotasksInvocation
|
||||
* This scope is used to control microtasks when MicrotasksPolicy::kScoped
|
||||
* is used on Isolate. In this mode every non-primitive call to V8 should be
|
||||
* done inside some MicrotasksScope.
|
||||
* Microtasks are executed when topmost MicrotasksScope marked as kRunMicrotasks
|
||||
@ -8459,10 +8459,13 @@ class V8_EXPORT Isolate {
|
||||
* objects are originally built when a WeakRef is created or
|
||||
* successfully dereferenced.
|
||||
*
|
||||
* The embedder is expected to call this when a synchronous sequence
|
||||
* of ECMAScript execution completes. It's the embedders
|
||||
* responsiblity to make this call at a time which does not
|
||||
* interrupt synchronous ECMAScript code execution.
|
||||
* This is invoked automatically after microtasks are run. See
|
||||
* MicrotasksPolicy for when microtasks are run.
|
||||
*
|
||||
* This needs to be manually invoked only if the embedder is manually running
|
||||
* microtasks via a custom MicrotaskQueue class's PerformCheckpoint. In that
|
||||
* case, it is the embedder's responsibility to make this call at a time which
|
||||
* does not interrupt synchronous ECMAScript code execution.
|
||||
*/
|
||||
void ClearKeptObjects();
|
||||
|
||||
@ -8990,10 +8993,18 @@ class V8_EXPORT Isolate {
|
||||
void SetPromiseRejectCallback(PromiseRejectCallback callback);
|
||||
|
||||
/**
|
||||
* Runs the default MicrotaskQueue until it gets empty.
|
||||
* Any exceptions thrown by microtask callbacks are swallowed.
|
||||
* An alias for PerformMicrotaskCheckpoint.
|
||||
*/
|
||||
void RunMicrotasks();
|
||||
V8_DEPRECATE_SOON("Use PerformMicrotaskCheckpoint.")
|
||||
void RunMicrotasks() { PerformMicrotaskCheckpoint(); }
|
||||
|
||||
/**
|
||||
* Runs the default MicrotaskQueue until it gets empty and perform other
|
||||
* microtask checkpoint steps, such as calling ClearKeptObjects. Asserts that
|
||||
* the MicrotasksPolicy is not kScoped. Any exceptions thrown by microtask
|
||||
* callbacks are swallowed.
|
||||
*/
|
||||
void PerformMicrotaskCheckpoint();
|
||||
|
||||
/**
|
||||
* Enqueues the callback to the default MicrotaskQueue
|
||||
|
@ -309,6 +309,7 @@ class CallDepthScope {
|
||||
#ifdef V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY
|
||||
if (do_callback) CheckMicrotasksScopesConsistency(microtask_queue);
|
||||
#endif
|
||||
DCHECK(CheckKeptObjectsClearedAfterMicrotaskCheckpoint(microtask_queue));
|
||||
isolate_->set_next_v8_call_is_safe_for_termination(safe_for_termination_);
|
||||
}
|
||||
|
||||
@ -323,6 +324,15 @@ class CallDepthScope {
|
||||
}
|
||||
|
||||
private:
|
||||
bool CheckKeptObjectsClearedAfterMicrotaskCheckpoint(
|
||||
i::MicrotaskQueue* microtask_queue) {
|
||||
bool did_perform_microtask_checkpoint =
|
||||
do_callback && microtask_queue &&
|
||||
microtask_queue->microtasks_policy() == MicrotasksPolicy::kAuto;
|
||||
return !did_perform_microtask_checkpoint ||
|
||||
isolate_->heap()->weak_refs_keep_during_job().IsUndefined(isolate_);
|
||||
}
|
||||
|
||||
i::Isolate* const isolate_;
|
||||
Local<Context> context_;
|
||||
bool escaped_;
|
||||
@ -8654,10 +8664,10 @@ void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
|
||||
isolate->SetPromiseRejectCallback(callback);
|
||||
}
|
||||
|
||||
void Isolate::RunMicrotasks() {
|
||||
void Isolate::PerformMicrotaskCheckpoint() {
|
||||
DCHECK_NE(MicrotasksPolicy::kScoped, GetMicrotasksPolicy());
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->default_microtask_queue()->RunMicrotasks(isolate);
|
||||
isolate->default_microtask_queue()->PerformCheckpoint(this);
|
||||
}
|
||||
|
||||
void Isolate::EnqueueMicrotask(Local<Function> v8_function) {
|
||||
|
@ -1056,7 +1056,7 @@ bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
|
||||
// able to just busy loop waiting for execution to finish.
|
||||
Local<Promise> result_promise(Local<Promise>::Cast(result));
|
||||
while (result_promise->State() == Promise::kPending) {
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
}
|
||||
|
||||
if (result_promise->State() == Promise::kRejected) {
|
||||
@ -3262,7 +3262,6 @@ bool ProcessMessages(
|
||||
while (v8::platform::PumpMessageLoop(g_default_platform, isolate,
|
||||
behavior())) {
|
||||
MicrotasksScope::PerformCheckpoint(isolate);
|
||||
isolate->ClearKeptObjects();
|
||||
}
|
||||
if (g_default_platform->IdleTasksEnabled(isolate)) {
|
||||
v8::platform::RunIdleTasks(g_default_platform, isolate,
|
||||
|
@ -115,6 +115,7 @@ void MicrotaskQueue::PerformCheckpoint(v8::Isolate* v8_isolate) {
|
||||
!HasMicrotasksSuppressions()) {
|
||||
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
|
||||
RunMicrotasks(isolate);
|
||||
isolate->ClearKeptObjects();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19911,7 +19911,7 @@ TEST(RunMicrotasksIgnoresThrownExceptionsFromApi) {
|
||||
CHECK(!isolate->IsExecutionTerminating());
|
||||
isolate->EnqueueMicrotask(ThrowExceptionMicrotask);
|
||||
isolate->EnqueueMicrotask(IncrementCounterMicrotask);
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(1, microtask_callback_count);
|
||||
CHECK(!try_catch.HasCaught());
|
||||
}
|
||||
@ -19957,7 +19957,7 @@ TEST(SetAutorunMicrotasks) {
|
||||
CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(7u, microtasks_completed_callback_count);
|
||||
|
||||
env->GetIsolate()->RunMicrotasks();
|
||||
env->GetIsolate()->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(8u, microtasks_completed_callback_count);
|
||||
@ -19969,7 +19969,7 @@ TEST(SetAutorunMicrotasks) {
|
||||
CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(8u, microtasks_completed_callback_count);
|
||||
|
||||
env->GetIsolate()->RunMicrotasks();
|
||||
env->GetIsolate()->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value(env.local()).FromJust());
|
||||
CHECK_EQ(9u, microtasks_completed_callback_count);
|
||||
@ -20019,7 +20019,7 @@ TEST(RunMicrotasksWithoutEnteringContext) {
|
||||
isolate->EnqueueMicrotask(
|
||||
Function::New(context, MicrotaskOne).ToLocalChecked());
|
||||
}
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
{
|
||||
Context::Scope context_scope(context);
|
||||
CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value(context).FromJust());
|
||||
@ -20043,7 +20043,7 @@ static void Regress808911_CurrentContextWrapper(
|
||||
CHECK(isolate->GetCurrentContext() !=
|
||||
isolate->GetEnteredOrMicrotaskContext());
|
||||
isolate->EnqueueMicrotask(Regress808911_MicrotaskCallback, isolate);
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
}
|
||||
|
||||
THREADED_TEST(Regress808911) {
|
||||
@ -22511,7 +22511,7 @@ TEST(PromiseThen) {
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
.FromJust());
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -22537,7 +22537,7 @@ TEST(PromiseThen) {
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
.FromJust());
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(0, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -22557,7 +22557,7 @@ TEST(PromiseThen) {
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
.FromJust());
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(3, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -22606,7 +22606,7 @@ TEST(PromiseThen2) {
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
.FromJust());
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -22617,7 +22617,7 @@ TEST(PromiseThen2) {
|
||||
.FromJust());
|
||||
|
||||
Local<v8::Promise> b = a->Then(context.local(), f3, f2).ToLocalChecked();
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -22628,7 +22628,7 @@ TEST(PromiseThen2) {
|
||||
.FromJust());
|
||||
|
||||
Local<v8::Promise> c = b->Then(context.local(), f1, f2).ToLocalChecked();
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(1, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -22639,7 +22639,7 @@ TEST(PromiseThen2) {
|
||||
.FromJust());
|
||||
|
||||
v8::Local<v8::Promise> d = c->Then(context.local(), f1, f2).ToLocalChecked();
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -22650,7 +22650,7 @@ TEST(PromiseThen2) {
|
||||
.FromJust());
|
||||
|
||||
v8::Local<v8::Promise> e = d->Then(context.local(), f3, f2).ToLocalChecked();
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -22661,7 +22661,7 @@ TEST(PromiseThen2) {
|
||||
.FromJust());
|
||||
|
||||
v8::Local<v8::Promise> f = e->Then(context.local(), f1, f3).ToLocalChecked();
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -22672,7 +22672,7 @@ TEST(PromiseThen2) {
|
||||
.FromJust());
|
||||
|
||||
f->Then(context.local(), f1, f2).ToLocalChecked();
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(103, global->Get(context.local(), v8_str("x1"))
|
||||
.ToLocalChecked()
|
||||
->Int32Value(context.local())
|
||||
@ -25739,7 +25739,7 @@ TEST(DynamicImport) {
|
||||
i::MaybeHandle<i::JSPromise> maybe_promise =
|
||||
i_isolate->RunHostImportModuleDynamicallyCallback(referrer, specifier);
|
||||
i::Handle<i::JSPromise> promise = maybe_promise.ToHandleChecked();
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK(result->Equals(i::String::cast(promise->result())));
|
||||
}
|
||||
|
||||
@ -26441,7 +26441,7 @@ TEST(MicrotaskContextShouldBeNativeContext) {
|
||||
" await 42;"
|
||||
"})().then(callback);}");
|
||||
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
}
|
||||
|
||||
TEST(PreviewSetKeysIteratorEntriesWithDeleted) {
|
||||
|
@ -158,6 +158,17 @@ void VerifyWeakCellKeyChain(Isolate* isolate, SimpleNumberDictionary key_map,
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
Handle<JSWeakRef> MakeWeakRefAndKeepDuringJob(Isolate* isolate) {
|
||||
HandleScope inner_scope(isolate);
|
||||
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
Handle<JSWeakRef> inner_weak_ref = ConstructJSWeakRef(js_object, isolate);
|
||||
isolate->heap()->KeepDuringJob(js_object);
|
||||
|
||||
return inner_scope.CloseAndEscape(inner_weak_ref);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(TestRegister) {
|
||||
@ -715,30 +726,35 @@ TEST(TestJSWeakRefKeepDuringJob) {
|
||||
LocalContext context;
|
||||
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Heap* heap = isolate->heap();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSWeakRef> weak_ref;
|
||||
{
|
||||
HandleScope inner_scope(isolate);
|
||||
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
Handle<JSWeakRef> inner_weak_ref = ConstructJSWeakRef(js_object, isolate);
|
||||
heap->KeepDuringJob(js_object);
|
||||
|
||||
weak_ref = inner_scope.CloseAndEscape(inner_weak_ref);
|
||||
}
|
||||
|
||||
Handle<JSWeakRef> weak_ref = MakeWeakRefAndKeepDuringJob(isolate);
|
||||
CHECK(!weak_ref->target().IsUndefined(isolate));
|
||||
|
||||
CcTest::CollectAllGarbage();
|
||||
|
||||
CHECK(!weak_ref->target().IsUndefined(isolate));
|
||||
|
||||
// Clears the KeepDuringJob set.
|
||||
context->GetIsolate()->ClearKeptObjects();
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK(weak_ref->target().IsUndefined(isolate));
|
||||
|
||||
weak_ref = MakeWeakRefAndKeepDuringJob(isolate);
|
||||
CHECK(!weak_ref->target().IsUndefined(isolate));
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK(!weak_ref->target().IsUndefined(isolate));
|
||||
|
||||
// ClearKeptObjects should be called by PerformMicrotasksCheckpoint.
|
||||
CcTest::isolate()->PerformMicrotaskCheckpoint();
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK(weak_ref->target().IsUndefined(isolate));
|
||||
|
||||
weak_ref = MakeWeakRefAndKeepDuringJob(isolate);
|
||||
CHECK(!weak_ref->target().IsUndefined(isolate));
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK(!weak_ref->target().IsUndefined(isolate));
|
||||
|
||||
// ClearKeptObjects should be called by MicrotasksScope::PerformCheckpoint.
|
||||
v8::MicrotasksScope::PerformCheckpoint(CcTest::isolate());
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK(weak_ref->target().IsUndefined(isolate));
|
||||
}
|
||||
|
||||
@ -754,17 +770,7 @@ TEST(TestJSWeakRefKeepDuringJobIncrementalMarking) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
Heap* heap = isolate->heap();
|
||||
HandleScope outer_scope(isolate);
|
||||
Handle<JSWeakRef> weak_ref;
|
||||
{
|
||||
HandleScope inner_scope(isolate);
|
||||
|
||||
Handle<JSObject> js_object =
|
||||
isolate->factory()->NewJSObject(isolate->object_function());
|
||||
Handle<JSWeakRef> inner_weak_ref = ConstructJSWeakRef(js_object, isolate);
|
||||
heap->KeepDuringJob(js_object);
|
||||
|
||||
weak_ref = inner_scope.CloseAndEscape(inner_weak_ref);
|
||||
}
|
||||
Handle<JSWeakRef> weak_ref = MakeWeakRefAndKeepDuringJob(isolate);
|
||||
|
||||
CHECK(!weak_ref->target().IsUndefined(isolate));
|
||||
|
||||
|
@ -830,7 +830,7 @@ TEST(ModuleEvaluationTopLevelAwaitDynamicImport) {
|
||||
CHECK_EQ(promise->State(), v8::Promise::kPending);
|
||||
CHECK(!try_catch.HasCaught());
|
||||
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
|
||||
}
|
||||
i::FLAG_harmony_top_level_await = previous_top_level_await_flag_value;
|
||||
@ -874,7 +874,7 @@ TEST(ModuleEvaluationTopLevelAwaitDynamicImportError) {
|
||||
CHECK_EQ(promise->State(), v8::Promise::kPending);
|
||||
CHECK(!try_catch.HasCaught());
|
||||
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK_EQ(Module::kErrored, module->GetStatus());
|
||||
CHECK_EQ(promise->State(), v8::Promise::kRejected);
|
||||
CHECK(promise->Result()->StrictEquals(v8_str("boom")));
|
||||
|
@ -492,10 +492,11 @@ TEST(TerminateFromOtherThreadWhileMicrotaskRunning) {
|
||||
isolate->EnqueueMicrotask(
|
||||
v8::Function::New(isolate->GetCurrentContext(), MicrotaskShouldNotRun)
|
||||
.ToLocalChecked());
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
|
||||
isolate->CancelTerminateExecution();
|
||||
isolate->RunMicrotasks(); // should not run MicrotaskShouldNotRun
|
||||
// Should not run MicrotaskShouldNotRun.
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
|
||||
thread.Join();
|
||||
delete semaphore;
|
||||
@ -913,7 +914,7 @@ TEST(TerminateInMicrotask) {
|
||||
CHECK(context2 == isolate->GetCurrentContext());
|
||||
CHECK(context2 == isolate->GetEnteredOrMicrotaskContext());
|
||||
CHECK(!isolate->IsExecutionTerminating());
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK(context2 == isolate->GetCurrentContext());
|
||||
CHECK(context2 == isolate->GetEnteredOrMicrotaskContext());
|
||||
CHECK(try_catch.HasCaught());
|
||||
@ -948,7 +949,7 @@ TEST(TerminateInApiMicrotask) {
|
||||
CHECK(!isolate->IsExecutionTerminating());
|
||||
isolate->EnqueueMicrotask(TerminationMicrotask);
|
||||
isolate->EnqueueMicrotask(UnreachableMicrotask);
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
CHECK(try_catch.HasCaught());
|
||||
CHECK(try_catch.HasTerminated());
|
||||
CHECK(isolate->IsExecutionTerminating());
|
||||
|
@ -78,7 +78,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
// Wait for the promise to resolve.
|
||||
while (!done) {
|
||||
support->PumpMessageLoop(platform::MessageLoopBehavior::kWaitForWork);
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -69,6 +69,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
|
||||
// Pump the message loop and run micro tasks, e.g. GC finalization tasks.
|
||||
support->PumpMessageLoop(v8::platform::MessageLoopBehavior::kDoNotWait);
|
||||
isolate->RunMicrotasks();
|
||||
isolate->PerformMicrotaskCheckpoint();
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user