Revert "[builtins] Mega-revert to address the Dev blocker in crbug.com/808911."

This reverts commit 14108f4c2e.

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 commit 7632da067b.
> - Revert "[builtins] Also use the Promise#then protector for Promise#finally()."
>   This reverts commit d4f072ced3.
> - Revert "[builtins] Don't mess with entered context for MicrotaskCallbacks."
>   This reverts commit 6703dacdd6.
> - Revert "[debugger] Properly deal with settled promises in catch prediction."
>   This reverts commit 40dd065823.
> - Revert "[builtins] Widen the fast-path for Promise builtins."
>   This reverts commit db0556b7e8.
> - Revert "[builtins] Unify PerformPromiseThen and optimize it with TurboFan."
>   This reverts commit a582199c5e.
> - Revert "[builtins] Remove obsolete PromiseBuiltinsAssembler::AppendPromiseCallback."
>   This reverts commit 6bf8885290.
> - Revert "[builtins] Turn NewPromiseCapability into a proper builtin."
>   This reverts commit 313b490ddd.
> - Revert "[builtins] Inline InternalPromiseThen into it's only caller"
>   This reverts commit f7bd6a2fd6.
> - Revert "[builtins] Implement Promise#catch by really calling into Promise#then."
>   This reverts commit b23b098fa0.
> - Revert "[promise] Remove incorrect fast path"
>   This reverts commit 0f6eafe855.
> - Revert "[builtins] Squeeze JSPromise::result and JSPromise::reactions into a single field."
>   This reverts commit 8a677a2831.
> - Revert "[builtins] Refactor promises to reduce GC overhead."
>   This reverts commit 8e7737cb58.
> 
> 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:
Adam Klein 2018-02-08 16:36:52 +00:00 committed by Commit Bot
parent 2ef90158fb
commit 3916401e4b
59 changed files with 2338 additions and 1498 deletions

View File

@ -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.

View File

@ -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);
}

View File

@ -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(

View File

@ -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,

View File

@ -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);

View File

@ -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(...)

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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(); }

View File

@ -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);

View File

@ -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),

View File

@ -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(); }

View File

@ -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)

View File

@ -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);

View File

@ -195,6 +195,7 @@
V(JSGeneratorRestoreContext) \
V(JSGeneratorRestoreRegister) \
V(JSGeneratorRestoreInputOrDebugPos) \
V(JSPerformPromiseThen) \
V(JSStackCheck) \
V(JSDebugger)

View File

@ -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(); }

View File

@ -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();

View File

@ -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:

View File

@ -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) \

View File

@ -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(),

View File

@ -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);

View File

@ -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) \

View File

@ -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) \

View File

@ -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());

View File

@ -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);

View File

@ -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_; }

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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());

View File

@ -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();

View File

@ -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";
}

View File

@ -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); }

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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);

View File

@ -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();
}

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View 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(); })();

View File

@ -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);

View File

@ -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);

View 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));

View 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));
})();

View File

@ -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);

View File

@ -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);

View 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));

View 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);
})();

View 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);
})();

View 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);

View 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]);

View File

@ -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

View File

@ -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.