Commit 52ff3ae4 authored by Caitlin Potter's avatar Caitlin Potter Committed by Commit Bot

[builtins] implement RunMicrotasks pump as a code stub

- Implement RunMicrotasks in CSA to prevent a potentially large number
  of jumps between C++ and JS code while consuming te queue. Appears to
  provide a ~60% speedup in microtask-heavy code, which from limited
  testing appears to scale linearly.

  The code-stub microtask pump bails out to the old C++ microtask pump
  if it encounters a CallHandlerInfo microtask, and remains in C++ for
  the remainder of the queue (returning to the JS/stub implementation
  after the bailed out queue is exhausted).

- Add a variation of JSEntryStub which enters the new RunMicrotasks code
  stub.

- Add a new RunMicrotasks helper to Execution, which uses the
  RunMicrotasks entry stub.

Bug: 
Change-Id: I4667d4dd633d24455ea5d7cef239da0af1a7365e
Reviewed-on: https://chromium-review.googlesource.com/650486
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49842}
parent fd554885
...@@ -405,6 +405,7 @@ class HandleScopeImplementer { ...@@ -405,6 +405,7 @@ class HandleScopeImplementer {
call_depth_(0), call_depth_(0),
microtasks_depth_(0), microtasks_depth_(0),
microtasks_suppressions_(0), microtasks_suppressions_(0),
entered_contexts_count_(0),
entered_context_count_during_microtasks_(0), entered_context_count_during_microtasks_(0),
#ifdef DEBUG #ifdef DEBUG
debug_microtasks_depth_(0), debug_microtasks_depth_(0),
...@@ -531,6 +532,7 @@ class HandleScopeImplementer { ...@@ -531,6 +532,7 @@ class HandleScopeImplementer {
int call_depth_; int call_depth_;
int microtasks_depth_; int microtasks_depth_;
int microtasks_suppressions_; int microtasks_suppressions_;
size_t entered_contexts_count_;
size_t entered_context_count_during_microtasks_; size_t entered_context_count_during_microtasks_;
#ifdef DEBUG #ifdef DEBUG
int debug_microtasks_depth_; int debug_microtasks_depth_;
...@@ -546,10 +548,25 @@ class HandleScopeImplementer { ...@@ -546,10 +548,25 @@ class HandleScopeImplementer {
friend class DeferredHandles; friend class DeferredHandles;
friend class DeferredHandleScope; friend class DeferredHandleScope;
friend class HandleScopeImplementerOffsets;
DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer); DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer);
}; };
class HandleScopeImplementerOffsets {
public:
enum Offsets {
kMicrotaskContext = offsetof(HandleScopeImplementer, microtask_context_),
kEnteredContexts = offsetof(HandleScopeImplementer, entered_contexts_),
kEnteredContextsCount =
offsetof(HandleScopeImplementer, entered_contexts_count_),
kEnteredContextCountDuringMicrotasks = offsetof(
HandleScopeImplementer, entered_context_count_during_microtasks_)
};
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(HandleScopeImplementerOffsets);
};
const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page
...@@ -584,9 +601,13 @@ bool HandleScopeImplementer::HasSavedContexts() { ...@@ -584,9 +601,13 @@ bool HandleScopeImplementer::HasSavedContexts() {
void HandleScopeImplementer::EnterContext(Handle<Context> context) { void HandleScopeImplementer::EnterContext(Handle<Context> context) {
entered_contexts_.push_back(*context); entered_contexts_.push_back(*context);
entered_contexts_count_ = entered_contexts_.size();
} }
void HandleScopeImplementer::LeaveContext() { entered_contexts_.pop_back(); } void HandleScopeImplementer::LeaveContext() {
entered_contexts_.pop_back();
entered_contexts_count_ = entered_contexts_.size();
}
bool HandleScopeImplementer::LastEnteredContextWas(Handle<Context> context) { bool HandleScopeImplementer::LastEnteredContextWas(Handle<Context> context) {
return !entered_contexts_.empty() && entered_contexts_.back() == *context; return !entered_contexts_.empty() && entered_contexts_.back() == *context;
......
...@@ -414,6 +414,8 @@ void JSEntryStub::Generate(MacroAssembler* masm) { ...@@ -414,6 +414,8 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// Set up the reserved register for 0.0. // Set up the reserved register for 0.0.
__ vmov(kDoubleRegZero, Double(0.0)); __ vmov(kDoubleRegZero, Double(0.0));
__ InitializeRootRegister();
// Get address of argv, see stm above. // Get address of argv, see stm above.
// r0: code entry // r0: code entry
// r1: function // r1: function
...@@ -509,12 +511,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) { ...@@ -509,12 +511,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// r2: receiver // r2: receiver
// r3: argc // r3: argc
// r4: argv // r4: argv
if (type() == StackFrame::CONSTRUCT_ENTRY) { __ Call(EntryTrampoline(), RelocInfo::CODE_TARGET);
__ Call(BUILTIN_CODE(isolate(), JSConstructEntryTrampoline),
RelocInfo::CODE_TARGET);
} else {
__ Call(BUILTIN_CODE(isolate(), JSEntryTrampoline), RelocInfo::CODE_TARGET);
}
// Unlink this frame from the handler chain. // Unlink this frame from the handler chain.
__ PopStackHandler(); __ PopStackHandler();
......
...@@ -517,6 +517,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) { ...@@ -517,6 +517,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// Set up the reserved register for 0.0. // Set up the reserved register for 0.0.
__ Fmov(fp_zero, 0.0); __ Fmov(fp_zero, 0.0);
// Initialize the root array register
__ InitializeRootRegister();
// Build an entry frame (see layout below). // Build an entry frame (see layout below).
StackFrame::Type marker = type(); StackFrame::Type marker = type();
int64_t bad_frame_pointer = -1L; // Bad frame pointer to fail if it is used. int64_t bad_frame_pointer = -1L; // Bad frame pointer to fail if it is used.
...@@ -612,13 +615,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) { ...@@ -612,13 +615,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// x2: receiver. // x2: receiver.
// x3: argc. // x3: argc.
// x4: argv. // x4: argv.
__ Call(EntryTrampoline(), RelocInfo::CODE_TARGET);
if (type() == StackFrame::CONSTRUCT_ENTRY) {
__ Call(BUILTIN_CODE(isolate(), JSConstructEntryTrampoline),
RelocInfo::CODE_TARGET);
} else {
__ Call(BUILTIN_CODE(isolate(), JSEntryTrampoline), RelocInfo::CODE_TARGET);
}
// Pop the stack handler and unlink this frame from the handler chain. // Pop the stack handler and unlink this frame from the handler chain.
static_assert(StackHandlerConstants::kNextOffset == 0 * kPointerSize, static_assert(StackHandlerConstants::kNextOffset == 0 * kPointerSize,
......
...@@ -801,6 +801,16 @@ ExternalReference ExternalReference::builtins_address(Isolate* isolate) { ...@@ -801,6 +801,16 @@ ExternalReference ExternalReference::builtins_address(Isolate* isolate) {
return ExternalReference(isolate->builtins()->builtins_table_address()); return ExternalReference(isolate->builtins()->builtins_table_address());
} }
ExternalReference ExternalReference::handle_scope_implementer_address(
Isolate* isolate) {
return ExternalReference(isolate->handle_scope_implementer_address());
}
ExternalReference ExternalReference::pending_microtask_count_address(
Isolate* isolate) {
return ExternalReference(isolate->pending_microtask_count_address());
}
ExternalReference ExternalReference::interpreter_dispatch_table_address( ExternalReference ExternalReference::interpreter_dispatch_table_address(
Isolate* isolate) { Isolate* isolate) {
return ExternalReference(isolate->interpreter()->dispatch_table_address()); return ExternalReference(isolate->interpreter()->dispatch_table_address());
......
...@@ -824,6 +824,9 @@ class ExternalReference BASE_EMBEDDED { ...@@ -824,6 +824,9 @@ class ExternalReference BASE_EMBEDDED {
// The builtins table as an external reference, used by lazy deserialization. // The builtins table as an external reference, used by lazy deserialization.
static ExternalReference builtins_address(Isolate* isolate); static ExternalReference builtins_address(Isolate* isolate);
static ExternalReference handle_scope_implementer_address(Isolate* isolate);
static ExternalReference pending_microtask_count_address(Isolate* isolate);
// One-of-a-kind references. These references are not part of a general // One-of-a-kind references. These references are not part of a general
// pattern. This means that they have to be added to the // pattern. This means that they have to be added to the
// ExternalReferenceTable in serialize.cc manually. // ExternalReferenceTable in serialize.cc manually.
......
...@@ -2410,8 +2410,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -2410,8 +2410,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
} }
{ // Internal: PromiseHandle { // Internal: PromiseHandle
Handle<JSFunction> function = SimpleCreateFunction( Handle<JSFunction> function =
isolate, factory->empty_string(), Builtins::kPromiseHandle, 5, false); SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kPromiseHandleJS, 5, false);
native_context()->set_promise_handle(*function); native_context()->set_promise_handle(*function);
} }
......
...@@ -629,8 +629,6 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, ...@@ -629,8 +629,6 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
__ mov(cp, Operand(context_address)); __ mov(cp, Operand(context_address));
__ ldr(cp, MemOperand(cp)); __ ldr(cp, MemOperand(cp));
__ InitializeRootRegister();
// Push the function and the receiver onto the stack. // Push the function and the receiver onto the stack.
__ Push(r1, r2); __ Push(r1, r2);
......
...@@ -226,6 +226,8 @@ namespace internal { ...@@ -226,6 +226,8 @@ namespace internal {
TFS(RejectNativePromise, kPromise, kValue, kDebugEvent) \ TFS(RejectNativePromise, kPromise, kValue, kDebugEvent) \
TFS(PerformNativePromiseThen, kPromise, kResolveReaction, kRejectReaction, \ TFS(PerformNativePromiseThen, kPromise, kResolveReaction, kRejectReaction, \
kResultPromise) \ kResultPromise) \
TFC(RunMicrotasks, RunMicrotasks, 1) \
TFS(PromiseResolveThenableJob, kMicrotask) \
\ \
/* Object property helpers */ \ /* Object property helpers */ \
TFS(HasProperty, kKey, kObject) \ TFS(HasProperty, kKey, kObject) \
...@@ -777,7 +779,9 @@ namespace internal { ...@@ -777,7 +779,9 @@ namespace internal {
/* ES #sec-fulfillpromise */ \ /* ES #sec-fulfillpromise */ \
TFJ(ResolvePromise, 2, kPromise, kValue) \ TFJ(ResolvePromise, 2, kPromise, kValue) \
TFS(PromiseHandleReject, kPromise, kOnReject, kException) \ TFS(PromiseHandleReject, kPromise, kOnReject, kException) \
TFJ(PromiseHandle, 5, kValue, kHandler, kDeferredPromise, \ TFS(PromiseHandle, kValue, kHandler, kDeferredPromise, kDeferredOnResolve, \
kDeferredOnReject) \
TFJ(PromiseHandleJS, 5, kValue, kHandler, kDeferredPromise, \
kDeferredOnResolve, kDeferredOnReject) \ kDeferredOnResolve, kDeferredOnReject) \
/* ES #sec-promise.resolve */ \ /* ES #sec-promise.resolve */ \
TFJ(PromiseResolveWrapper, 1, kValue) \ TFJ(PromiseResolveWrapper, 1, kValue) \
......
This diff is collapsed.
...@@ -1183,7 +1183,14 @@ TF_BUILTIN(PromiseHandleReject, PromiseBuiltinsAssembler) { ...@@ -1183,7 +1183,14 @@ TF_BUILTIN(PromiseHandleReject, PromiseBuiltinsAssembler) {
BIND(&if_customhandler); BIND(&if_customhandler);
{ {
CallJS(call_callable, context, on_reject, UndefinedConstant(), exception); VARIABLE(var_exception, MachineRepresentation::kTagged, TheHoleConstant());
Label if_exception(this);
Node* const ret = CallJS(call_callable, context, on_reject,
UndefinedConstant(), exception);
GotoIfException(ret, &if_exception, &var_exception);
Return(UndefinedConstant());
BIND(&if_exception);
CallRuntime(Runtime::kReportMessage, context, var_exception.value());
Return(UndefinedConstant()); Return(UndefinedConstant());
} }
} }
...@@ -1297,6 +1304,20 @@ TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) { ...@@ -1297,6 +1304,20 @@ TF_BUILTIN(PromiseHandle, PromiseBuiltinsAssembler) {
} }
} }
TF_BUILTIN(PromiseHandleJS, PromiseBuiltinsAssembler) {
Node* const value = Parameter(Descriptor::kValue);
Node* const handler = Parameter(Descriptor::kHandler);
Node* const deferred_promise = Parameter(Descriptor::kDeferredPromise);
Node* const deferred_on_resolve = Parameter(Descriptor::kDeferredOnResolve);
Node* const deferred_on_reject = Parameter(Descriptor::kDeferredOnReject);
Node* const context = Parameter(Descriptor::kContext);
Node* const result =
CallBuiltin(Builtins::kPromiseHandle, context, value, handler,
deferred_promise, deferred_on_resolve, deferred_on_reject);
Return(result);
}
// ES#sec-promise.prototype.catch // ES#sec-promise.prototype.catch
// Promise.prototype.catch ( onRejected ) // Promise.prototype.catch ( onRejected )
TF_BUILTIN(PromiseCatch, PromiseBuiltinsAssembler) { TF_BUILTIN(PromiseCatch, PromiseBuiltinsAssembler) {
......
...@@ -697,10 +697,18 @@ class CEntryStub : public PlatformCodeStub { ...@@ -697,10 +697,18 @@ class CEntryStub : public PlatformCodeStub {
class JSEntryStub : public PlatformCodeStub { class JSEntryStub : public PlatformCodeStub {
public: public:
enum class SpecialTarget { kNone, kRunMicrotasks };
JSEntryStub(Isolate* isolate, StackFrame::Type type) JSEntryStub(Isolate* isolate, StackFrame::Type type)
: PlatformCodeStub(isolate) { : PlatformCodeStub(isolate) {
DCHECK(type == StackFrame::ENTRY || type == StackFrame::CONSTRUCT_ENTRY); DCHECK(type == StackFrame::ENTRY || type == StackFrame::CONSTRUCT_ENTRY);
minor_key_ = StackFrameTypeBits::encode(type); minor_key_ = StackFrameTypeBits::encode(type) |
SpecialTargetBits::encode(SpecialTarget::kNone);
}
JSEntryStub(Isolate* isolate, SpecialTarget target)
: PlatformCodeStub(isolate) {
minor_key_ = StackFrameTypeBits::encode(StackFrame::ENTRY) |
SpecialTargetBits::encode(target);
} }
private: private:
...@@ -715,7 +723,26 @@ class JSEntryStub : public PlatformCodeStub { ...@@ -715,7 +723,26 @@ class JSEntryStub : public PlatformCodeStub {
return StackFrameTypeBits::decode(minor_key_); return StackFrameTypeBits::decode(minor_key_);
} }
SpecialTarget special_target() const {
return SpecialTargetBits::decode(minor_key_);
}
Handle<Code> EntryTrampoline() {
switch (special_target()) {
case SpecialTarget::kNone:
return (type() == StackFrame::CONSTRUCT_ENTRY)
? BUILTIN_CODE(isolate(), JSConstructEntryTrampoline)
: BUILTIN_CODE(isolate(), JSEntryTrampoline);
case SpecialTarget::kRunMicrotasks:
return BUILTIN_CODE(isolate(), RunMicrotasks);
}
UNREACHABLE();
return Handle<Code>();
}
class StackFrameTypeBits : public BitField<StackFrame::Type, 0, 5> {}; class StackFrameTypeBits : public BitField<StackFrame::Type, 0, 5> {};
class SpecialTargetBits
: public BitField<SpecialTarget, StackFrameTypeBits::kNext, 1> {};
int handler_offset_; int handler_offset_;
......
...@@ -55,7 +55,8 @@ namespace { ...@@ -55,7 +55,8 @@ namespace {
MUST_USE_RESULT MaybeHandle<Object> Invoke( MUST_USE_RESULT MaybeHandle<Object> Invoke(
Isolate* isolate, bool is_construct, Handle<Object> target, Isolate* isolate, bool is_construct, Handle<Object> target,
Handle<Object> receiver, int argc, Handle<Object> args[], Handle<Object> receiver, int argc, Handle<Object> args[],
Handle<Object> new_target, Execution::MessageHandling message_handling) { Handle<Object> new_target, Execution::MessageHandling message_handling,
Execution::Target execution_target) {
DCHECK(!receiver->IsJSGlobalObject()); DCHECK(!receiver->IsJSGlobalObject());
#ifdef USE_SIMULATOR #ifdef USE_SIMULATOR
...@@ -117,9 +118,18 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke( ...@@ -117,9 +118,18 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(
Object* receiver, int argc, Object* receiver, int argc,
Object*** args); Object*** args);
Handle<Code> code = is_construct Handle<Code> code;
? isolate->factory()->js_construct_entry_code() switch (execution_target) {
: isolate->factory()->js_entry_code(); case Execution::Target::kCallable:
code = is_construct ? isolate->factory()->js_construct_entry_code()
: isolate->factory()->js_entry_code();
break;
case Execution::Target::kRunMicrotasks:
code = isolate->factory()->js_run_microtasks_entry_code();
break;
default:
UNREACHABLE();
}
{ {
// Save and restore context around invocation and block the // Save and restore context around invocation and block the
...@@ -167,7 +177,8 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke( ...@@ -167,7 +177,8 @@ MUST_USE_RESULT MaybeHandle<Object> Invoke(
MaybeHandle<Object> CallInternal(Isolate* isolate, Handle<Object> callable, MaybeHandle<Object> CallInternal(Isolate* isolate, Handle<Object> callable,
Handle<Object> receiver, int argc, Handle<Object> receiver, int argc,
Handle<Object> argv[], Handle<Object> argv[],
Execution::MessageHandling message_handling) { Execution::MessageHandling message_handling,
Execution::Target target) {
// Convert calls on global objects to be calls on the global // Convert calls on global objects to be calls on the global
// receiver instead to avoid having a 'this' pointer which refers // receiver instead to avoid having a 'this' pointer which refers
// directly to a global object. // directly to a global object.
...@@ -176,7 +187,8 @@ MaybeHandle<Object> CallInternal(Isolate* isolate, Handle<Object> callable, ...@@ -176,7 +187,8 @@ MaybeHandle<Object> CallInternal(Isolate* isolate, Handle<Object> callable,
handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(), isolate); handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(), isolate);
} }
return Invoke(isolate, false, callable, receiver, argc, argv, return Invoke(isolate, false, callable, receiver, argc, argv,
isolate->factory()->undefined_value(), message_handling); isolate->factory()->undefined_value(), message_handling,
target);
} }
} // namespace } // namespace
...@@ -186,7 +198,7 @@ MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable, ...@@ -186,7 +198,7 @@ MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
Handle<Object> receiver, int argc, Handle<Object> receiver, int argc,
Handle<Object> argv[]) { Handle<Object> argv[]) {
return CallInternal(isolate, callable, receiver, argc, argv, return CallInternal(isolate, callable, receiver, argc, argv,
MessageHandling::kReport); MessageHandling::kReport, Execution::Target::kCallable);
} }
...@@ -203,15 +215,13 @@ MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor, ...@@ -203,15 +215,13 @@ MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
Handle<Object> argv[]) { Handle<Object> argv[]) {
return Invoke(isolate, true, constructor, return Invoke(isolate, true, constructor,
isolate->factory()->undefined_value(), argc, argv, new_target, isolate->factory()->undefined_value(), argc, argv, new_target,
MessageHandling::kReport); MessageHandling::kReport, Execution::Target::kCallable);
} }
MaybeHandle<Object> Execution::TryCall(Isolate* isolate, MaybeHandle<Object> Execution::TryCall(
Handle<Object> callable, Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
Handle<Object> receiver, int argc, int argc, Handle<Object> args[], MessageHandling message_handling,
Handle<Object> args[], MaybeHandle<Object>* exception_out, Target target) {
MessageHandling message_handling,
MaybeHandle<Object>* exception_out) {
bool is_termination = false; bool is_termination = false;
MaybeHandle<Object> maybe_result; MaybeHandle<Object> maybe_result;
if (exception_out != nullptr) *exception_out = MaybeHandle<Object>(); if (exception_out != nullptr) *exception_out = MaybeHandle<Object>();
...@@ -226,8 +236,8 @@ MaybeHandle<Object> Execution::TryCall(Isolate* isolate, ...@@ -226,8 +236,8 @@ MaybeHandle<Object> Execution::TryCall(Isolate* isolate,
catcher.SetVerbose(false); catcher.SetVerbose(false);
catcher.SetCaptureMessage(false); catcher.SetCaptureMessage(false);
maybe_result = maybe_result = CallInternal(isolate, callable, receiver, argc, args,
CallInternal(isolate, callable, receiver, argc, args, message_handling); message_handling, target);
if (maybe_result.is_null()) { if (maybe_result.is_null()) {
DCHECK(isolate->has_pending_exception()); DCHECK(isolate->has_pending_exception());
...@@ -253,6 +263,13 @@ MaybeHandle<Object> Execution::TryCall(Isolate* isolate, ...@@ -253,6 +263,13 @@ MaybeHandle<Object> Execution::TryCall(Isolate* isolate,
return maybe_result; return maybe_result;
} }
MaybeHandle<Object> Execution::RunMicrotasks(
Isolate* isolate, MessageHandling message_handling,
MaybeHandle<Object>* exception_out) {
auto undefined = isolate->factory()->undefined_value();
return TryCall(isolate, undefined, undefined, 0, {}, message_handling,
exception_out, Target::kRunMicrotasks);
}
void StackGuard::SetStackLimit(uintptr_t limit) { void StackGuard::SetStackLimit(uintptr_t limit) {
ExecutionAccess access(isolate_); ExecutionAccess access(isolate_);
......
...@@ -20,6 +20,7 @@ class Execution final : public AllStatic { ...@@ -20,6 +20,7 @@ class Execution final : public AllStatic {
public: public:
// Whether to report pending messages, or keep them pending on the isolate. // Whether to report pending messages, or keep them pending on the isolate.
enum class MessageHandling { kReport, kKeepPending }; enum class MessageHandling { kReport, kKeepPending };
enum class Target { kCallable, kRunMicrotasks };
// Call a function, the caller supplies a receiver and an array // Call a function, the caller supplies a receiver and an array
// of arguments. // of arguments.
...@@ -54,7 +55,12 @@ class Execution final : public AllStatic { ...@@ -54,7 +55,12 @@ class Execution final : public AllStatic {
Handle<Object> receiver, int argc, Handle<Object> receiver, int argc,
Handle<Object> argv[], Handle<Object> argv[],
MessageHandling message_handling, MessageHandling message_handling,
MaybeHandle<Object>* exception_out); MaybeHandle<Object>* exception_out,
Target target = Target::kCallable);
// Convenience method for performing RunMicrotasks
static MaybeHandle<Object> RunMicrotasks(Isolate* isolate,
MessageHandling message_handling,
MaybeHandle<Object>* exception_out);
}; };
......
...@@ -92,6 +92,10 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) { ...@@ -92,6 +92,10 @@ void ExternalReferenceTable::AddReferences(Isolate* isolate) {
"LDoubleConstant::one_half"); "LDoubleConstant::one_half");
Add(ExternalReference::isolate_address(isolate).address(), "isolate"); Add(ExternalReference::isolate_address(isolate).address(), "isolate");
Add(ExternalReference::builtins_address(isolate).address(), "builtins"); Add(ExternalReference::builtins_address(isolate).address(), "builtins");
Add(ExternalReference::handle_scope_implementer_address(isolate).address(),
"Isolate::handle_scope_implementer_address");
Add(ExternalReference::pending_microtask_count_address(isolate).address(),
"Isolate::pending_microtask_count_address()");
Add(ExternalReference::interpreter_dispatch_table_address(isolate).address(), Add(ExternalReference::interpreter_dispatch_table_address(isolate).address(),
"Interpreter::dispatch_table_address"); "Interpreter::dispatch_table_address");
Add(ExternalReference::bytecode_size_table_address(isolate).address(), Add(ExternalReference::bytecode_size_table_address(isolate).address(),
......
...@@ -1459,7 +1459,9 @@ enum class ConcurrencyMode { kNotConcurrent, kConcurrent }; ...@@ -1459,7 +1459,9 @@ enum class ConcurrencyMode { kNotConcurrent, kConcurrent };
C(PendingHandlerFP, pending_handler_fp) \ C(PendingHandlerFP, pending_handler_fp) \
C(PendingHandlerSP, pending_handler_sp) \ C(PendingHandlerSP, pending_handler_sp) \
C(ExternalCaughtException, external_caught_exception) \ C(ExternalCaughtException, external_caught_exception) \
C(JSEntrySP, js_entry_sp) C(JSEntrySP, js_entry_sp) \
C(MicrotaskQueueBailoutIndex, microtask_queue_bailout_index) \
C(MicrotaskQueueBailoutCount, microtask_queue_bailout_count)
enum IsolateAddressId { enum IsolateAddressId {
#define DECLARE_ENUM(CamelName, hacker_name) k##CamelName##Address, #define DECLARE_ENUM(CamelName, hacker_name) k##CamelName##Address,
......
...@@ -2629,6 +2629,10 @@ void Heap::CreateJSConstructEntryStub() { ...@@ -2629,6 +2629,10 @@ void Heap::CreateJSConstructEntryStub() {
set_js_construct_entry_code(*stub.GetCode()); set_js_construct_entry_code(*stub.GetCode());
} }
void Heap::CreateJSRunMicrotasksEntryStub() {
JSEntryStub stub(isolate(), JSEntryStub::SpecialTarget::kRunMicrotasks);
set_js_run_microtasks_entry_code(*stub.GetCode());
}
void Heap::CreateFixedStubs() { void Heap::CreateFixedStubs() {
// Here we create roots for fixed stubs. They are needed at GC // Here we create roots for fixed stubs. They are needed at GC
...@@ -2660,6 +2664,7 @@ void Heap::CreateFixedStubs() { ...@@ -2660,6 +2664,7 @@ void Heap::CreateFixedStubs() {
// To workaround the problem, make separate functions without inlining. // To workaround the problem, make separate functions without inlining.
Heap::CreateJSEntryStub(); Heap::CreateJSEntryStub();
Heap::CreateJSConstructEntryStub(); Heap::CreateJSConstructEntryStub();
Heap::CreateJSRunMicrotasksEntryStub();
} }
bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) { bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
......
...@@ -256,7 +256,8 @@ using v8::MemoryPressureLevel; ...@@ -256,7 +256,8 @@ using v8::MemoryPressureLevel;
DeserializeLazyHandlerExtraWide) \ DeserializeLazyHandlerExtraWide) \
/* JS Entries */ \ /* JS Entries */ \
V(Code, js_entry_code, JsEntryCode) \ V(Code, js_entry_code, JsEntryCode) \
V(Code, js_construct_entry_code, JsConstructEntryCode) V(Code, js_construct_entry_code, JsConstructEntryCode) \
V(Code, js_run_microtasks_entry_code, JsRunMicrotasksEntryCode)
// Entries in this list are limited to Smis and are not visited during GC. // Entries in this list are limited to Smis and are not visited during GC.
#define SMI_ROOT_LIST(V) \ #define SMI_ROOT_LIST(V) \
...@@ -1830,6 +1831,7 @@ class Heap { ...@@ -1830,6 +1831,7 @@ class Heap {
// because of a gcc-4.4 bug that assigns wrong vtable entries. // because of a gcc-4.4 bug that assigns wrong vtable entries.
NO_INLINE(void CreateJSEntryStub()); NO_INLINE(void CreateJSEntryStub());
NO_INLINE(void CreateJSConstructEntryStub()); NO_INLINE(void CreateJSConstructEntryStub());
NO_INLINE(void CreateJSRunMicrotasksEntryStub());
void CreateFixedStubs(); void CreateFixedStubs();
......
...@@ -486,12 +486,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) { ...@@ -486,12 +486,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// pop the faked function when we return. Notice that we cannot store a // pop the faked function when we return. Notice that we cannot store a
// reference to the trampoline code directly in this stub, because the // reference to the trampoline code directly in this stub, because the
// builtin stubs may not have been generated yet. // builtin stubs may not have been generated yet.
if (type() == StackFrame::CONSTRUCT_ENTRY) { __ Call(EntryTrampoline(), RelocInfo::CODE_TARGET);
__ Call(BUILTIN_CODE(isolate(), JSConstructEntryTrampoline),
RelocInfo::CODE_TARGET);
} else {
__ Call(BUILTIN_CODE(isolate(), JSEntryTrampoline), RelocInfo::CODE_TARGET);
}
// Unlink this frame from the handler chain. // Unlink this frame from the handler chain.
__ PopStackHandler(); __ PopStackHandler();
......
...@@ -78,6 +78,7 @@ class PlatformInterfaceDescriptor; ...@@ -78,6 +78,7 @@ class PlatformInterfaceDescriptor;
V(ResumeGenerator) \ V(ResumeGenerator) \
V(FrameDropperTrampoline) \ V(FrameDropperTrampoline) \
V(WasmRuntimeCall) \ V(WasmRuntimeCall) \
V(RunMicrotasks) \
BUILTIN_LIST_TFS(V) BUILTIN_LIST_TFS(V)
class V8_EXPORT_PRIVATE CallInterfaceDescriptorData { class V8_EXPORT_PRIVATE CallInterfaceDescriptorData {
...@@ -846,6 +847,13 @@ class WasmRuntimeCallDescriptor final : public CallInterfaceDescriptor { ...@@ -846,6 +847,13 @@ class WasmRuntimeCallDescriptor final : public CallInterfaceDescriptor {
0) 0)
}; };
class RunMicrotasksDescriptor final : public CallInterfaceDescriptor {
public:
DEFINE_EMPTY_PARAMETERS()
DECLARE_DEFAULT_DESCRIPTOR(RunMicrotasksDescriptor, CallInterfaceDescriptor,
0)
};
#define DEFINE_TFS_BUILTIN_DESCRIPTOR(Name, ...) \ #define DEFINE_TFS_BUILTIN_DESCRIPTOR(Name, ...) \
class Name##Descriptor : public CallInterfaceDescriptor { \ class Name##Descriptor : public CallInterfaceDescriptor { \
public: \ public: \
......
This diff is collapsed.
...@@ -373,6 +373,9 @@ class ThreadLocalTop BASE_EMBEDDED { ...@@ -373,6 +373,9 @@ class ThreadLocalTop BASE_EMBEDDED {
// Call back function to report unsafe JS accesses. // Call back function to report unsafe JS accesses.
v8::FailedAccessCheckCallback failed_access_check_callback_; v8::FailedAccessCheckCallback failed_access_check_callback_;
int microtask_queue_bailout_index_;
int microtask_queue_bailout_count_;
private: private:
void InitializeInternal(); void InitializeInternal();
...@@ -675,6 +678,18 @@ class Isolate { ...@@ -675,6 +678,18 @@ class Isolate {
return &thread_local_top_.js_entry_sp_; return &thread_local_top_.js_entry_sp_;
} }
THREAD_LOCAL_TOP_ACCESSOR(int, microtask_queue_bailout_index)
Address microtask_queue_bailout_index_address() {
return reinterpret_cast<Address>(
&thread_local_top_.microtask_queue_bailout_index_);
}
THREAD_LOCAL_TOP_ACCESSOR(int, microtask_queue_bailout_count)
Address microtask_queue_bailout_count_address() {
return reinterpret_cast<Address>(
&thread_local_top_.microtask_queue_bailout_count_);
}
// Returns the global object of the current context. It could be // Returns the global object of the current context. It could be
// a builtin object, or a JS global object. // a builtin object, or a JS global object.
inline Handle<JSGlobalObject> global_object(); inline Handle<JSGlobalObject> global_object();
...@@ -808,6 +823,11 @@ class Isolate { ...@@ -808,6 +823,11 @@ class Isolate {
// Un-schedule an exception that was caught by a TryCatch handler. // Un-schedule an exception that was caught by a TryCatch handler.
void CancelScheduledExceptionFromTryCatch(v8::TryCatch* handler); void CancelScheduledExceptionFromTryCatch(v8::TryCatch* handler);
void ReportPendingMessages(); void ReportPendingMessages();
void ReportPendingMessagesFromJavaScript();
// Implements code shared between the two above methods
void ReportPendingMessagesImpl(bool report_externally);
// Return pending location if any or unfilled structure. // Return pending location if any or unfilled structure.
MessageLocation GetMessageLocation(); MessageLocation GetMessageLocation();
...@@ -1210,6 +1230,7 @@ class Isolate { ...@@ -1210,6 +1230,7 @@ class Isolate {
void PromiseResolveThenableJob(Handle<PromiseResolveThenableJobInfo> info, void PromiseResolveThenableJob(Handle<PromiseResolveThenableJobInfo> info,
MaybeHandle<Object>* result, MaybeHandle<Object>* result,
MaybeHandle<Object>* maybe_exception); MaybeHandle<Object>* maybe_exception);
void EnqueueMicrotask(Handle<Object> microtask); void EnqueueMicrotask(Handle<Object> microtask);
void RunMicrotasks(); void RunMicrotasks();
bool IsRunningMicrotasks() const { return is_running_microtasks_; } bool IsRunningMicrotasks() const { return is_running_microtasks_; }
...@@ -1233,6 +1254,14 @@ class Isolate { ...@@ -1233,6 +1254,14 @@ class Isolate {
return reinterpret_cast<Address>(&promise_hook_or_debug_is_active_); return reinterpret_cast<Address>(&promise_hook_or_debug_is_active_);
} }
Address pending_microtask_count_address() {
return reinterpret_cast<Address>(&pending_microtask_count_);
}
Address handle_scope_implementer_address() {
return reinterpret_cast<Address>(&handle_scope_implementer_);
}
void DebugStateUpdated(); void DebugStateUpdated();
void SetPromiseHook(PromiseHook hook); void SetPromiseHook(PromiseHook hook);
......
...@@ -589,13 +589,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) { ...@@ -589,13 +589,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// callee saved registers + ra // callee saved registers + ra
// 4 args slots // 4 args slots
// args // args
__ Call(EntryTrampoline(), RelocInfo::CODE_TARGET);
if (type() == StackFrame::CONSTRUCT_ENTRY) {
__ Call(BUILTIN_CODE(isolate, JSConstructEntryTrampoline),
RelocInfo::CODE_TARGET);
} else {
__ Call(BUILTIN_CODE(isolate, JSEntryTrampoline), RelocInfo::CODE_TARGET);
}
// Unlink this frame from the handler chain. // Unlink this frame from the handler chain.
__ PopStackHandler(); __ PopStackHandler();
......
...@@ -587,13 +587,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) { ...@@ -587,13 +587,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// callee saved registers + ra // callee saved registers + ra
// [ O32: 4 args slots] // [ O32: 4 args slots]
// args // args
__ Call(EntryTrampoline(), RelocInfo::CODE_TARGET);
if (type() == StackFrame::CONSTRUCT_ENTRY) {
__ Call(BUILTIN_CODE(isolate, JSConstructEntryTrampoline),
RelocInfo::CODE_TARGET);
} else {
__ Call(BUILTIN_CODE(isolate, JSEntryTrampoline), RelocInfo::CODE_TARGET);
}
// Unlink this frame from the handler chain. // Unlink this frame from the handler chain.
__ PopStackHandler(); __ PopStackHandler();
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include "src/api.h"
#include "src/arguments.h" #include "src/arguments.h"
#include "src/ast/prettyprinter.h" #include "src/ast/prettyprinter.h"
#include "src/bootstrapper.h" #include "src/bootstrapper.h"
...@@ -650,5 +651,22 @@ RUNTIME_FUNCTION(Runtime_GetTemplateObject) { ...@@ -650,5 +651,22 @@ RUNTIME_FUNCTION(Runtime_GetTemplateObject) {
description, isolate->native_context()); description, isolate->native_context());
} }
RUNTIME_FUNCTION(Runtime_ReportMessage) {
// Helper to report messages and continue JS execution. This is intended to
// behave similarly to reporting exceptions which reach the top-level in
// Execution.cc, but allow the JS code to continue. This is useful for
// implementing algorithms such as RunMicrotasks in JS.
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, message_obj, 0);
DCHECK(!isolate->has_pending_exception());
isolate->set_pending_exception(*message_obj);
isolate->ReportPendingMessagesFromJavaScript();
isolate->clear_pending_exception();
return isolate->heap()->undefined_value();
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -339,7 +339,8 @@ namespace internal { ...@@ -339,7 +339,8 @@ namespace internal {
F(Typeof, 1, 1) \ F(Typeof, 1, 1) \
F(UnwindAndFindExceptionHandler, 0, 1) \ F(UnwindAndFindExceptionHandler, 0, 1) \
F(AllowDynamicFunction, 1, 1) \ F(AllowDynamicFunction, 1, 1) \
F(GetTemplateObject, 1, 1) F(GetTemplateObject, 1, 1) \
F(ReportMessage, 1, 1)
#define FOR_EACH_INTRINSIC_LITERALS(F) \ #define FOR_EACH_INTRINSIC_LITERALS(F) \
F(CreateRegExpLiteral, 4, 1) \ F(CreateRegExpLiteral, 4, 1) \
......
...@@ -523,12 +523,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) { ...@@ -523,12 +523,7 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// external reference instead of inlining the call target address directly // external reference instead of inlining the call target address directly
// in the code, because the builtin stubs may not have been generated yet // in the code, because the builtin stubs may not have been generated yet
// at the time this code is generated. // at the time this code is generated.
if (type() == StackFrame::CONSTRUCT_ENTRY) { __ Call(EntryTrampoline(), RelocInfo::CODE_TARGET);
__ Call(BUILTIN_CODE(isolate(), JSConstructEntryTrampoline),
RelocInfo::CODE_TARGET);
} else {
__ Call(BUILTIN_CODE(isolate(), JSEntryTrampoline), RelocInfo::CODE_TARGET);
}
// Unlink this frame from the handler chain. // Unlink this frame from the handler chain.
__ PopStackHandler(); __ PopStackHandler();
......
...@@ -43,7 +43,7 @@ Running test: testRejectedPromiseWithError ...@@ -43,7 +43,7 @@ Running test: testRejectedPromiseWithError
columnNumber : 11 columnNumber : 11
exception : { exception : {
className : Error className : Error
description : Error: MyError at foo (<anonymous>:13:11) at throwError (<anonymous>:15:3) at <anonymous> description : Error: MyError at foo (<anonymous>:13:11) at throwError (<anonymous>:15:3)
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -58,14 +58,14 @@ Running test: testRejectedPromiseWithError ...@@ -58,14 +58,14 @@ Running test: testRejectedPromiseWithError
functionName : foo functionName : foo
lineNumber : 12 lineNumber : 12
scriptId : <scriptId> scriptId : <scriptId>
url : url :
} }
[1] : { [1] : {
columnNumber : 2 columnNumber : 2
functionName : throwError functionName : throwError
lineNumber : 14 lineNumber : 14
scriptId : <scriptId> scriptId : <scriptId>
url : url :
} }
] ]
} }
...@@ -73,7 +73,7 @@ Running test: testRejectedPromiseWithError ...@@ -73,7 +73,7 @@ Running test: testRejectedPromiseWithError
} }
result : { result : {
className : Error className : Error
description : Error: MyError at foo (<anonymous>:13:11) at throwError (<anonymous>:15:3) at <anonymous> description : Error: MyError at foo (<anonymous>:13:11) at throwError (<anonymous>:15:3)
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -89,7 +89,7 @@ Running test: testRejectedPromiseWithSyntaxError ...@@ -89,7 +89,7 @@ Running test: testRejectedPromiseWithSyntaxError
columnNumber : 5 columnNumber : 5
exception : { exception : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token } at foo (<anonymous>:21:5) at throwSyntaxError (<anonymous>:23:3) at <anonymous> description : SyntaxError: Unexpected token } at foo (<anonymous>:21:5) at throwSyntaxError (<anonymous>:23:3)
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -104,14 +104,14 @@ Running test: testRejectedPromiseWithSyntaxError ...@@ -104,14 +104,14 @@ Running test: testRejectedPromiseWithSyntaxError
functionName : foo functionName : foo
lineNumber : 20 lineNumber : 20
scriptId : <scriptId> scriptId : <scriptId>
url : url :
} }
[1] : { [1] : {
columnNumber : 2 columnNumber : 2
functionName : throwSyntaxError functionName : throwSyntaxError
lineNumber : 22 lineNumber : 22
scriptId : <scriptId> scriptId : <scriptId>
url : url :
} }
] ]
} }
...@@ -119,7 +119,7 @@ Running test: testRejectedPromiseWithSyntaxError ...@@ -119,7 +119,7 @@ Running test: testRejectedPromiseWithSyntaxError
} }
result : { result : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token } at foo (<anonymous>:21:5) at throwSyntaxError (<anonymous>:23:3) at <anonymous> description : SyntaxError: Unexpected token } at foo (<anonymous>:21:5) at throwSyntaxError (<anonymous>:23:3)
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
......
...@@ -86,7 +86,7 @@ let buffer = builder.toBuffer(); ...@@ -86,7 +86,7 @@ let buffer = builder.toBuffer();
// Test async compilation and instantiation. // Test async compilation and instantiation.
assertPromiseResult(WebAssembly.instantiate(buffer), pair => { assertPromiseResult(WebAssembly.instantiate(buffer), pair => {
testTrapLocations(pair.instance, 6); testTrapLocations(pair.instance, 5);
}); });
// Test sync compilation and instantiation. // Test sync compilation and instantiation.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment