From 4dd8b111714fc42ecb1159629695ffc2089316a9 Mon Sep 17 00:00:00 2001 From: "jochen@chromium.org" Date: Fri, 2 May 2014 19:30:54 +0000 Subject: [PATCH] Introduce a microtask suppression scope and move microtask methods to isolate BUG=369503 R=adamk@chromium.org LOG=y TEST=cctest/test-api/SetAutorunMicrotasks Review URL: https://codereview.chromium.org/263933002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@21128 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8.h | 40 +++++++++++++++++++ src/api.cc | 41 +++++++++++++++---- src/isolate.cc | 13 ++++++ src/isolate.h | 2 + src/v8.cc | 15 ------- src/v8.h | 2 - test/cctest/test-api.cc | 73 ++++++++++++++++++++-------------- test/cctest/test-microtask-delivery.cc | 4 +- 8 files changed, 134 insertions(+), 56 deletions(-) diff --git a/include/v8.h b/include/v8.h index 684b2c2..6a91140 100644 --- a/include/v8.h +++ b/include/v8.h @@ -4113,6 +4113,24 @@ class V8_EXPORT Isolate { }; /** + * Do not run microtasks while this scope is active, even if microtasks are + * automatically executed otherwise. + */ + class V8_EXPORT SuppressMicrotaskExecutionScope { + public: + explicit SuppressMicrotaskExecutionScope(Isolate* isolate); + ~SuppressMicrotaskExecutionScope(); + + private: + internal::Isolate* isolate_; + + // Prevent copying of Scope objects. + SuppressMicrotaskExecutionScope(const SuppressMicrotaskExecutionScope&); + SuppressMicrotaskExecutionScope& operator=( + const SuppressMicrotaskExecutionScope&); + }; + + /** * Types of garbage collections that can be requested via * RequestGarbageCollectionForTesting. */ @@ -4361,6 +4379,22 @@ class V8_EXPORT Isolate { */ void RemoveCallCompletedCallback(CallCompletedCallback callback); + /** + * Experimental: Runs the Microtask Work Queue until empty + */ + void RunMicrotasks(); + + /** + * Experimental: Enqueues the callback to the Microtask Work Queue + */ + void EnqueueMicrotask(Handle microtask); + + /** + * Experimental: Controls whether the Microtask Work Queue is automatically + * run when the script call depth decrements to zero. + */ + void SetAutorunMicrotasks(bool autorun); + private: template friend class PersistentValueMap; @@ -4724,17 +4758,23 @@ class V8_EXPORT V8 { /** * Experimental: Runs the Microtask Work Queue until empty + * + * Deprecated: Use methods on Isolate instead. */ static void RunMicrotasks(Isolate* isolate); /** * Experimental: Enqueues the callback to the Microtask Work Queue + * + * Deprecated: Use methods on Isolate instead. */ static void EnqueueMicrotask(Isolate* isolate, Handle microtask); /** * Experimental: Controls whether the Microtask Work Queue is automatically * run when the script call depth decrements to zero. + * + * Deprecated: Use methods on Isolate instead. */ static void SetAutorunMicrotasks(Isolate *source, bool autorun); diff --git a/src/api.cc b/src/api.cc index 82e4c54..41b5a45 100644 --- a/src/api.cc +++ b/src/api.cc @@ -6455,21 +6455,17 @@ void V8::RemoveMemoryAllocationCallback(MemoryAllocationCallback callback) { void V8::RunMicrotasks(Isolate* isolate) { - i::Isolate* i_isolate = reinterpret_cast(isolate); - i::HandleScope scope(i_isolate); - i::V8::RunMicrotasks(i_isolate); + isolate->RunMicrotasks(); } void V8::EnqueueMicrotask(Isolate* isolate, Handle microtask) { - i::Isolate* i_isolate = reinterpret_cast(isolate); - ENTER_V8(i_isolate); - i::Execution::EnqueueMicrotask(i_isolate, Utils::OpenHandle(*microtask)); + isolate->EnqueueMicrotask(microtask); } void V8::SetAutorunMicrotasks(Isolate* isolate, bool autorun) { - reinterpret_cast(isolate)->set_autorun_microtasks(autorun); + isolate->SetAutorunMicrotasks(autorun); } @@ -6593,6 +6589,18 @@ Isolate::AllowJavascriptExecutionScope::~AllowJavascriptExecutionScope() { } +Isolate::SuppressMicrotaskExecutionScope::SuppressMicrotaskExecutionScope( + Isolate* isolate) + : isolate_(reinterpret_cast(isolate)) { + isolate_->handle_scope_implementer()->IncrementCallDepth(); +} + + +Isolate::SuppressMicrotaskExecutionScope::~SuppressMicrotaskExecutionScope() { + isolate_->handle_scope_implementer()->DecrementCallDepth(); +} + + void Isolate::GetHeapStatistics(HeapStatistics* heap_statistics) { i::Isolate* isolate = reinterpret_cast(this); if (!isolate->IsInitialized()) { @@ -6632,6 +6640,25 @@ void Isolate::RemoveCallCompletedCallback(CallCompletedCallback callback) { } +void Isolate::RunMicrotasks() { + i::Isolate* i_isolate = reinterpret_cast(this); + i::HandleScope scope(i_isolate); + i_isolate->RunMicrotasks(); +} + + +void Isolate::EnqueueMicrotask(Handle microtask) { + i::Isolate* i_isolate = reinterpret_cast(this); + ENTER_V8(i_isolate); + i::Execution::EnqueueMicrotask(i_isolate, Utils::OpenHandle(*microtask)); +} + + +void Isolate::SetAutorunMicrotasks(bool autorun) { + reinterpret_cast(this)->set_autorun_microtasks(autorun); +} + + String::Utf8Value::Utf8Value(v8::Handle obj) : str_(NULL), length_(0) { i::Isolate* isolate = i::Isolate::Current(); diff --git a/src/isolate.cc b/src/isolate.cc index 72df9b4..82ad5fc 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -2252,4 +2252,17 @@ void Isolate::FireCallCompletedCallback() { } +void Isolate::RunMicrotasks() { + if (!microtask_pending()) + return; + + ASSERT(handle_scope_implementer()->CallDepthIsZero()); + + // Increase call depth to prevent recursive callbacks. + handle_scope_implementer()->IncrementCallDepth(); + Execution::RunMicrotasks(this); + handle_scope_implementer()->DecrementCallDepth(); +} + + } } // namespace v8::internal diff --git a/src/isolate.h b/src/isolate.h index fdd89b4..6a438c3 100644 --- a/src/isolate.h +++ b/src/isolate.h @@ -1077,6 +1077,8 @@ class Isolate { void RemoveCallCompletedCallback(CallCompletedCallback callback); void FireCallCompletedCallback(); + void RunMicrotasks(); + private: Isolate(); diff --git a/src/v8.cc b/src/v8.cc index eed4333..30f64d6 100644 --- a/src/v8.cc +++ b/src/v8.cc @@ -87,21 +87,6 @@ void V8::SetReturnAddressLocationResolver( } -void V8::RunMicrotasks(Isolate* isolate) { - if (!isolate->microtask_pending()) - return; - - HandleScopeImplementer* handle_scope_implementer = - isolate->handle_scope_implementer(); - ASSERT(handle_scope_implementer->CallDepthIsZero()); - - // Increase call depth to prevent recursive callbacks. - handle_scope_implementer->IncrementCallDepth(); - Execution::RunMicrotasks(isolate); - handle_scope_implementer->DecrementCallDepth(); -} - - void V8::InitializeOncePerProcessImpl() { FlagList::EnforceFlagImplications(); Serializer::InitializeOncePerProcess(); diff --git a/src/v8.h b/src/v8.h index 7ea853e..f019e68 100644 --- a/src/v8.h +++ b/src/v8.h @@ -75,8 +75,6 @@ class V8 : public AllStatic { // Support for entry hooking JITed code. static void SetFunctionEntryHook(FunctionEntryHook entry_hook); - static void RunMicrotasks(Isolate* isolate); - static v8::ArrayBuffer::Allocator* ArrayBufferAllocator() { return array_buffer_allocator_; } diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 5f82bd7..14912b7 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -20717,22 +20717,22 @@ TEST(EnqueueMicrotask) { CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); - v8::V8::EnqueueMicrotask(env->GetIsolate(), - Function::New(env->GetIsolate(), MicrotaskOne)); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskOne)); CompileRun("1+1;"); CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); - v8::V8::EnqueueMicrotask(env->GetIsolate(), - Function::New(env->GetIsolate(), MicrotaskOne)); - v8::V8::EnqueueMicrotask(env->GetIsolate(), - Function::New(env->GetIsolate(), MicrotaskTwo)); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskOne)); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskTwo)); CompileRun("1+1;"); CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value()); - v8::V8::EnqueueMicrotask(env->GetIsolate(), - Function::New(env->GetIsolate(), MicrotaskTwo)); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskTwo)); CompileRun("1+1;"); CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); @@ -20753,41 +20753,54 @@ TEST(SetAutorunMicrotasks) { CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); - v8::V8::EnqueueMicrotask(env->GetIsolate(), - Function::New(env->GetIsolate(), MicrotaskOne)); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskOne)); CompileRun("1+1;"); CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); - V8::SetAutorunMicrotasks(env->GetIsolate(), false); - v8::V8::EnqueueMicrotask(env->GetIsolate(), - Function::New(env->GetIsolate(), MicrotaskOne)); - v8::V8::EnqueueMicrotask(env->GetIsolate(), - Function::New(env->GetIsolate(), MicrotaskTwo)); + env->GetIsolate()->SetAutorunMicrotasks(false); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskOne)); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskTwo)); CompileRun("1+1;"); CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value()); - V8::RunMicrotasks(env->GetIsolate()); + env->GetIsolate()->RunMicrotasks(); CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value()); - v8::V8::EnqueueMicrotask(env->GetIsolate(), - Function::New(env->GetIsolate(), MicrotaskTwo)); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskTwo)); CompileRun("1+1;"); CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value()); - V8::RunMicrotasks(env->GetIsolate()); + env->GetIsolate()->RunMicrotasks(); CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value()); - V8::SetAutorunMicrotasks(env->GetIsolate(), true); - v8::V8::EnqueueMicrotask(env->GetIsolate(), - Function::New(env->GetIsolate(), MicrotaskTwo)); + env->GetIsolate()->SetAutorunMicrotasks(true); + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskTwo)); CompileRun("1+1;"); CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value()); + + env->GetIsolate()->EnqueueMicrotask( + Function::New(env->GetIsolate(), MicrotaskTwo)); + { + v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate()); + CompileRun("1+1;"); + CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); + CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value()); + } + + CompileRun("1+1;"); + CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value()); + CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value()); } @@ -22342,20 +22355,20 @@ TEST(Promises) { p->Chain(f1); CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); - V8::RunMicrotasks(isolate); + isolate->RunMicrotasks(); CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); p->Catch(f2); - V8::RunMicrotasks(isolate); + isolate->RunMicrotasks(); CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); r->Catch(f2); CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); - V8::RunMicrotasks(isolate); + isolate->RunMicrotasks(); CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value()); r->Chain(f1); - V8::RunMicrotasks(isolate); + isolate->RunMicrotasks(); CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); // Chaining pending promises. @@ -22365,7 +22378,7 @@ TEST(Promises) { pr->GetPromise()->Chain(f1); rr->GetPromise()->Catch(f2); - V8::RunMicrotasks(isolate); + isolate->RunMicrotasks(); CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); @@ -22374,7 +22387,7 @@ TEST(Promises) { CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); - V8::RunMicrotasks(isolate); + isolate->RunMicrotasks(); CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value()); CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value()); @@ -22385,7 +22398,7 @@ TEST(Promises) { pr->Resolve(v8::Integer::New(isolate, 3)); CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); - V8::RunMicrotasks(isolate); + isolate->RunMicrotasks(); CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value()); CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value()); @@ -22395,7 +22408,7 @@ TEST(Promises) { rr->Reject(v8::Integer::New(isolate, 3)); CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value()); CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value()); - V8::RunMicrotasks(isolate); + isolate->RunMicrotasks(); CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value()); CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value()); } diff --git a/test/cctest/test-microtask-delivery.cc b/test/cctest/test-microtask-delivery.cc index 108337a..cfe5d69 100644 --- a/test/cctest/test-microtask-delivery.cc +++ b/test/cctest/test-microtask-delivery.cc @@ -96,7 +96,7 @@ TEST(MicrotaskPerIsolateState) { HarmonyIsolate isolate; HandleScope scope(isolate.GetIsolate()); LocalContext context1(isolate.GetIsolate()); - V8::SetAutorunMicrotasks(isolate.GetIsolate(), false); + isolate.GetIsolate()->SetAutorunMicrotasks(false); CompileRun( "var obj = { calls: 0 };"); Handle obj = CompileRun("obj"); @@ -130,7 +130,7 @@ TEST(MicrotaskPerIsolateState) { LocalContext context4(isolate.GetIsolate()); context4->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"), obj); - V8::RunMicrotasks(isolate.GetIsolate()); + isolate.GetIsolate()->RunMicrotasks(); CHECK_EQ(2, CompileRun("obj.calls")->Int32Value()); } } -- 2.7.4