Index: src/api.cc |
diff --git a/src/api.cc b/src/api.cc |
index caa7d002f5fa43b2b4c3649febafbe64db704394..8f92929c959d826e35414fb81880d98c76a2ec03 100644 |
--- a/src/api.cc |
+++ b/src/api.cc |
@@ -75,17 +75,18 @@ namespace v8 { |
#define ENTER_V8(isolate) i::VMState<v8::OTHER> __state__((isolate)) |
-#define PREPARE_FOR_EXECUTION_GENERIC(isolate, context, function_name, \ |
- bailout_value, HandleScopeClass, \ |
- do_callback) \ |
- if (IsExecutionTerminatingCheck(isolate)) { \ |
- return bailout_value; \ |
- } \ |
- TRACE_EVENT_SCOPED_CONTEXT("v8", "Isolate", isolate); \ |
- HandleScopeClass handle_scope(isolate); \ |
- CallDepthScope call_depth_scope(isolate, context, do_callback); \ |
- LOG_API(isolate, function_name); \ |
- ENTER_V8(isolate); \ |
+#define PREPARE_FOR_EXECUTION_GENERIC(isolate, context, function_name, \ |
+ bailout_value, HandleScopeClass, \ |
+ do_callback) \ |
+ if (IsExecutionTerminatingCheck(isolate)) { \ |
+ return bailout_value; \ |
+ } \ |
+ TRACE_EVENT_SCOPED_CONTEXT("v8", "Isolate", isolate); \ |
+ HandleScopeClass handle_scope(isolate); \ |
+ isolate->IncrementJsCallsFromApiCounter(); \ |
+ CallDepthScope call_depth_scope(isolate, context, do_callback, false);\ |
+ LOG_API(isolate, function_name); \ |
+ ENTER_V8(isolate); \ |
bool has_pending_exception = false |
@@ -157,41 +158,92 @@ class InternalEscapableScope : public v8::EscapableHandleScope { |
}; |
+inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) { |
+ if (isolate->has_scheduled_exception()) { |
+ return isolate->scheduled_exception() == |
+ isolate->heap()->termination_exception(); |
+ } |
+ return false; |
+} |
+ |
+ |
class CallDepthScope { |
public: |
- explicit CallDepthScope(i::Isolate* isolate, Local<Context> context, |
- bool do_callback) |
+ CallDepthScope(i::Isolate* isolate, |
+ Local<Context> context, |
+ bool do_callback_and_microtasks, |
+ bool is_external) |
: isolate_(isolate), |
context_(context), |
- escaped_(false), |
- do_callback_(do_callback) { |
- // TODO(dcarney): remove this when blink stops crashing. |
- DCHECK(!isolate_->external_caught_exception()); |
- isolate_->IncrementJsCallsFromApiCounter(); |
- isolate_->handle_scope_implementer()->IncrementCallDepth(); |
+ handle_exception_(!is_external), |
+ do_callback_(do_callback_and_microtasks && !is_external) { |
+ bool affects_microtasks = is_external || |
+ isolate_->handle_scope_implementer()->microtasks_policy() == |
+ i::kAutoMicrotasksInvocation; |
+ run_microtasks_ = affects_microtasks && do_callback_and_microtasks; |
+#ifdef V8_ENABLE_CHECKS |
+ debug_microtasks_ = affects_microtasks && !do_callback_and_microtasks; |
+#endif |
+ auto handle_scope_implementer = isolate_->handle_scope_implementer(); |
+ if (handle_exception_) { |
+ // TODO(dcarney): remove this when blink stops crashing. |
+ DCHECK(!isolate_->external_caught_exception()); |
+ handle_scope_implementer->IncrementInternalCallDepth(); |
+ } |
+ if (run_microtasks_) handle_scope_implementer->IncrementCallDepth(); |
+#ifdef V8_ENABLE_CHECKS |
+ if (debug_microtasks_) handle_scope_implementer->IncrementDebugCallDepth(); |
+#endif |
if (!context_.IsEmpty()) context_->Enter(); |
if (do_callback_) isolate_->FireBeforeCallEnteredCallback(); |
} |
+ |
~CallDepthScope() { |
if (!context_.IsEmpty()) context_->Exit(); |
- if (!escaped_) isolate_->handle_scope_implementer()->DecrementCallDepth(); |
+ auto handle_scope_implementer = isolate_->handle_scope_implementer(); |
+ if (handle_exception_) |
+ handle_scope_implementer->DecrementInternalCallDepth(); |
if (do_callback_) isolate_->FireCallCompletedCallback(); |
+#ifdef V8_ENABLE_CHECKS |
+ bool scoped_policy = handle_scope_implementer->microtasks_policy() == |
+ i::kScopedMicrotasksInvocation; |
+ DCHECK(!(scoped_policy && do_callback_ |
+ && !handle_scope_implementer->GetCallDepth() |
+ && !handle_scope_implementer->GetDebugCallDepth())); |
+#endif |
+ if (run_microtasks_) { |
+ handle_scope_implementer->DecrementCallDepth(); |
+ PerformCheckpoint(isolate_); |
+ } |
+#ifdef V8_ENABLE_CHECKS |
+ if (debug_microtasks_) handle_scope_implementer->DecrementDebugCallDepth(); |
+#endif |
} |
void Escape() { |
- DCHECK(!escaped_); |
- escaped_ = true; |
+ DCHECK(handle_exception_); |
+ handle_exception_ = false; |
auto handle_scope_implementer = isolate_->handle_scope_implementer(); |
- handle_scope_implementer->DecrementCallDepth(); |
- bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero(); |
+ handle_scope_implementer->DecrementInternalCallDepth(); |
+ bool call_depth_is_zero = !handle_scope_implementer->GetInternalCallDepth(); |
isolate_->OptionalRescheduleException(call_depth_is_zero); |
} |
+ static void PerformCheckpoint(i::Isolate* isolate) { |
+ if (IsExecutionTerminatingCheck(isolate)) return; |
+ if (!isolate->handle_scope_implementer()->GetCallDepth() && |
+ !isolate->handle_scope_implementer()->GetMicrotasksSuppression()) { |
+ isolate->RunMicrotasks(); |
+ } |
+ } |
+ |
private: |
i::Isolate* const isolate_; |
Local<Context> context_; |
- bool escaped_; |
+ bool handle_exception_; |
bool do_callback_; |
+ bool run_microtasks_; |
+ bool debug_microtasks_; |
}; |
} // namespace |
@@ -310,15 +362,6 @@ void Utils::ReportApiFailure(const char* location, const char* message) { |
} |
-static inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) { |
- if (isolate->has_scheduled_exception()) { |
- return isolate->scheduled_exception() == |
- isolate->heap()->termination_exception(); |
- } |
- return false; |
-} |
- |
- |
void V8::SetNativesDataBlob(StartupData* natives_blob) { |
i::V8::SetNativesBlob(natives_blob); |
} |
@@ -7290,12 +7333,12 @@ Isolate::AllowJavascriptExecutionScope::~AllowJavascriptExecutionScope() { |
Isolate::SuppressMicrotaskExecutionScope::SuppressMicrotaskExecutionScope( |
Isolate* isolate) |
: isolate_(reinterpret_cast<i::Isolate*>(isolate)) { |
- isolate_->handle_scope_implementer()->IncrementCallDepth(); |
+ isolate_->handle_scope_implementer()->IncrementMicrotasksSuppression(); |
} |
Isolate::SuppressMicrotaskExecutionScope::~SuppressMicrotaskExecutionScope() { |
- isolate_->handle_scope_implementer()->DecrementCallDepth(); |
+ isolate_->handle_scope_implementer()->DecrementMicrotasksSuppression(); |
} |
@@ -7436,6 +7479,7 @@ void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) { |
void Isolate::RunMicrotasks() { |
+ DCHECK_EQ(Isolate::kExplicitMicrotasksInvocation, GetMicrotasksPolicy()); |
reinterpret_cast<i::Isolate*>(this)->RunMicrotasks(); |
} |
@@ -7459,12 +7503,25 @@ void Isolate::EnqueueMicrotask(MicrotaskCallback microtask, void* data) { |
void Isolate::SetAutorunMicrotasks(bool autorun) { |
- reinterpret_cast<i::Isolate*>(this)->set_autorun_microtasks(autorun); |
+ SetMicrotasksPolicy(kAutoMicrotasksInvocation); |
} |
bool Isolate::WillAutorunMicrotasks() const { |
- return reinterpret_cast<const i::Isolate*>(this)->autorun_microtasks(); |
+ return GetMicrotasksPolicy() == kAutoMicrotasksInvocation; |
+} |
+ |
+ |
+void Isolate::SetMicrotasksPolicy(MicrotasksPolicy policy) { |
+ reinterpret_cast<i::Isolate*>(this)->handle_scope_implementer()-> |
+ set_microtasks_policy(static_cast<i::MicrotasksPolicy>(policy)); |
+} |
+ |
+ |
+Isolate::MicrotasksPolicy Isolate::GetMicrotasksPolicy() const { |
+ return static_cast<MicrotasksPolicy>( |
+ reinterpret_cast<i::Isolate*>(const_cast<Isolate*>(this))-> |
+ handle_scope_implementer()->microtasks_policy()); |
} |
@@ -7703,6 +7760,33 @@ void Isolate::VisitWeakHandles(PersistentHandleVisitor* visitor) { |
} |
+MicrotasksScope::MicrotasksScope(Isolate* isolate, MicrotasksScope::Type type) { |
+ DCHECK_EQ(Isolate::kScopedMicrotasksInvocation, |
+ isolate->GetMicrotasksPolicy()); |
+ internal_ = reinterpret_cast<void*>(new CallDepthScope( |
adamk
2016/03/01 19:10:34
I'm a little bit worried about the added heap allo
dgozman
2016/03/03 01:22:06
I think this patch would be easier to understand w
|
+ reinterpret_cast<i::Isolate*>(isolate), |
+ Local<Context>(), |
+ type == MicrotasksScope::kRunMicrotasks, |
+ true)); |
+} |
+ |
+ |
+MicrotasksScope::~MicrotasksScope() { |
+ delete reinterpret_cast<CallDepthScope*>(internal_); |
+} |
+ |
+ |
+void MicrotasksScope::PerformCheckpoint(Isolate* isolate) { |
+ CallDepthScope::PerformCheckpoint(reinterpret_cast<i::Isolate*>(isolate)); |
+} |
+ |
+ |
+int MicrotasksScope::GetRecursionLevel(Isolate* isolate) { |
+ return reinterpret_cast<i::Isolate*>(isolate)->handle_scope_implementer()-> |
+ GetCallDepth(); |
+} |
+ |
+ |
String::Utf8Value::Utf8Value(v8::Local<v8::Value> obj) |
: str_(NULL), length_(0) { |
if (obj.IsEmpty()) return; |