Skip to content

Commit

Permalink
[promises] Port remaining promise code to Torque.
Browse files Browse the repository at this point in the history
Bug: v8:9838
Change-Id: Idc6bda122354a54dd24e39b0356f35b0f54ef089
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2012596
Commit-Queue: Joshua Litt <[email protected]>
Reviewed-by: Jakob Gruber <[email protected]>
Cr-Commit-Position: refs/heads/master@{#66031}
  • Loading branch information
joshualitt authored and Commit Bot committed Jan 29, 2020
1 parent 01646bc commit f22c213
Show file tree
Hide file tree
Showing 15 changed files with 297 additions and 391 deletions.
1 change: 1 addition & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,7 @@ torque_files = [
"src/builtins/promise-all-element-closure.tq",
"src/builtins/promise-constructor.tq",
"src/builtins/promise-finally.tq",
"src/builtins/promise-misc.tq",
"src/builtins/promise-race.tq",
"src/builtins/promise-reaction-job.tq",
"src/builtins/promise-resolve.tq",
Expand Down
2 changes: 1 addition & 1 deletion src/builtins/builtins-async-generator-gen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ void AsyncGeneratorBuiltinsAssembler::AsyncGeneratorEnqueue(
// presently executing, then this method will loop through, processing each
// request from front to back.
// This loop resides in AsyncGeneratorResumeNext.
TNode<JSPromise> promise = AllocateAndInitJSPromise(context);
TNode<JSPromise> promise = NewJSPromise(context);

Label if_receiverisincompatible(this, Label::kDeferred);
GotoIf(TaggedIsSmi(receiver), &if_receiverisincompatible);
Expand Down
2 changes: 1 addition & 1 deletion src/builtins/builtins-async-iterator-gen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
const char* operation_name, Label::Type reject_label_type,
base::Optional<TNode<Object>> initial_exception_value) {
const TNode<NativeContext> native_context = LoadNativeContext(context);
const TNode<JSPromise> promise = AllocateAndInitJSPromise(context);
const TNode<JSPromise> promise = NewJSPromise(context);

TVARIABLE(
Object, var_exception,
Expand Down
226 changes: 7 additions & 219 deletions src/builtins/builtins-promise-gen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,234 +20,22 @@
namespace v8 {
namespace internal {

using Node = compiler::Node;
using IteratorRecord = TorqueStructIteratorRecord;
using PromiseResolvingFunctions = TorqueStructPromiseResolvingFunctions;

TNode<JSPromise> PromiseBuiltinsAssembler::AllocateJSPromise(
TNode<Context> context) {
const TNode<NativeContext> native_context = LoadNativeContext(context);
const TNode<JSFunction> promise_fun =
CAST(LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX));
CSA_ASSERT(this, IsFunctionWithPrototypeSlotMap(LoadMap(promise_fun)));
const TNode<Map> promise_map = LoadObjectField<Map>(
promise_fun, JSFunction::kPrototypeOrInitialMapOffset);
const TNode<HeapObject> promise =
Allocate(JSPromise::kSizeWithEmbedderFields);
StoreMapNoWriteBarrier(promise, promise_map);
StoreObjectFieldRoot(promise, JSPromise::kPropertiesOrHashOffset,
RootIndex::kEmptyFixedArray);
StoreObjectFieldRoot(promise, JSPromise::kElementsOffset,
RootIndex::kEmptyFixedArray);
return CAST(promise);
}

void PromiseBuiltinsAssembler::PromiseInit(TNode<JSPromise> promise) {
STATIC_ASSERT(v8::Promise::kPending == 0);
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kReactionsOrResultOffset,
SmiConstant(Smi::zero()));
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset,
SmiConstant(Smi::zero()));
void PromiseBuiltinsAssembler::ZeroOutEmbedderOffsets(
TNode<JSPromise> promise) {
for (int offset = JSPromise::kHeaderSize;
offset < JSPromise::kSizeWithEmbedderFields; offset += kTaggedSize) {
StoreObjectFieldNoWriteBarrier(promise, offset, SmiConstant(Smi::zero()));
}
}

TNode<JSPromise> PromiseBuiltinsAssembler::AllocateAndInitJSPromise(
TNode<HeapObject> PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask(
TNode<Context> context) {
return AllocateAndInitJSPromise(context, UndefinedConstant());
}

TNode<JSPromise> PromiseBuiltinsAssembler::AllocateAndInitJSPromise(
TNode<Context> context, TNode<Object> parent) {
const TNode<JSPromise> instance = AllocateJSPromise(context);
PromiseInit(instance);

Label out(this);
GotoIfNot(IsPromiseHookEnabledOrHasAsyncEventDelegate(), &out);
CallRuntime(Runtime::kPromiseHookInit, context, instance, parent);
Goto(&out);

BIND(&out);
return instance;
}

TNode<JSPromise> PromiseBuiltinsAssembler::AllocateAndSetJSPromise(
TNode<Context> context, v8::Promise::PromiseState status,
TNode<Object> result) {
DCHECK_NE(Promise::kPending, status);

const TNode<JSPromise> instance = AllocateJSPromise(context);
StoreObjectFieldNoWriteBarrier(instance, JSPromise::kReactionsOrResultOffset,
result);
STATIC_ASSERT(JSPromise::kStatusShift == 0);
StoreObjectFieldNoWriteBarrier(instance, JSPromise::kFlagsOffset,
SmiConstant(status));
for (int offset = JSPromise::kHeaderSize;
offset < JSPromise::kSizeWithEmbedderFields; offset += kTaggedSize) {
StoreObjectFieldNoWriteBarrier(instance, offset, SmiConstant(0));
}

Label out(this);
GotoIfNot(IsPromiseHookEnabledOrHasAsyncEventDelegate(), &out);
CallRuntime(Runtime::kPromiseHookInit, context, instance,
UndefinedConstant());
Goto(&out);

BIND(&out);
return instance;
}

TNode<BoolT> PromiseBuiltinsAssembler::PromiseHasHandler(
TNode<JSPromise> promise) {
const TNode<Smi> flags =
LoadObjectField<Smi>(promise, JSPromise::kFlagsOffset);
return IsSetWord(SmiUntag(flags), 1 << JSPromise::kHasHandlerBit);
}

TNode<PromiseReaction> PromiseBuiltinsAssembler::AllocatePromiseReaction(
TNode<Object> next, TNode<HeapObject> promise_or_capability,
TNode<HeapObject> fulfill_handler, TNode<HeapObject> reject_handler) {
const TNode<HeapObject> reaction = Allocate(PromiseReaction::kSize);
StoreMapNoWriteBarrier(reaction, RootIndex::kPromiseReactionMap);
StoreObjectFieldNoWriteBarrier(reaction, PromiseReaction::kNextOffset, next);
StoreObjectFieldNoWriteBarrier(reaction,
PromiseReaction::kPromiseOrCapabilityOffset,
promise_or_capability);
StoreObjectFieldNoWriteBarrier(
reaction, PromiseReaction::kFulfillHandlerOffset, fulfill_handler);
StoreObjectFieldNoWriteBarrier(
reaction, PromiseReaction::kRejectHandlerOffset, reject_handler);
return CAST(reaction);
}

TNode<PromiseReactionJobTask>
PromiseBuiltinsAssembler::AllocatePromiseReactionJobTask(
TNode<Map> map, TNode<Context> context, TNode<Object> argument,
TNode<HeapObject> handler, TNode<HeapObject> promise_or_capability) {
const TNode<HeapObject> microtask =
Allocate(PromiseReactionJobTask::kSizeOfAllPromiseReactionJobTasks);
StoreMapNoWriteBarrier(microtask, map);
StoreObjectFieldNoWriteBarrier(
microtask, PromiseReactionJobTask::kArgumentOffset, argument);
StoreObjectFieldNoWriteBarrier(
microtask, PromiseReactionJobTask::kContextOffset, context);
StoreObjectFieldNoWriteBarrier(
microtask, PromiseReactionJobTask::kHandlerOffset, handler);
StoreObjectFieldNoWriteBarrier(
microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset,
promise_or_capability);
return CAST(microtask);
}

TNode<PromiseResolveThenableJobTask>
PromiseBuiltinsAssembler::AllocatePromiseResolveThenableJobTask(
TNode<JSPromise> promise_to_resolve, TNode<JSReceiver> then,
TNode<JSReceiver> thenable, TNode<Context> context) {
const TNode<HeapObject> microtask =
Allocate(PromiseResolveThenableJobTask::kSize);
StoreMapNoWriteBarrier(microtask,
RootIndex::kPromiseResolveThenableJobTaskMap);
StoreObjectFieldNoWriteBarrier(
microtask, PromiseResolveThenableJobTask::kContextOffset, context);
StoreObjectFieldNoWriteBarrier(
microtask, PromiseResolveThenableJobTask::kPromiseToResolveOffset,
promise_to_resolve);
StoreObjectFieldNoWriteBarrier(
microtask, PromiseResolveThenableJobTask::kThenOffset, then);
StoreObjectFieldNoWriteBarrier(
microtask, PromiseResolveThenableJobTask::kThenableOffset, thenable);
return CAST(microtask);
}

void PromiseBuiltinsAssembler::BranchIfPromiseResolveLookupChainIntact(
TNode<NativeContext> native_context, TNode<Object> constructor,
Label* if_fast, Label* if_slow) {
GotoIfForceSlowPath(if_slow);
TNode<Object> promise_fun =
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
GotoIfNot(TaggedEqual(promise_fun, constructor), if_slow);
Branch(IsPromiseResolveProtectorCellInvalid(), if_slow, if_fast);
}

void PromiseBuiltinsAssembler::GotoIfNotPromiseResolveLookupChainIntact(
TNode<NativeContext> native_context, TNode<Object> constructor,
Label* if_slow) {
Label if_fast(this);
BranchIfPromiseResolveLookupChainIntact(native_context, constructor, &if_fast,
if_slow);
BIND(&if_fast);
}

void PromiseBuiltinsAssembler::BranchIfPromiseSpeciesLookupChainIntact(
TNode<NativeContext> native_context, TNode<Map> promise_map, Label* if_fast,
Label* if_slow) {
TNode<Object> promise_prototype =
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
GotoIfForceSlowPath(if_slow);
GotoIfNot(TaggedEqual(LoadMapPrototype(promise_map), promise_prototype),
if_slow);
Branch(IsPromiseSpeciesProtectorCellInvalid(), if_slow, if_fast);
return Allocate(PromiseReactionJobTask::kSizeOfAllPromiseReactionJobTasks);
}

void PromiseBuiltinsAssembler::BranchIfPromiseThenLookupChainIntact(
TNode<NativeContext> native_context, TNode<Map> receiver_map,
Label* if_fast, Label* if_slow) {
GotoIfForceSlowPath(if_slow);
GotoIfNot(IsJSPromiseMap(receiver_map), if_slow);
const TNode<Object> promise_prototype =
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
GotoIfNot(TaggedEqual(LoadMapPrototype(receiver_map), promise_prototype),
if_slow);
Branch(IsPromiseThenProtectorCellInvalid(), if_slow, if_fast);
}

void PromiseBuiltinsAssembler::BranchIfAccessCheckFailed(
TNode<Context> context, TNode<Context> native_context,
TNode<Object> promise_constructor, TNode<Object> executor,
Label* if_noaccess) {
TVARIABLE(HeapObject, var_executor);
var_executor = CAST(executor);
Label has_access(this), call_runtime(this, Label::kDeferred);

// If executor is a bound function, load the bound function until we've
// reached an actual function.
Label found_function(this), loop_over_bound_function(this, &var_executor);
Goto(&loop_over_bound_function);
BIND(&loop_over_bound_function);
{
TNode<Uint16T> executor_type = LoadInstanceType(var_executor.value());
GotoIf(InstanceTypeEqual(executor_type, JS_FUNCTION_TYPE), &found_function);
GotoIfNot(InstanceTypeEqual(executor_type, JS_BOUND_FUNCTION_TYPE),
&call_runtime);
var_executor = LoadObjectField<HeapObject>(
var_executor.value(), JSBoundFunction::kBoundTargetFunctionOffset);
Goto(&loop_over_bound_function);
}

// Load the context from the function and compare it to the Promise
// constructor's context. If they match, everything is fine, otherwise, bail
// out to the runtime.
BIND(&found_function);
{
TNode<Context> function_context = LoadObjectField<Context>(
var_executor.value(), JSFunction::kContextOffset);
TNode<NativeContext> native_function_context =
LoadNativeContext(function_context);
Branch(TaggedEqual(native_context, native_function_context), &has_access,
&call_runtime);
}

BIND(&call_runtime);
{
Branch(TaggedEqual(CallRuntime(Runtime::kAllowDynamicFunction, context,
promise_constructor),
TrueConstant()),
&has_access, if_noaccess);
}

BIND(&has_access);
TNode<HeapObject> PromiseBuiltinsAssembler::AllocateJSPromise(
TNode<Context> context) {
return Allocate(JSPromise::kSizeWithEmbedderFields);
}

} // namespace internal
Expand Down
107 changes: 3 additions & 104 deletions src/builtins/builtins-promise-gen.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,112 +17,11 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
public:
explicit PromiseBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
// These allocate and initialize a promise with pending state and
// undefined fields.
//
// This uses undefined as the parent promise for the promise init
// hook.
TNode<JSPromise> AllocateAndInitJSPromise(TNode<Context> context);
// This uses the given parent as the parent promise for the promise
// init hook.
TNode<JSPromise> AllocateAndInitJSPromise(TNode<Context> context,
TNode<Object> parent);
void ZeroOutEmbedderOffsets(TNode<JSPromise> promise);

// This allocates and initializes a promise with the given state and
// fields.
TNode<JSPromise> AllocateAndSetJSPromise(TNode<Context> context,
v8::Promise::PromiseState status,
TNode<Object> result);
TNode<HeapObject> AllocateJSPromise(TNode<Context> context);

TNode<PromiseReaction> AllocatePromiseReaction(
TNode<Object> next, TNode<HeapObject> promise_or_capability,
TNode<HeapObject> fulfill_handler, TNode<HeapObject> reject_handler);

TNode<PromiseReactionJobTask> AllocatePromiseReactionJobTask(
TNode<Map> map, TNode<Context> context, TNode<Object> argument,
TNode<HeapObject> handler, TNode<HeapObject> promise_or_capability);

TNode<PromiseResolveThenableJobTask> AllocatePromiseResolveThenableJobTask(
TNode<JSPromise> promise_to_resolve, TNode<JSReceiver> then,
TNode<JSReceiver> thenable, TNode<Context> context);
TNode<BoolT> PromiseHasHandler(TNode<JSPromise> promise);

void BranchIfAccessCheckFailed(TNode<Context> context,
TNode<Context> native_context,
TNode<Object> promise_constructor,
TNode<Object> executor, Label* if_noaccess);
void PromiseInit(TNode<JSPromise> promise);

// 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(
TNode<NativeContext> native_context, TNode<Map> promise_map,
Label* if_fast, Label* if_slow);

template <typename... TArgs>
TNode<Object> InvokeThen(TNode<NativeContext> native_context,
TNode<Object> receiver, TArgs... args) {
TVARIABLE(Object, var_result);
Label if_fast(this), if_slow(this, Label::kDeferred),
done(this, &var_result);
GotoIf(TaggedIsSmi(receiver), &if_slow);
const TNode<Map> receiver_map = LoadMap(CAST(receiver));
// We can skip the "then" lookup on {receiver} 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%.
BranchIfPromiseThenLookupChainIntact(native_context, receiver_map, &if_fast,
&if_slow);

BIND(&if_fast);
{
const TNode<Object> then =
LoadContextElement(native_context, Context::PROMISE_THEN_INDEX);
var_result =
CallJS(CodeFactory::CallFunction(
isolate(), ConvertReceiverMode::kNotNullOrUndefined),
native_context, then, receiver, args...);
Goto(&done);
}

BIND(&if_slow);
{
const TNode<Object> then = GetProperty(
native_context, receiver, isolate()->factory()->then_string());
var_result =
CallJS(CodeFactory::Call(isolate(),
ConvertReceiverMode::kNotNullOrUndefined),
native_context, then, receiver, args...);
Goto(&done);
}

BIND(&done);
return var_result.value();
}

protected:
// We can skip the "resolve" lookup on {constructor} if it's the (initial)
// Promise constructor and the Promise.resolve() protector is intact, as
// that guards the lookup path for the "resolve" property on the %Promise%
// intrinsic object.
void BranchIfPromiseResolveLookupChainIntact(
TNode<NativeContext> native_context, TNode<Object> constructor,
Label* if_fast, Label* if_slow);
void GotoIfNotPromiseResolveLookupChainIntact(
TNode<NativeContext> native_context, TNode<Object> constructor,
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(TNode<NativeContext> native_context,
TNode<Map> receiver_map,
Label* if_fast, Label* if_slow);

TNode<JSPromise> AllocateJSPromise(TNode<Context> context);
TNode<HeapObject> AllocatePromiseReactionJobTask(TNode<Context> context);
};

} // namespace internal
Expand Down
Loading

0 comments on commit f22c213

Please sign in to comment.