void Isolate::RunMicrotasks() {
- i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(this);
- i::HandleScope scope(i_isolate);
- i_isolate->RunMicrotasks();
+ reinterpret_cast<i::Isolate*>(this)->RunMicrotasks();
}
void Isolate::EnqueueMicrotask(Handle<Function> microtask) {
- i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(this);
- ENTER_V8(i_isolate);
- i::Execution::EnqueueMicrotask(i_isolate, Utils::OpenHandle(*microtask));
+ i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
+ isolate->EnqueueMicrotask(Utils::OpenHandle(*microtask));
}
void Genesis::InstallExperimentalNativeFunctions() {
- INSTALL_NATIVE(JSFunction, "RunMicrotasksJS", run_microtasks);
- INSTALL_NATIVE(JSFunction, "EnqueueMicrotask", enqueue_microtask);
-
if (FLAG_harmony_proxies) {
INSTALL_NATIVE(JSFunction, "DerivedHasTrap", derived_has_trap);
INSTALL_NATIVE(JSFunction, "DerivedGetTrap", derived_get_trap);
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
error_message_for_code_gen_from_strings) \
- V(RUN_MICROTASKS_INDEX, JSFunction, run_microtasks) \
- V(ENQUEUE_MICROTASK_INDEX, JSFunction, enqueue_microtask) \
V(IS_PROMISE_INDEX, JSFunction, is_promise) \
V(PROMISE_CREATE_INDEX, JSFunction, promise_create) \
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
}
-void Execution::RunMicrotasks(Isolate* isolate) {
- ASSERT(isolate->microtask_pending());
- Execution::Call(
- isolate,
- isolate->run_microtasks(),
- isolate->factory()->undefined_value(),
- 0,
- NULL).Check();
-}
-
-
-void Execution::EnqueueMicrotask(Isolate* isolate, Handle<Object> microtask) {
- Handle<Object> args[] = { microtask };
- Execution::Call(
- isolate,
- isolate->enqueue_microtask(),
- isolate->factory()->undefined_value(),
- 1,
- args).Check();
-}
-
-
bool StackGuard::IsStackOverflow() {
ExecutionAccess access(isolate_);
return (thread_local_.jslimit_ != kInterruptLimit &&
Handle<Object> object);
static MaybeHandle<Object> TryGetConstructorDelegate(Isolate* isolate,
Handle<Object> object);
-
- static void RunMicrotasks(Isolate* isolate);
- static void EnqueueMicrotask(Isolate* isolate, Handle<Object> microtask);
};
set_observation_state(*factory->NewJSObjectFromMap(
factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize)));
- // Allocate object to hold object microtask state.
- set_microtask_state(*factory->NewJSObjectFromMap(
- factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize)));
+ // Microtask queue uses the empty fixed array as a sentinel for "empty".
+ // Number of queued microtasks stored in Isolate::pending_microtask_count().
+ set_microtask_queue(empty_fixed_array());
set_frozen_symbol(*factory->NewPrivateSymbol());
set_nonexistent_symbol(*factory->NewPrivateSymbol());
V(Symbol, megamorphic_symbol, MegamorphicSymbol) \
V(FixedArray, materialized_objects, MaterializedObjects) \
V(FixedArray, allocation_sites_scratchpad, AllocationSitesScratchpad) \
- V(JSObject, microtask_state, MicrotaskState)
+ V(FixedArray, microtask_queue, MicrotaskQueue)
// Entries in this list are limited to Smis and are not visited during GC.
#define SMI_ROOT_LIST(V) \
void Isolate::FireCallCompletedCallback() {
bool has_call_completed_callbacks = !call_completed_callbacks_.is_empty();
- bool run_microtasks = autorun_microtasks() && microtask_pending();
+ bool run_microtasks = autorun_microtasks() && pending_microtask_count();
if (!has_call_completed_callbacks && !run_microtasks) return;
if (!handle_scope_implementer()->CallDepthIsZero()) return;
+ if (run_microtasks) RunMicrotasks();
// Fire callbacks. Increase call depth to prevent recursive callbacks.
handle_scope_implementer()->IncrementCallDepth();
- if (run_microtasks) Execution::RunMicrotasks(this);
for (int i = 0; i < call_completed_callbacks_.length(); i++) {
call_completed_callbacks_.at(i)();
}
}
-void Isolate::RunMicrotasks() {
- if (!microtask_pending())
- return;
+void Isolate::EnqueueMicrotask(Handle<JSFunction> microtask) {
+ Handle<FixedArray> queue(heap()->microtask_queue(), this);
+ int num_tasks = pending_microtask_count();
+ ASSERT(num_tasks <= queue->length());
+ if (num_tasks == 0) {
+ queue = factory()->NewFixedArray(8);
+ heap()->set_microtask_queue(*queue);
+ } else if (num_tasks == queue->length()) {
+ queue = FixedArray::CopySize(queue, num_tasks * 2);
+ heap()->set_microtask_queue(*queue);
+ }
+ ASSERT(queue->get(num_tasks)->IsUndefined());
+ queue->set(num_tasks, *microtask);
+ set_pending_microtask_count(num_tasks + 1);
+}
+
+void Isolate::RunMicrotasks() {
ASSERT(handle_scope_implementer()->CallDepthIsZero());
// Increase call depth to prevent recursive callbacks.
handle_scope_implementer()->IncrementCallDepth();
- Execution::RunMicrotasks(this);
+
+ while (pending_microtask_count() > 0) {
+ HandleScope scope(this);
+ int num_tasks = pending_microtask_count();
+ Handle<FixedArray> queue(heap()->microtask_queue(), this);
+ ASSERT(num_tasks <= queue->length());
+ set_pending_microtask_count(0);
+ heap()->set_microtask_queue(heap()->empty_fixed_array());
+
+ for (int i = 0; i < num_tasks; i++) {
+ HandleScope scope(this);
+ Handle<JSFunction> microtask(JSFunction::cast(queue->get(i)), this);
+ // TODO(adamk): This should ignore/clear exceptions instead of Checking.
+ Execution::Call(this, microtask, factory()->undefined_value(),
+ 0, NULL).Check();
+ }
+ }
+
handle_scope_implementer()->DecrementCallDepth();
}
/* AstNode state. */ \
V(int, ast_node_id, 0) \
V(unsigned, ast_node_count, 0) \
- V(bool, microtask_pending, false) \
+ V(int, pending_microtask_count, 0) \
V(bool, autorun_microtasks, true) \
V(HStatistics*, hstatistics, NULL) \
V(HTracer*, htracer, NULL) \
void RemoveCallCompletedCallback(CallCompletedCallback callback);
void FireCallCompletedCallback();
+ void EnqueueMicrotask(Handle<JSFunction> microtask);
void RunMicrotasks();
private:
var callbackInfo = CallbackInfoNormalize(callback);
if (IS_NULL(GetPendingObservers())) {
- SetPendingObservers(nullProtoObject())
- EnqueueMicrotask(ObserveMicrotaskRunner);
+ SetPendingObservers(nullProtoObject());
+ %EnqueueMicrotask(ObserveMicrotaskRunner);
}
GetPendingObservers()[callbackInfo.priority] = callback;
callbackInfo.push(changeRecord);
}
function PromiseEnqueue(value, tasks) {
- EnqueueMicrotask(function() {
+ %EnqueueMicrotask(function() {
for (var i = 0; i < tasks.length; i += 2) {
PromiseHandle(value, tasks[i], tasks[i + 1])
}
}
-RUNTIME_FUNCTION(Runtime_SetMicrotaskPending) {
- SealHandleScope shs(isolate);
+RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
+ HandleScope scope(isolate);
ASSERT(args.length() == 1);
- CONVERT_BOOLEAN_ARG_CHECKED(new_state, 0);
- bool old_state = isolate->microtask_pending();
- isolate->set_microtask_pending(new_state);
- return isolate->heap()->ToBoolean(old_state);
+ CONVERT_ARG_HANDLE_CHECKED(JSFunction, microtask, 0);
+ isolate->EnqueueMicrotask(microtask);
+ return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_RunMicrotasks) {
HandleScope scope(isolate);
ASSERT(args.length() == 0);
- if (isolate->microtask_pending()) Execution::RunMicrotasks(isolate);
+ isolate->RunMicrotasks();
return isolate->heap()->undefined_value();
}
-RUNTIME_FUNCTION(Runtime_GetMicrotaskState) {
- SealHandleScope shs(isolate);
- ASSERT(args.length() == 0);
- return isolate->heap()->microtask_state();
-}
-
-
RUNTIME_FUNCTION(Runtime_GetObservationState) {
SealHandleScope shs(isolate);
ASSERT(args.length() == 0);
/* ES5 */ \
F(ObjectFreeze, 1, 1) \
\
- /* Harmony microtasks */ \
- F(GetMicrotaskState, 0, 1) \
- \
/* Harmony modules */ \
F(IsJSModule, 1, 1) \
\
F(WeakCollectionSet, 3, 1) \
\
/* Harmony events */ \
- F(SetMicrotaskPending, 1, 1) \
+ F(EnqueueMicrotask, 1, 1) \
F(RunMicrotasks, 0, 1) \
\
/* Harmony observe */ \
}
SetUpFunction();
-
-
-//----------------------------------------------------------------------------
-
-// TODO(rossberg): very simple abstraction for generic microtask queue.
-// Eventually, we should move to a real event queue that allows to maintain
-// relative ordering of different kinds of tasks.
-
-function RunMicrotasksJS() {
- while (%SetMicrotaskPending(false)) {
- var microtaskState = %GetMicrotaskState();
- if (IS_UNDEFINED(microtaskState.queue))
- return;
-
- var microtasks = microtaskState.queue;
- microtaskState.queue = null;
-
- for (var i = 0; i < microtasks.length; i++) {
- microtasks[i]();
- }
- }
-}
-
-function EnqueueMicrotask(fn) {
- if (!IS_FUNCTION(fn)) {
- throw new $TypeError('Can only enqueue functions');
- }
- var microtaskState = %GetMicrotaskState();
- if (IS_UNDEFINED(microtaskState.queue) || IS_NULL(microtaskState.queue)) {
- microtaskState.queue = new InternalArray;
- }
- microtaskState.queue.push(fn);
- %SetMicrotaskPending(true);
-}
}
+TEST(RunMicrotasksWithoutEnteringContext) {
+ v8::Isolate* isolate = CcTest::isolate();
+ HandleScope handle_scope(isolate);
+ isolate->SetAutorunMicrotasks(false);
+ Handle<Context> context = Context::New(isolate);
+ {
+ Context::Scope context_scope(context);
+ CompileRun("var ext1Calls = 0;");
+ isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
+ }
+ isolate->RunMicrotasks();
+ {
+ Context::Scope context_scope(context);
+ CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
+ }
+ isolate->SetAutorunMicrotasks(true);
+}
+
+
static int probes_counter = 0;
static int misses_counter = 0;
static int updates_counter = 0;
// Copyright 2014 the V8 project authors. All rights reserved.
// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
// Flags: --allow-natives-syntax --harmony
-%GetMicrotaskState();
+var _microtask = function() {};
+%EnqueueMicrotask(_microtask);
+++ /dev/null
-// Copyright 2014 the V8 project authors. All rights reserved.
-// AUTO-GENERATED BY tools/generate-runtime-tests.py, DO NOT MODIFY
-// Flags: --allow-natives-syntax --harmony
-var _new_state = true;
-%SetMicrotaskPending(_new_state);
# that the parser doesn't bit-rot. Change the values as needed when you add,
# remove or change runtime functions, but make sure we don't lose our ability
# to parse them!
-EXPECTED_FUNCTION_COUNT = 362
+EXPECTED_FUNCTION_COUNT = 361
EXPECTED_FUZZABLE_COUNT = 329
EXPECTED_CCTEST_COUNT = 6
EXPECTED_UNKNOWN_COUNT = 5
-EXPECTED_BUILTINS_COUNT = 826
+EXPECTED_BUILTINS_COUNT = 824
# Don't call these at all.