Commit 5bcaca3a authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[promise] Refactor Promise.all

The resolve/reject callbacks to PerformPromiseAll is refactored out so
that we can just pass different closures for PerformPromiseAllSettled.

Similarly, a closure to update the value is passed to
Generate_PromiseAllResolveElementClosure so that we can create a
diferrent value in case of Promise.allSettled.

Bug: v8:9060
Change-Id: I4e1bebe6da4ea0965a67cccc8365ed91cf4683c7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1559216
Auto-Submit: Sathya Gunasekaran <gsathya@chromium.org>
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60732}
parent 4e0b0c65
......@@ -288,8 +288,9 @@ Node* PromiseBuiltinsAssembler::CreatePromiseAllResolveElementContext(
return context;
}
Node* PromiseBuiltinsAssembler::CreatePromiseAllResolveElementFunction(
Node* context, TNode<Smi> index, Node* native_context) {
TNode<JSFunction>
PromiseBuiltinsAssembler::CreatePromiseAllResolveElementFunction(
Node* context, TNode<Smi> index, Node* native_context, int slot_index) {
CSA_ASSERT(this, SmiGreaterThan(index, SmiConstant(0)));
CSA_ASSERT(this, SmiLessThanOrEqual(
index, SmiConstant(PropertyArray::HashField::kMax)));
......@@ -297,10 +298,9 @@ Node* PromiseBuiltinsAssembler::CreatePromiseAllResolveElementFunction(
Node* const map = LoadContextElement(
native_context, Context::STRICT_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX);
Node* const resolve_info = LoadContextElement(
native_context, Context::PROMISE_ALL_RESOLVE_ELEMENT_SHARED_FUN);
Node* const resolve =
AllocateFunctionWithMapAndContext(map, resolve_info, context);
Node* const resolve_info = LoadContextElement(native_context, slot_index);
TNode<JSFunction> resolve =
Cast(AllocateFunctionWithMapAndContext(map, resolve_info, context));
STATIC_ASSERT(PropertyArray::kNoHashSentinel == 0);
StoreObjectFieldNoWriteBarrier(resolve, JSFunction::kPropertiesOrHashOffset,
......@@ -2027,11 +2027,13 @@ TF_BUILTIN(ResolvePromise, PromiseBuiltinsAssembler) {
Node* PromiseBuiltinsAssembler::PerformPromiseAll(
Node* context, Node* constructor, Node* capability,
const IteratorRecord& iterator, Label* if_exception,
Variable* var_exception) {
const IteratorRecord& iterator,
const PromiseAllResolvingElementFunction& create_resolve_element_function,
const PromiseAllResolvingElementFunction& create_reject_element_function,
Label* if_exception, Variable* var_exception) {
IteratorBuiltinsAssembler iter_assembler(state());
Node* const native_context = LoadNativeContext(context);
TNode<NativeContext> native_context = Cast(LoadNativeContext(context));
// For catch prediction, don't treat the .then calls as handling it;
// instead, recurse outwards.
......@@ -2039,8 +2041,8 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
native_context, IsDebugActive(),
LoadObjectField(capability, PromiseCapability::kRejectOffset));
Node* const resolve_element_context =
CreatePromiseAllResolveElementContext(capability, native_context);
TNode<Context> resolve_element_context =
Cast(CreatePromiseAllResolveElementContext(capability, native_context));
TVARIABLE(Smi, var_index, SmiConstant(1));
Label loop(this, &var_index), done_loop(this),
......@@ -2095,8 +2097,10 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
// Set resolveElement.[[Values]] to values.
// Set resolveElement.[[Capability]] to resultCapability.
// Set resolveElement.[[RemainingElements]] to remainingElementsCount.
Node* const resolve_element_fun = CreatePromiseAllResolveElementFunction(
resolve_element_context, index, native_context);
Node* const resolve_element_fun = create_resolve_element_function(
resolve_element_context, index, native_context, Cast(capability));
Node* const reject_element_fun = create_reject_element_function(
resolve_element_context, index, native_context, Cast(capability));
// We can skip the "resolve" lookup on the {constructor} as well as the
// "then" lookup on the result of the "resolve" call, and immediately
......@@ -2155,7 +2159,7 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
CallJS(CodeFactory::Call(isolate(),
ConvertReceiverMode::kNotNullOrUndefined),
native_context, then, next_promise, resolve_element_fun,
LoadObjectField(capability, PromiseCapability::kRejectOffset));
reject_element_fun);
GotoIfException(then_call, &close_iterator, var_exception);
// For catch prediction, mark that rejections here are semantically
......@@ -2259,15 +2263,14 @@ Node* PromiseBuiltinsAssembler::PerformPromiseAll(
return promise;
}
// ES#sec-promise.all
// Promise.all ( iterable )
TF_BUILTIN(PromiseAll, PromiseBuiltinsAssembler) {
void PromiseBuiltinsAssembler::Generate_PromiseAll(
TNode<Context> context, TNode<Object> receiver, TNode<Object> iterable,
const PromiseAllResolvingElementFunction& create_resolve_element_function,
const PromiseAllResolvingElementFunction& create_reject_element_function) {
IteratorBuiltinsAssembler iter_assembler(state());
// Let C be the this value.
// If Type(C) is not Object, throw a TypeError exception.
Node* const receiver = Parameter(Descriptor::kReceiver);
Node* const context = Parameter(Descriptor::kContext);
ThrowIfNotJSReceiver(context, receiver, MessageTemplate::kCalledOnNonObject,
"Promise.all");
......@@ -2283,7 +2286,6 @@ TF_BUILTIN(PromiseAll, PromiseBuiltinsAssembler) {
// Let iterator be GetIterator(iterable).
// IfAbruptRejectPromise(iterator, promiseCapability).
Node* const iterable = Parameter(Descriptor::kIterable);
IteratorRecord iterator = iter_assembler.GetIterator(
context, iterable, &reject_promise, &var_exception);
......@@ -2293,7 +2295,8 @@ TF_BUILTIN(PromiseAll, PromiseBuiltinsAssembler) {
// IteratorClose(iterator, result).
// IfAbruptRejectPromise(result, promiseCapability).
Node* const result = PerformPromiseAll(
context, receiver, capability, iterator, &reject_promise, &var_exception);
context, receiver, capability, iterator, create_resolve_element_function,
create_reject_element_function, &reject_promise, &var_exception);
Return(result);
......@@ -2312,11 +2315,31 @@ TF_BUILTIN(PromiseAll, PromiseBuiltinsAssembler) {
}
}
TF_BUILTIN(PromiseAllResolveElementClosure, PromiseBuiltinsAssembler) {
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<JSFunction> function = CAST(Parameter(Descriptor::kJSTarget));
// ES#sec-promise.all
// Promise.all ( iterable )
TF_BUILTIN(PromiseAll, PromiseBuiltinsAssembler) {
TNode<Object> receiver = Cast(Parameter(Descriptor::kReceiver));
TNode<Context> context = Cast(Parameter(Descriptor::kContext));
TNode<Object> iterable = Cast(Parameter(Descriptor::kIterable));
Generate_PromiseAll(
context, receiver, iterable,
[this](TNode<Context> context, TNode<Smi> index,
TNode<NativeContext> native_context,
TNode<PromiseCapability> capability) {
return CreatePromiseAllResolveElementFunction(
context, index, native_context,
Context::PROMISE_ALL_RESOLVE_ELEMENT_SHARED_FUN);
},
[this](TNode<Context> context, TNode<Smi> index,
TNode<NativeContext> native_context,
TNode<PromiseCapability> capability) {
return LoadObjectField(capability, PromiseCapability::kRejectOffset);
});
}
void PromiseBuiltinsAssembler::Generate_PromiseAllResolveElementClosure(
TNode<Context> context, TNode<Object> value, TNode<JSFunction> function,
const CreatePromiseAllResolveElementFunctionValue& callback) {
Label already_called(this, Label::kDeferred), resolve_promise(this);
// We use the {function}s context as the marker to remember whether this
......@@ -2332,6 +2355,10 @@ TF_BUILTIN(PromiseAllResolveElementClosure, PromiseBuiltinsAssembler) {
TNode<Context> native_context = LoadNativeContext(context);
StoreObjectField(function, JSFunction::kContextOffset, native_context);
// Update the value depending on whether Promise.all or
// Promise.allSettled is called.
value = callback(context, value);
// Determine the index from the {function}.
Label unreachable(this, Label::kDeferred);
STATIC_ASSERT(PropertyArray::kNoHashSentinel == 0);
......@@ -2426,6 +2453,16 @@ TF_BUILTIN(PromiseAllResolveElementClosure, PromiseBuiltinsAssembler) {
Unreachable();
}
TF_BUILTIN(PromiseAllResolveElementClosure, PromiseBuiltinsAssembler) {
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<JSFunction> function = CAST(Parameter(Descriptor::kJSTarget));
Generate_PromiseAllResolveElementClosure(
context, value, function,
[](TNode<Object> context, TNode<Object> value) { return value; });
}
// ES#sec-promise.race
// Promise.race ( iterable )
TF_BUILTIN(PromiseRace, PromiseBuiltinsAssembler) {
......
......@@ -62,8 +62,10 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
// case to mark it's done).
Node* CreatePromiseAllResolveElementContext(Node* promise_capability,
Node* native_context);
Node* CreatePromiseAllResolveElementFunction(Node* context, TNode<Smi> index,
Node* native_context);
TNode<JSFunction> CreatePromiseAllResolveElementFunction(Node* context,
TNode<Smi> index,
Node* native_context,
int slot_index);
Node* CreatePromiseResolvingFunctionsContext(Node* promise, Node* debug_event,
Node* native_context);
......@@ -129,9 +131,16 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
Node* CreateThrowerFunction(Node* reason, Node* native_context);
typedef std::function<TNode<Object>(TNode<Context> context, TNode<Smi> index,
TNode<NativeContext> native_context,
TNode<PromiseCapability> capability)>
PromiseAllResolvingElementFunction;
Node* PerformPromiseAll(
Node* context, Node* constructor, Node* capability,
const IteratorBuiltinsFromDSLAssembler::IteratorRecord& record,
const PromiseAllResolvingElementFunction& create_resolve_element_function,
const PromiseAllResolvingElementFunction& create_reject_element_function,
Label* if_exception, Variable* var_exception);
void SetForwardingHandlerIfTrue(Node* context, Node* condition,
......@@ -156,6 +165,18 @@ class V8_EXPORT_PRIVATE PromiseBuiltinsAssembler : public CodeStubAssembler {
Node* AllocateJSPromise(Node* context);
void ExtractHandlerContext(Node* handler, Variable* var_context);
void Generate_PromiseAll(
TNode<Context> context, TNode<Object> receiver, TNode<Object> iterable,
const PromiseAllResolvingElementFunction& create_resolve_element_function,
const PromiseAllResolvingElementFunction& create_reject_element_function);
typedef std::function<TNode<Object>(TNode<Context> context,
TNode<Object> value)>
CreatePromiseAllResolveElementFunctionValue;
void Generate_PromiseAllResolveElementClosure(
TNode<Context> context, TNode<Object> value, TNode<JSFunction> function,
const CreatePromiseAllResolveElementFunctionValue& callback);
};
} // namespace internal
......
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