[await] Update async iterators to return a rejected promise on error
This implements the behavior discussed and specified here: https://github.com/tc39/ecma262/issues/1461 https://github.com/tc39/ecma262/pull/1470 As part of making this change, I realized that we didn't actually toggle the behavior between the optimized and unoptimized version based on the --harmony-await-optimization flag at all and just the unoptimized version by default. This patch removes the unoptimized version and uses the optimized version as the default. The other builtins that use this flag are not touched as part of this CL, they will be updated separately. Bug: v8:8998 Change-Id: I315e1b39dda91d0127b5e567986485d713eaa78d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1525872 Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Cr-Commit-Position: refs/heads/master@{#60310}
This commit is contained in:
parent
efa249a898
commit
1cb05f1ff4
@ -36,13 +36,6 @@ class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler {
|
||||
const char* operation_name,
|
||||
Label::Type reject_label_type = Label::kDeferred,
|
||||
Node* const initial_exception_value = nullptr);
|
||||
void Generate_AsyncFromSyncIteratorMethodOptimized(
|
||||
Node* const context, Node* const iterator, Node* const sent_value,
|
||||
const SyncIteratorNodeGenerator& get_method,
|
||||
const UndefinedMethodHandler& if_method_undefined,
|
||||
const char* operation_name,
|
||||
Label::Type reject_label_type = Label::kDeferred,
|
||||
Node* const initial_exception_value = nullptr);
|
||||
|
||||
void Generate_AsyncFromSyncIteratorMethod(
|
||||
Node* const context, Node* const iterator, Node* const sent_value,
|
||||
@ -57,19 +50,6 @@ class AsyncFromSyncBuiltinsAssembler : public AsyncBuiltinsAssembler {
|
||||
context, iterator, sent_value, get_method, if_method_undefined,
|
||||
operation_name, reject_label_type, initial_exception_value);
|
||||
}
|
||||
void Generate_AsyncFromSyncIteratorMethodOptimized(
|
||||
Node* const context, Node* const iterator, Node* const sent_value,
|
||||
Handle<String> name, const UndefinedMethodHandler& if_method_undefined,
|
||||
const char* operation_name,
|
||||
Label::Type reject_label_type = Label::kDeferred,
|
||||
Node* const initial_exception_value = nullptr) {
|
||||
auto get_method = [=](Node* const sync_iterator) {
|
||||
return GetProperty(context, sync_iterator, name);
|
||||
};
|
||||
return Generate_AsyncFromSyncIteratorMethodOptimized(
|
||||
context, iterator, sent_value, get_method, if_method_undefined,
|
||||
operation_name, reject_label_type, initial_exception_value);
|
||||
}
|
||||
|
||||
// Load "value" and "done" from an iterator result object. If an exception
|
||||
// is thrown at any point, jumps to te `if_exception` label with exception
|
||||
@ -148,71 +128,6 @@ void AsyncFromSyncBuiltinsAssembler::Generate_AsyncFromSyncIteratorMethod(
|
||||
method, sync_iterator, sent_value);
|
||||
GotoIfException(iter_result, &reject_promise, &var_exception);
|
||||
|
||||
Node* value;
|
||||
Node* done;
|
||||
std::tie(value, done) = LoadIteratorResult(
|
||||
context, native_context, iter_result, &reject_promise, &var_exception);
|
||||
Node* const wrapper = AllocateAndInitJSPromise(context);
|
||||
|
||||
// Perform ! Call(valueWrapperCapability.[[Resolve]], undefined, «
|
||||
// throwValue »).
|
||||
CallBuiltin(Builtins::kResolvePromise, context, wrapper, value);
|
||||
|
||||
// Let onFulfilled be a new built-in function object as defined in
|
||||
// Async Iterator Value Unwrap Functions.
|
||||
// Set onFulfilled.[[Done]] to throwDone.
|
||||
Node* const on_fulfilled = CreateUnwrapClosure(native_context, done);
|
||||
|
||||
// Perform ! PerformPromiseThen(valueWrapperCapability.[[Promise]],
|
||||
// onFulfilled, undefined, promiseCapability).
|
||||
Return(CallBuiltin(Builtins::kPerformPromiseThen, context, wrapper,
|
||||
on_fulfilled, UndefinedConstant(), promise));
|
||||
|
||||
BIND(&reject_promise);
|
||||
{
|
||||
Node* const exception = var_exception.value();
|
||||
CallBuiltin(Builtins::kRejectPromise, context, promise, exception,
|
||||
TrueConstant());
|
||||
Return(promise);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncFromSyncBuiltinsAssembler::
|
||||
Generate_AsyncFromSyncIteratorMethodOptimized(
|
||||
Node* const context, Node* const iterator, Node* const sent_value,
|
||||
const SyncIteratorNodeGenerator& get_method,
|
||||
const UndefinedMethodHandler& if_method_undefined,
|
||||
const char* operation_name, Label::Type reject_label_type,
|
||||
Node* const initial_exception_value) {
|
||||
Node* const native_context = LoadNativeContext(context);
|
||||
Node* const promise = AllocateAndInitJSPromise(context);
|
||||
|
||||
VARIABLE(var_exception, MachineRepresentation::kTagged,
|
||||
initial_exception_value == nullptr ? UndefinedConstant()
|
||||
: initial_exception_value);
|
||||
Label reject_promise(this, reject_label_type);
|
||||
|
||||
ThrowIfNotAsyncFromSyncIterator(context, iterator, &reject_promise,
|
||||
&var_exception, operation_name);
|
||||
|
||||
Node* const sync_iterator =
|
||||
LoadObjectField(iterator, JSAsyncFromSyncIterator::kSyncIteratorOffset);
|
||||
|
||||
Node* const method = get_method(sync_iterator);
|
||||
|
||||
if (if_method_undefined) {
|
||||
Label if_isnotundefined(this);
|
||||
|
||||
GotoIfNot(IsUndefined(method), &if_isnotundefined);
|
||||
if_method_undefined(native_context, promise, &reject_promise);
|
||||
|
||||
BIND(&if_isnotundefined);
|
||||
}
|
||||
|
||||
Node* const iter_result = CallJS(CodeFactory::Call(isolate()), context,
|
||||
method, sync_iterator, sent_value);
|
||||
GotoIfException(iter_result, &reject_promise, &var_exception);
|
||||
|
||||
Node* value;
|
||||
Node* done;
|
||||
std::tie(value, done) = LoadIteratorResult(
|
||||
@ -222,9 +137,11 @@ void AsyncFromSyncBuiltinsAssembler::
|
||||
LoadContextElement(native_context, Context::PROMISE_FUNCTION_INDEX);
|
||||
CSA_ASSERT(this, IsConstructor(promise_fun));
|
||||
|
||||
// Let valueWrapper be ? PromiseResolve(« value »).
|
||||
Node* const valueWrapper = CallBuiltin(Builtins::kPromiseResolve,
|
||||
native_context, promise_fun, value);
|
||||
// Let valueWrapper be PromiseResolve(%Promise%, « value »).
|
||||
Node* const value_wrapper = CallBuiltin(Builtins::kPromiseResolve,
|
||||
native_context, promise_fun, value);
|
||||
// IfAbruptRejectPromise(valueWrapper, promiseCapability).
|
||||
GotoIfException(value_wrapper, &reject_promise, &var_exception);
|
||||
|
||||
// Let onFulfilled be a new built-in function object as defined in
|
||||
// Async Iterator Value Unwrap Functions.
|
||||
@ -233,7 +150,7 @@ void AsyncFromSyncBuiltinsAssembler::
|
||||
|
||||
// Perform ! PerformPromiseThen(valueWrapper,
|
||||
// onFulfilled, undefined, promiseCapability).
|
||||
Return(CallBuiltin(Builtins::kPerformPromiseThen, context, valueWrapper,
|
||||
Return(CallBuiltin(Builtins::kPerformPromiseThen, context, value_wrapper,
|
||||
on_fulfilled, UndefinedConstant(), promise));
|
||||
|
||||
BIND(&reject_promise);
|
||||
|
29
test/mjsunit/harmony/async-iterators-resolve.js
Normal file
29
test/mjsunit/harmony/async-iterators-resolve.js
Normal file
@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
//
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
let actual = [];
|
||||
|
||||
async function f() {
|
||||
var p = Promise.resolve(0);
|
||||
Object.defineProperty(p, "constructor", {
|
||||
get() {
|
||||
throw new Error();
|
||||
}
|
||||
});
|
||||
actual.push("start");
|
||||
for await (var x of [p]);
|
||||
actual.push("never reached");
|
||||
}
|
||||
|
||||
Promise.resolve(0)
|
||||
.then(() => actual.push("tick 1"))
|
||||
.then(() => actual.push("tick 2"))
|
||||
|
||||
f().catch(() => actual.push("catch"));
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
|
||||
assertSame(["start", "tick 1", "tick 2", "catch"].join(), actual.join());
|
Loading…
Reference in New Issue
Block a user