Revert "[builtins] Mega-revert to address the Dev blocker in crbug.com/808911."
This reverts commit14108f4c2e
. Reason for revert: Not the culprit for Canary microtask crashes Original change's description: > [builtins] Mega-revert to address the Dev blocker in crbug.com/808911. > > - Revert "[builtins] Save one word in contexts for Promise.all." > This reverts commit7632da067b
. > - Revert "[builtins] Also use the Promise#then protector for Promise#finally()." > This reverts commitd4f072ced3
. > - Revert "[builtins] Don't mess with entered context for MicrotaskCallbacks." > This reverts commit6703dacdd6
. > - Revert "[debugger] Properly deal with settled promises in catch prediction." > This reverts commit40dd065823
. > - Revert "[builtins] Widen the fast-path for Promise builtins." > This reverts commitdb0556b7e8
. > - Revert "[builtins] Unify PerformPromiseThen and optimize it with TurboFan." > This reverts commita582199c5e
. > - Revert "[builtins] Remove obsolete PromiseBuiltinsAssembler::AppendPromiseCallback." > This reverts commit6bf8885290
. > - Revert "[builtins] Turn NewPromiseCapability into a proper builtin." > This reverts commit313b490ddd
. > - Revert "[builtins] Inline InternalPromiseThen into it's only caller" > This reverts commitf7bd6a2fd6
. > - Revert "[builtins] Implement Promise#catch by really calling into Promise#then." > This reverts commitb23b098fa0
. > - Revert "[promise] Remove incorrect fast path" > This reverts commit0f6eafe855
. > - Revert "[builtins] Squeeze JSPromise::result and JSPromise::reactions into a single field." > This reverts commit8a677a2831
. > - Revert "[builtins] Refactor promises to reduce GC overhead." > This reverts commit8e7737cb58
. > > Tbr: hpayer@chromium.org > Bug: chromium:800651, chromium:808911, v8:5691, v8:7253 > Change-Id: I8c8ea5ed32ed62f6cd8b0d027a3707ddd891e5f1 > Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng > Reviewed-on: https://chromium-review.googlesource.com/906991 > Commit-Queue: Yang Guo <yangguo@chromium.org> > Commit-Queue: Adam Klein <adamk@chromium.org> > Reviewed-by: Adam Klein <adamk@chromium.org> > Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> > Cr-Commit-Position: refs/heads/master@{#51158} Change-Id: I09d958cbebd635a325809072a290f2f53df8c5d4 Tbr: adamk@chromium.org,yangguo@chromium.org,bmeurer@chromium.org Bug: chromium:800651, chromium:808911, v8:5691, v8:7253 Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng Reviewed-on: https://chromium-review.googlesource.com/908988 Reviewed-by: Adam Klein <adamk@chromium.org> Commit-Queue: Adam Klein <adamk@chromium.org> Cr-Commit-Position: refs/heads/master@{#51181}
This commit is contained in:
parent
2ef90158fb
commit
3916401e4b
@ -7460,7 +7460,7 @@ class V8_EXPORT Isolate {
|
||||
/**
|
||||
* Enqueues the callback to the Microtask Work Queue
|
||||
*/
|
||||
void EnqueueMicrotask(MicrotaskCallback microtask, void* data = NULL);
|
||||
void EnqueueMicrotask(MicrotaskCallback callback, void* data = nullptr);
|
||||
|
||||
/**
|
||||
* Controls how Microtasks are invoked. See MicrotasksPolicy for details.
|
||||
|
20
src/api.cc
20
src/api.cc
@ -8705,22 +8705,20 @@ void Isolate::RunMicrotasks() {
|
||||
reinterpret_cast<i::Isolate*>(this)->RunMicrotasks();
|
||||
}
|
||||
|
||||
void Isolate::EnqueueMicrotask(Local<Function> microtask) {
|
||||
void Isolate::EnqueueMicrotask(Local<Function> function) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->EnqueueMicrotask(Utils::OpenHandle(*microtask));
|
||||
i::Handle<i::CallableTask> microtask = isolate->factory()->NewCallableTask(
|
||||
Utils::OpenHandle(*function), isolate->native_context());
|
||||
isolate->EnqueueMicrotask(microtask);
|
||||
}
|
||||
|
||||
void Isolate::EnqueueMicrotask(MicrotaskCallback microtask, void* data) {
|
||||
void Isolate::EnqueueMicrotask(MicrotaskCallback callback, void* data) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
i::HandleScope scope(isolate);
|
||||
i::Handle<i::CallHandlerInfo> callback_info =
|
||||
i::Handle<i::CallHandlerInfo>::cast(
|
||||
isolate->factory()->NewStruct(i::TUPLE3_TYPE, i::NOT_TENURED));
|
||||
SET_FIELD_WRAPPED(callback_info, set_callback, microtask);
|
||||
SET_FIELD_WRAPPED(callback_info, set_js_callback,
|
||||
callback_info->redirected_callback());
|
||||
SET_FIELD_WRAPPED(callback_info, set_data, data);
|
||||
isolate->EnqueueMicrotask(callback_info);
|
||||
i::Handle<i::CallbackTask> microtask = isolate->factory()->NewCallbackTask(
|
||||
isolate->factory()->NewForeign(reinterpret_cast<i::Address>(callback)),
|
||||
isolate->factory()->NewForeign(reinterpret_cast<i::Address>(data)));
|
||||
isolate->EnqueueMicrotask(microtask);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2361,12 +2361,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
isolate, Builtins::kPromiseGetCapabilitiesExecutor,
|
||||
factory->empty_string(), factory->Object_string(), 2);
|
||||
native_context()->set_promise_get_capabilities_executor_shared_fun(*info);
|
||||
|
||||
// %new_promise_capability(C, debugEvent)
|
||||
Handle<JSFunction> new_promise_capability =
|
||||
SimpleCreateFunction(isolate, factory->empty_string(),
|
||||
Builtins::kNewPromiseCapability, 2, false);
|
||||
native_context()->set_new_promise_capability(*new_promise_capability);
|
||||
}
|
||||
|
||||
{ // -- P r o m i s e
|
||||
@ -2426,10 +2420,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Handle<Map> prototype_map(prototype->map());
|
||||
Map::SetShouldBeFastPrototypeMap(prototype_map, true, isolate);
|
||||
|
||||
// Store the initial Promise.prototype map. This is used in fast-path
|
||||
// checks. Do not alter the prototype after this point.
|
||||
native_context()->set_promise_prototype_map(*prototype_map);
|
||||
|
||||
{ // Internal: PromiseInternalConstructor
|
||||
// Also exposed as extrasUtils.createPromise.
|
||||
Handle<JSFunction> function =
|
||||
@ -4437,7 +4427,6 @@ void Genesis::InitializeGlobal_harmony_promise_finally() {
|
||||
// to prototype, so we update the saved map.
|
||||
Handle<Map> prototype_map(prototype->map());
|
||||
Map::SetShouldBeFastPrototypeMap(prototype_map, true, isolate());
|
||||
native_context()->set_promise_prototype_map(*prototype_map);
|
||||
|
||||
{
|
||||
Handle<SharedFunctionInfo> info = SimpleCreateSharedFunctionInfo(
|
||||
|
@ -143,11 +143,8 @@ Node* AsyncBuiltinsAssembler::Await(
|
||||
|
||||
Goto(&do_perform_promise_then);
|
||||
BIND(&do_perform_promise_then);
|
||||
|
||||
CallBuiltin(Builtins::kPerformNativePromiseThen, context, wrapped_value,
|
||||
on_resolve, on_reject, throwaway);
|
||||
|
||||
return wrapped_value;
|
||||
return CallBuiltin(Builtins::kPerformPromiseThen, context, wrapped_value,
|
||||
on_resolve, on_reject, throwaway);
|
||||
}
|
||||
|
||||
void AsyncBuiltinsAssembler::InitializeNativeClosure(Node* context,
|
||||
|
@ -145,7 +145,7 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
|
||||
|
||||
// Perform ! PerformPromiseThen(valueWrapperCapability.[[Promise]],
|
||||
// onFulfilled, undefined, promiseCapability).
|
||||
Return(CallBuiltin(Builtins::kPerformNativePromiseThen, context, wrapper,
|
||||
Return(CallBuiltin(Builtins::kPerformPromiseThen, context, wrapper,
|
||||
on_fulfilled, UndefinedConstant(), promise));
|
||||
|
||||
BIND(&reject_promise);
|
||||
|
@ -219,11 +219,8 @@ namespace internal {
|
||||
/* Promise helpers */ \
|
||||
TFS(ResolveNativePromise, kPromise, kValue) \
|
||||
TFS(RejectNativePromise, kPromise, kValue, kDebugEvent) \
|
||||
TFS(PerformNativePromiseThen, kPromise, kResolveReaction, kRejectReaction, \
|
||||
kResultPromise) \
|
||||
TFS(EnqueueMicrotask, kMicrotask) \
|
||||
TFC(RunMicrotasks, RunMicrotasks, 1) \
|
||||
TFS(PromiseResolveThenableJob, kMicrotask) \
|
||||
\
|
||||
/* Object property helpers */ \
|
||||
TFS(HasProperty, kKey, kObject) \
|
||||
@ -802,7 +799,7 @@ namespace internal {
|
||||
/* ES6 #sec-getcapabilitiesexecutor-functions */ \
|
||||
TFJ(PromiseGetCapabilitiesExecutor, 2, kResolve, kReject) \
|
||||
/* ES6 #sec-newpromisecapability */ \
|
||||
TFJ(NewPromiseCapability, 2, kConstructor, kDebugEvent) \
|
||||
TFS(NewPromiseCapability, kConstructor, kDebugEvent) \
|
||||
/* ES6 #sec-promise-executor */ \
|
||||
TFJ(PromiseConstructor, 1, kExecutor) \
|
||||
TFJ(PromiseInternalConstructor, 1, kParent) \
|
||||
@ -813,14 +810,18 @@ namespace internal {
|
||||
TFJ(PromiseRejectClosure, 1, kValue) \
|
||||
TFJ(PromiseAllResolveElementClosure, 1, kValue) \
|
||||
/* ES #sec-promise.prototype.then */ \
|
||||
TFJ(PromisePrototypeThen, 2, kOnFullfilled, kOnRejected) \
|
||||
TFJ(PromisePrototypeThen, 2, kOnFulfilled, kOnRejected) \
|
||||
/* ES #sec-performpromisethen */ \
|
||||
TFS(PerformPromiseThen, kPromise, kOnFulfilled, kOnRejected, kResultPromise) \
|
||||
/* ES #sec-promise.prototype.catch */ \
|
||||
TFJ(PromisePrototypeCatch, 1, kOnRejected) \
|
||||
/* ES #sec-fulfillpromise */ \
|
||||
TFJ(ResolvePromise, 2, kPromise, kValue) \
|
||||
TFS(PromiseHandleReject, kPromise, kOnReject, kException) \
|
||||
TFS(PromiseHandle, kValue, kHandler, kDeferredPromise, kDeferredOnResolve, \
|
||||
kDeferredOnReject) \
|
||||
/* ES #sec-promisereactionjob */ \
|
||||
TFS(PromiseRejectReactionJob, kReason, kHandler, kPromiseOrCapability) \
|
||||
TFS(PromiseFulfillReactionJob, kValue, kHandler, kPromiseOrCapability) \
|
||||
/* ES #sec-promiseresolvethenablejob */ \
|
||||
TFS(PromiseResolveThenableJob, kPromiseToResolve, kThenable, kThen) \
|
||||
/* ES #sec-promise.resolve */ \
|
||||
TFJ(PromiseResolveWrapper, 1, kValue) \
|
||||
TFS(PromiseResolve, kConstructor, kValue) \
|
||||
@ -1247,10 +1248,9 @@ namespace internal {
|
||||
V(AsyncGeneratorResolve) \
|
||||
V(AsyncGeneratorAwaitCaught) \
|
||||
V(AsyncGeneratorAwaitUncaught) \
|
||||
V(PerformNativePromiseThen) \
|
||||
V(PromiseAll) \
|
||||
V(PromiseConstructor) \
|
||||
V(PromiseHandle) \
|
||||
V(PromiseFulfillReactionJob) \
|
||||
V(PromiseRace) \
|
||||
V(PromiseResolve) \
|
||||
V(PromiseResolveClosure) \
|
||||
@ -1260,7 +1260,7 @@ namespace internal {
|
||||
|
||||
// The exception thrown in the following builtins are caught internally and will
|
||||
// not be propagated further or re-thrown
|
||||
#define BUILTIN_EXCEPTION_CAUGHT_PREDICTION_LIST(V) V(PromiseHandleReject)
|
||||
#define BUILTIN_EXCEPTION_CAUGHT_PREDICTION_LIST(V) V(PromiseRejectReactionJob)
|
||||
|
||||
#define IGNORE_BUILTIN(...)
|
||||
|
||||
|
@ -628,6 +628,9 @@ class InternalBuiltinsAssembler : public CodeStubAssembler {
|
||||
void EnterMicrotaskContext(TNode<Context> context);
|
||||
void LeaveMicrotaskContext();
|
||||
|
||||
void RunPromiseHook(Runtime::FunctionId id, TNode<Context> context,
|
||||
SloppyTNode<HeapObject> promise_or_capability);
|
||||
|
||||
TNode<Object> GetPendingException() {
|
||||
auto ref = ExternalReference(kPendingExceptionAddress, isolate());
|
||||
return TNode<Object>::UncheckedCast(
|
||||
@ -745,6 +748,28 @@ void InternalBuiltinsAssembler::LeaveMicrotaskContext() {
|
||||
}
|
||||
}
|
||||
|
||||
void InternalBuiltinsAssembler::RunPromiseHook(
|
||||
Runtime::FunctionId id, TNode<Context> context,
|
||||
SloppyTNode<HeapObject> promise_or_capability) {
|
||||
Label hook(this, Label::kDeferred), done_hook(this);
|
||||
Branch(IsPromiseHookEnabledOrDebugIsActive(), &hook, &done_hook);
|
||||
BIND(&hook);
|
||||
{
|
||||
// Get to the underlying JSPromise instance.
|
||||
Node* const promise =
|
||||
Select(IsJSPromise(promise_or_capability),
|
||||
[=] { return promise_or_capability; },
|
||||
[=] {
|
||||
return LoadObjectField(promise_or_capability,
|
||||
PromiseCapability::kPromiseOffset);
|
||||
},
|
||||
MachineRepresentation::kTagged);
|
||||
CallRuntime(id, context, promise);
|
||||
Goto(&done_hook);
|
||||
}
|
||||
BIND(&done_hook);
|
||||
}
|
||||
|
||||
TF_BUILTIN(EnqueueMicrotask, InternalBuiltinsAssembler) {
|
||||
Node* microtask = Parameter(Descriptor::kMicrotask);
|
||||
|
||||
@ -820,7 +845,7 @@ TF_BUILTIN(RunMicrotasks, InternalBuiltinsAssembler) {
|
||||
BIND(&init_queue_loop);
|
||||
{
|
||||
TVARIABLE(IntPtrT, index, IntPtrConstant(0));
|
||||
Label loop(this, &index);
|
||||
Label loop(this, &index), loop_next(this);
|
||||
|
||||
TNode<IntPtrT> num_tasks = GetPendingMicrotaskCount();
|
||||
ReturnIf(IntPtrEqual(num_tasks, IntPtrConstant(0)), UndefinedConstant());
|
||||
@ -847,31 +872,54 @@ TF_BUILTIN(RunMicrotasks, InternalBuiltinsAssembler) {
|
||||
TNode<Map> microtask_map = LoadMap(microtask);
|
||||
TNode<Int32T> microtask_type = LoadMapInstanceType(microtask_map);
|
||||
|
||||
Label is_call_handler_info(this);
|
||||
Label is_function(this);
|
||||
Label is_promise_resolve_thenable_job(this);
|
||||
Label is_promise_reaction_job(this);
|
||||
Label is_unreachable(this);
|
||||
|
||||
int32_t case_values[] = {TUPLE3_TYPE, // CallHandlerInfo
|
||||
JS_FUNCTION_TYPE,
|
||||
PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE,
|
||||
PROMISE_REACTION_JOB_INFO_TYPE};
|
||||
|
||||
Label* case_labels[] = {&is_call_handler_info, &is_function,
|
||||
&is_promise_resolve_thenable_job,
|
||||
&is_promise_reaction_job};
|
||||
VARIABLE(var_exception, MachineRepresentation::kTagged,
|
||||
TheHoleConstant());
|
||||
Label if_exception(this, Label::kDeferred);
|
||||
Label is_callable(this), is_callback(this),
|
||||
is_promise_fulfill_reaction_job(this),
|
||||
is_promise_reject_reaction_job(this),
|
||||
is_promise_resolve_thenable_job(this),
|
||||
is_unreachable(this, Label::kDeferred);
|
||||
|
||||
int32_t case_values[] = {CALLABLE_TASK_TYPE, CALLBACK_TASK_TYPE,
|
||||
PROMISE_FULFILL_REACTION_JOB_TASK_TYPE,
|
||||
PROMISE_REJECT_REACTION_JOB_TASK_TYPE,
|
||||
PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE};
|
||||
Label* case_labels[] = {
|
||||
&is_callable, &is_callback, &is_promise_fulfill_reaction_job,
|
||||
&is_promise_reject_reaction_job, &is_promise_resolve_thenable_job};
|
||||
static_assert(arraysize(case_values) == arraysize(case_labels), "");
|
||||
Switch(microtask_type, &is_unreachable, case_values, case_labels,
|
||||
arraysize(case_labels));
|
||||
|
||||
BIND(&is_call_handler_info);
|
||||
BIND(&is_callable);
|
||||
{
|
||||
// Enter the context of the {microtask}.
|
||||
TNode<Context> microtask_context = TNode<Context>::UncheckedCast(
|
||||
LoadObjectField(microtask, CallableTask::kContextOffset));
|
||||
TNode<Context> native_context =
|
||||
TNode<Context>::UncheckedCast(LoadNativeContext(microtask_context));
|
||||
CSA_ASSERT(this, IsNativeContext(native_context));
|
||||
EnterMicrotaskContext(microtask_context);
|
||||
SetCurrentContext(native_context);
|
||||
|
||||
TNode<JSReceiver> callable = TNode<JSReceiver>::UncheckedCast(
|
||||
LoadObjectField(microtask, CallableTask::kCallableOffset));
|
||||
Node* const result = CallJS(
|
||||
CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
|
||||
microtask_context, callable, UndefinedConstant());
|
||||
GotoIfException(result, &if_exception, &var_exception);
|
||||
LeaveMicrotaskContext();
|
||||
SetCurrentContext(current_context);
|
||||
Goto(&loop_next);
|
||||
}
|
||||
|
||||
BIND(&is_callback);
|
||||
{
|
||||
Node* const microtask_callback =
|
||||
LoadObjectField(microtask, CallHandlerInfo::kCallbackOffset);
|
||||
LoadObjectField(microtask, CallbackTask::kCallbackOffset);
|
||||
Node* const microtask_data =
|
||||
LoadObjectField(microtask, CallHandlerInfo::kDataOffset);
|
||||
LoadObjectField(microtask, CallbackTask::kDataOffset);
|
||||
|
||||
// If this turns out to become a bottleneck because of the calls
|
||||
// to C++ via CEntryStub, we can choose to speed them up using a
|
||||
@ -882,169 +930,131 @@ TF_BUILTIN(RunMicrotasks, InternalBuiltinsAssembler) {
|
||||
//
|
||||
// But from our current measurements it doesn't seem to be a
|
||||
// serious performance problem, even if the microtask is full
|
||||
// of CallHandlerInfo tasks (which is not a realistic use case
|
||||
// anyways).
|
||||
Label if_continue(this);
|
||||
Node* const result =
|
||||
CallRuntime(Runtime::kRunMicrotaskCallback, current_context,
|
||||
microtask_callback, microtask_data);
|
||||
GotoIfException(result, &if_continue);
|
||||
Goto(&if_continue);
|
||||
BIND(&if_continue);
|
||||
Branch(IntPtrLessThan(index, num_tasks), &loop, &init_queue_loop);
|
||||
}
|
||||
|
||||
BIND(&is_function);
|
||||
{
|
||||
Label cont(this);
|
||||
VARIABLE(exception, MachineRepresentation::kTagged, TheHoleConstant());
|
||||
TNode<Context> fn_context = TNode<Context>::UncheckedCast(
|
||||
LoadObjectField(microtask, JSFunction::kContextOffset));
|
||||
TNode<Context> native_context =
|
||||
TNode<Context>::UncheckedCast(LoadNativeContext(fn_context));
|
||||
SetCurrentContext(native_context);
|
||||
EnterMicrotaskContext(fn_context);
|
||||
Node* const call = CallJS(CodeFactory::Call(isolate()), native_context,
|
||||
microtask, UndefinedConstant());
|
||||
GotoIfException(call, &cont);
|
||||
Goto(&cont);
|
||||
BIND(&cont);
|
||||
LeaveMicrotaskContext();
|
||||
SetCurrentContext(current_context);
|
||||
Branch(IntPtrLessThan(index, num_tasks), &loop, &init_queue_loop);
|
||||
// of CallHandlerTasks (which is not a realistic use case anyways).
|
||||
CallRuntime(Runtime::kRunMicrotaskCallback, current_context,
|
||||
microtask_callback, microtask_data);
|
||||
Goto(&loop_next);
|
||||
}
|
||||
|
||||
BIND(&is_promise_resolve_thenable_job);
|
||||
{
|
||||
VARIABLE(exception, MachineRepresentation::kTagged, TheHoleConstant());
|
||||
// Enter the context of the {microtask}.
|
||||
TNode<Context> microtask_context =
|
||||
TNode<Context>::UncheckedCast(LoadObjectField(
|
||||
microtask, PromiseResolveThenableJobInfo::kContextOffset));
|
||||
microtask, PromiseResolveThenableJobTask::kContextOffset));
|
||||
TNode<Context> native_context =
|
||||
TNode<Context>::UncheckedCast(LoadNativeContext(microtask_context));
|
||||
SetCurrentContext(native_context);
|
||||
CSA_ASSERT(this, IsNativeContext(native_context));
|
||||
EnterMicrotaskContext(microtask_context);
|
||||
SetCurrentContext(native_context);
|
||||
|
||||
Label if_unhandled_exception(this), done(this);
|
||||
Node* const ret = CallBuiltin(Builtins::kPromiseResolveThenableJob,
|
||||
native_context, microtask);
|
||||
GotoIfException(ret, &if_unhandled_exception, &exception);
|
||||
Goto(&done);
|
||||
Node* const promise_to_resolve = LoadObjectField(
|
||||
microtask, PromiseResolveThenableJobTask::kPromiseToResolveOffset);
|
||||
Node* const then = LoadObjectField(
|
||||
microtask, PromiseResolveThenableJobTask::kThenOffset);
|
||||
Node* const thenable = LoadObjectField(
|
||||
microtask, PromiseResolveThenableJobTask::kThenableOffset);
|
||||
|
||||
BIND(&if_unhandled_exception);
|
||||
CallRuntime(Runtime::kReportMessage, native_context, exception.value());
|
||||
Goto(&done);
|
||||
|
||||
BIND(&done);
|
||||
Node* const result =
|
||||
CallBuiltin(Builtins::kPromiseResolveThenableJob, microtask_context,
|
||||
promise_to_resolve, thenable, then);
|
||||
GotoIfException(result, &if_exception, &var_exception);
|
||||
LeaveMicrotaskContext();
|
||||
SetCurrentContext(current_context);
|
||||
|
||||
Branch(IntPtrLessThan(index, num_tasks), &loop, &init_queue_loop);
|
||||
Goto(&loop_next);
|
||||
}
|
||||
|
||||
BIND(&is_promise_reaction_job);
|
||||
BIND(&is_promise_fulfill_reaction_job);
|
||||
{
|
||||
Label if_multiple(this);
|
||||
Label if_single(this);
|
||||
|
||||
Node* const value =
|
||||
LoadObjectField(microtask, PromiseReactionJobInfo::kValueOffset);
|
||||
Node* const tasks =
|
||||
LoadObjectField(microtask, PromiseReactionJobInfo::kTasksOffset);
|
||||
Node* const deferred_promises = LoadObjectField(
|
||||
microtask, PromiseReactionJobInfo::kDeferredPromiseOffset);
|
||||
Node* const deferred_on_resolves = LoadObjectField(
|
||||
microtask, PromiseReactionJobInfo::kDeferredOnResolveOffset);
|
||||
Node* const deferred_on_rejects = LoadObjectField(
|
||||
microtask, PromiseReactionJobInfo::kDeferredOnRejectOffset);
|
||||
|
||||
// Enter the context of the {microtask}.
|
||||
TNode<Context> microtask_context = TNode<Context>::UncheckedCast(
|
||||
LoadObjectField(microtask, PromiseReactionJobInfo::kContextOffset));
|
||||
LoadObjectField(microtask, PromiseReactionJobTask::kContextOffset));
|
||||
TNode<Context> native_context =
|
||||
TNode<Context>::UncheckedCast(LoadNativeContext(microtask_context));
|
||||
SetCurrentContext(native_context);
|
||||
CSA_ASSERT(this, IsNativeContext(native_context));
|
||||
EnterMicrotaskContext(microtask_context);
|
||||
SetCurrentContext(native_context);
|
||||
|
||||
Branch(IsFixedArray(deferred_promises), &if_multiple, &if_single);
|
||||
Node* const argument =
|
||||
LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset);
|
||||
Node* const handler =
|
||||
LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset);
|
||||
Node* const promise_or_capability = LoadObjectField(
|
||||
microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset);
|
||||
|
||||
BIND(&if_single);
|
||||
{
|
||||
CallBuiltin(Builtins::kPromiseHandle, native_context, value, tasks,
|
||||
deferred_promises, deferred_on_resolves,
|
||||
deferred_on_rejects);
|
||||
LeaveMicrotaskContext();
|
||||
SetCurrentContext(current_context);
|
||||
Branch(IntPtrLessThan(index, num_tasks), &loop, &init_queue_loop);
|
||||
}
|
||||
// Run the promise before/debug hook if enabled.
|
||||
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
|
||||
promise_or_capability);
|
||||
|
||||
BIND(&if_multiple);
|
||||
{
|
||||
TVARIABLE(IntPtrT, inner_index, IntPtrConstant(0));
|
||||
TNode<IntPtrT> inner_length =
|
||||
LoadAndUntagFixedArrayBaseLength(deferred_promises);
|
||||
Label inner_loop(this, &inner_index), done(this);
|
||||
Node* const result =
|
||||
CallBuiltin(Builtins::kPromiseFulfillReactionJob, microtask_context,
|
||||
argument, handler, promise_or_capability);
|
||||
GotoIfException(result, &if_exception, &var_exception);
|
||||
|
||||
CSA_ASSERT(this, IntPtrGreaterThan(inner_length, IntPtrConstant(0)));
|
||||
Goto(&inner_loop);
|
||||
BIND(&inner_loop);
|
||||
{
|
||||
Node* const task = LoadFixedArrayElement(tasks, inner_index);
|
||||
Node* const deferred_promise =
|
||||
LoadFixedArrayElement(deferred_promises, inner_index);
|
||||
Node* const deferred_on_resolve =
|
||||
LoadFixedArrayElement(deferred_on_resolves, inner_index);
|
||||
Node* const deferred_on_reject =
|
||||
LoadFixedArrayElement(deferred_on_rejects, inner_index);
|
||||
CallBuiltin(Builtins::kPromiseHandle, native_context, value, task,
|
||||
deferred_promise, deferred_on_resolve,
|
||||
deferred_on_reject);
|
||||
inner_index = IntPtrAdd(inner_index, IntPtrConstant(1));
|
||||
Branch(IntPtrLessThan(inner_index, inner_length), &inner_loop,
|
||||
&done);
|
||||
}
|
||||
BIND(&done);
|
||||
// Run the promise after/debug hook if enabled.
|
||||
RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
|
||||
promise_or_capability);
|
||||
|
||||
LeaveMicrotaskContext();
|
||||
SetCurrentContext(current_context);
|
||||
LeaveMicrotaskContext();
|
||||
SetCurrentContext(current_context);
|
||||
Goto(&loop_next);
|
||||
}
|
||||
|
||||
Branch(IntPtrLessThan(index, num_tasks), &loop, &init_queue_loop);
|
||||
}
|
||||
BIND(&is_promise_reject_reaction_job);
|
||||
{
|
||||
// Enter the context of the {microtask}.
|
||||
TNode<Context> microtask_context = TNode<Context>::UncheckedCast(
|
||||
LoadObjectField(microtask, PromiseReactionJobTask::kContextOffset));
|
||||
TNode<Context> native_context =
|
||||
TNode<Context>::UncheckedCast(LoadNativeContext(microtask_context));
|
||||
CSA_ASSERT(this, IsNativeContext(native_context));
|
||||
EnterMicrotaskContext(microtask_context);
|
||||
SetCurrentContext(native_context);
|
||||
|
||||
Node* const argument =
|
||||
LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset);
|
||||
Node* const handler =
|
||||
LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset);
|
||||
Node* const promise_or_capability = LoadObjectField(
|
||||
microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset);
|
||||
|
||||
// Run the promise before/debug hook if enabled.
|
||||
RunPromiseHook(Runtime::kPromiseHookBefore, microtask_context,
|
||||
promise_or_capability);
|
||||
|
||||
Node* const result =
|
||||
CallBuiltin(Builtins::kPromiseRejectReactionJob, microtask_context,
|
||||
argument, handler, promise_or_capability);
|
||||
GotoIfException(result, &if_exception, &var_exception);
|
||||
|
||||
// Run the promise after/debug hook if enabled.
|
||||
RunPromiseHook(Runtime::kPromiseHookAfter, microtask_context,
|
||||
promise_or_capability);
|
||||
|
||||
LeaveMicrotaskContext();
|
||||
SetCurrentContext(current_context);
|
||||
Goto(&loop_next);
|
||||
}
|
||||
|
||||
BIND(&is_unreachable);
|
||||
Unreachable();
|
||||
|
||||
BIND(&if_exception);
|
||||
{
|
||||
// Report unhandled exceptions from microtasks.
|
||||
CallRuntime(Runtime::kReportMessage, current_context,
|
||||
var_exception.value());
|
||||
LeaveMicrotaskContext();
|
||||
SetCurrentContext(current_context);
|
||||
Goto(&loop_next);
|
||||
}
|
||||
|
||||
BIND(&loop_next);
|
||||
Branch(IntPtrLessThan(index, num_tasks), &loop, &init_queue_loop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TF_BUILTIN(PromiseResolveThenableJob, InternalBuiltinsAssembler) {
|
||||
VARIABLE(exception, MachineRepresentation::kTagged, TheHoleConstant());
|
||||
Callable call = CodeFactory::Call(isolate());
|
||||
Label reject_promise(this, Label::kDeferred);
|
||||
TNode<PromiseResolveThenableJobInfo> microtask =
|
||||
TNode<PromiseResolveThenableJobInfo>::UncheckedCast(
|
||||
Parameter(Descriptor::kMicrotask));
|
||||
TNode<Context> context =
|
||||
TNode<Context>::UncheckedCast(Parameter(Descriptor::kContext));
|
||||
|
||||
TNode<JSReceiver> thenable = TNode<JSReceiver>::UncheckedCast(LoadObjectField(
|
||||
microtask, PromiseResolveThenableJobInfo::kThenableOffset));
|
||||
TNode<JSReceiver> then = TNode<JSReceiver>::UncheckedCast(
|
||||
LoadObjectField(microtask, PromiseResolveThenableJobInfo::kThenOffset));
|
||||
TNode<JSFunction> resolve = TNode<JSFunction>::UncheckedCast(LoadObjectField(
|
||||
microtask, PromiseResolveThenableJobInfo::kResolveOffset));
|
||||
TNode<JSFunction> reject = TNode<JSFunction>::UncheckedCast(
|
||||
LoadObjectField(microtask, PromiseResolveThenableJobInfo::kRejectOffset));
|
||||
|
||||
Node* const result = CallJS(call, context, then, thenable, resolve, reject);
|
||||
GotoIfException(result, &reject_promise, &exception);
|
||||
Return(UndefinedConstant());
|
||||
|
||||
BIND(&reject_promise);
|
||||
CallJS(call, context, reject, UndefinedConstant(), exception.value());
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
TF_BUILTIN(AbortJS, CodeStubAssembler) {
|
||||
Node* message = Parameter(Descriptor::kObject);
|
||||
Node* reason = SmiConstant(0);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,11 +29,8 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
|
||||
|
||||
protected:
|
||||
enum PromiseAllResolveElementContextSlots {
|
||||
// Whether the resolve callback was already called.
|
||||
kPromiseAllResolveElementAlreadyVisitedSlot = Context::MIN_CONTEXT_SLOTS,
|
||||
|
||||
// Index into the values array
|
||||
kPromiseAllResolveElementIndexSlot,
|
||||
// Index into the values array, or -1 if the callback was already called
|
||||
kPromiseAllResolveElementIndexSlot = Context::MIN_CONTEXT_SLOTS,
|
||||
|
||||
// Remaining elements count (mutable HeapNumber)
|
||||
kPromiseAllResolveElementRemainingElementsSlot,
|
||||
@ -90,8 +87,18 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
|
||||
Node* AllocateAndSetJSPromise(Node* context, v8::Promise::PromiseState status,
|
||||
Node* result);
|
||||
|
||||
Node* AllocatePromiseResolveThenableJobInfo(Node* result, Node* then,
|
||||
Node* resolve, Node* reject,
|
||||
Node* AllocatePromiseReaction(Node* next, Node* promise_or_capability,
|
||||
Node* fulfill_handler, Node* reject_handler);
|
||||
|
||||
Node* AllocatePromiseReactionJobTask(Heap::RootListIndex map_root_index,
|
||||
Node* context, Node* argument,
|
||||
Node* handler,
|
||||
Node* promise_or_capability);
|
||||
Node* AllocatePromiseReactionJobTask(Node* map, Node* context, Node* argument,
|
||||
Node* handler,
|
||||
Node* promise_or_capability);
|
||||
Node* AllocatePromiseResolveThenableJobTask(Node* promise_to_resolve,
|
||||
Node* then, Node* thenable,
|
||||
Node* context);
|
||||
|
||||
std::pair<Node*, Node*> CreatePromiseResolvingFunctions(
|
||||
@ -105,39 +112,41 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
|
||||
Node* CreatePromiseGetCapabilitiesExecutorContext(Node* native_context,
|
||||
Node* promise_capability);
|
||||
|
||||
Node* NewPromiseCapability(Node* context, Node* constructor,
|
||||
Node* debug_event = nullptr);
|
||||
|
||||
protected:
|
||||
void PromiseInit(Node* promise);
|
||||
|
||||
void PromiseSetHasHandler(Node* promise);
|
||||
void PromiseSetHandledHint(Node* promise);
|
||||
|
||||
void AppendPromiseCallback(int offset, compiler::Node* promise,
|
||||
compiler::Node* value);
|
||||
|
||||
Node* InternalPromiseThen(Node* context, Node* promise, Node* on_resolve,
|
||||
Node* on_reject);
|
||||
|
||||
Node* InternalPerformPromiseThen(Node* context, Node* promise,
|
||||
Node* on_resolve, Node* on_reject,
|
||||
Node* deferred_promise,
|
||||
Node* deferred_on_resolve,
|
||||
Node* deferred_on_reject);
|
||||
void PerformPromiseThen(Node* context, Node* promise, Node* on_fulfilled,
|
||||
Node* on_rejected,
|
||||
Node* result_promise_or_capability);
|
||||
|
||||
void InternalResolvePromise(Node* context, Node* promise, Node* result);
|
||||
|
||||
void BranchIfFastPath(Node* context, Node* promise, Label* if_isunmodified,
|
||||
Label* if_ismodified);
|
||||
|
||||
void BranchIfFastPath(Node* native_context, Node* promise_fun, Node* promise,
|
||||
Label* if_isunmodified, Label* if_ismodified);
|
||||
|
||||
Node* CreatePromiseContext(Node* native_context, int slots);
|
||||
void PromiseFulfill(Node* context, Node* promise, Node* result,
|
||||
v8::Promise::PromiseState status);
|
||||
|
||||
// We can shortcut the SpeciesConstructor on {promise_map} if it's
|
||||
// [[Prototype]] is the (initial) Promise.prototype and the @@species
|
||||
// protector is intact, as that guards the lookup path for the "constructor"
|
||||
// property on JSPromise instances which have the %PromisePrototype%.
|
||||
void BranchIfPromiseSpeciesLookupChainIntact(Node* native_context,
|
||||
Node* promise_map,
|
||||
Label* if_fast, Label* if_slow);
|
||||
|
||||
// We can skip the "then" lookup on {receiver_map} if it's [[Prototype]]
|
||||
// is the (initial) Promise.prototype and the Promise#then() protector
|
||||
// is intact, as that guards the lookup path for the "then" property
|
||||
// on JSPromise instances which have the (initial) %PromisePrototype%.
|
||||
void BranchIfPromiseThenLookupChainIntact(Node* native_context,
|
||||
Node* receiver_map, Label* if_fast,
|
||||
Label* if_slow);
|
||||
|
||||
template <typename... TArgs>
|
||||
Node* InvokeThen(Node* native_context, Node* receiver, TArgs... args);
|
||||
|
||||
void BranchIfAccessCheckFailed(Node* context, Node* native_context,
|
||||
Node* promise_constructor, Node* executor,
|
||||
Label* if_noaccess);
|
||||
@ -171,9 +180,13 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
|
||||
const NodeGenerator& handled_by);
|
||||
|
||||
Node* PromiseStatus(Node* promise);
|
||||
void PerformFulfillClosure(Node* context, Node* value, bool should_resolve);
|
||||
void PerformFulfillClosure(Node* context, Node* value,
|
||||
PromiseReaction::Type type);
|
||||
|
||||
void PromiseReactionJob(Node* context, Node* argument, Node* handler,
|
||||
Node* promise_or_capability,
|
||||
PromiseReaction::Type type);
|
||||
|
||||
private:
|
||||
Node* IsPromiseStatus(Node* actual, v8::Promise::PromiseState expected);
|
||||
void PromiseSetStatus(Node* promise, v8::Promise::PromiseState status);
|
||||
|
||||
|
@ -4177,6 +4177,13 @@ Node* CodeStubAssembler::IsNoElementsProtectorCellInvalid() {
|
||||
return WordEqual(cell_value, invalid);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::IsPromiseThenProtectorCellInvalid() {
|
||||
Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
|
||||
Node* cell = LoadRoot(Heap::kPromiseThenProtectorRootIndex);
|
||||
Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
|
||||
return WordEqual(cell_value, invalid);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::IsSpeciesProtectorCellInvalid() {
|
||||
Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
|
||||
Node* cell = LoadRoot(Heap::kSpeciesProtectorRootIndex);
|
||||
@ -4332,6 +4339,10 @@ Node* CodeStubAssembler::IsJSPromiseMap(Node* map) {
|
||||
return InstanceTypeEqual(LoadMapInstanceType(map), JS_PROMISE_TYPE);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::IsJSPromise(Node* object) {
|
||||
return IsJSPromiseMap(LoadMap(object));
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::IsJSProxy(Node* object) {
|
||||
return HasInstanceType(object, JS_PROXY_TYPE);
|
||||
}
|
||||
@ -4378,6 +4389,10 @@ Node* CodeStubAssembler::IsFixedArraySubclass(Node* object) {
|
||||
Int32Constant(LAST_FIXED_ARRAY_TYPE)));
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::IsPromiseCapability(Node* object) {
|
||||
return HasInstanceType(object, PROMISE_CAPABILITY_TYPE);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::IsPropertyArray(Node* object) {
|
||||
return HasInstanceType(object, PROPERTY_ARRAY_TYPE);
|
||||
}
|
||||
@ -7600,6 +7615,7 @@ void CodeStubAssembler::CheckForAssociatedProtector(Node* name,
|
||||
if_protector);
|
||||
GotoIf(WordEqual(name, LoadRoot(Heap::kis_concat_spreadable_symbolRootIndex)),
|
||||
if_protector);
|
||||
GotoIf(WordEqual(name, LoadRoot(Heap::kthen_stringRootIndex)), if_protector);
|
||||
// Fall through if no case matched.
|
||||
}
|
||||
|
||||
@ -10734,28 +10750,6 @@ Node* CodeStubAssembler::AllocateFunctionWithMapAndContext(Node* map,
|
||||
return fun;
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::AllocatePromiseReactionJobInfo(
|
||||
Node* value, Node* tasks, Node* deferred_promise, Node* deferred_on_resolve,
|
||||
Node* deferred_on_reject, Node* context) {
|
||||
Node* const result = Allocate(PromiseReactionJobInfo::kSize);
|
||||
StoreMapNoWriteBarrier(result, Heap::kPromiseReactionJobInfoMapRootIndex);
|
||||
StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kValueOffset,
|
||||
value);
|
||||
StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kTasksOffset,
|
||||
tasks);
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
result, PromiseReactionJobInfo::kDeferredPromiseOffset, deferred_promise);
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
result, PromiseReactionJobInfo::kDeferredOnResolveOffset,
|
||||
deferred_on_resolve);
|
||||
StoreObjectFieldNoWriteBarrier(
|
||||
result, PromiseReactionJobInfo::kDeferredOnRejectOffset,
|
||||
deferred_on_reject);
|
||||
StoreObjectFieldNoWriteBarrier(result, PromiseReactionJobInfo::kContextOffset,
|
||||
context);
|
||||
return result;
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::MarkerIsFrameType(Node* marker_or_function,
|
||||
StackFrame::Type frame_type) {
|
||||
return WordEqual(marker_or_function,
|
||||
|
@ -22,54 +22,49 @@ class StubCache;
|
||||
|
||||
enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
|
||||
#define HEAP_CONSTANT_LIST(V) \
|
||||
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
|
||||
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
|
||||
V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \
|
||||
V(BooleanMap, boolean_map, BooleanMap) \
|
||||
V(CodeMap, code_map, CodeMap) \
|
||||
V(EmptyPropertyDictionary, empty_property_dictionary, \
|
||||
EmptyPropertyDictionary) \
|
||||
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
|
||||
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
|
||||
EmptySlowElementDictionary) \
|
||||
V(empty_string, empty_string, EmptyString) \
|
||||
V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \
|
||||
V(FalseValue, false_value, False) \
|
||||
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
|
||||
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
|
||||
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
|
||||
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
|
||||
V(FunctionTemplateInfoMap, function_template_info_map, \
|
||||
FunctionTemplateInfoMap) \
|
||||
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
|
||||
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
|
||||
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
|
||||
V(length_string, length_string, LengthString) \
|
||||
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
|
||||
V(MetaMap, meta_map, MetaMap) \
|
||||
V(MinusZeroValue, minus_zero_value, MinusZero) \
|
||||
V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
|
||||
V(NanValue, nan_value, Nan) \
|
||||
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
|
||||
V(NullValue, null_value, Null) \
|
||||
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
|
||||
V(prototype_string, prototype_string, PrototypeString) \
|
||||
V(SpeciesProtector, species_protector, SpeciesProtector) \
|
||||
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
|
||||
V(SymbolMap, symbol_map, SymbolMap) \
|
||||
V(TheHoleValue, the_hole_value, TheHole) \
|
||||
V(TrueValue, true_value, True) \
|
||||
V(Tuple2Map, tuple2_map, Tuple2Map) \
|
||||
V(Tuple3Map, tuple3_map, Tuple3Map) \
|
||||
V(UndefinedValue, undefined_value, Undefined) \
|
||||
V(WeakCellMap, weak_cell_map, WeakCellMap) \
|
||||
V(SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfoMap) \
|
||||
V(promise_default_reject_handler_symbol, \
|
||||
promise_default_reject_handler_symbol, PromiseDefaultRejectHandlerSymbol) \
|
||||
V(promise_default_resolve_handler_symbol, \
|
||||
promise_default_resolve_handler_symbol, \
|
||||
PromiseDefaultResolveHandlerSymbol)
|
||||
#define HEAP_CONSTANT_LIST(V) \
|
||||
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
|
||||
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
|
||||
V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \
|
||||
V(BooleanMap, boolean_map, BooleanMap) \
|
||||
V(CodeMap, code_map, CodeMap) \
|
||||
V(EmptyPropertyDictionary, empty_property_dictionary, \
|
||||
EmptyPropertyDictionary) \
|
||||
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
|
||||
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
|
||||
EmptySlowElementDictionary) \
|
||||
V(empty_string, empty_string, EmptyString) \
|
||||
V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \
|
||||
V(FalseValue, false_value, False) \
|
||||
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
|
||||
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
|
||||
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
|
||||
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
|
||||
V(FunctionTemplateInfoMap, function_template_info_map, \
|
||||
FunctionTemplateInfoMap) \
|
||||
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
|
||||
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
|
||||
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
|
||||
V(length_string, length_string, LengthString) \
|
||||
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
|
||||
V(MetaMap, meta_map, MetaMap) \
|
||||
V(MinusZeroValue, minus_zero_value, MinusZero) \
|
||||
V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
|
||||
V(NanValue, nan_value, Nan) \
|
||||
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
|
||||
V(NullValue, null_value, Null) \
|
||||
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
|
||||
V(prototype_string, prototype_string, PrototypeString) \
|
||||
V(SpeciesProtector, species_protector, SpeciesProtector) \
|
||||
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
|
||||
V(SymbolMap, symbol_map, SymbolMap) \
|
||||
V(TheHoleValue, the_hole_value, TheHole) \
|
||||
V(TrueValue, true_value, True) \
|
||||
V(Tuple2Map, tuple2_map, Tuple2Map) \
|
||||
V(Tuple3Map, tuple3_map, Tuple3Map) \
|
||||
V(UndefinedValue, undefined_value, Undefined) \
|
||||
V(WeakCellMap, weak_cell_map, WeakCellMap) \
|
||||
V(SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfoMap)
|
||||
|
||||
// Returned from IteratorBuiltinsAssembler::GetIterator(). Struct is declared
|
||||
// here to simplify use in other generated builtins.
|
||||
@ -1126,6 +1121,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
Node* IsJSObjectMap(Node* map);
|
||||
Node* IsJSObject(Node* object);
|
||||
Node* IsJSPromiseMap(Node* map);
|
||||
Node* IsJSPromise(Node* object);
|
||||
Node* IsJSProxy(Node* object);
|
||||
Node* IsJSReceiverInstanceType(Node* instance_type);
|
||||
Node* IsJSReceiverMap(Node* map);
|
||||
@ -1145,6 +1141,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
Node* IsOneByteStringInstanceType(Node* instance_type);
|
||||
Node* IsPrimitiveInstanceType(Node* instance_type);
|
||||
Node* IsPrivateSymbol(Node* object);
|
||||
Node* IsPromiseCapability(Node* object);
|
||||
Node* IsPropertyArray(Node* object);
|
||||
Node* IsPropertyCell(Node* object);
|
||||
Node* IsPrototypeInitialArrayPrototype(Node* context, Node* map);
|
||||
@ -1154,7 +1151,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
Node* IsShortExternalStringInstanceType(Node* instance_type);
|
||||
Node* IsSpecialReceiverInstanceType(Node* instance_type);
|
||||
Node* IsSpecialReceiverMap(Node* map);
|
||||
Node* IsSpeciesProtectorCellInvalid();
|
||||
Node* IsStringInstanceType(Node* instance_type);
|
||||
Node* IsString(Node* object);
|
||||
Node* IsSymbolInstanceType(Node* instance_type);
|
||||
@ -1167,6 +1163,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
return IsSharedFunctionInfoMap(LoadMap(object));
|
||||
}
|
||||
|
||||
Node* IsPromiseThenProtectorCellInvalid();
|
||||
Node* IsSpeciesProtectorCellInvalid();
|
||||
|
||||
// True iff |object| is a Smi or a HeapNumber.
|
||||
Node* IsNumber(Node* object);
|
||||
// True iff |object| is a Smi or a HeapNumber or a BigInt.
|
||||
@ -1893,11 +1892,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
// Promise helpers
|
||||
Node* IsPromiseHookEnabledOrDebugIsActive();
|
||||
|
||||
Node* AllocatePromiseReactionJobInfo(Node* value, Node* tasks,
|
||||
Node* deferred_promise,
|
||||
Node* deferred_on_resolve,
|
||||
Node* deferred_on_reject, Node* context);
|
||||
|
||||
// Helpers for StackFrame markers.
|
||||
Node* MarkerIsFrameType(Node* marker_or_function,
|
||||
StackFrame::Type frame_type);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/compiler/js-call-reducer.h"
|
||||
|
||||
#include "src/api.h"
|
||||
#include "src/builtins/builtins-promise-gen.h"
|
||||
#include "src/builtins/builtins-utils.h"
|
||||
#include "src/code-factory.h"
|
||||
#include "src/code-stubs.h"
|
||||
@ -2977,6 +2978,12 @@ Reduction JSCallReducer::ReduceJSCall(Node* node) {
|
||||
return ReduceAsyncFunctionPromiseCreate(node);
|
||||
case Builtins::kAsyncFunctionPromiseRelease:
|
||||
return ReduceAsyncFunctionPromiseRelease(node);
|
||||
case Builtins::kPromisePrototypeCatch:
|
||||
return ReducePromisePrototypeCatch(node);
|
||||
case Builtins::kPromisePrototypeFinally:
|
||||
return ReducePromisePrototypeFinally(node);
|
||||
case Builtins::kPromisePrototypeThen:
|
||||
return ReducePromisePrototypeThen(node);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -3939,6 +3946,293 @@ Reduction JSCallReducer::ReduceAsyncFunctionPromiseRelease(Node* node) {
|
||||
return Replace(value);
|
||||
}
|
||||
|
||||
// ES section #sec-promise.prototype.catch
|
||||
Reduction JSCallReducer::ReducePromisePrototypeCatch(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
|
||||
CallParameters const& p = CallParametersOf(node->op());
|
||||
int arity = static_cast<int>(p.arity() - 2);
|
||||
Node* receiver = NodeProperties::GetValueInput(node, 1);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// Check that the Promise.then protector is intact. This protector guards
|
||||
// that all JSPromise instances whose [[Prototype]] is the initial
|
||||
// %PromisePrototype% yield the initial %PromisePrototype%.then method
|
||||
// when looking up "then".
|
||||
if (!isolate()->IsPromiseThenLookupChainIntact()) return NoChange();
|
||||
|
||||
// Check if we know something about {receiver} already.
|
||||
ZoneHandleSet<Map> receiver_maps;
|
||||
NodeProperties::InferReceiverMapsResult result =
|
||||
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
|
||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||
DCHECK_NE(0, receiver_maps.size());
|
||||
|
||||
// Check whether all {receiver_maps} are JSPromise maps and
|
||||
// have the initial Promise.prototype as their [[Prototype]].
|
||||
for (Handle<Map> receiver_map : receiver_maps) {
|
||||
if (!receiver_map->IsJSPromiseMap()) return NoChange();
|
||||
if (receiver_map->prototype() != native_context()->promise_prototype()) {
|
||||
return NoChange();
|
||||
}
|
||||
}
|
||||
|
||||
// Add a code dependency on the necessary protectors.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_then_protector());
|
||||
|
||||
// If the {receiver_maps} aren't reliable, we need to repeat the
|
||||
// map check here, guarded by the CALL_IC.
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
effect =
|
||||
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
|
||||
receiver_maps, p.feedback()),
|
||||
receiver, effect, control);
|
||||
}
|
||||
|
||||
// Massage the {node} to call "then" instead by first removing all inputs
|
||||
// following the onRejected parameter, and then filling up the parameters
|
||||
// to two inputs from the left with undefined.
|
||||
Node* target = jsgraph()->Constant(handle(native_context()->promise_then()));
|
||||
NodeProperties::ReplaceValueInput(node, target, 0);
|
||||
NodeProperties::ReplaceEffectInput(node, effect);
|
||||
for (; arity > 1; --arity) node->RemoveInput(3);
|
||||
for (; arity < 2; ++arity) {
|
||||
node->InsertInput(graph()->zone(), 2, jsgraph()->UndefinedConstant());
|
||||
}
|
||||
NodeProperties::ChangeOp(
|
||||
node, javascript()->Call(2 + arity, p.frequency(), p.feedback(),
|
||||
ConvertReceiverMode::kNotNullOrUndefined,
|
||||
p.speculation_mode()));
|
||||
Reduction const reduction = ReducePromisePrototypeThen(node);
|
||||
return reduction.Changed() ? reduction : Changed(node);
|
||||
}
|
||||
|
||||
// ES section #sec-promise.prototype.finally
|
||||
Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
|
||||
CallParameters const& p = CallParametersOf(node->op());
|
||||
int arity = static_cast<int>(p.arity() - 2);
|
||||
Node* receiver = NodeProperties::GetValueInput(node, 1);
|
||||
Node* on_finally = arity >= 1 ? NodeProperties::GetValueInput(node, 2)
|
||||
: jsgraph()->UndefinedConstant();
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// Check that promises aren't being observed through (debug) hooks.
|
||||
if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
|
||||
|
||||
// Check that the Promise#then protector is intact. This protector guards
|
||||
// that all JSPromise instances whose [[Prototype]] is the initial
|
||||
// %PromisePrototype% yield the initial %PromisePrototype%.then method
|
||||
// when looking up "then".
|
||||
if (!isolate()->IsPromiseThenLookupChainIntact()) return NoChange();
|
||||
|
||||
// Also check that the @@species protector is intact, which guards the
|
||||
// lookup of "constructor" on JSPromise instances, whoch [[Prototype]] is
|
||||
// the initial %PromisePrototype%, and the Symbol.species lookup on the
|
||||
// %PromisePrototype%.
|
||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
||||
|
||||
// Check if we know something about {receiver} already.
|
||||
ZoneHandleSet<Map> receiver_maps;
|
||||
NodeProperties::InferReceiverMapsResult result =
|
||||
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
|
||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||
DCHECK_NE(0, receiver_maps.size());
|
||||
|
||||
// Check whether all {receiver_maps} are JSPromise maps and
|
||||
// have the initial Promise.prototype as their [[Prototype]].
|
||||
for (Handle<Map> receiver_map : receiver_maps) {
|
||||
if (!receiver_map->IsJSPromiseMap()) return NoChange();
|
||||
if (receiver_map->prototype() != native_context()->promise_prototype()) {
|
||||
return NoChange();
|
||||
}
|
||||
}
|
||||
|
||||
// Add a code dependency on the necessary protectors.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->promise_then_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
||||
|
||||
// If the {receiver_maps} aren't reliable, we need to repeat the
|
||||
// map check here, guarded by the CALL_IC.
|
||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
effect =
|
||||
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
|
||||
receiver_maps, p.feedback()),
|
||||
receiver, effect, control);
|
||||
}
|
||||
|
||||
// Check if {on_finally} is callable, and if so wrap it into appropriate
|
||||
// closures that perform the finalization.
|
||||
Node* check = graph()->NewNode(simplified()->ObjectIsCallable(), on_finally);
|
||||
Node* branch =
|
||||
graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
|
||||
|
||||
Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
||||
Node* etrue = effect;
|
||||
Node* catch_true;
|
||||
Node* then_true;
|
||||
{
|
||||
Node* context = jsgraph()->HeapConstant(native_context());
|
||||
Node* constructor = jsgraph()->HeapConstant(
|
||||
handle(native_context()->promise_function(), isolate()));
|
||||
|
||||
// Allocate shared context for the closures below.
|
||||
context = etrue = graph()->NewNode(
|
||||
javascript()->CreateFunctionContext(
|
||||
PromiseBuiltinsAssembler::kPromiseFinallyContextLength,
|
||||
FUNCTION_SCOPE),
|
||||
context, context, etrue, if_true);
|
||||
etrue =
|
||||
graph()->NewNode(simplified()->StoreField(AccessBuilder::ForContextSlot(
|
||||
PromiseBuiltinsAssembler::kOnFinallySlot)),
|
||||
context, on_finally, etrue, if_true);
|
||||
etrue =
|
||||
graph()->NewNode(simplified()->StoreField(AccessBuilder::ForContextSlot(
|
||||
PromiseBuiltinsAssembler::kConstructorSlot)),
|
||||
context, constructor, etrue, if_true);
|
||||
|
||||
// Allocate the closure for the reject case.
|
||||
Handle<SharedFunctionInfo> catch_finally(
|
||||
native_context()->promise_catch_finally_shared_fun(), isolate());
|
||||
catch_true = etrue = graph()->NewNode(
|
||||
javascript()->CreateClosure(catch_finally), context, etrue, if_true);
|
||||
|
||||
// Allocate the closure for the fulfill case.
|
||||
Handle<SharedFunctionInfo> then_finally(
|
||||
native_context()->promise_then_finally_shared_fun(), isolate());
|
||||
then_true = etrue = graph()->NewNode(
|
||||
javascript()->CreateClosure(then_finally), context, etrue, if_true);
|
||||
}
|
||||
|
||||
Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
||||
Node* efalse = effect;
|
||||
Node* catch_false = on_finally;
|
||||
Node* then_false = on_finally;
|
||||
|
||||
control = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
||||
effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
|
||||
Node* catch_finally =
|
||||
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
|
||||
catch_true, catch_false, control);
|
||||
Node* then_finally =
|
||||
graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
|
||||
then_true, then_false, control);
|
||||
|
||||
// At this point we definitely know that {receiver} has one of the
|
||||
// {receiver_maps}, so insert a MapGuard as a hint for the lowering
|
||||
// of the call to "then" below.
|
||||
effect = graph()->NewNode(simplified()->MapGuard(receiver_maps), receiver,
|
||||
effect, control);
|
||||
|
||||
// Massage the {node} to call "then" instead by first removing all inputs
|
||||
// following the onFinally parameter, and then replacing the only parameter
|
||||
// input with the {on_finally} value.
|
||||
Node* target = jsgraph()->Constant(handle(native_context()->promise_then()));
|
||||
NodeProperties::ReplaceValueInput(node, target, 0);
|
||||
NodeProperties::ReplaceEffectInput(node, effect);
|
||||
NodeProperties::ReplaceControlInput(node, control);
|
||||
for (; arity > 2; --arity) node->RemoveInput(2);
|
||||
for (; arity < 2; ++arity)
|
||||
node->InsertInput(graph()->zone(), 2, then_finally);
|
||||
node->ReplaceInput(2, then_finally);
|
||||
node->ReplaceInput(3, catch_finally);
|
||||
NodeProperties::ChangeOp(
|
||||
node, javascript()->Call(2 + arity, p.frequency(), p.feedback(),
|
||||
ConvertReceiverMode::kNotNullOrUndefined,
|
||||
p.speculation_mode()));
|
||||
Reduction const reduction = ReducePromisePrototypeThen(node);
|
||||
return reduction.Changed() ? reduction : Changed(node);
|
||||
}
|
||||
|
||||
Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
|
||||
CallParameters const& p = CallParametersOf(node->op());
|
||||
Node* receiver = NodeProperties::GetValueInput(node, 1);
|
||||
Node* on_fulfilled = node->op()->ValueInputCount() > 2
|
||||
? NodeProperties::GetValueInput(node, 2)
|
||||
: jsgraph()->UndefinedConstant();
|
||||
Node* on_rejected = node->op()->ValueInputCount() > 3
|
||||
? NodeProperties::GetValueInput(node, 3)
|
||||
: jsgraph()->UndefinedConstant();
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// Check that promises aren't being observed through (debug) hooks.
|
||||
if (!isolate()->IsPromiseHookProtectorIntact()) return NoChange();
|
||||
|
||||
// Check if the @@species protector is intact. The @@species protector
|
||||
// guards the "constructor" lookup on all JSPromise instances and the
|
||||
// initial Promise.prototype, as well as the Symbol.species lookup on
|
||||
// the Promise constructor.
|
||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
||||
|
||||
// Check if we know something about {receiver} already.
|
||||
ZoneHandleSet<Map> receiver_maps;
|
||||
NodeProperties::InferReceiverMapsResult infer_receiver_maps_result =
|
||||
NodeProperties::InferReceiverMaps(receiver, effect, &receiver_maps);
|
||||
if (infer_receiver_maps_result == NodeProperties::kNoReceiverMaps) {
|
||||
return NoChange();
|
||||
}
|
||||
DCHECK_NE(0, receiver_maps.size());
|
||||
|
||||
// Check whether all {receiver_maps} are JSPromise maps and
|
||||
// have the initial Promise.prototype as their [[Prototype]].
|
||||
for (Handle<Map> receiver_map : receiver_maps) {
|
||||
if (!receiver_map->IsJSPromiseMap()) return NoChange();
|
||||
if (receiver_map->prototype() != native_context()->promise_prototype()) {
|
||||
return NoChange();
|
||||
}
|
||||
}
|
||||
|
||||
// Add a code dependency on the necessary protectors.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
||||
|
||||
// If the {receiver_maps} aren't reliable, we need to repeat the
|
||||
// map check here, guarded by the CALL_IC.
|
||||
if (infer_receiver_maps_result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
effect =
|
||||
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
|
||||
receiver_maps, p.feedback()),
|
||||
receiver, effect, control);
|
||||
}
|
||||
|
||||
// Check that {on_fulfilled} is callable.
|
||||
on_fulfilled = graph()->NewNode(
|
||||
common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
|
||||
graph()->NewNode(simplified()->ObjectIsCallable(), on_fulfilled),
|
||||
on_fulfilled, jsgraph()->UndefinedConstant());
|
||||
|
||||
// Check that {on_rejected} is callable.
|
||||
on_rejected = graph()->NewNode(
|
||||
common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue),
|
||||
graph()->NewNode(simplified()->ObjectIsCallable(), on_rejected),
|
||||
on_rejected, jsgraph()->UndefinedConstant());
|
||||
|
||||
// Create the resulting JSPromise.
|
||||
Node* result = effect =
|
||||
graph()->NewNode(javascript()->CreatePromise(), context, effect);
|
||||
|
||||
// Chain {result} onto {receiver}.
|
||||
result = effect = graph()->NewNode(javascript()->PerformPromiseThen(),
|
||||
receiver, on_fulfilled, on_rejected,
|
||||
result, context, effect, control);
|
||||
ReplaceWithValue(node, result, effect, control);
|
||||
return Replace(result);
|
||||
}
|
||||
|
||||
Graph* JSCallReducer::graph() const { return jsgraph()->graph(); }
|
||||
|
||||
Isolate* JSCallReducer::isolate() const { return jsgraph()->isolate(); }
|
||||
|
@ -101,6 +101,9 @@ class JSCallReducer final : public AdvancedReducer {
|
||||
const Operator* string_access_operator, Node* node);
|
||||
Reduction ReduceAsyncFunctionPromiseCreate(Node* node);
|
||||
Reduction ReduceAsyncFunctionPromiseRelease(Node* node);
|
||||
Reduction ReducePromisePrototypeCatch(Node* node);
|
||||
Reduction ReducePromisePrototypeFinally(Node* node);
|
||||
Reduction ReducePromisePrototypeThen(Node* node);
|
||||
|
||||
Reduction ReduceSoftDeoptimize(Node* node, DeoptimizeReason reason);
|
||||
|
||||
|
@ -901,49 +901,59 @@ Reduction JSCreateLowering::ReduceJSCreateClosure(Node* node) {
|
||||
Node* effect = NodeProperties::GetEffectInput(node);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
Node* context = NodeProperties::GetContextInput(node);
|
||||
Node* feedback_vector = jsgraph()->UndefinedConstant();
|
||||
|
||||
// Use inline allocation of closures only for instantiation sites that have
|
||||
// seen more than one instantiation, this simplifies the generated code and
|
||||
// also serves as a heuristic of which allocation sites benefit from it.
|
||||
FeedbackSlot slot(FeedbackVector::ToSlot(p.feedback().index()));
|
||||
Handle<Cell> vector_cell(Cell::cast(p.feedback().vector()->Get(slot)));
|
||||
if (vector_cell->map() == isolate()->heap()->many_closures_cell_map()) {
|
||||
Handle<Map> function_map(
|
||||
Map::cast(native_context()->get(shared->function_map_index())));
|
||||
Node* lazy_compile_builtin = jsgraph()->HeapConstant(
|
||||
handle(isolate()->builtins()->builtin(Builtins::kCompileLazy)));
|
||||
DCHECK(!function_map->IsInobjectSlackTrackingInProgress());
|
||||
DCHECK(!function_map->is_dictionary_map());
|
||||
|
||||
// Emit code to allocate the JSFunction instance.
|
||||
STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize);
|
||||
AllocationBuilder a(jsgraph(), effect, control);
|
||||
a.Allocate(function_map->instance_size());
|
||||
a.Store(AccessBuilder::ForMap(), function_map);
|
||||
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
|
||||
jsgraph()->EmptyFixedArrayConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectElements(),
|
||||
jsgraph()->EmptyFixedArrayConstant());
|
||||
a.Store(AccessBuilder::ForJSFunctionSharedFunctionInfo(), shared);
|
||||
a.Store(AccessBuilder::ForJSFunctionContext(), context);
|
||||
a.Store(AccessBuilder::ForJSFunctionFeedbackVector(), vector_cell);
|
||||
a.Store(AccessBuilder::ForJSFunctionCode(), lazy_compile_builtin);
|
||||
STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize);
|
||||
if (function_map->has_prototype_slot()) {
|
||||
a.Store(AccessBuilder::ForJSFunctionPrototypeOrInitialMap(),
|
||||
jsgraph()->TheHoleConstant());
|
||||
STATIC_ASSERT(JSFunction::kSizeWithPrototype == 8 * kPointerSize);
|
||||
if (p.feedback().IsValid()) {
|
||||
FeedbackSlot slot(FeedbackVector::ToSlot(p.feedback().index()));
|
||||
Handle<Cell> vector_cell(Cell::cast(p.feedback().vector()->Get(slot)));
|
||||
if (vector_cell->map() != isolate()->heap()->many_closures_cell_map()) {
|
||||
return NoChange();
|
||||
}
|
||||
for (int i = 0; i < function_map->GetInObjectProperties(); i++) {
|
||||
a.Store(AccessBuilder::ForJSObjectInObjectProperty(function_map, i),
|
||||
jsgraph()->UndefinedConstant());
|
||||
}
|
||||
RelaxControls(node);
|
||||
a.FinishAndChange(node);
|
||||
return Changed(node);
|
||||
feedback_vector = jsgraph()->HeapConstant(vector_cell);
|
||||
} else {
|
||||
// CreateClosure without a feedback vector is only allowed for
|
||||
// native (builtin) functions.
|
||||
DCHECK(shared->native());
|
||||
}
|
||||
|
||||
return NoChange();
|
||||
Handle<Map> function_map(
|
||||
Map::cast(native_context()->get(shared->function_map_index())));
|
||||
Node* lazy_compile_builtin = jsgraph()->HeapConstant(handle(
|
||||
shared->native() ? shared->code()
|
||||
: isolate()->builtins()->builtin(Builtins::kCompileLazy),
|
||||
isolate()));
|
||||
DCHECK(!function_map->IsInobjectSlackTrackingInProgress());
|
||||
DCHECK(!function_map->is_dictionary_map());
|
||||
|
||||
// Emit code to allocate the JSFunction instance.
|
||||
STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize);
|
||||
AllocationBuilder a(jsgraph(), effect, control);
|
||||
a.Allocate(function_map->instance_size(), p.pretenure(), Type::Function());
|
||||
a.Store(AccessBuilder::ForMap(), function_map);
|
||||
a.Store(AccessBuilder::ForJSObjectPropertiesOrHash(),
|
||||
jsgraph()->EmptyFixedArrayConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectElements(),
|
||||
jsgraph()->EmptyFixedArrayConstant());
|
||||
a.Store(AccessBuilder::ForJSFunctionSharedFunctionInfo(), shared);
|
||||
a.Store(AccessBuilder::ForJSFunctionContext(), context);
|
||||
a.Store(AccessBuilder::ForJSFunctionFeedbackVector(), feedback_vector);
|
||||
a.Store(AccessBuilder::ForJSFunctionCode(), lazy_compile_builtin);
|
||||
STATIC_ASSERT(JSFunction::kSizeWithoutPrototype == 7 * kPointerSize);
|
||||
if (function_map->has_prototype_slot()) {
|
||||
a.Store(AccessBuilder::ForJSFunctionPrototypeOrInitialMap(),
|
||||
jsgraph()->TheHoleConstant());
|
||||
STATIC_ASSERT(JSFunction::kSizeWithPrototype == 8 * kPointerSize);
|
||||
}
|
||||
for (int i = 0; i < function_map->GetInObjectProperties(); i++) {
|
||||
a.Store(AccessBuilder::ForJSObjectInObjectProperty(function_map, i),
|
||||
jsgraph()->UndefinedConstant());
|
||||
}
|
||||
RelaxControls(node);
|
||||
a.FinishAndChange(node);
|
||||
return Changed(node);
|
||||
}
|
||||
|
||||
Reduction JSCreateLowering::ReduceJSCreateIterResultObject(Node* node) {
|
||||
@ -1013,22 +1023,12 @@ Reduction JSCreateLowering::ReduceJSCreatePromise(Node* node) {
|
||||
jsgraph()->EmptyFixedArrayConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectElements(),
|
||||
jsgraph()->EmptyFixedArrayConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kResultOffset),
|
||||
jsgraph()->UndefinedConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kDeferredPromiseOffset),
|
||||
jsgraph()->UndefinedConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kDeferredOnResolveOffset),
|
||||
jsgraph()->UndefinedConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kDeferredOnRejectOffset),
|
||||
jsgraph()->UndefinedConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kFulfillReactionsOffset),
|
||||
jsgraph()->UndefinedConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kRejectReactionsOffset),
|
||||
jsgraph()->UndefinedConstant());
|
||||
a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kReactionsOrResultOffset),
|
||||
jsgraph()->ZeroConstant());
|
||||
STATIC_ASSERT(v8::Promise::kPending == 0);
|
||||
a.Store(AccessBuilder::ForJSObjectOffset(JSPromise::kFlagsOffset),
|
||||
jsgraph()->ZeroConstant());
|
||||
STATIC_ASSERT(JSPromise::kSize == 10 * kPointerSize);
|
||||
STATIC_ASSERT(JSPromise::kSize == 5 * kPointerSize);
|
||||
for (int i = 0; i < v8::Promise::kEmbedderFieldCount; ++i) {
|
||||
a.Store(
|
||||
AccessBuilder::ForJSObjectOffset(JSPromise::kSize + i * kPointerSize),
|
||||
|
@ -766,6 +766,13 @@ void JSGenericLowering::LowerJSDebugger(Node* node) {
|
||||
ReplaceWithStubCall(node, callable, flags);
|
||||
}
|
||||
|
||||
void JSGenericLowering::LowerJSPerformPromiseThen(Node* node) {
|
||||
CallDescriptor::Flags flags = FrameStateFlagForCall(node);
|
||||
Callable callable =
|
||||
Builtins::CallableFor(isolate(), Builtins::kPerformPromiseThen);
|
||||
ReplaceWithStubCall(node, callable, flags);
|
||||
}
|
||||
|
||||
Zone* JSGenericLowering::zone() const { return graph()->zone(); }
|
||||
|
||||
|
||||
|
@ -543,44 +543,45 @@ CompareOperationHint CompareOperationHintOf(const Operator* op) {
|
||||
return OpParameter<CompareOperationHint>(op);
|
||||
}
|
||||
|
||||
#define CACHED_OP_LIST(V) \
|
||||
V(BitwiseOr, Operator::kNoProperties, 2, 1) \
|
||||
V(BitwiseXor, Operator::kNoProperties, 2, 1) \
|
||||
V(BitwiseAnd, Operator::kNoProperties, 2, 1) \
|
||||
V(ShiftLeft, Operator::kNoProperties, 2, 1) \
|
||||
V(ShiftRight, Operator::kNoProperties, 2, 1) \
|
||||
V(ShiftRightLogical, Operator::kNoProperties, 2, 1) \
|
||||
V(Subtract, Operator::kNoProperties, 2, 1) \
|
||||
V(Multiply, Operator::kNoProperties, 2, 1) \
|
||||
V(Divide, Operator::kNoProperties, 2, 1) \
|
||||
V(Modulus, Operator::kNoProperties, 2, 1) \
|
||||
V(Exponentiate, Operator::kNoProperties, 2, 1) \
|
||||
V(BitwiseNot, Operator::kNoProperties, 1, 1) \
|
||||
V(Decrement, Operator::kNoProperties, 1, 1) \
|
||||
V(Increment, Operator::kNoProperties, 1, 1) \
|
||||
V(Negate, Operator::kNoProperties, 1, 1) \
|
||||
V(ToInteger, Operator::kNoProperties, 1, 1) \
|
||||
V(ToLength, Operator::kNoProperties, 1, 1) \
|
||||
V(ToName, Operator::kNoProperties, 1, 1) \
|
||||
V(ToNumber, Operator::kNoProperties, 1, 1) \
|
||||
V(ToNumeric, Operator::kNoProperties, 1, 1) \
|
||||
V(ToObject, Operator::kFoldable, 1, 1) \
|
||||
V(ToString, Operator::kNoProperties, 1, 1) \
|
||||
V(Create, Operator::kNoProperties, 2, 1) \
|
||||
V(CreateIterResultObject, Operator::kEliminatable, 2, 1) \
|
||||
V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \
|
||||
V(CreatePromise, Operator::kEliminatable, 0, 1) \
|
||||
V(HasProperty, Operator::kNoProperties, 2, 1) \
|
||||
V(HasInPrototypeChain, Operator::kNoProperties, 2, 1) \
|
||||
V(OrdinaryHasInstance, Operator::kNoProperties, 2, 1) \
|
||||
V(ForInEnumerate, Operator::kNoProperties, 1, 1) \
|
||||
V(LoadMessage, Operator::kNoThrow | Operator::kNoWrite, 0, 1) \
|
||||
V(StoreMessage, Operator::kNoRead | Operator::kNoThrow, 1, 0) \
|
||||
V(GeneratorRestoreContinuation, Operator::kNoThrow, 1, 1) \
|
||||
V(GeneratorRestoreContext, Operator::kNoThrow, 1, 1) \
|
||||
V(GeneratorRestoreInputOrDebugPos, Operator::kNoThrow, 1, 1) \
|
||||
V(StackCheck, Operator::kNoWrite, 0, 0) \
|
||||
V(Debugger, Operator::kNoProperties, 0, 0) \
|
||||
#define CACHED_OP_LIST(V) \
|
||||
V(BitwiseOr, Operator::kNoProperties, 2, 1) \
|
||||
V(BitwiseXor, Operator::kNoProperties, 2, 1) \
|
||||
V(BitwiseAnd, Operator::kNoProperties, 2, 1) \
|
||||
V(ShiftLeft, Operator::kNoProperties, 2, 1) \
|
||||
V(ShiftRight, Operator::kNoProperties, 2, 1) \
|
||||
V(ShiftRightLogical, Operator::kNoProperties, 2, 1) \
|
||||
V(Subtract, Operator::kNoProperties, 2, 1) \
|
||||
V(Multiply, Operator::kNoProperties, 2, 1) \
|
||||
V(Divide, Operator::kNoProperties, 2, 1) \
|
||||
V(Modulus, Operator::kNoProperties, 2, 1) \
|
||||
V(Exponentiate, Operator::kNoProperties, 2, 1) \
|
||||
V(BitwiseNot, Operator::kNoProperties, 1, 1) \
|
||||
V(Decrement, Operator::kNoProperties, 1, 1) \
|
||||
V(Increment, Operator::kNoProperties, 1, 1) \
|
||||
V(Negate, Operator::kNoProperties, 1, 1) \
|
||||
V(ToInteger, Operator::kNoProperties, 1, 1) \
|
||||
V(ToLength, Operator::kNoProperties, 1, 1) \
|
||||
V(ToName, Operator::kNoProperties, 1, 1) \
|
||||
V(ToNumber, Operator::kNoProperties, 1, 1) \
|
||||
V(ToNumeric, Operator::kNoProperties, 1, 1) \
|
||||
V(ToObject, Operator::kFoldable, 1, 1) \
|
||||
V(ToString, Operator::kNoProperties, 1, 1) \
|
||||
V(Create, Operator::kNoProperties, 2, 1) \
|
||||
V(CreateIterResultObject, Operator::kEliminatable, 2, 1) \
|
||||
V(CreateKeyValueArray, Operator::kEliminatable, 2, 1) \
|
||||
V(CreatePromise, Operator::kEliminatable, 0, 1) \
|
||||
V(HasProperty, Operator::kNoProperties, 2, 1) \
|
||||
V(HasInPrototypeChain, Operator::kNoProperties, 2, 1) \
|
||||
V(OrdinaryHasInstance, Operator::kNoProperties, 2, 1) \
|
||||
V(ForInEnumerate, Operator::kNoProperties, 1, 1) \
|
||||
V(LoadMessage, Operator::kNoThrow | Operator::kNoWrite, 0, 1) \
|
||||
V(StoreMessage, Operator::kNoRead | Operator::kNoThrow, 1, 0) \
|
||||
V(GeneratorRestoreContinuation, Operator::kNoThrow, 1, 1) \
|
||||
V(GeneratorRestoreContext, Operator::kNoThrow, 1, 1) \
|
||||
V(GeneratorRestoreInputOrDebugPos, Operator::kNoThrow, 1, 1) \
|
||||
V(StackCheck, Operator::kNoWrite, 0, 0) \
|
||||
V(Debugger, Operator::kNoProperties, 0, 0) \
|
||||
V(PerformPromiseThen, Operator::kNoDeopt | Operator::kNoThrow, 4, 1) \
|
||||
V(GetSuperConstructor, Operator::kNoWrite, 1, 1)
|
||||
|
||||
#define BINARY_OP_LIST(V) V(Add)
|
||||
|
@ -651,9 +651,10 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
|
||||
const Operator* CreateArguments(CreateArgumentsType type);
|
||||
const Operator* CreateArray(size_t arity, Handle<AllocationSite> site);
|
||||
const Operator* CreateBoundFunction(size_t arity, Handle<Map> map);
|
||||
const Operator* CreateClosure(Handle<SharedFunctionInfo> shared_info,
|
||||
VectorSlotPair const& feedback,
|
||||
PretenureFlag pretenure);
|
||||
const Operator* CreateClosure(
|
||||
Handle<SharedFunctionInfo> shared_info,
|
||||
VectorSlotPair const& feedback = VectorSlotPair(),
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
const Operator* CreateIterResultObject();
|
||||
const Operator* CreateKeyValueArray();
|
||||
const Operator* CreatePromise();
|
||||
@ -754,6 +755,8 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final
|
||||
const Operator* StackCheck();
|
||||
const Operator* Debugger();
|
||||
|
||||
const Operator* PerformPromiseThen();
|
||||
|
||||
const Operator* CreateFunctionContext(int slot_count, ScopeType scope_type);
|
||||
const Operator* CreateCatchContext(const Handle<String>& name,
|
||||
const Handle<ScopeInfo>& scope_info);
|
||||
|
@ -195,6 +195,7 @@
|
||||
V(JSGeneratorRestoreContext) \
|
||||
V(JSGeneratorRestoreRegister) \
|
||||
V(JSGeneratorRestoreInputOrDebugPos) \
|
||||
V(JSPerformPromiseThen) \
|
||||
V(JSStackCheck) \
|
||||
V(JSDebugger)
|
||||
|
||||
|
@ -1842,6 +1842,11 @@ Type* Typer::Visitor::TypeJSStackCheck(Node* node) { return Type::Any(); }
|
||||
|
||||
Type* Typer::Visitor::TypeJSDebugger(Node* node) { return Type::Any(); }
|
||||
|
||||
Type* Typer::Visitor::TypeJSPerformPromiseThen(Node* node) {
|
||||
// TODO(turbofan): Introduce a Type::Promise here.
|
||||
return Type::OtherObject();
|
||||
}
|
||||
|
||||
// Simplified operators.
|
||||
|
||||
Type* Typer::Visitor::TypeBooleanNot(Node* node) { return Type::Boolean(); }
|
||||
|
@ -299,8 +299,8 @@ Type::bitset BitsetType::Lub(i::Map* map) {
|
||||
case OBJECT_TEMPLATE_INFO_TYPE:
|
||||
case ALLOCATION_MEMENTO_TYPE:
|
||||
case ALIASED_ARGUMENTS_ENTRY_TYPE:
|
||||
case PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE:
|
||||
case PROMISE_REACTION_JOB_INFO_TYPE:
|
||||
case PROMISE_CAPABILITY_TYPE:
|
||||
case PROMISE_REACTION_TYPE:
|
||||
case DEBUG_INFO_TYPE:
|
||||
case STACK_FRAME_INFO_TYPE:
|
||||
case WEAK_CELL_TYPE:
|
||||
@ -314,6 +314,11 @@ Type::bitset BitsetType::Lub(i::Map* map) {
|
||||
case CONTEXT_EXTENSION_TYPE:
|
||||
case ASYNC_GENERATOR_REQUEST_TYPE:
|
||||
case CODE_DATA_CONTAINER_TYPE:
|
||||
case CALLBACK_TASK_TYPE:
|
||||
case CALLABLE_TASK_TYPE:
|
||||
case PROMISE_FULFILL_REACTION_JOB_TASK_TYPE:
|
||||
case PROMISE_REJECT_REACTION_JOB_TASK_TYPE:
|
||||
case PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
@ -853,6 +853,14 @@ void Verifier::Visitor::Check(Node* node, const AllNodes& all) {
|
||||
CheckNotTyped(node);
|
||||
break;
|
||||
|
||||
case IrOpcode::kJSPerformPromiseThen:
|
||||
CheckValueInputIs(node, 0, Type::Any());
|
||||
CheckValueInputIs(node, 1, Type::Any());
|
||||
CheckValueInputIs(node, 2, Type::Any());
|
||||
CheckValueInputIs(node, 3, Type::Any());
|
||||
CheckTypeIs(node, Type::OtherObject());
|
||||
break;
|
||||
|
||||
case IrOpcode::kComment:
|
||||
case IrOpcode::kDebugAbort:
|
||||
case IrOpcode::kDebugBreak:
|
||||
|
@ -334,7 +334,6 @@ enum ContextLookupFlags {
|
||||
V(PROMISE_ALL_RESOLVE_ELEMENT_SHARED_FUN, SharedFunctionInfo, \
|
||||
promise_all_resolve_element_shared_fun) \
|
||||
V(PROMISE_PROTOTYPE_INDEX, JSObject, promise_prototype) \
|
||||
V(PROMISE_PROTOTYPE_MAP_INDEX, Map, promise_prototype_map) \
|
||||
V(REGEXP_EXEC_FUNCTION_INDEX, JSFunction, regexp_exec_function) \
|
||||
V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \
|
||||
V(REGEXP_LAST_MATCH_INFO_INDEX, RegExpMatchInfo, regexp_last_match_info) \
|
||||
|
@ -1186,6 +1186,24 @@ Handle<Script> Factory::NewScript(Handle<String> source) {
|
||||
return script;
|
||||
}
|
||||
|
||||
Handle<CallableTask> Factory::NewCallableTask(Handle<JSReceiver> callable,
|
||||
Handle<Context> context) {
|
||||
DCHECK(callable->IsCallable());
|
||||
Handle<CallableTask> microtask =
|
||||
Handle<CallableTask>::cast(NewStruct(CALLABLE_TASK_TYPE));
|
||||
microtask->set_callable(*callable);
|
||||
microtask->set_context(*context);
|
||||
return microtask;
|
||||
}
|
||||
|
||||
Handle<CallbackTask> Factory::NewCallbackTask(Handle<Foreign> callback,
|
||||
Handle<Foreign> data) {
|
||||
Handle<CallbackTask> microtask =
|
||||
Handle<CallbackTask>::cast(NewStruct(CALLBACK_TASK_TYPE));
|
||||
microtask->set_callback(*callback);
|
||||
microtask->set_data(*data);
|
||||
return microtask;
|
||||
}
|
||||
|
||||
Handle<Foreign> Factory::NewForeign(Address addr, PretenureFlag pretenure) {
|
||||
CALL_HEAP_FUNCTION(isolate(),
|
||||
|
@ -388,6 +388,12 @@ class V8_EXPORT_PRIVATE Factory final {
|
||||
Handle<ByteArray> source_position_table,
|
||||
Handle<SimpleNumberDictionary> stack_frame_cache);
|
||||
|
||||
// Allocate various microtasks.
|
||||
Handle<CallableTask> NewCallableTask(Handle<JSReceiver> callable,
|
||||
Handle<Context> context);
|
||||
Handle<CallbackTask> NewCallbackTask(Handle<Foreign> callback,
|
||||
Handle<Foreign> data);
|
||||
|
||||
// Foreign objects are pretenured when allocated by the bootstrapper.
|
||||
Handle<Foreign> NewForeign(Address addr,
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
|
@ -237,8 +237,6 @@
|
||||
V(promise_forwarding_handler_symbol) \
|
||||
V(promise_handled_by_symbol) \
|
||||
V(promise_async_id_symbol) \
|
||||
V(promise_default_resolve_handler_symbol) \
|
||||
V(promise_default_reject_handler_symbol) \
|
||||
V(sealed_symbol) \
|
||||
V(stack_trace_symbol) \
|
||||
V(strict_function_transition_symbol) \
|
||||
|
@ -215,6 +215,7 @@ using v8::MemoryPressureLevel;
|
||||
V(PropertyCell, array_buffer_neutering_protector, \
|
||||
ArrayBufferNeuteringProtector) \
|
||||
V(PropertyCell, promise_hook_protector, PromiseHookProtector) \
|
||||
V(PropertyCell, promise_then_protector, PromiseThenProtector) \
|
||||
/* Special numbers */ \
|
||||
V(HeapNumber, nan_value, NanValue) \
|
||||
V(HeapNumber, hole_nan_value, HoleNanValue) \
|
||||
|
@ -643,6 +643,10 @@ void Heap::CreateInitialObjects() {
|
||||
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||
set_promise_hook_protector(*cell);
|
||||
|
||||
cell = factory->NewPropertyCell(factory->empty_string());
|
||||
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||
set_promise_then_protector(*cell);
|
||||
|
||||
set_serialized_objects(empty_fixed_array());
|
||||
set_serialized_global_proxy_sizes(empty_fixed_array());
|
||||
|
||||
|
@ -2058,39 +2058,30 @@ bool InternalPromiseHasUserDefinedRejectHandler(Isolate* isolate,
|
||||
return true;
|
||||
}
|
||||
|
||||
Handle<Object> queue(promise->reject_reactions(), isolate);
|
||||
Handle<Object> deferred_promise(promise->deferred_promise(), isolate);
|
||||
|
||||
if (queue->IsUndefined(isolate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (queue->IsCallable()) {
|
||||
return PromiseHandlerCheck(isolate, Handle<JSReceiver>::cast(queue),
|
||||
Handle<JSReceiver>::cast(deferred_promise));
|
||||
}
|
||||
|
||||
if (queue->IsSymbol()) {
|
||||
return InternalPromiseHasUserDefinedRejectHandler(
|
||||
isolate, Handle<JSPromise>::cast(deferred_promise));
|
||||
}
|
||||
|
||||
Handle<FixedArray> queue_arr = Handle<FixedArray>::cast(queue);
|
||||
Handle<FixedArray> deferred_promise_arr =
|
||||
Handle<FixedArray>::cast(deferred_promise);
|
||||
for (int i = 0; i < deferred_promise_arr->length(); i++) {
|
||||
Handle<JSReceiver> deferred_promise_item(
|
||||
JSReceiver::cast(deferred_promise_arr->get(i)));
|
||||
if (queue_arr->get(i)->IsSymbol()) {
|
||||
if (InternalPromiseHasUserDefinedRejectHandler(
|
||||
isolate, Handle<JSPromise>::cast(deferred_promise_item))) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
Handle<JSReceiver> queue_item(JSReceiver::cast(queue_arr->get(i)));
|
||||
if (PromiseHandlerCheck(isolate, queue_item, deferred_promise_item)) {
|
||||
return true;
|
||||
if (promise->status() == Promise::kPending) {
|
||||
for (Handle<Object> current(promise->reactions(), isolate);
|
||||
!current->IsSmi();) {
|
||||
Handle<PromiseReaction> reaction = Handle<PromiseReaction>::cast(current);
|
||||
Handle<HeapObject> promise_or_capability(
|
||||
reaction->promise_or_capability(), isolate);
|
||||
Handle<JSPromise> promise = Handle<JSPromise>::cast(
|
||||
promise_or_capability->IsJSPromise()
|
||||
? promise_or_capability
|
||||
: handle(Handle<PromiseCapability>::cast(promise_or_capability)
|
||||
->promise(),
|
||||
isolate));
|
||||
if (reaction->reject_handler()->IsUndefined(isolate)) {
|
||||
if (InternalPromiseHasUserDefinedRejectHandler(isolate, promise)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
Handle<JSReceiver> current_handler(
|
||||
JSReceiver::cast(reaction->reject_handler()), isolate);
|
||||
if (PromiseHandlerCheck(isolate, current_handler, promise)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
current = handle(reaction->next(), isolate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3495,6 +3486,13 @@ bool Isolate::IsPromiseHookProtectorIntact() {
|
||||
return is_promise_hook_protector_intact;
|
||||
}
|
||||
|
||||
bool Isolate::IsPromiseThenLookupChainIntact() {
|
||||
PropertyCell* promise_then_cell = heap()->promise_then_protector();
|
||||
bool is_promise_then_protector_intact =
|
||||
Smi::ToInt(promise_then_cell->value()) == kProtectorValid;
|
||||
return is_promise_then_protector_intact;
|
||||
}
|
||||
|
||||
void Isolate::UpdateNoElementsProtectorOnSetElement(Handle<JSObject> object) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
if (!object->map()->is_prototype_map()) return;
|
||||
@ -3563,6 +3561,15 @@ void Isolate::InvalidatePromiseHookProtector() {
|
||||
DCHECK(!IsPromiseHookProtectorIntact());
|
||||
}
|
||||
|
||||
void Isolate::InvalidatePromiseThenProtector() {
|
||||
DCHECK(factory()->promise_then_protector()->value()->IsSmi());
|
||||
DCHECK(IsPromiseThenLookupChainIntact());
|
||||
PropertyCell::SetValueWithInvalidation(
|
||||
factory()->promise_then_protector(),
|
||||
handle(Smi::FromInt(kProtectorInvalid), this));
|
||||
DCHECK(!IsPromiseThenLookupChainIntact());
|
||||
}
|
||||
|
||||
bool Isolate::IsAnyInitialArrayPrototype(Handle<JSArray> array) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
return IsInAnyContext(*array, Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
|
||||
@ -3838,20 +3845,16 @@ void Isolate::ReportPromiseReject(Handle<JSPromise> promise,
|
||||
v8::Utils::StackTraceToLocal(stack_trace)));
|
||||
}
|
||||
|
||||
void Isolate::EnqueueMicrotask(Handle<Object> microtask) {
|
||||
DCHECK(microtask->IsJSFunction() || microtask->IsCallHandlerInfo() ||
|
||||
microtask->IsPromiseResolveThenableJobInfo() ||
|
||||
microtask->IsPromiseReactionJobInfo());
|
||||
void Isolate::EnqueueMicrotask(Handle<Microtask> microtask) {
|
||||
Handle<FixedArray> queue(heap()->microtask_queue(), this);
|
||||
int num_tasks = pending_microtask_count();
|
||||
DCHECK(num_tasks <= queue->length());
|
||||
if (num_tasks == 0) {
|
||||
queue = factory()->NewFixedArray(8);
|
||||
heap()->set_microtask_queue(*queue);
|
||||
} else if (num_tasks == queue->length()) {
|
||||
queue = factory()->CopyFixedArrayAndGrow(queue, num_tasks);
|
||||
DCHECK_LE(num_tasks, queue->length());
|
||||
if (num_tasks == queue->length()) {
|
||||
queue = factory()->CopyFixedArrayAndGrow(queue, std::max(num_tasks, 8));
|
||||
heap()->set_microtask_queue(*queue);
|
||||
}
|
||||
DCHECK_LE(8, queue->length());
|
||||
DCHECK_LT(num_tasks, queue->length());
|
||||
DCHECK(queue->get(num_tasks)->IsUndefined(this));
|
||||
queue->set(num_tasks, *microtask);
|
||||
set_pending_microtask_count(num_tasks + 1);
|
||||
|
@ -1106,6 +1106,10 @@ class Isolate {
|
||||
// active.
|
||||
bool IsPromiseHookProtectorIntact();
|
||||
|
||||
// Make sure a lookup of "then" on any JSPromise whose [[Prototype]] is the
|
||||
// initial %PromisePrototype% yields the initial method.
|
||||
bool IsPromiseThenLookupChainIntact();
|
||||
|
||||
// On intent to set an element in object, make sure that appropriate
|
||||
// notifications occur if the set is on the elements of the array or
|
||||
// object prototype. Also ensure that changes to prototype chain between
|
||||
@ -1127,6 +1131,7 @@ class Isolate {
|
||||
void InvalidateArrayIteratorProtector();
|
||||
void InvalidateArrayBufferNeuteringProtector();
|
||||
void InvalidatePromiseHookProtector();
|
||||
void InvalidatePromiseThenProtector();
|
||||
|
||||
// Returns true if array is the initial array prototype in any native context.
|
||||
bool IsAnyInitialArrayPrototype(Handle<JSArray> array);
|
||||
@ -1206,7 +1211,7 @@ class Isolate {
|
||||
void ReportPromiseReject(Handle<JSPromise> promise, Handle<Object> value,
|
||||
v8::PromiseRejectEvent event);
|
||||
|
||||
void EnqueueMicrotask(Handle<Object> microtask);
|
||||
void EnqueueMicrotask(Handle<Microtask> microtask);
|
||||
void RunMicrotasks();
|
||||
bool IsRunningMicrotasks() const { return is_running_microtasks_; }
|
||||
|
||||
|
@ -306,6 +306,14 @@ void LookupIterator::InternalUpdateProtector() {
|
||||
if (holder_->IsJSArray()) {
|
||||
isolate_->InvalidateArrayIteratorProtector();
|
||||
}
|
||||
} else if (*name_ == heap()->then_string()) {
|
||||
if (!isolate_->IsPromiseThenLookupChainIntact()) return;
|
||||
// Setting the "then" property on any JSPromise instance or on the
|
||||
// initial %PromisePrototype% invalidates the Promise#then protector.
|
||||
if (holder_->IsJSPromise() ||
|
||||
isolate_->IsInAnyContext(*holder_, Context::PROMISE_PROTOTYPE_INDEX)) {
|
||||
isolate_->InvalidatePromiseThenProtector();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,11 +275,12 @@ class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
|
||||
inline void UpdateProtector() {
|
||||
if (IsElement()) return;
|
||||
// This list must be kept in sync with
|
||||
// CodeStubAssembler::HasAssociatedProtector!
|
||||
// CodeStubAssembler::CheckForAssociatedProtector!
|
||||
if (*name_ == heap()->is_concat_spreadable_symbol() ||
|
||||
*name_ == heap()->constructor_string() ||
|
||||
*name_ == heap()->species_symbol() ||
|
||||
*name_ == heap()->iterator_symbol()) {
|
||||
*name_ == heap()->iterator_symbol() ||
|
||||
*name_ == heap()->then_string()) {
|
||||
InternalUpdateProtector();
|
||||
}
|
||||
}
|
||||
|
@ -1041,33 +1041,95 @@ void JSWeakSet::JSWeakSetVerify() {
|
||||
CHECK(table()->IsHashTable() || table()->IsUndefined(GetIsolate()));
|
||||
}
|
||||
|
||||
void Microtask::MicrotaskVerify() { CHECK(IsMicrotask()); }
|
||||
|
||||
void CallableTask::CallableTaskVerify() {
|
||||
CHECK(IsCallableTask());
|
||||
MicrotaskVerify();
|
||||
VerifyHeapPointer(callable());
|
||||
CHECK(callable()->IsCallable());
|
||||
VerifyHeapPointer(context());
|
||||
CHECK(context()->IsContext());
|
||||
}
|
||||
|
||||
void CallbackTask::CallbackTaskVerify() {
|
||||
CHECK(IsCallbackTask());
|
||||
MicrotaskVerify();
|
||||
VerifyHeapPointer(callback());
|
||||
VerifyHeapPointer(data());
|
||||
}
|
||||
|
||||
void PromiseReactionJobTask::PromiseReactionJobTaskVerify() {
|
||||
CHECK(IsPromiseReactionJobTask());
|
||||
MicrotaskVerify();
|
||||
Isolate* isolate = GetIsolate();
|
||||
VerifyPointer(argument());
|
||||
VerifyHeapPointer(context());
|
||||
CHECK(context()->IsContext());
|
||||
VerifyHeapPointer(handler());
|
||||
CHECK(handler()->IsUndefined(isolate) || handler()->IsCallable());
|
||||
VerifyHeapPointer(promise_or_capability());
|
||||
CHECK(promise_or_capability()->IsJSPromise() ||
|
||||
promise_or_capability()->IsPromiseCapability());
|
||||
}
|
||||
|
||||
void PromiseFulfillReactionJobTask::PromiseFulfillReactionJobTaskVerify() {
|
||||
CHECK(IsPromiseFulfillReactionJobTask());
|
||||
PromiseReactionJobTaskVerify();
|
||||
}
|
||||
|
||||
void PromiseRejectReactionJobTask::PromiseRejectReactionJobTaskVerify() {
|
||||
CHECK(IsPromiseRejectReactionJobTask());
|
||||
PromiseReactionJobTaskVerify();
|
||||
}
|
||||
|
||||
void PromiseResolveThenableJobTask::PromiseResolveThenableJobTaskVerify() {
|
||||
CHECK(IsPromiseResolveThenableJobTask());
|
||||
MicrotaskVerify();
|
||||
VerifyHeapPointer(context());
|
||||
CHECK(context()->IsContext());
|
||||
VerifyHeapPointer(promise_to_resolve());
|
||||
CHECK(promise_to_resolve()->IsJSPromise());
|
||||
VerifyHeapPointer(then());
|
||||
CHECK(then()->IsCallable());
|
||||
CHECK(then()->IsJSReceiver());
|
||||
VerifyHeapPointer(thenable());
|
||||
CHECK(thenable()->IsJSReceiver());
|
||||
}
|
||||
|
||||
void PromiseCapability::PromiseCapabilityVerify() {
|
||||
CHECK(IsPromiseCapability());
|
||||
VerifyPointer(promise());
|
||||
Isolate* isolate = GetIsolate();
|
||||
VerifyHeapPointer(promise());
|
||||
CHECK(promise()->IsJSReceiver() || promise()->IsUndefined(isolate));
|
||||
VerifyPointer(resolve());
|
||||
VerifyPointer(reject());
|
||||
}
|
||||
|
||||
void PromiseReaction::PromiseReactionVerify() {
|
||||
CHECK(IsPromiseReaction());
|
||||
Isolate* isolate = GetIsolate();
|
||||
VerifyPointer(next());
|
||||
CHECK(next()->IsSmi() || next()->IsPromiseReaction());
|
||||
VerifyHeapPointer(reject_handler());
|
||||
CHECK(reject_handler()->IsUndefined(isolate) ||
|
||||
reject_handler()->IsCallable());
|
||||
VerifyHeapPointer(fulfill_handler());
|
||||
CHECK(fulfill_handler()->IsUndefined(isolate) ||
|
||||
fulfill_handler()->IsCallable());
|
||||
VerifyHeapPointer(promise_or_capability());
|
||||
CHECK(promise_or_capability()->IsJSPromise() ||
|
||||
promise_or_capability()->IsPromiseCapability());
|
||||
}
|
||||
|
||||
void JSPromise::JSPromiseVerify() {
|
||||
CHECK(IsJSPromise());
|
||||
JSObjectVerify();
|
||||
Isolate* isolate = GetIsolate();
|
||||
CHECK(result()->IsUndefined(isolate) || result()->IsObject());
|
||||
CHECK(deferred_promise()->IsUndefined(isolate) ||
|
||||
deferred_promise()->IsJSReceiver() ||
|
||||
deferred_promise()->IsFixedArray());
|
||||
CHECK(deferred_on_resolve()->IsUndefined(isolate) ||
|
||||
deferred_on_resolve()->IsCallable() ||
|
||||
deferred_on_resolve()->IsFixedArray());
|
||||
CHECK(deferred_on_reject()->IsUndefined(isolate) ||
|
||||
deferred_on_reject()->IsCallable() ||
|
||||
deferred_on_reject()->IsFixedArray());
|
||||
CHECK(fulfill_reactions()->IsUndefined(isolate) ||
|
||||
fulfill_reactions()->IsCallable() || fulfill_reactions()->IsSymbol() ||
|
||||
fulfill_reactions()->IsFixedArray());
|
||||
CHECK(reject_reactions()->IsUndefined(isolate) ||
|
||||
reject_reactions()->IsSymbol() || reject_reactions()->IsCallable() ||
|
||||
reject_reactions()->IsFixedArray());
|
||||
VerifyPointer(reactions_or_result());
|
||||
VerifySmiField(kFlagsOffset);
|
||||
if (status() == Promise::kPending) {
|
||||
CHECK(reactions()->IsSmi() || reactions()->IsPromiseReaction());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
@ -1213,32 +1275,6 @@ void Foreign::ForeignVerify() {
|
||||
CHECK(IsForeign());
|
||||
}
|
||||
|
||||
void PromiseResolveThenableJobInfo::PromiseResolveThenableJobInfoVerify() {
|
||||
CHECK(IsPromiseResolveThenableJobInfo());
|
||||
CHECK(thenable()->IsJSReceiver());
|
||||
CHECK(then()->IsJSReceiver());
|
||||
CHECK(resolve()->IsJSFunction());
|
||||
CHECK(reject()->IsJSFunction());
|
||||
CHECK(context()->IsContext());
|
||||
}
|
||||
|
||||
void PromiseReactionJobInfo::PromiseReactionJobInfoVerify() {
|
||||
Isolate* isolate = GetIsolate();
|
||||
CHECK(IsPromiseReactionJobInfo());
|
||||
CHECK(value()->IsObject());
|
||||
CHECK(tasks()->IsFixedArray() || tasks()->IsCallable() ||
|
||||
tasks()->IsSymbol());
|
||||
CHECK(deferred_promise()->IsUndefined(isolate) ||
|
||||
deferred_promise()->IsJSReceiver() ||
|
||||
deferred_promise()->IsFixedArray());
|
||||
CHECK(deferred_on_resolve()->IsUndefined(isolate) ||
|
||||
deferred_on_resolve()->IsCallable() ||
|
||||
deferred_on_resolve()->IsFixedArray());
|
||||
CHECK(deferred_on_reject()->IsUndefined(isolate) ||
|
||||
deferred_on_reject()->IsCallable() ||
|
||||
deferred_on_reject()->IsFixedArray());
|
||||
CHECK(context()->IsContext());
|
||||
}
|
||||
|
||||
void AsyncGeneratorRequest::AsyncGeneratorRequestVerify() {
|
||||
CHECK(IsAsyncGeneratorRequest());
|
||||
|
@ -322,7 +322,15 @@ bool HeapObject::IsJSWeakCollection() const {
|
||||
|
||||
bool HeapObject::IsJSCollection() const { return IsJSMap() || IsJSSet(); }
|
||||
|
||||
bool HeapObject::IsPromiseCapability() const { return IsTuple3(); }
|
||||
bool HeapObject::IsMicrotask() const {
|
||||
InstanceType instance_type = map()->instance_type();
|
||||
return (instance_type >= FIRST_MICROTASK_TYPE &&
|
||||
instance_type <= LAST_MICROTASK_TYPE);
|
||||
}
|
||||
|
||||
bool HeapObject::IsPromiseReactionJobTask() const {
|
||||
return IsPromiseFulfillReactionJobTask() || IsPromiseRejectReactionJobTask();
|
||||
}
|
||||
|
||||
bool HeapObject::IsEnumCache() const { return IsTuple2(); }
|
||||
|
||||
@ -554,6 +562,7 @@ CAST_ACCESSOR(AllocationSite)
|
||||
CAST_ACCESSOR(AsyncGeneratorRequest)
|
||||
CAST_ACCESSOR(BigInt)
|
||||
CAST_ACCESSOR(BoilerplateDescription)
|
||||
CAST_ACCESSOR(CallbackTask)
|
||||
CAST_ACCESSOR(CallHandlerInfo)
|
||||
CAST_ACCESSOR(Cell)
|
||||
CAST_ACCESSOR(ConstantElementsPair)
|
||||
@ -561,6 +570,7 @@ CAST_ACCESSOR(ContextExtension)
|
||||
CAST_ACCESSOR(DescriptorArray)
|
||||
CAST_ACCESSOR(EnumCache)
|
||||
CAST_ACCESSOR(Foreign)
|
||||
CAST_ACCESSOR(CallableTask)
|
||||
CAST_ACCESSOR(FunctionTemplateInfo)
|
||||
CAST_ACCESSOR(GlobalDictionary)
|
||||
CAST_ACCESSOR(HeapObject)
|
||||
@ -582,6 +592,7 @@ CAST_ACCESSOR(JSReceiver)
|
||||
CAST_ACCESSOR(JSStringIterator)
|
||||
CAST_ACCESSOR(JSValue)
|
||||
CAST_ACCESSOR(LayoutDescriptor)
|
||||
CAST_ACCESSOR(Microtask)
|
||||
CAST_ACCESSOR(NameDictionary)
|
||||
CAST_ACCESSOR(NormalizedMapCache)
|
||||
CAST_ACCESSOR(NumberDictionary)
|
||||
@ -593,8 +604,11 @@ CAST_ACCESSOR(Oddball)
|
||||
CAST_ACCESSOR(OrderedHashMap)
|
||||
CAST_ACCESSOR(OrderedHashSet)
|
||||
CAST_ACCESSOR(PromiseCapability)
|
||||
CAST_ACCESSOR(PromiseReactionJobInfo)
|
||||
CAST_ACCESSOR(PromiseResolveThenableJobInfo)
|
||||
CAST_ACCESSOR(PromiseReaction)
|
||||
CAST_ACCESSOR(PromiseReactionJobTask)
|
||||
CAST_ACCESSOR(PromiseFulfillReactionJobTask)
|
||||
CAST_ACCESSOR(PromiseRejectReactionJobTask)
|
||||
CAST_ACCESSOR(PromiseResolveThenableJobTask)
|
||||
CAST_ACCESSOR(PropertyArray)
|
||||
CAST_ACCESSOR(PropertyCell)
|
||||
CAST_ACCESSOR(PrototypeInfo)
|
||||
@ -2277,21 +2291,11 @@ bool AccessorInfo::has_getter() {
|
||||
return result;
|
||||
}
|
||||
|
||||
ACCESSORS(PromiseResolveThenableJobInfo, thenable, JSReceiver, kThenableOffset)
|
||||
ACCESSORS(PromiseResolveThenableJobInfo, then, JSReceiver, kThenOffset)
|
||||
ACCESSORS(PromiseResolveThenableJobInfo, resolve, JSFunction, kResolveOffset)
|
||||
ACCESSORS(PromiseResolveThenableJobInfo, reject, JSFunction, kRejectOffset)
|
||||
ACCESSORS(PromiseResolveThenableJobInfo, context, Context, kContextOffset);
|
||||
|
||||
ACCESSORS(PromiseReactionJobInfo, value, Object, kValueOffset);
|
||||
ACCESSORS(PromiseReactionJobInfo, tasks, Object, kTasksOffset);
|
||||
ACCESSORS(PromiseReactionJobInfo, deferred_promise, Object,
|
||||
kDeferredPromiseOffset);
|
||||
ACCESSORS(PromiseReactionJobInfo, deferred_on_resolve, Object,
|
||||
kDeferredOnResolveOffset);
|
||||
ACCESSORS(PromiseReactionJobInfo, deferred_on_reject, Object,
|
||||
kDeferredOnRejectOffset);
|
||||
ACCESSORS(PromiseReactionJobInfo, context, Context, kContextOffset);
|
||||
ACCESSORS(PromiseReaction, next, Object, kNextOffset)
|
||||
ACCESSORS(PromiseReaction, reject_handler, HeapObject, kRejectHandlerOffset)
|
||||
ACCESSORS(PromiseReaction, fulfill_handler, HeapObject, kFulfillHandlerOffset)
|
||||
ACCESSORS(PromiseReaction, promise_or_capability, HeapObject,
|
||||
kPromiseOrCapabilityOffset)
|
||||
|
||||
ACCESSORS(AsyncGeneratorRequest, next, Object, kNextOffset)
|
||||
SMI_ACCESSORS(AsyncGeneratorRequest, resume_mode, kResumeModeOffset)
|
||||
@ -2809,20 +2813,42 @@ SMI_ACCESSORS(JSMessageObject, start_position, kStartPositionOffset)
|
||||
SMI_ACCESSORS(JSMessageObject, end_position, kEndPositionOffset)
|
||||
SMI_ACCESSORS(JSMessageObject, error_level, kErrorLevelOffset)
|
||||
|
||||
ACCESSORS(PromiseCapability, promise, Object, kPromiseOffset)
|
||||
ACCESSORS(CallableTask, callable, JSReceiver, kCallableOffset)
|
||||
ACCESSORS(CallableTask, context, Context, kContextOffset)
|
||||
|
||||
ACCESSORS(CallbackTask, callback, Foreign, kCallbackOffset)
|
||||
ACCESSORS(CallbackTask, data, Foreign, kDataOffset)
|
||||
|
||||
ACCESSORS(PromiseResolveThenableJobTask, context, Context, kContextOffset)
|
||||
ACCESSORS(PromiseResolveThenableJobTask, promise_to_resolve, JSPromise,
|
||||
kPromiseToResolveOffset)
|
||||
ACCESSORS(PromiseResolveThenableJobTask, then, JSReceiver, kThenOffset)
|
||||
ACCESSORS(PromiseResolveThenableJobTask, thenable, JSReceiver, kThenableOffset)
|
||||
|
||||
ACCESSORS(PromiseReactionJobTask, context, Context, kContextOffset)
|
||||
ACCESSORS(PromiseReactionJobTask, argument, Object, kArgumentOffset);
|
||||
ACCESSORS(PromiseReactionJobTask, handler, HeapObject, kHandlerOffset);
|
||||
ACCESSORS(PromiseReactionJobTask, promise_or_capability, HeapObject,
|
||||
kPromiseOrCapabilityOffset);
|
||||
|
||||
ACCESSORS(PromiseCapability, promise, HeapObject, kPromiseOffset)
|
||||
ACCESSORS(PromiseCapability, resolve, Object, kResolveOffset)
|
||||
ACCESSORS(PromiseCapability, reject, Object, kRejectOffset)
|
||||
|
||||
ACCESSORS(JSPromise, result, Object, kResultOffset)
|
||||
ACCESSORS(JSPromise, deferred_promise, Object, kDeferredPromiseOffset)
|
||||
ACCESSORS(JSPromise, deferred_on_resolve, Object, kDeferredOnResolveOffset)
|
||||
ACCESSORS(JSPromise, deferred_on_reject, Object, kDeferredOnRejectOffset)
|
||||
ACCESSORS(JSPromise, fulfill_reactions, Object, kFulfillReactionsOffset)
|
||||
ACCESSORS(JSPromise, reject_reactions, Object, kRejectReactionsOffset)
|
||||
ACCESSORS(JSPromise, reactions_or_result, Object, kReactionsOrResultOffset)
|
||||
SMI_ACCESSORS(JSPromise, flags, kFlagsOffset)
|
||||
BOOL_ACCESSORS(JSPromise, flags, has_handler, kHasHandlerBit)
|
||||
BOOL_ACCESSORS(JSPromise, flags, handled_hint, kHandledHintBit)
|
||||
|
||||
Object* JSPromise::result() const {
|
||||
DCHECK_NE(Promise::kPending, status());
|
||||
return reactions_or_result();
|
||||
}
|
||||
|
||||
Object* JSPromise::reactions() const {
|
||||
DCHECK_EQ(Promise::kPending, status());
|
||||
return reactions_or_result();
|
||||
}
|
||||
|
||||
ElementsKind JSObject::GetElementsKind() {
|
||||
ElementsKind kind = map()->elements_kind();
|
||||
|
@ -552,12 +552,11 @@ void JSArray::JSArrayPrint(std::ostream& os) { // NOLINT
|
||||
void JSPromise::JSPromisePrint(std::ostream& os) { // NOLINT
|
||||
JSObjectPrintHeader(os, this, "JSPromise");
|
||||
os << "\n - status = " << JSPromise::Status(status());
|
||||
os << "\n - result = " << Brief(result());
|
||||
os << "\n - deferred_promise: " << Brief(deferred_promise());
|
||||
os << "\n - deferred_on_resolve: " << Brief(deferred_on_resolve());
|
||||
os << "\n - deferred_on_reject: " << Brief(deferred_on_reject());
|
||||
os << "\n - fulfill_reactions = " << Brief(fulfill_reactions());
|
||||
os << "\n - reject_reactions = " << Brief(reject_reactions());
|
||||
if (status() == Promise::kPending) {
|
||||
os << "\n - reactions = " << Brief(reactions());
|
||||
} else {
|
||||
os << "\n - result = " << Brief(result());
|
||||
}
|
||||
os << "\n - has_handler = " << has_handler();
|
||||
os << "\n ";
|
||||
}
|
||||
@ -1340,6 +1339,50 @@ void AccessorInfo::AccessorInfoPrint(std::ostream& os) { // NOLINT
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void CallbackTask::CallbackTaskPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "CallbackTask");
|
||||
os << "\n - callback: " << Brief(callback());
|
||||
os << "\n - data: " << Brief(data());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void CallableTask::CallableTaskPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "CallableTask");
|
||||
os << "\n - context: " << Brief(context());
|
||||
os << "\n - callable: " << Brief(callable());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void PromiseFulfillReactionJobTask::PromiseFulfillReactionJobTaskPrint(
|
||||
std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PromiseFulfillReactionJobTask");
|
||||
os << "\n - argument: " << Brief(argument());
|
||||
os << "\n - context: " << Brief(context());
|
||||
os << "\n - handler: " << Brief(handler());
|
||||
os << "\n - promise_or_capability: " << Brief(promise_or_capability());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void PromiseRejectReactionJobTask::PromiseRejectReactionJobTaskPrint(
|
||||
std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PromiseRejectReactionJobTask");
|
||||
os << "\n - argument: " << Brief(argument());
|
||||
os << "\n - context: " << Brief(context());
|
||||
os << "\n - handler: " << Brief(handler());
|
||||
os << "\n - promise_or_capability: " << Brief(promise_or_capability());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void PromiseResolveThenableJobTask::PromiseResolveThenableJobTaskPrint(
|
||||
std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PromiseResolveThenableJobTask");
|
||||
os << "\n - context: " << Brief(context());
|
||||
os << "\n - promise_to_resolve: " << Brief(promise_to_resolve());
|
||||
os << "\n - then: " << Brief(then());
|
||||
os << "\n - thenable: " << Brief(thenable());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void PromiseCapability::PromiseCapabilityPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PromiseCapability");
|
||||
os << "\n - promise: " << Brief(promise());
|
||||
@ -1348,26 +1391,12 @@ void PromiseCapability::PromiseCapabilityPrint(std::ostream& os) { // NOLINT
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void PromiseResolveThenableJobInfo::PromiseResolveThenableJobInfoPrint(
|
||||
std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PromiseResolveThenableJobInfo");
|
||||
os << "\n - thenable: " << Brief(thenable());
|
||||
os << "\n - then: " << Brief(then());
|
||||
os << "\n - resolve: " << Brief(resolve());
|
||||
os << "\n - reject: " << Brief(reject());
|
||||
os << "\n - context: " << Brief(context());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void PromiseReactionJobInfo::PromiseReactionJobInfoPrint(
|
||||
std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PromiseReactionJobInfo");
|
||||
os << "\n - value: " << Brief(value());
|
||||
os << "\n - tasks: " << Brief(tasks());
|
||||
os << "\n - deferred_promise: " << Brief(deferred_promise());
|
||||
os << "\n - deferred_on_resolve: " << Brief(deferred_on_resolve());
|
||||
os << "\n - deferred_on_reject: " << Brief(deferred_on_reject());
|
||||
os << "\n - reaction context: " << Brief(context());
|
||||
void PromiseReaction::PromiseReactionPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PromiseReaction");
|
||||
os << "\n - next: " << Brief(next());
|
||||
os << "\n - reject_handler: " << Brief(reject_handler());
|
||||
os << "\n - fulfill_handler: " << Brief(fulfill_handler());
|
||||
os << "\n - promise_or_capability: " << Brief(promise_or_capability());
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
@ -3540,6 +3540,10 @@ void Tuple3::BriefPrintDetails(std::ostream& os) {
|
||||
<< Brief(value3());
|
||||
}
|
||||
|
||||
void CallableTask::BriefPrintDetails(std::ostream& os) {
|
||||
os << " callable=" << Brief(callable());
|
||||
}
|
||||
|
||||
void HeapObject::Iterate(ObjectVisitor* v) { IterateFast<ObjectVisitor>(v); }
|
||||
|
||||
|
||||
|
346
src/objects.h
346
src/objects.h
@ -140,8 +140,7 @@
|
||||
// - SharedFunctionInfo
|
||||
// - Struct
|
||||
// - AccessorInfo
|
||||
// - PromiseResolveThenableJobInfo
|
||||
// - PromiseReactionJobInfo
|
||||
// - PromiseReaction
|
||||
// - PromiseCapability
|
||||
// - AccessorPair
|
||||
// - AccessCheckInfo
|
||||
@ -159,6 +158,13 @@
|
||||
// - SourcePositionTableWithFrameCache
|
||||
// - CodeCache
|
||||
// - PrototypeInfo
|
||||
// - Microtask
|
||||
// - CallbackTask
|
||||
// - CallableTask
|
||||
// - PromiseReactionJobTask
|
||||
// - PromiseFulfillReactionJobTask
|
||||
// - PromiseRejectReactionJobTask
|
||||
// - PromiseResolveThenableJobTask
|
||||
// - Module
|
||||
// - ModuleInfoEntry
|
||||
// - PreParsedScopeData
|
||||
@ -367,14 +373,20 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(MODULE_INFO_ENTRY_TYPE) \
|
||||
V(MODULE_TYPE) \
|
||||
V(OBJECT_TEMPLATE_INFO_TYPE) \
|
||||
V(PROMISE_REACTION_JOB_INFO_TYPE) \
|
||||
V(PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE) \
|
||||
V(PROMISE_CAPABILITY_TYPE) \
|
||||
V(PROMISE_REACTION_TYPE) \
|
||||
V(PROTOTYPE_INFO_TYPE) \
|
||||
V(SCRIPT_TYPE) \
|
||||
V(STACK_FRAME_INFO_TYPE) \
|
||||
V(TUPLE2_TYPE) \
|
||||
V(TUPLE3_TYPE) \
|
||||
\
|
||||
V(CALLABLE_TASK_TYPE) \
|
||||
V(CALLBACK_TASK_TYPE) \
|
||||
V(PROMISE_FULFILL_REACTION_JOB_TASK_TYPE) \
|
||||
V(PROMISE_REJECT_REACTION_JOB_TASK_TYPE) \
|
||||
V(PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE) \
|
||||
\
|
||||
V(FIXED_ARRAY_TYPE) \
|
||||
V(DESCRIPTOR_ARRAY_TYPE) \
|
||||
V(HASH_TABLE_TYPE) \
|
||||
@ -555,15 +567,21 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1;
|
||||
V(MODULE_INFO_ENTRY, ModuleInfoEntry, module_info_entry) \
|
||||
V(MODULE, Module, module) \
|
||||
V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \
|
||||
V(PROMISE_REACTION_JOB_INFO, PromiseReactionJobInfo, \
|
||||
promise_reaction_job_info) \
|
||||
V(PROMISE_RESOLVE_THENABLE_JOB_INFO, PromiseResolveThenableJobInfo, \
|
||||
promise_resolve_thenable_job_info) \
|
||||
V(PROMISE_CAPABILITY, PromiseCapability, promise_capability) \
|
||||
V(PROMISE_REACTION, PromiseReaction, promise_reaction) \
|
||||
V(PROTOTYPE_INFO, PrototypeInfo, prototype_info) \
|
||||
V(SCRIPT, Script, script) \
|
||||
V(STACK_FRAME_INFO, StackFrameInfo, stack_frame_info) \
|
||||
V(TUPLE2, Tuple2, tuple2) \
|
||||
V(TUPLE3, Tuple3, tuple3)
|
||||
V(TUPLE3, Tuple3, tuple3) \
|
||||
V(CALLABLE_TASK, CallableTask, callable_task) \
|
||||
V(CALLBACK_TASK, CallbackTask, callback_task) \
|
||||
V(PROMISE_FULFILL_REACTION_JOB_TASK, PromiseFulfillReactionJobTask, \
|
||||
promise_fulfill_reaction_job_task) \
|
||||
V(PROMISE_REJECT_REACTION_JOB_TASK, PromiseRejectReactionJobTask, \
|
||||
promise_reject_reaction_job_task) \
|
||||
V(PROMISE_RESOLVE_THENABLE_JOB_TASK, PromiseResolveThenableJobTask, \
|
||||
promise_resolve_thenable_job_task)
|
||||
|
||||
#define DATA_HANDLER_LIST(V) \
|
||||
V(LOAD_HANDLER, LoadHandler, 1, load_handler1) \
|
||||
@ -737,14 +755,20 @@ enum InstanceType : uint16_t {
|
||||
MODULE_INFO_ENTRY_TYPE,
|
||||
MODULE_TYPE,
|
||||
OBJECT_TEMPLATE_INFO_TYPE,
|
||||
PROMISE_REACTION_JOB_INFO_TYPE,
|
||||
PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE,
|
||||
PROMISE_CAPABILITY_TYPE,
|
||||
PROMISE_REACTION_TYPE,
|
||||
PROTOTYPE_INFO_TYPE,
|
||||
SCRIPT_TYPE,
|
||||
STACK_FRAME_INFO_TYPE,
|
||||
TUPLE2_TYPE,
|
||||
TUPLE3_TYPE,
|
||||
|
||||
CALLABLE_TASK_TYPE, // FIRST_MICROTASK_TYPE
|
||||
CALLBACK_TASK_TYPE,
|
||||
PROMISE_FULFILL_REACTION_JOB_TASK_TYPE,
|
||||
PROMISE_REJECT_REACTION_JOB_TASK_TYPE,
|
||||
PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE, // LAST_MICROTASK_TYPE
|
||||
|
||||
// FixedArrays.
|
||||
FIXED_ARRAY_TYPE, // FIRST_FIXED_ARRAY_TYPE
|
||||
DESCRIPTOR_ARRAY_TYPE,
|
||||
@ -834,6 +858,9 @@ enum InstanceType : uint16_t {
|
||||
// Boundaries for testing if given HeapObject is a subclass of FixedArray.
|
||||
FIRST_FIXED_ARRAY_TYPE = FIXED_ARRAY_TYPE,
|
||||
LAST_FIXED_ARRAY_TYPE = TRANSITION_ARRAY_TYPE,
|
||||
// Boundaries for testing if given HeapObject is a subclass of Microtask.
|
||||
FIRST_MICROTASK_TYPE = CALLABLE_TASK_TYPE,
|
||||
LAST_MICROTASK_TYPE = PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE,
|
||||
// Boundaries for testing for a fixed typed array.
|
||||
FIRST_FIXED_TYPED_ARRAY_TYPE = FIXED_INT8_ARRAY_TYPE,
|
||||
LAST_FIXED_TYPED_ARRAY_TYPE = FIXED_UINT8_CLAMPED_ARRAY_TYPE,
|
||||
@ -911,6 +938,7 @@ class FixedArrayBase;
|
||||
class PropertyArray;
|
||||
class FunctionLiteral;
|
||||
class JSGlobalObject;
|
||||
class JSPromise;
|
||||
class KeyAccumulator;
|
||||
class LayoutDescriptor;
|
||||
class LookupIterator;
|
||||
@ -1046,6 +1074,7 @@ template <class C> inline bool Is(Object* obj);
|
||||
V(LoadHandler) \
|
||||
V(Map) \
|
||||
V(MapCache) \
|
||||
V(Microtask) \
|
||||
V(ModuleInfo) \
|
||||
V(MutableHeapNumber) \
|
||||
V(Name) \
|
||||
@ -1059,7 +1088,7 @@ template <class C> inline bool Is(Object* obj);
|
||||
V(OrderedHashMap) \
|
||||
V(OrderedHashSet) \
|
||||
V(PreParsedScopeData) \
|
||||
V(PromiseCapability) \
|
||||
V(PromiseReactionJobTask) \
|
||||
V(PropertyArray) \
|
||||
V(PropertyCell) \
|
||||
V(PropertyDescriptorObject) \
|
||||
@ -2873,84 +2902,203 @@ class Tuple3 : public Tuple2 {
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Tuple3);
|
||||
};
|
||||
|
||||
class PromiseCapability : public Tuple3 {
|
||||
// Abstract base class for all microtasks that can be scheduled on the
|
||||
// microtask queue. This class merely serves the purpose of a marker
|
||||
// interface.
|
||||
class Microtask : public Struct {
|
||||
public:
|
||||
DECL_CAST(PromiseCapability)
|
||||
DECL_PRINTER(PromiseCapability)
|
||||
DECL_VERIFIER(PromiseCapability)
|
||||
// Dispatched behavior.
|
||||
DECL_CAST(Microtask)
|
||||
DECL_VERIFIER(Microtask)
|
||||
|
||||
DECL_ACCESSORS(promise, Object)
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Microtask);
|
||||
};
|
||||
|
||||
// A CallbackTask is a special Microtask that allows us to schedule
|
||||
// C++ microtask callbacks on the microtask queue. This is heavily
|
||||
// used by Blink for example.
|
||||
class CallbackTask : public Microtask {
|
||||
public:
|
||||
DECL_ACCESSORS(callback, Foreign)
|
||||
DECL_ACCESSORS(data, Foreign)
|
||||
|
||||
static const int kCallbackOffset = Microtask::kHeaderSize;
|
||||
static const int kDataOffset = kCallbackOffset + kPointerSize;
|
||||
static const int kSize = kDataOffset + kPointerSize;
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_CAST(CallbackTask)
|
||||
DECL_PRINTER(CallbackTask)
|
||||
DECL_VERIFIER(CallbackTask)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(CallbackTask)
|
||||
};
|
||||
|
||||
// A CallableTask is a special (internal) Microtask that allows us to
|
||||
// schedule arbitrary callables on the microtask queue. We use this
|
||||
// for various tests of the microtask queue.
|
||||
class CallableTask : public Microtask {
|
||||
public:
|
||||
DECL_ACCESSORS(callable, JSReceiver)
|
||||
DECL_ACCESSORS(context, Context)
|
||||
|
||||
static const int kCallableOffset = Microtask::kHeaderSize;
|
||||
static const int kContextOffset = kCallableOffset + kPointerSize;
|
||||
static const int kSize = kContextOffset + kPointerSize;
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_CAST(CallableTask)
|
||||
DECL_PRINTER(CallableTask)
|
||||
DECL_VERIFIER(CallableTask)
|
||||
void BriefPrintDetails(std::ostream& os);
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(CallableTask);
|
||||
};
|
||||
|
||||
// Struct to hold state required for PromiseReactionJob. See the comment on the
|
||||
// PromiseReaction below for details on how this is being managed to reduce the
|
||||
// memory and allocation overhead. This is the base class for the concrete
|
||||
//
|
||||
// - PromiseFulfillReactionJobTask
|
||||
// - PromiseRejectReactionJobTask
|
||||
//
|
||||
// classes, which are used to represent either reactions, and we distinguish
|
||||
// them by their instance types.
|
||||
class PromiseReactionJobTask : public Microtask {
|
||||
public:
|
||||
DECL_ACCESSORS(argument, Object)
|
||||
DECL_ACCESSORS(context, Context)
|
||||
DECL_ACCESSORS(handler, HeapObject)
|
||||
// [promise_or_capability]: Either a JSPromise or a PromiseCapability.
|
||||
DECL_ACCESSORS(promise_or_capability, HeapObject)
|
||||
|
||||
static const int kArgumentOffset = Microtask::kHeaderSize;
|
||||
static const int kContextOffset = kArgumentOffset + kPointerSize;
|
||||
static const int kHandlerOffset = kContextOffset + kPointerSize;
|
||||
static const int kPromiseOrCapabilityOffset = kHandlerOffset + kPointerSize;
|
||||
static const int kSize = kPromiseOrCapabilityOffset + kPointerSize;
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_CAST(PromiseReactionJobTask)
|
||||
DECL_VERIFIER(PromiseReactionJobTask)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PromiseReactionJobTask);
|
||||
};
|
||||
|
||||
// Struct to hold state required for a PromiseReactionJob of type "Fulfill".
|
||||
class PromiseFulfillReactionJobTask : public PromiseReactionJobTask {
|
||||
public:
|
||||
// Dispatched behavior.
|
||||
DECL_CAST(PromiseFulfillReactionJobTask)
|
||||
DECL_PRINTER(PromiseFulfillReactionJobTask)
|
||||
DECL_VERIFIER(PromiseFulfillReactionJobTask)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PromiseFulfillReactionJobTask);
|
||||
};
|
||||
|
||||
// Struct to hold state required for a PromiseReactionJob of type "Reject".
|
||||
class PromiseRejectReactionJobTask : public PromiseReactionJobTask {
|
||||
public:
|
||||
// Dispatched behavior.
|
||||
DECL_CAST(PromiseRejectReactionJobTask)
|
||||
DECL_PRINTER(PromiseRejectReactionJobTask)
|
||||
DECL_VERIFIER(PromiseRejectReactionJobTask)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PromiseRejectReactionJobTask);
|
||||
};
|
||||
|
||||
// A container struct to hold state required for PromiseResolveThenableJob.
|
||||
class PromiseResolveThenableJobTask : public Microtask {
|
||||
public:
|
||||
DECL_ACCESSORS(context, Context)
|
||||
DECL_ACCESSORS(promise_to_resolve, JSPromise)
|
||||
DECL_ACCESSORS(then, JSReceiver)
|
||||
DECL_ACCESSORS(thenable, JSReceiver)
|
||||
|
||||
static const int kContextOffset = Microtask::kHeaderSize;
|
||||
static const int kPromiseToResolveOffset = kContextOffset + kPointerSize;
|
||||
static const int kThenOffset = kPromiseToResolveOffset + kPointerSize;
|
||||
static const int kThenableOffset = kThenOffset + kPointerSize;
|
||||
static const int kSize = kThenableOffset + kPointerSize;
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_CAST(PromiseResolveThenableJobTask)
|
||||
DECL_PRINTER(PromiseResolveThenableJobTask)
|
||||
DECL_VERIFIER(PromiseResolveThenableJobTask)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PromiseResolveThenableJobTask);
|
||||
};
|
||||
|
||||
// Struct to hold the state of a PromiseCapability.
|
||||
class PromiseCapability : public Struct {
|
||||
public:
|
||||
DECL_ACCESSORS(promise, HeapObject)
|
||||
DECL_ACCESSORS(resolve, Object)
|
||||
DECL_ACCESSORS(reject, Object)
|
||||
|
||||
static const int kPromiseOffset = Tuple3::kValue1Offset;
|
||||
static const int kResolveOffset = Tuple3::kValue2Offset;
|
||||
static const int kRejectOffset = Tuple3::kValue3Offset;
|
||||
static const int kSize = Tuple3::kSize;
|
||||
static const int kPromiseOffset = Struct::kHeaderSize;
|
||||
static const int kResolveOffset = kPromiseOffset + kPointerSize;
|
||||
static const int kRejectOffset = kResolveOffset + kPointerSize;
|
||||
static const int kSize = kRejectOffset + kPointerSize;
|
||||
|
||||
// Dispatched behavior.
|
||||
DECL_CAST(PromiseCapability)
|
||||
DECL_PRINTER(PromiseCapability)
|
||||
DECL_VERIFIER(PromiseCapability)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PromiseCapability);
|
||||
};
|
||||
|
||||
// A container struct to hold state required for PromiseResolveThenableJob.
|
||||
class PromiseResolveThenableJobInfo : public Struct {
|
||||
// A representation of promise reaction. This differs from the specification
|
||||
// in that the PromiseReaction here holds both handlers for the fulfill and
|
||||
// the reject case. When a JSPromise is eventually resolved (either via
|
||||
// fulfilling it or rejecting it), we morph this PromiseReaction object in
|
||||
// memory into a proper PromiseReactionJobTask and schedule it on the queue
|
||||
// of microtasks. So the size of PromiseReaction and the size of the
|
||||
// PromiseReactionJobTask has to be same for this to work.
|
||||
//
|
||||
// The PromiseReaction::promise_or_capability field can either hold a JSPromise
|
||||
// instance (in the fast case of a native promise) or a PromiseCapability in
|
||||
// case of a Promise subclass.
|
||||
//
|
||||
// We need to keep the context in the PromiseReaction so that we can run
|
||||
// the default handlers (in case they are undefined) in the proper context.
|
||||
//
|
||||
// The PromiseReaction objects form a singly-linked list, terminated by
|
||||
// Smi 0. On the JSPromise instance they are linked in reverse order,
|
||||
// and are turned into the proper order again when scheduling them on
|
||||
// the microtask queue.
|
||||
class PromiseReaction : public Struct {
|
||||
public:
|
||||
DECL_ACCESSORS(thenable, JSReceiver)
|
||||
DECL_ACCESSORS(then, JSReceiver)
|
||||
DECL_ACCESSORS(resolve, JSFunction)
|
||||
DECL_ACCESSORS(reject, JSFunction)
|
||||
enum Type { kFulfill, kReject };
|
||||
|
||||
DECL_ACCESSORS(context, Context)
|
||||
DECL_ACCESSORS(next, Object)
|
||||
DECL_ACCESSORS(reject_handler, HeapObject)
|
||||
DECL_ACCESSORS(fulfill_handler, HeapObject)
|
||||
DECL_ACCESSORS(promise_or_capability, HeapObject)
|
||||
|
||||
static const int kThenableOffset = Struct::kHeaderSize;
|
||||
static const int kThenOffset = kThenableOffset + kPointerSize;
|
||||
static const int kResolveOffset = kThenOffset + kPointerSize;
|
||||
static const int kRejectOffset = kResolveOffset + kPointerSize;
|
||||
static const int kContextOffset = kRejectOffset + kPointerSize;
|
||||
static const int kSize = kContextOffset + kPointerSize;
|
||||
static const int kNextOffset = Struct::kHeaderSize;
|
||||
static const int kRejectHandlerOffset = kNextOffset + kPointerSize;
|
||||
static const int kFulfillHandlerOffset = kRejectHandlerOffset + kPointerSize;
|
||||
static const int kPromiseOrCapabilityOffset =
|
||||
kFulfillHandlerOffset + kPointerSize;
|
||||
static const int kSize = kPromiseOrCapabilityOffset + kPointerSize;
|
||||
|
||||
DECL_CAST(PromiseResolveThenableJobInfo)
|
||||
DECL_PRINTER(PromiseResolveThenableJobInfo)
|
||||
DECL_VERIFIER(PromiseResolveThenableJobInfo)
|
||||
// Dispatched behavior.
|
||||
DECL_CAST(PromiseReaction)
|
||||
DECL_PRINTER(PromiseReaction)
|
||||
DECL_VERIFIER(PromiseReaction)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PromiseResolveThenableJobInfo);
|
||||
};
|
||||
|
||||
class JSPromise;
|
||||
|
||||
// Struct to hold state required for PromiseReactionJob.
|
||||
class PromiseReactionJobInfo : public Struct {
|
||||
public:
|
||||
DECL_ACCESSORS(value, Object)
|
||||
DECL_ACCESSORS(tasks, Object)
|
||||
|
||||
// Check comment in JSPromise for information on what state these
|
||||
// deferred fields could be in.
|
||||
DECL_ACCESSORS(deferred_promise, Object)
|
||||
DECL_ACCESSORS(deferred_on_resolve, Object)
|
||||
DECL_ACCESSORS(deferred_on_reject, Object)
|
||||
|
||||
DECL_INT_ACCESSORS(debug_id)
|
||||
|
||||
DECL_ACCESSORS(context, Context)
|
||||
|
||||
static const int kValueOffset = Struct::kHeaderSize;
|
||||
static const int kTasksOffset = kValueOffset + kPointerSize;
|
||||
static const int kDeferredPromiseOffset = kTasksOffset + kPointerSize;
|
||||
static const int kDeferredOnResolveOffset =
|
||||
kDeferredPromiseOffset + kPointerSize;
|
||||
static const int kDeferredOnRejectOffset =
|
||||
kDeferredOnResolveOffset + kPointerSize;
|
||||
static const int kContextOffset = kDeferredOnRejectOffset + kPointerSize;
|
||||
static const int kSize = kContextOffset + kPointerSize;
|
||||
|
||||
DECL_CAST(PromiseReactionJobInfo)
|
||||
DECL_PRINTER(PromiseReactionJobInfo)
|
||||
DECL_VERIFIER(PromiseReactionJobInfo)
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PromiseReactionJobInfo);
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PromiseReaction);
|
||||
};
|
||||
|
||||
class AsyncGeneratorRequest : public Struct {
|
||||
@ -3852,28 +4000,27 @@ class JSMessageObject: public JSObject {
|
||||
typedef BodyDescriptor BodyDescriptorWeak;
|
||||
};
|
||||
|
||||
// Representation of promise objects in the specification. Our layout of
|
||||
// JSPromise differs a bit from the layout in the specification, for example
|
||||
// there's only a single list of PromiseReaction objects, instead of separate
|
||||
// lists for fulfill and reject reactions. The PromiseReaction carries both
|
||||
// callbacks from the start, and is eventually morphed into the proper kind of
|
||||
// PromiseReactionJobTask when the JSPromise is settled.
|
||||
//
|
||||
// We also overlay the result and reactions fields on the JSPromise, since
|
||||
// the reactions are only necessary for pending promises, whereas the result
|
||||
// is only meaningful for settled promises.
|
||||
class JSPromise : public JSObject {
|
||||
public:
|
||||
DECL_ACCESSORS(result, Object)
|
||||
// [reactions_or_result]: Smi 0 terminated list of PromiseReaction objects
|
||||
// in case the JSPromise was not settled yet, otherwise the result.
|
||||
DECL_ACCESSORS(reactions_or_result, Object)
|
||||
|
||||
// There are 3 possible states for these fields --
|
||||
// 1) Undefined -- This is the zero state when there is no callback
|
||||
// or deferred fields registered.
|
||||
//
|
||||
// 2) Object -- There is a single callback directly attached to the
|
||||
// fulfill_reactions, reject_reactions and the deferred fields are
|
||||
// directly attached to the slots. In this state, deferred_promise
|
||||
// is a JSReceiver and deferred_on_{resolve, reject} are Callables.
|
||||
//
|
||||
// 3) FixedArray -- There is more than one callback and deferred
|
||||
// fields attached to a FixedArray.
|
||||
//
|
||||
// The callback can be a Callable or a Symbol.
|
||||
DECL_ACCESSORS(deferred_promise, Object)
|
||||
DECL_ACCESSORS(deferred_on_resolve, Object)
|
||||
DECL_ACCESSORS(deferred_on_reject, Object)
|
||||
DECL_ACCESSORS(fulfill_reactions, Object)
|
||||
DECL_ACCESSORS(reject_reactions, Object)
|
||||
// [result]: Checks that the promise is settled and returns the result.
|
||||
inline Object* result() const;
|
||||
|
||||
// [reactions]: Checks that the promise is pending and returns the reactions.
|
||||
inline Object* reactions() const;
|
||||
|
||||
DECL_INT_ACCESSORS(flags)
|
||||
|
||||
@ -3900,17 +4047,8 @@ class JSPromise : public JSObject {
|
||||
DECL_VERIFIER(JSPromise)
|
||||
|
||||
// Layout description.
|
||||
static const int kResultOffset = JSObject::kHeaderSize;
|
||||
static const int kDeferredPromiseOffset = kResultOffset + kPointerSize;
|
||||
static const int kDeferredOnResolveOffset =
|
||||
kDeferredPromiseOffset + kPointerSize;
|
||||
static const int kDeferredOnRejectOffset =
|
||||
kDeferredOnResolveOffset + kPointerSize;
|
||||
static const int kFulfillReactionsOffset =
|
||||
kDeferredOnRejectOffset + kPointerSize;
|
||||
static const int kRejectReactionsOffset =
|
||||
kFulfillReactionsOffset + kPointerSize;
|
||||
static const int kFlagsOffset = kRejectReactionsOffset + kPointerSize;
|
||||
static const int kReactionsOrResultOffset = JSObject::kHeaderSize;
|
||||
static const int kFlagsOffset = kReactionsOrResultOffset + kPointerSize;
|
||||
static const int kSize = kFlagsOffset + kPointerSize;
|
||||
static const int kSizeWithEmbedderFields =
|
||||
kSize + v8::Promise::kEmbedderFieldCount * kPointerSize;
|
||||
|
@ -503,6 +503,7 @@ bool Map::IsJSObjectMap() const {
|
||||
STATIC_ASSERT(LAST_JS_OBJECT_TYPE == LAST_TYPE);
|
||||
return instance_type() >= FIRST_JS_OBJECT_TYPE;
|
||||
}
|
||||
bool Map::IsJSPromiseMap() const { return instance_type() == JS_PROMISE_TYPE; }
|
||||
bool Map::IsJSArrayMap() const { return instance_type() == JS_ARRAY_TYPE; }
|
||||
bool Map::IsJSFunctionMap() const {
|
||||
return instance_type() == JS_FUNCTION_TYPE;
|
||||
|
@ -713,6 +713,7 @@ class Map : public HeapObject {
|
||||
inline bool IsPrimitiveMap() const;
|
||||
inline bool IsJSReceiverMap() const;
|
||||
inline bool IsJSObjectMap() const;
|
||||
inline bool IsJSPromiseMap() const;
|
||||
inline bool IsJSArrayMap() const;
|
||||
inline bool IsJSFunctionMap() const;
|
||||
inline bool IsStringMap() const;
|
||||
|
@ -1311,23 +1311,9 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences(
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractJSPromiseReferences(int entry, JSPromise* promise) {
|
||||
SetInternalReference(promise, entry, "result", promise->result(),
|
||||
JSPromise::kResultOffset);
|
||||
SetInternalReference(promise, entry, "deferred_promise",
|
||||
promise->deferred_promise(),
|
||||
JSPromise::kDeferredPromiseOffset);
|
||||
SetInternalReference(promise, entry, "deferred_on_resolve",
|
||||
promise->deferred_on_resolve(),
|
||||
JSPromise::kDeferredOnResolveOffset);
|
||||
SetInternalReference(promise, entry, "deferred_on_reject",
|
||||
promise->deferred_on_reject(),
|
||||
JSPromise::kDeferredOnRejectOffset);
|
||||
SetInternalReference(promise, entry, "fulfill_reactions",
|
||||
promise->fulfill_reactions(),
|
||||
JSPromise::kFulfillReactionsOffset);
|
||||
SetInternalReference(promise, entry, "reject_reactions",
|
||||
promise->reject_reactions(),
|
||||
JSPromise::kRejectReactionsOffset);
|
||||
SetInternalReference(promise, entry, "reactions_or_result",
|
||||
promise->reactions_or_result(),
|
||||
JSPromise::kReactionsOrResultOffset);
|
||||
}
|
||||
|
||||
void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
|
||||
|
@ -265,7 +265,10 @@ MaybeHandle<JSArray> Runtime::GetInternalProperties(Isolate* isolate,
|
||||
Handle<String> status_str = factory->NewStringFromAsciiChecked(status);
|
||||
result->set(1, *status_str);
|
||||
|
||||
Handle<Object> value_obj(promise->result(), isolate);
|
||||
Handle<Object> value_obj(promise->status() == Promise::kPending
|
||||
? isolate->heap()->undefined_value()
|
||||
: promise->result(),
|
||||
isolate);
|
||||
Handle<String> promise_value =
|
||||
factory->NewStringFromAsciiChecked("[[PromiseValue]]");
|
||||
result->set(2, *promise_value);
|
||||
|
@ -75,7 +75,9 @@ RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) {
|
||||
RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, microtask, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
||||
Handle<CallableTask> microtask =
|
||||
isolate->factory()->NewCallableTask(function, isolate->native_context());
|
||||
isolate->EnqueueMicrotask(microtask);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
@ -112,8 +112,6 @@ TEST(ContextMaps) {
|
||||
Context::STRING_FUNCTION_INDEX);
|
||||
VerifyStoredPrototypeMap(isolate, Context::REGEXP_PROTOTYPE_MAP_INDEX,
|
||||
Context::REGEXP_FUNCTION_INDEX);
|
||||
VerifyStoredPrototypeMap(isolate, Context::PROMISE_PROTOTYPE_MAP_INDEX,
|
||||
Context::PROMISE_FUNCTION_INDEX);
|
||||
}
|
||||
|
||||
TEST(InitialObjects) {
|
||||
|
@ -21648,6 +21648,42 @@ TEST(RunMicrotasksWithoutEnteringContext) {
|
||||
isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kAuto);
|
||||
}
|
||||
|
||||
static void Regress808911_MicrotaskCallback(void* data) {
|
||||
// So here we expect "current context" to be context1 and
|
||||
// "entered or microtask context" to be context2.
|
||||
v8::Isolate* isolate = static_cast<v8::Isolate*>(data);
|
||||
CHECK(isolate->GetCurrentContext() != isolate->GetEnteredContext());
|
||||
CHECK(isolate->GetCurrentContext() !=
|
||||
isolate->GetEnteredOrMicrotaskContext());
|
||||
}
|
||||
|
||||
static void Regress808911_CurrentContextWrapper(
|
||||
const v8::FunctionCallbackInfo<Value>& info) {
|
||||
// So here we expect "current context" to be context1 and
|
||||
// "entered or microtask context" to be context2.
|
||||
v8::Isolate* isolate = info.GetIsolate();
|
||||
CHECK(isolate->GetCurrentContext() != isolate->GetEnteredContext());
|
||||
CHECK(isolate->GetCurrentContext() !=
|
||||
isolate->GetEnteredOrMicrotaskContext());
|
||||
isolate->EnqueueMicrotask(Regress808911_MicrotaskCallback, isolate);
|
||||
isolate->RunMicrotasks();
|
||||
}
|
||||
|
||||
THREADED_TEST(Regress808911) {
|
||||
v8::Isolate* isolate = CcTest::isolate();
|
||||
HandleScope handle_scope(isolate);
|
||||
Local<Context> context1 = Context::New(isolate);
|
||||
Local<Function> function;
|
||||
{
|
||||
Context::Scope context_scope(context1);
|
||||
function = Function::New(context1, Regress808911_CurrentContextWrapper)
|
||||
.ToLocalChecked();
|
||||
}
|
||||
Local<Context> context2 = Context::New(isolate);
|
||||
Context::Scope context_scope(context2);
|
||||
function->CallAsFunction(context2, v8::Undefined(isolate), 0, nullptr)
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
TEST(ScopedMicrotasks) {
|
||||
LocalContext env;
|
||||
|
@ -2069,74 +2069,6 @@ TEST(AllocateAndSetJSPromise) {
|
||||
CHECK(!js_promise->has_handler());
|
||||
}
|
||||
|
||||
TEST(AllocatePromiseReactionJobInfo) {
|
||||
Isolate* isolate(CcTest::InitIsolateOnce());
|
||||
|
||||
const int kNumParams = 1;
|
||||
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
||||
CodeStubAssembler m(asm_tester.state());
|
||||
PromiseBuiltinsAssembler p(asm_tester.state());
|
||||
|
||||
Node* const context = m.Parameter(kNumParams + 2);
|
||||
Node* const tasks =
|
||||
m.AllocateFixedArray(PACKED_ELEMENTS, m.IntPtrConstant(1));
|
||||
m.StoreFixedArrayElement(tasks, 0, m.UndefinedConstant());
|
||||
Node* const deferred_promise =
|
||||
m.AllocateFixedArray(PACKED_ELEMENTS, m.IntPtrConstant(1));
|
||||
m.StoreFixedArrayElement(deferred_promise, 0, m.UndefinedConstant());
|
||||
Node* const info = m.AllocatePromiseReactionJobInfo(
|
||||
m.SmiConstant(1), tasks, deferred_promise, m.UndefinedConstant(),
|
||||
m.UndefinedConstant(), context);
|
||||
m.Return(info);
|
||||
|
||||
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
||||
Handle<Object> result =
|
||||
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
||||
CHECK(result->IsPromiseReactionJobInfo());
|
||||
Handle<PromiseReactionJobInfo> promise_info =
|
||||
Handle<PromiseReactionJobInfo>::cast(result);
|
||||
CHECK_EQ(Smi::FromInt(1), promise_info->value());
|
||||
CHECK(promise_info->tasks()->IsFixedArray());
|
||||
CHECK(promise_info->deferred_promise()->IsFixedArray());
|
||||
CHECK(promise_info->deferred_on_resolve()->IsUndefined(isolate));
|
||||
CHECK(promise_info->deferred_on_reject()->IsUndefined(isolate));
|
||||
CHECK(promise_info->context()->IsContext());
|
||||
}
|
||||
|
||||
TEST(AllocatePromiseResolveThenableJobInfo) {
|
||||
Isolate* isolate(CcTest::InitIsolateOnce());
|
||||
|
||||
const int kNumParams = 1;
|
||||
CodeAssemblerTester asm_tester(isolate, kNumParams);
|
||||
PromiseBuiltinsAssembler p(asm_tester.state());
|
||||
|
||||
Node* const context = p.Parameter(kNumParams + 2);
|
||||
Node* const native_context = p.LoadNativeContext(context);
|
||||
Node* const thenable = p.AllocateAndInitJSPromise(context);
|
||||
Node* const then =
|
||||
p.GetProperty(context, thenable, isolate->factory()->then_string());
|
||||
Node* resolve = nullptr;
|
||||
Node* reject = nullptr;
|
||||
std::tie(resolve, reject) = p.CreatePromiseResolvingFunctions(
|
||||
thenable, p.FalseConstant(), native_context);
|
||||
|
||||
Node* const info = p.AllocatePromiseResolveThenableJobInfo(
|
||||
thenable, then, resolve, reject, context);
|
||||
p.Return(info);
|
||||
|
||||
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
||||
Handle<Object> result =
|
||||
ft.Call(isolate->factory()->undefined_value()).ToHandleChecked();
|
||||
CHECK(result->IsPromiseResolveThenableJobInfo());
|
||||
Handle<PromiseResolveThenableJobInfo> promise_info =
|
||||
Handle<PromiseResolveThenableJobInfo>::cast(result);
|
||||
CHECK(promise_info->thenable()->IsJSPromise());
|
||||
CHECK(promise_info->then()->IsJSFunction());
|
||||
CHECK(promise_info->resolve()->IsJSFunction());
|
||||
CHECK(promise_info->reject()->IsJSFunction());
|
||||
CHECK(promise_info->context()->IsContext());
|
||||
}
|
||||
|
||||
TEST(IsSymbol) {
|
||||
Isolate* isolate(CcTest::InitIsolateOnce());
|
||||
|
||||
@ -2357,7 +2289,7 @@ TEST(CreatePromiseGetCapabilitiesExecutorContext) {
|
||||
Node* const context = m.Parameter(kNumParams + 2);
|
||||
Node* const native_context = m.LoadNativeContext(context);
|
||||
|
||||
Node* const map = m.LoadRoot(Heap::kTuple3MapRootIndex);
|
||||
Node* const map = m.LoadRoot(Heap::kPromiseCapabilityMapRootIndex);
|
||||
Node* const capability = m.AllocateStruct(map);
|
||||
m.StoreObjectFieldNoWriteBarrier(
|
||||
capability, PromiseCapability::kPromiseOffset, m.UndefinedConstant());
|
||||
@ -2396,8 +2328,10 @@ TEST(NewPromiseCapability) {
|
||||
Node* const promise_constructor =
|
||||
m.LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
|
||||
|
||||
Node* const debug_event = m.TrueConstant();
|
||||
Node* const capability =
|
||||
m.NewPromiseCapability(context, promise_constructor);
|
||||
m.CallBuiltin(Builtins::kNewPromiseCapability, context,
|
||||
promise_constructor, debug_event);
|
||||
m.Return(capability);
|
||||
|
||||
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
||||
@ -2440,7 +2374,9 @@ TEST(NewPromiseCapability) {
|
||||
Node* const context = m.Parameter(kNumParams + 2);
|
||||
|
||||
Node* const constructor = m.Parameter(1);
|
||||
Node* const capability = m.NewPromiseCapability(context, constructor);
|
||||
Node* const debug_event = m.TrueConstant();
|
||||
Node* const capability = m.CallBuiltin(Builtins::kNewPromiseCapability,
|
||||
context, constructor, debug_event);
|
||||
m.Return(capability);
|
||||
|
||||
FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
|
||||
|
@ -2794,21 +2794,17 @@ TEST(JSPromise) {
|
||||
const v8::HeapGraphNode* resolved = GetProperty(
|
||||
env->GetIsolate(), global, v8::HeapGraphEdge::kProperty, "resolved");
|
||||
CHECK(GetProperty(env->GetIsolate(), resolved, v8::HeapGraphEdge::kInternal,
|
||||
"result"));
|
||||
"reactions_or_result"));
|
||||
|
||||
const v8::HeapGraphNode* rejected = GetProperty(
|
||||
env->GetIsolate(), global, v8::HeapGraphEdge::kProperty, "rejected");
|
||||
CHECK(GetProperty(env->GetIsolate(), rejected, v8::HeapGraphEdge::kInternal,
|
||||
"result"));
|
||||
"reactions_or_result"));
|
||||
|
||||
const v8::HeapGraphNode* pending = GetProperty(
|
||||
env->GetIsolate(), global, v8::HeapGraphEdge::kProperty, "pending");
|
||||
CHECK(GetProperty(env->GetIsolate(), pending, v8::HeapGraphEdge::kInternal,
|
||||
"deferred_promise"));
|
||||
CHECK(GetProperty(env->GetIsolate(), pending, v8::HeapGraphEdge::kInternal,
|
||||
"fulfill_reactions"));
|
||||
CHECK(GetProperty(env->GetIsolate(), pending, v8::HeapGraphEdge::kInternal,
|
||||
"reject_reactions"));
|
||||
"reactions_or_result"));
|
||||
|
||||
const char* objectNames[] = {"resolved", "rejected", "pending", "chained"};
|
||||
for (auto objectName : objectNames) {
|
||||
|
18
test/debugger/regress/regress-crbug-808973.js
Normal file
18
test/debugger/regress/regress-crbug-808973.js
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax --enable-inspector
|
||||
|
||||
const Debug = debug.Debug;
|
||||
Debug.setListener(() => {});
|
||||
Debug.setBreakOnUncaughtException()
|
||||
|
||||
function sleep() {
|
||||
return new Promise(resolve => setTimeout(resolve, 1));
|
||||
}
|
||||
async function thrower() {
|
||||
await sleep();
|
||||
throw "a"; // Exception a
|
||||
}
|
||||
(async function() { thrower(); })();
|
@ -0,0 +1,19 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function foo(p) { return p.catch(x => x); }
|
||||
|
||||
const a = Promise.resolve(1);
|
||||
|
||||
foo(a);
|
||||
foo(a);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(a);
|
||||
|
||||
let custom_then_called = false;
|
||||
a.__proto__.then = function() { custom_then_called = true; }
|
||||
foo(a);
|
||||
assertTrue(custom_then_called);
|
@ -0,0 +1,19 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function foo(p) { return p.catch(x => x); }
|
||||
|
||||
const a = Promise.resolve(1);
|
||||
|
||||
foo(a);
|
||||
foo(a);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(a);
|
||||
|
||||
let custom_then_called = false;
|
||||
a.then = function() { custom_then_called = true; }
|
||||
foo(a);
|
||||
assertTrue(custom_then_called);
|
27
test/mjsunit/compiler/promise-prototype-catch-subclass.js
Normal file
27
test/mjsunit/compiler/promise-prototype-catch-subclass.js
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
let custom_then_called = false;
|
||||
|
||||
function foo(p) {
|
||||
custom_then_called = false;
|
||||
p.catch(x => x);
|
||||
return custom_then_called;
|
||||
}
|
||||
|
||||
class MyPromise extends Promise {
|
||||
then(onFulfilled, onRejected) {
|
||||
custom_then_called = true;
|
||||
return super.then(onFulfilled, onRejected);
|
||||
}
|
||||
}
|
||||
|
||||
const a = MyPromise.resolve(1);
|
||||
|
||||
assertTrue(foo(a));
|
||||
assertTrue(foo(a));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
assertTrue(foo(a));
|
29
test/mjsunit/compiler/promise-prototype-catch.js
Normal file
29
test/mjsunit/compiler/promise-prototype-catch.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
(function() {
|
||||
function foo(p) { return p.catch(); }
|
||||
foo(Promise.resolve(1));
|
||||
foo(Promise.resolve(1));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(Promise.resolve(1));
|
||||
})();
|
||||
|
||||
(function() {
|
||||
function foo(p) { return p.catch(foo); }
|
||||
foo(Promise.resolve(1));
|
||||
foo(Promise.resolve(1));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(Promise.resolve(1));
|
||||
})();
|
||||
|
||||
(function() {
|
||||
function foo(p) { return p.catch(foo, undefined); }
|
||||
foo(Promise.resolve(1));
|
||||
foo(Promise.resolve(1));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(Promise.resolve(1));
|
||||
})();
|
@ -0,0 +1,19 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function foo(p) { return p.finally(x => x); }
|
||||
|
||||
const a = Promise.resolve(1);
|
||||
|
||||
foo(a);
|
||||
foo(a);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(a);
|
||||
|
||||
let custom_then_called = false;
|
||||
a.__proto__.then = function() { custom_then_called = true; }
|
||||
foo(a);
|
||||
assertTrue(custom_then_called);
|
@ -0,0 +1,19 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function foo(p) { return p.finally(x => x); }
|
||||
|
||||
const a = Promise.resolve(1);
|
||||
|
||||
foo(a);
|
||||
foo(a);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(a);
|
||||
|
||||
let custom_then_called = false;
|
||||
a.then = function() { custom_then_called = true; }
|
||||
foo(a);
|
||||
assertTrue(custom_then_called);
|
27
test/mjsunit/compiler/promise-prototype-finally-subclass.js
Normal file
27
test/mjsunit/compiler/promise-prototype-finally-subclass.js
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
let custom_then_called = false;
|
||||
|
||||
function foo(p) {
|
||||
custom_then_called = false;
|
||||
p.finally(x => x);
|
||||
return custom_then_called;
|
||||
}
|
||||
|
||||
class MyPromise extends Promise {
|
||||
then(onFulfilled, onRejected) {
|
||||
custom_then_called = true;
|
||||
return super.then(onFulfilled, onRejected);
|
||||
}
|
||||
}
|
||||
|
||||
const a = MyPromise.resolve(1);
|
||||
|
||||
assertTrue(foo(a));
|
||||
assertTrue(foo(a));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
assertTrue(foo(a));
|
41
test/mjsunit/compiler/promise-prototype-finally.js
Normal file
41
test/mjsunit/compiler/promise-prototype-finally.js
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
(function() {
|
||||
const p = Promise.resolve(1);
|
||||
function foo(p) { return p.finally(); }
|
||||
foo(p);
|
||||
foo(p);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(p);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
const p = Promise.resolve(1);
|
||||
function foo(p) { return p.finally(x => x); }
|
||||
foo(p);
|
||||
foo(p);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(p);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
const p = Promise.resolve(1);
|
||||
function foo(p, f) { return p.finally(f); }
|
||||
foo(p, x => x);
|
||||
foo(p, x => x);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(p, x => x);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
const p = Promise.resolve(1);
|
||||
function foo(p, f) { return p.finally(f).finally(f); }
|
||||
foo(p, x => x);
|
||||
foo(p, x => x);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(p, x => x);
|
||||
})();
|
50
test/mjsunit/compiler/promise-prototype-then.js
Normal file
50
test/mjsunit/compiler/promise-prototype-then.js
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
(function() {
|
||||
const p = Promise.resolve(1);
|
||||
function foo(p) { return p.then(); }
|
||||
foo(p);
|
||||
foo(p);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(p);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
const p = Promise.resolve(1);
|
||||
function foo(p) { return p.then(x => x); }
|
||||
foo(p);
|
||||
foo(p);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(p);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
const p = Promise.resolve(1);
|
||||
function foo(p) { return p.then(x => x, y => y); }
|
||||
foo(p);
|
||||
foo(p);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(p);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
const p = Promise.resolve(1);
|
||||
function foo(p, f) { return p.then(f, f); }
|
||||
foo(p, x => x);
|
||||
foo(p, x => x);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(p, x => x);
|
||||
})();
|
||||
|
||||
(function() {
|
||||
const p = Promise.resolve(1);
|
||||
function foo(p, f) { return p.then(f, f).then(f, f); }
|
||||
foo(p, x => x);
|
||||
foo(p, x => x);
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(p, x => x);
|
||||
})();
|
23
test/mjsunit/regress/regress-5691.js
Normal file
23
test/mjsunit/regress/regress-5691.js
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
var log = "";
|
||||
var result;
|
||||
Promise.resolve()
|
||||
.then(() => log += "|turn1")
|
||||
.then(() => log += "|turn2")
|
||||
.then(() => log += "|turn3")
|
||||
.then(() => log += "|turn4")
|
||||
.then(() => result = "|start|turn1|fast-resolve|turn2|turn3|slow-resolve|turn4\n"+log)
|
||||
.catch(e => print("ERROR", e));
|
||||
|
||||
Promise.resolve(Promise.resolve()).then(() => log += "|fast-resolve");
|
||||
(class extends Promise {}).resolve(Promise.resolve()).then(() => log += "|slow-resolve");
|
||||
|
||||
log += "|start";
|
||||
%RunMicrotasks();
|
||||
assertEquals("|start|turn1|fast-resolve|turn2|turn3|slow-resolve|turn4\n\
|
||||
|start|turn1|fast-resolve|turn2|turn3|slow-resolve|turn4", result);
|
27
test/mjsunit/regress/regress-800651.js
Normal file
27
test/mjsunit/regress/regress-800651.js
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
var list = [];
|
||||
function log(item) { list.push(item); }
|
||||
async function f() {
|
||||
try {
|
||||
let namespace = await import(/a/);
|
||||
} catch(e) {
|
||||
log(1);
|
||||
}
|
||||
}
|
||||
f();
|
||||
|
||||
async function g() {
|
||||
try {
|
||||
let namespace = await import({ get toString() { return undefined; }});
|
||||
} catch(e) {
|
||||
log(2);
|
||||
}
|
||||
}
|
||||
g();
|
||||
%RunMicrotasks();
|
||||
assertEquals(list, [1,2]);
|
@ -3,8 +3,6 @@ Test whether Promise treats thenable correctly.
|
||||
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
|
||||
|
||||
The promise is already rejected now.
|
||||
PASS rejected
|
||||
PASS result is "hello"
|
||||
PASS successfullyParsed is true
|
||||
|
||||
TEST COMPLETE
|
||||
|
@ -65,28 +65,33 @@ INSTANCE_TYPES = {
|
||||
161: "MODULE_INFO_ENTRY_TYPE",
|
||||
162: "MODULE_TYPE",
|
||||
163: "OBJECT_TEMPLATE_INFO_TYPE",
|
||||
164: "PROMISE_REACTION_JOB_INFO_TYPE",
|
||||
165: "PROMISE_RESOLVE_THENABLE_JOB_INFO_TYPE",
|
||||
164: "PROMISE_CAPABILITY_TYPE",
|
||||
165: "PROMISE_REACTION_TYPE",
|
||||
166: "PROTOTYPE_INFO_TYPE",
|
||||
167: "SCRIPT_TYPE",
|
||||
168: "STACK_FRAME_INFO_TYPE",
|
||||
169: "TUPLE2_TYPE",
|
||||
170: "TUPLE3_TYPE",
|
||||
171: "FIXED_ARRAY_TYPE",
|
||||
172: "DESCRIPTOR_ARRAY_TYPE",
|
||||
173: "HASH_TABLE_TYPE",
|
||||
174: "TRANSITION_ARRAY_TYPE",
|
||||
175: "CELL_TYPE",
|
||||
176: "CODE_DATA_CONTAINER_TYPE",
|
||||
177: "FEEDBACK_VECTOR_TYPE",
|
||||
178: "LOAD_HANDLER_TYPE",
|
||||
179: "PROPERTY_ARRAY_TYPE",
|
||||
180: "PROPERTY_CELL_TYPE",
|
||||
181: "SHARED_FUNCTION_INFO_TYPE",
|
||||
182: "SMALL_ORDERED_HASH_MAP_TYPE",
|
||||
183: "SMALL_ORDERED_HASH_SET_TYPE",
|
||||
184: "STORE_HANDLER_TYPE",
|
||||
185: "WEAK_CELL_TYPE",
|
||||
171: "CALLABLE_TASK_TYPE",
|
||||
172: "CALLBACK_TASK_TYPE",
|
||||
173: "PROMISE_FULFILL_REACTION_JOB_TASK_TYPE",
|
||||
174: "PROMISE_REJECT_REACTION_JOB_TASK_TYPE",
|
||||
175: "PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE",
|
||||
176: "FIXED_ARRAY_TYPE",
|
||||
177: "DESCRIPTOR_ARRAY_TYPE",
|
||||
178: "HASH_TABLE_TYPE",
|
||||
179: "TRANSITION_ARRAY_TYPE",
|
||||
180: "CELL_TYPE",
|
||||
181: "CODE_DATA_CONTAINER_TYPE",
|
||||
182: "FEEDBACK_VECTOR_TYPE",
|
||||
183: "LOAD_HANDLER_TYPE",
|
||||
184: "PROPERTY_ARRAY_TYPE",
|
||||
185: "PROPERTY_CELL_TYPE",
|
||||
186: "SHARED_FUNCTION_INFO_TYPE",
|
||||
187: "SMALL_ORDERED_HASH_MAP_TYPE",
|
||||
188: "SMALL_ORDERED_HASH_SET_TYPE",
|
||||
189: "STORE_HANDLER_TYPE",
|
||||
190: "WEAK_CELL_TYPE",
|
||||
1024: "JS_PROXY_TYPE",
|
||||
1025: "JS_GLOBAL_OBJECT_TYPE",
|
||||
1026: "JS_GLOBAL_PROXY_TYPE",
|
||||
@ -167,8 +172,8 @@ KNOWN_MAPS = {
|
||||
0x02201: (138, "FreeSpaceMap"),
|
||||
0x02251: (132, "MetaMap"),
|
||||
0x022a1: (131, "NullMap"),
|
||||
0x022f1: (172, "DescriptorArrayMap"),
|
||||
0x02341: (171, "FixedArrayMap"),
|
||||
0x022f1: (177, "DescriptorArrayMap"),
|
||||
0x02341: (176, "FixedArrayMap"),
|
||||
0x02391: (149, "OnePointerFillerMap"),
|
||||
0x023e1: (149, "TwoPointerFillerMap"),
|
||||
0x02431: (131, "UninitializedMap"),
|
||||
@ -178,57 +183,57 @@ KNOWN_MAPS = {
|
||||
0x02571: (131, "TheHoleMap"),
|
||||
0x025c1: (131, "BooleanMap"),
|
||||
0x02611: (136, "ByteArrayMap"),
|
||||
0x02661: (171, "FixedCOWArrayMap"),
|
||||
0x026b1: (173, "HashTableMap"),
|
||||
0x02661: (176, "FixedCOWArrayMap"),
|
||||
0x026b1: (178, "HashTableMap"),
|
||||
0x02701: (128, "SymbolMap"),
|
||||
0x02751: (72, "OneByteStringMap"),
|
||||
0x027a1: (171, "ScopeInfoMap"),
|
||||
0x027f1: (181, "SharedFunctionInfoMap"),
|
||||
0x027a1: (176, "ScopeInfoMap"),
|
||||
0x027f1: (186, "SharedFunctionInfoMap"),
|
||||
0x02841: (133, "CodeMap"),
|
||||
0x02891: (171, "FunctionContextMap"),
|
||||
0x028e1: (175, "CellMap"),
|
||||
0x02931: (185, "WeakCellMap"),
|
||||
0x02981: (180, "GlobalPropertyCellMap"),
|
||||
0x02891: (176, "FunctionContextMap"),
|
||||
0x028e1: (180, "CellMap"),
|
||||
0x02931: (190, "WeakCellMap"),
|
||||
0x02981: (185, "GlobalPropertyCellMap"),
|
||||
0x029d1: (135, "ForeignMap"),
|
||||
0x02a21: (174, "TransitionArrayMap"),
|
||||
0x02a71: (177, "FeedbackVectorMap"),
|
||||
0x02a21: (179, "TransitionArrayMap"),
|
||||
0x02a71: (182, "FeedbackVectorMap"),
|
||||
0x02ac1: (131, "ArgumentsMarkerMap"),
|
||||
0x02b11: (131, "ExceptionMap"),
|
||||
0x02b61: (131, "TerminationExceptionMap"),
|
||||
0x02bb1: (131, "OptimizedOutMap"),
|
||||
0x02c01: (131, "StaleRegisterMap"),
|
||||
0x02c51: (171, "NativeContextMap"),
|
||||
0x02ca1: (171, "ModuleContextMap"),
|
||||
0x02cf1: (171, "EvalContextMap"),
|
||||
0x02d41: (171, "ScriptContextMap"),
|
||||
0x02d91: (171, "BlockContextMap"),
|
||||
0x02de1: (171, "CatchContextMap"),
|
||||
0x02e31: (171, "WithContextMap"),
|
||||
0x02e81: (171, "DebugEvaluateContextMap"),
|
||||
0x02ed1: (171, "ScriptContextTableMap"),
|
||||
0x02f21: (171, "ArrayListMap"),
|
||||
0x02c51: (176, "NativeContextMap"),
|
||||
0x02ca1: (176, "ModuleContextMap"),
|
||||
0x02cf1: (176, "EvalContextMap"),
|
||||
0x02d41: (176, "ScriptContextMap"),
|
||||
0x02d91: (176, "BlockContextMap"),
|
||||
0x02de1: (176, "CatchContextMap"),
|
||||
0x02e31: (176, "WithContextMap"),
|
||||
0x02e81: (176, "DebugEvaluateContextMap"),
|
||||
0x02ed1: (176, "ScriptContextTableMap"),
|
||||
0x02f21: (176, "ArrayListMap"),
|
||||
0x02f71: (148, "FixedDoubleArrayMap"),
|
||||
0x02fc1: (134, "MutableHeapNumberMap"),
|
||||
0x03011: (173, "OrderedHashMapMap"),
|
||||
0x03061: (173, "OrderedHashSetMap"),
|
||||
0x030b1: (173, "NameDictionaryMap"),
|
||||
0x03101: (173, "GlobalDictionaryMap"),
|
||||
0x03151: (173, "NumberDictionaryMap"),
|
||||
0x031a1: (173, "SimpleNumberDictionaryMap"),
|
||||
0x031f1: (173, "StringTableMap"),
|
||||
0x03241: (173, "WeakHashTableMap"),
|
||||
0x03291: (171, "SloppyArgumentsElementsMap"),
|
||||
0x032e1: (182, "SmallOrderedHashMapMap"),
|
||||
0x03331: (183, "SmallOrderedHashSetMap"),
|
||||
0x03381: (176, "CodeDataContainerMap"),
|
||||
0x03011: (178, "OrderedHashMapMap"),
|
||||
0x03061: (178, "OrderedHashSetMap"),
|
||||
0x030b1: (178, "NameDictionaryMap"),
|
||||
0x03101: (178, "GlobalDictionaryMap"),
|
||||
0x03151: (178, "NumberDictionaryMap"),
|
||||
0x031a1: (178, "SimpleNumberDictionaryMap"),
|
||||
0x031f1: (178, "StringTableMap"),
|
||||
0x03241: (178, "WeakHashTableMap"),
|
||||
0x03291: (176, "SloppyArgumentsElementsMap"),
|
||||
0x032e1: (187, "SmallOrderedHashMapMap"),
|
||||
0x03331: (188, "SmallOrderedHashSetMap"),
|
||||
0x03381: (181, "CodeDataContainerMap"),
|
||||
0x033d1: (1071, "JSMessageObjectMap"),
|
||||
0x03421: (1057, "ExternalMap"),
|
||||
0x03471: (137, "BytecodeArrayMap"),
|
||||
0x034c1: (171, "ModuleInfoMap"),
|
||||
0x03511: (175, "NoClosuresCellMap"),
|
||||
0x03561: (175, "OneClosureCellMap"),
|
||||
0x035b1: (175, "ManyClosuresCellMap"),
|
||||
0x03601: (179, "PropertyArrayMap"),
|
||||
0x034c1: (176, "ModuleInfoMap"),
|
||||
0x03511: (180, "NoClosuresCellMap"),
|
||||
0x03561: (180, "OneClosureCellMap"),
|
||||
0x035b1: (180, "ManyClosuresCellMap"),
|
||||
0x03601: (184, "PropertyArrayMap"),
|
||||
0x03651: (130, "BigIntMap"),
|
||||
0x036a1: (106, "NativeSourceStringMap"),
|
||||
0x036f1: (64, "StringMap"),
|
||||
@ -276,11 +281,16 @@ KNOWN_MAPS = {
|
||||
0x04411: (161, "ModuleInfoEntryMap"),
|
||||
0x04461: (162, "ModuleMap"),
|
||||
0x044b1: (163, "ObjectTemplateInfoMap"),
|
||||
0x04501: (164, "PromiseReactionJobInfoMap"),
|
||||
0x04551: (165, "PromiseResolveThenableJobInfoMap"),
|
||||
0x04501: (164, "PromiseCapabilityMap"),
|
||||
0x04551: (165, "PromiseReactionMap"),
|
||||
0x045a1: (166, "PrototypeInfoMap"),
|
||||
0x045f1: (168, "StackFrameInfoMap"),
|
||||
0x04641: (170, "Tuple3Map"),
|
||||
0x04691: (171, "CallableTaskMap"),
|
||||
0x046e1: (172, "CallbackTaskMap"),
|
||||
0x04731: (173, "PromiseFulfillReactionJobTaskMap"),
|
||||
0x04781: (174, "PromiseRejectReactionJobTaskMap"),
|
||||
0x047d1: (175, "PromiseResolveThenableJobTaskMap"),
|
||||
}
|
||||
|
||||
# List of known V8 objects.
|
||||
@ -327,9 +337,9 @@ KNOWN_OBJECTS = {
|
||||
("OLD_SPACE", 0x029d9): "FastArrayIterationProtector",
|
||||
("OLD_SPACE", 0x029e9): "ArrayIteratorProtector",
|
||||
("OLD_SPACE", 0x02a11): "ArrayBufferNeuteringProtector",
|
||||
("OLD_SPACE", 0x02a61): "InfinityValue",
|
||||
("OLD_SPACE", 0x02a71): "MinusZeroValue",
|
||||
("OLD_SPACE", 0x02a81): "MinusInfinityValue",
|
||||
("OLD_SPACE", 0x02a89): "InfinityValue",
|
||||
("OLD_SPACE", 0x02a99): "MinusZeroValue",
|
||||
("OLD_SPACE", 0x02aa9): "MinusInfinityValue",
|
||||
}
|
||||
|
||||
# List of known V8 Frame Markers.
|
||||
|
Loading…
Reference in New Issue
Block a user