Commit 60f922b4 authored by Joshua Litt's avatar Joshua Litt Committed by Commit Bot

[promises] Port PromiseResolve to torque.

Bug: v8:9838
Change-Id: Iae406457754c66c8e03843bdfc42b6defd76e3ad
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1955756
Commit-Queue: Joshua Litt <joshualitt@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65435}
parent 8aa58897
......@@ -973,6 +973,7 @@ torque_files = [
"src/builtins/object.tq",
"src/builtins/promise-abstract-operations.tq",
"src/builtins/promise-constructor.tq",
"src/builtins/promise-resolve.tq",
"src/builtins/promise-then.tq",
"src/builtins/promise-jobs.tq",
"src/builtins/proxy-constructor.tq",
......
......@@ -723,10 +723,6 @@ namespace internal {
/* ES #sec-promisereactionjob */ \
TFS(PromiseRejectReactionJob, kReason, kHandler, kPromiseOrCapability) \
TFS(PromiseFulfillReactionJob, kValue, kHandler, kPromiseOrCapability) \
/* ES #sec-promise.resolve */ \
TFJ(PromiseResolveTrampoline, 1, kReceiver, kValue) \
/* ES #sec-promise-resolve */ \
TFS(PromiseResolve, kConstructor, kValue) \
/* ES #sec-promise.reject */ \
TFJ(PromiseReject, 1, kReceiver, kReason) \
TFJ(PromisePrototypeFinally, 1, kReceiver, kOnFinally) \
......
......@@ -679,97 +679,6 @@ TF_BUILTIN(PromiseRejectReactionJob, PromiseBuiltinsAssembler) {
PromiseReaction::kReject);
}
TF_BUILTIN(PromiseResolveTrampoline, PromiseBuiltinsAssembler) {
// 1. Let C be the this value.
Node* receiver = Parameter(Descriptor::kReceiver);
Node* value = Parameter(Descriptor::kValue);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
// 2. If Type(C) is not Object, throw a TypeError exception.
ThrowIfNotJSReceiver(context, CAST(receiver),
MessageTemplate::kCalledOnNonObject, "PromiseResolve");
// 3. Return ? PromiseResolve(C, x).
Return(CallBuiltin(Builtins::kPromiseResolve, context, receiver, value));
}
TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
TNode<JSReceiver> constructor = CAST(Parameter(Descriptor::kConstructor));
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<JSFunction> promise_fun =
CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
Label if_slow_constructor(this, Label::kDeferred), if_need_to_allocate(this);
// Check if {value} is a JSPromise.
GotoIf(TaggedIsSmi(value), &if_need_to_allocate);
const TNode<Map> value_map = LoadMap(CAST(value));
GotoIfNot(IsJSPromiseMap(value_map), &if_need_to_allocate);
// We can skip the "constructor" lookup on {value} if it's [[Prototype]]
// is the (initial) Promise.prototype and the @@species protector is
// intact, as that guards the lookup path for "constructor" on
// JSPromise instances which have the (initial) Promise.prototype.
TNode<Object> promise_prototype =
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
GotoIfNot(TaggedEqual(LoadMapPrototype(value_map), promise_prototype),
&if_slow_constructor);
GotoIf(IsPromiseSpeciesProtectorCellInvalid(), &if_slow_constructor);
// If the {constructor} is the Promise function, we just immediately
// return the {value} here and don't bother wrapping it into a
// native Promise.
GotoIfNot(TaggedEqual(promise_fun, constructor), &if_slow_constructor);
Return(value);
// At this point, value or/and constructor are not native promises, but
// they could be of the same subclass.
BIND(&if_slow_constructor);
{
TNode<Object> value_constructor =
GetProperty(context, value, isolate()->factory()->constructor_string());
GotoIfNot(TaggedEqual(value_constructor, constructor),
&if_need_to_allocate);
Return(value);
}
BIND(&if_need_to_allocate);
{
Label if_nativepromise(this), if_notnativepromise(this, Label::kDeferred);
Branch(TaggedEqual(promise_fun, constructor), &if_nativepromise,
&if_notnativepromise);
// This adds a fast path for native promises that don't need to
// create NewPromiseCapability.
BIND(&if_nativepromise);
{
const TNode<JSPromise> result = AllocateAndInitJSPromise(context);
CallBuiltin(Builtins::kResolvePromise, context, result, value);
Return(result);
}
BIND(&if_notnativepromise);
{
const TNode<Oddball> debug_event = TrueConstant();
const TNode<PromiseCapability> capability = CAST(CallBuiltin(
Builtins::kNewPromiseCapability, context, constructor, debug_event));
const TNode<Object> resolve =
LoadObjectField(capability, PromiseCapability::kResolveOffset);
CallJS(
CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
context, resolve, UndefinedConstant(), value);
const TNode<Object> result =
LoadObjectField(capability, PromiseCapability::kPromiseOffset);
Return(result);
}
}
}
// ES6 #sec-getcapabilitiesexecutor-functions
TF_BUILTIN(PromiseGetCapabilitiesExecutor, PromiseBuiltinsAssembler) {
Node* const resolve = Parameter(Descriptor::kResolve);
......
// Copyright 2019 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.
#include 'src/builtins/builtins-promise-gen.h'
namespace promise {
const kCalledOnNonObject: constexpr MessageTemplate
generates 'MessageTemplate::kCalledOnNonObject';
const PROMISE_PROTOTYPE_INDEX: constexpr NativeContextSlot
generates 'Context::PROMISE_PROTOTYPE_INDEX';
extern macro ConstructorStringConstant(): String;
const kConstructorString: String = ConstructorStringConstant();
// https://tc39.es/ecma262/#sec-promise.resolve
transitioning javascript builtin
PromiseResolveTrampoline(js-implicit context: NativeContext, receiver: JSAny)(
value: JSAny): JSAny {
// 1. Let C be the this value.
// 2. If Type(C) is not Object, throw a TypeError exception.
const receiver = Cast<JSReceiver>(receiver) otherwise
ThrowTypeError(kCalledOnNonObject, 'PromiseResolve');
// 3. Return ? PromiseResolve(C, x).
return PromiseResolve(receiver, value);
}
transitioning builtin
PromiseResolve(implicit context:
Context)(constructor: JSReceiver, value: JSAny): JSAny {
const nativeContext = LoadNativeContext(context);
const promiseFun = nativeContext[PROMISE_FUNCTION_INDEX];
try {
// Check if {value} is a JSPromise.
const value = Cast<JSPromise>(value) otherwise NeedToAllocate;
// We can skip the "constructor" lookup on {value} if it's [[Prototype]]
// is the (initial) Promise.prototype and the @@species protector is
// intact, as that guards the lookup path for "constructor" on
// JSPromise instances which have the (initial) Promise.prototype.
const promisePrototype = nativeContext[PROMISE_PROTOTYPE_INDEX];
if (value.map.prototype != promisePrototype) {
goto SlowConstructor;
}
if (IsPromiseSpeciesProtectorCellInvalid()) goto SlowConstructor;
// If the {constructor} is the Promise function, we just immediately
// return the {value} here and don't bother wrapping it into a
// native Promise.
if (promiseFun != constructor) goto SlowConstructor;
return value;
}
label SlowConstructor deferred {
// At this point, value or/and constructor are not native promises, but
// they could be of the same subclass.
const valueConstructor = GetProperty(value, kConstructorString);
if (valueConstructor != constructor) goto NeedToAllocate;
return value;
}
label NeedToAllocate deferred {
if (promiseFun == constructor) {
// This adds a fast path for native promises that don't need to
// create NewPromiseCapability.
const result = AllocateAndInitJSPromise(context);
ResolvePromise(context, result, value);
return result;
} else
deferred {
const capability = NewPromiseCapability(constructor, True);
const resolve = UnsafeCast<Callable>(capability.resolve);
Call(context, resolve, Undefined, value);
return capability.promise;
}
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment