[async-iteration] implement spec update for yield* in async generators
e3246ad69c
removed some redundancies in yield and yield*.
In particular:
- AsyncGeneratorRawYield becomes unnecessary, and is deleted in this CL
- Parser::RewriteYieldStar() is updated to perform the IteratorValue() algorithm as appropriate
BUG=v8:6187, v8:5855
R=rmcilroy@chromium.org, adamk@chromium.org, littledan@chromium.org, vogelheim@chromium.org
Change-Id: I05e8429b9cbd4531c330ee53a05656b90162064c
Reviewed-on: https://chromium-review.googlesource.com/471806
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Daniel Vogelheim <vogelheim@chromium.org>
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Cr-Commit-Position: refs/heads/master@{#44649}
This commit is contained in:
parent
38c3b71c26
commit
fa0066d170
@ -1416,12 +1416,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
InstallWithIntrinsicDefaultProto(isolate, yield,
|
||||
Context::ASYNC_GENERATOR_YIELD);
|
||||
|
||||
Handle<JSFunction> raw_yield =
|
||||
SimpleCreateFunction(isolate, factory->empty_string(),
|
||||
Builtins::kAsyncGeneratorRawYield, 2, false);
|
||||
InstallWithIntrinsicDefaultProto(isolate, raw_yield,
|
||||
Context::ASYNC_GENERATOR_RAW_YIELD);
|
||||
|
||||
Handle<Code> code =
|
||||
isolate->builtins()->AsyncGeneratorAwaitResolveClosure();
|
||||
Handle<SharedFunctionInfo> info =
|
||||
|
@ -378,50 +378,6 @@ TF_BUILTIN(AsyncGeneratorYield, AsyncGeneratorBuiltinsAssembler) {
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
TF_BUILTIN(AsyncGeneratorRawYield, AsyncGeneratorBuiltinsAssembler) {
|
||||
Node* const generator = Parameter(Descriptor::kReceiver);
|
||||
Node* const iter_result = Parameter(Descriptor::kValue);
|
||||
Node* const context = Parameter(Descriptor::kContext);
|
||||
|
||||
CSA_ASSERT_JS_ARGC_EQ(this, 1);
|
||||
CSA_SLOW_ASSERT(this,
|
||||
HasInstanceType(generator, JS_ASYNC_GENERATOR_OBJECT_TYPE));
|
||||
CSA_ASSERT(this, IsGeneratorNotSuspendedForAwait(generator));
|
||||
|
||||
VARIABLE(var_value, MachineRepresentation::kTagged);
|
||||
VARIABLE(var_done, MachineRepresentation::kTagged);
|
||||
|
||||
// RawYield is used for yield*, and values sent to yield* are always
|
||||
// iterator result objects.
|
||||
Label if_slow(this), async_generator_resolve(this);
|
||||
|
||||
GotoIfNot(IsFastJSIterResult(context, iter_result), &if_slow);
|
||||
var_value.Bind(LoadObjectField(iter_result, JSIteratorResult::kValueOffset));
|
||||
var_done.Bind(LoadObjectField(iter_result, JSIteratorResult::kDoneOffset));
|
||||
Goto(&async_generator_resolve);
|
||||
|
||||
BIND(&if_slow);
|
||||
{
|
||||
var_value.Bind(
|
||||
GetProperty(context, iter_result, factory()->value_string()));
|
||||
Node* const done =
|
||||
GetProperty(context, iter_result, factory()->done_string());
|
||||
|
||||
var_done.Bind(Select(
|
||||
IsBoolean(done), [=]() { return done; },
|
||||
[=]() { return CallBuiltin(Builtins::kToBoolean, context, done); },
|
||||
MachineRepresentation::kTagged));
|
||||
Goto(&async_generator_resolve);
|
||||
}
|
||||
|
||||
BIND(&async_generator_resolve);
|
||||
Node* const value = var_value.value();
|
||||
Node* const done = var_done.value();
|
||||
CallBuiltin(Builtins::kAsyncGeneratorResolve, context, generator, value,
|
||||
done);
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
TF_BUILTIN(AsyncGeneratorAwaitResolveClosure, AsyncGeneratorBuiltinsAssembler) {
|
||||
Node* value = Parameter(Descriptor::kValue);
|
||||
Node* context = Parameter(Descriptor::kContext);
|
||||
|
@ -956,7 +956,6 @@ namespace internal {
|
||||
/* resume behaviour specific to Async Generators. Internal / not exposed */ \
|
||||
/* to JS code. */ \
|
||||
TFJ(AsyncGeneratorYield, 1, kValue) \
|
||||
TFJ(AsyncGeneratorRawYield, 1, kValue) \
|
||||
\
|
||||
/* Async-from-Sync Iterator */ \
|
||||
\
|
||||
|
115
src/contexts.h
115
src/contexts.h
@ -34,64 +34,63 @@ enum ContextLookupFlags {
|
||||
// must always be allocated via Heap::AllocateContext() or
|
||||
// Factory::NewContext.
|
||||
|
||||
#define NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(V) \
|
||||
V(ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX, JSFunction, \
|
||||
async_function_await_caught) \
|
||||
V(ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX, JSFunction, \
|
||||
async_function_await_uncaught) \
|
||||
V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \
|
||||
async_function_promise_create) \
|
||||
V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \
|
||||
async_function_promise_release) \
|
||||
V(IS_ARRAYLIKE, JSFunction, is_arraylike) \
|
||||
V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \
|
||||
V(GET_TEMPLATE_CALL_SITE_INDEX, JSFunction, get_template_call_site) \
|
||||
V(MAKE_ERROR_INDEX, JSFunction, make_error) \
|
||||
V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \
|
||||
V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \
|
||||
V(MAKE_TYPE_ERROR_INDEX, JSFunction, make_type_error) \
|
||||
V(MAKE_URI_ERROR_INDEX, JSFunction, make_uri_error) \
|
||||
V(OBJECT_CREATE, JSFunction, object_create) \
|
||||
V(OBJECT_DEFINE_PROPERTIES, JSFunction, object_define_properties) \
|
||||
V(OBJECT_DEFINE_PROPERTY, JSFunction, object_define_property) \
|
||||
V(OBJECT_FREEZE, JSFunction, object_freeze) \
|
||||
V(OBJECT_GET_PROTOTYPE_OF, JSFunction, object_get_prototype_of) \
|
||||
V(OBJECT_IS_EXTENSIBLE, JSFunction, object_is_extensible) \
|
||||
V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \
|
||||
V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \
|
||||
V(OBJECT_KEYS, JSFunction, object_keys) \
|
||||
V(REGEXP_INTERNAL_MATCH, JSFunction, regexp_internal_match) \
|
||||
V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \
|
||||
V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \
|
||||
V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \
|
||||
V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \
|
||||
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
|
||||
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
|
||||
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_BUFFER_INDEX, JSFunction, \
|
||||
typed_array_construct_by_array_buffer) \
|
||||
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_LIKE_INDEX, JSFunction, \
|
||||
typed_array_construct_by_array_like) \
|
||||
V(TYPED_ARRAY_CONSTRUCT_BY_LENGTH_INDEX, JSFunction, \
|
||||
typed_array_construct_by_length) \
|
||||
V(TYPED_ARRAY_INITIALIZE_INDEX, JSFunction, typed_array_initialize) \
|
||||
V(TYPED_ARRAY_SET_FROM_ARRAY_LIKE, JSFunction, \
|
||||
typed_array_set_from_array_like) \
|
||||
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
|
||||
V(MATH_POW_INDEX, JSFunction, math_pow) \
|
||||
V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \
|
||||
V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \
|
||||
promise_internal_constructor) \
|
||||
V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \
|
||||
V(IS_PROMISE_INDEX, JSFunction, is_promise) \
|
||||
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
|
||||
V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
|
||||
V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \
|
||||
V(PROMISE_HANDLE_REJECT_INDEX, JSFunction, promise_handle_reject) \
|
||||
V(ASYNC_GENERATOR_AWAIT_CAUGHT, JSFunction, async_generator_await_caught) \
|
||||
V(ASYNC_GENERATOR_AWAIT_UNCAUGHT, JSFunction, \
|
||||
async_generator_await_uncaught) \
|
||||
V(ASYNC_GENERATOR_YIELD, JSFunction, async_generator_yield) \
|
||||
V(ASYNC_GENERATOR_RAW_YIELD, JSFunction, async_generator_raw_yield)
|
||||
#define NATIVE_CONTEXT_INTRINSIC_FUNCTIONS(V) \
|
||||
V(ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX, JSFunction, \
|
||||
async_function_await_caught) \
|
||||
V(ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX, JSFunction, \
|
||||
async_function_await_uncaught) \
|
||||
V(ASYNC_FUNCTION_PROMISE_CREATE_INDEX, JSFunction, \
|
||||
async_function_promise_create) \
|
||||
V(ASYNC_FUNCTION_PROMISE_RELEASE_INDEX, JSFunction, \
|
||||
async_function_promise_release) \
|
||||
V(IS_ARRAYLIKE, JSFunction, is_arraylike) \
|
||||
V(GENERATOR_NEXT_INTERNAL, JSFunction, generator_next_internal) \
|
||||
V(GET_TEMPLATE_CALL_SITE_INDEX, JSFunction, get_template_call_site) \
|
||||
V(MAKE_ERROR_INDEX, JSFunction, make_error) \
|
||||
V(MAKE_RANGE_ERROR_INDEX, JSFunction, make_range_error) \
|
||||
V(MAKE_SYNTAX_ERROR_INDEX, JSFunction, make_syntax_error) \
|
||||
V(MAKE_TYPE_ERROR_INDEX, JSFunction, make_type_error) \
|
||||
V(MAKE_URI_ERROR_INDEX, JSFunction, make_uri_error) \
|
||||
V(OBJECT_CREATE, JSFunction, object_create) \
|
||||
V(OBJECT_DEFINE_PROPERTIES, JSFunction, object_define_properties) \
|
||||
V(OBJECT_DEFINE_PROPERTY, JSFunction, object_define_property) \
|
||||
V(OBJECT_FREEZE, JSFunction, object_freeze) \
|
||||
V(OBJECT_GET_PROTOTYPE_OF, JSFunction, object_get_prototype_of) \
|
||||
V(OBJECT_IS_EXTENSIBLE, JSFunction, object_is_extensible) \
|
||||
V(OBJECT_IS_FROZEN, JSFunction, object_is_frozen) \
|
||||
V(OBJECT_IS_SEALED, JSFunction, object_is_sealed) \
|
||||
V(OBJECT_KEYS, JSFunction, object_keys) \
|
||||
V(REGEXP_INTERNAL_MATCH, JSFunction, regexp_internal_match) \
|
||||
V(REFLECT_APPLY_INDEX, JSFunction, reflect_apply) \
|
||||
V(REFLECT_CONSTRUCT_INDEX, JSFunction, reflect_construct) \
|
||||
V(REFLECT_DEFINE_PROPERTY_INDEX, JSFunction, reflect_define_property) \
|
||||
V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \
|
||||
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
|
||||
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
|
||||
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_BUFFER_INDEX, JSFunction, \
|
||||
typed_array_construct_by_array_buffer) \
|
||||
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_LIKE_INDEX, JSFunction, \
|
||||
typed_array_construct_by_array_like) \
|
||||
V(TYPED_ARRAY_CONSTRUCT_BY_LENGTH_INDEX, JSFunction, \
|
||||
typed_array_construct_by_length) \
|
||||
V(TYPED_ARRAY_INITIALIZE_INDEX, JSFunction, typed_array_initialize) \
|
||||
V(TYPED_ARRAY_SET_FROM_ARRAY_LIKE, JSFunction, \
|
||||
typed_array_set_from_array_like) \
|
||||
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
|
||||
V(MATH_POW_INDEX, JSFunction, math_pow) \
|
||||
V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \
|
||||
V(PROMISE_INTERNAL_CONSTRUCTOR_INDEX, JSFunction, \
|
||||
promise_internal_constructor) \
|
||||
V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \
|
||||
V(IS_PROMISE_INDEX, JSFunction, is_promise) \
|
||||
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
|
||||
V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
|
||||
V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \
|
||||
V(PROMISE_HANDLE_REJECT_INDEX, JSFunction, promise_handle_reject) \
|
||||
V(ASYNC_GENERATOR_AWAIT_CAUGHT, JSFunction, async_generator_await_caught) \
|
||||
V(ASYNC_GENERATOR_AWAIT_UNCAUGHT, JSFunction, \
|
||||
async_generator_await_uncaught) \
|
||||
V(ASYNC_GENERATOR_YIELD, JSFunction, async_generator_yield)
|
||||
|
||||
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
|
||||
V(ARRAY_CONCAT_INDEX, JSFunction, array_concat) \
|
||||
|
@ -2396,16 +2396,12 @@ void BytecodeGenerator::VisitSuspend(Suspend* expr) {
|
||||
// to AsyncGeneratorResolve(), implemented via the runtime call below.
|
||||
RegisterList args = register_allocator()->NewRegisterList(2);
|
||||
|
||||
int context_index = expr->is_yield_star()
|
||||
? Context::ASYNC_GENERATOR_RAW_YIELD
|
||||
: Context::ASYNC_GENERATOR_YIELD;
|
||||
|
||||
// Async GeneratorYield:
|
||||
// AsyncGeneratorYield:
|
||||
// perform AsyncGeneratorResolve(<generator>, <value>, false).
|
||||
builder()
|
||||
->MoveRegister(generator, args[0])
|
||||
.MoveRegister(value, args[1])
|
||||
.CallJSRuntime(context_index, args);
|
||||
.CallJSRuntime(Context::ASYNC_GENERATOR_YIELD, args);
|
||||
} else {
|
||||
builder()->LoadAccumulatorWithRegister(value);
|
||||
}
|
||||
|
@ -4704,10 +4704,26 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
|
||||
// while (true) { ... }
|
||||
// Already defined earlier: WhileStatement* loop = ...
|
||||
{
|
||||
Block* loop_body = factory()->NewBlock(nullptr, 4, false, nopos);
|
||||
Block* loop_body = factory()->NewBlock(nullptr, 5, false, nopos);
|
||||
loop_body->statements()->Add(switch_mode, zone());
|
||||
loop_body->statements()->Add(if_done, zone());
|
||||
loop_body->statements()->Add(set_mode_return, zone());
|
||||
|
||||
if (is_async_generator()) {
|
||||
// AsyncGeneratorYield does not yield the original iterator result,
|
||||
// unlike sync generators. Do `output = output.value`
|
||||
VariableProxy* output_proxy = factory()->NewVariableProxy(var_output);
|
||||
Expression* literal = factory()->NewStringLiteral(
|
||||
ast_value_factory()->value_string(), nopos);
|
||||
Assignment* assign = factory()->NewAssignment(
|
||||
Token::ASSIGN, output_proxy,
|
||||
factory()->NewProperty(factory()->NewVariableProxy(var_output),
|
||||
literal, nopos),
|
||||
nopos);
|
||||
loop_body->statements()->Add(
|
||||
factory()->NewExpressionStatement(assign, nopos), zone());
|
||||
}
|
||||
|
||||
loop_body->statements()->Add(try_finally, zone());
|
||||
|
||||
loop->Initialize(factory()->NewBooleanLiteral(true, nopos), loop_body);
|
||||
|
@ -1658,3 +1658,73 @@ assertEqualsAsync({ value: undefined, done: true }, () => it.next("x"));
|
||||
assertEqualsAsync({ value: "nores", done: true },
|
||||
() => it.return("nores"));
|
||||
assertThrowsAsync(() => it.throw(new MyError("nores")), MyError, "nores");
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Simple yield*:
|
||||
|
||||
log = [];
|
||||
async function* asyncGeneratorYieldStar1() {
|
||||
yield* {
|
||||
get [Symbol.asyncIterator]() {
|
||||
log.push({ name: "get @@asyncIterator" });
|
||||
return (...args) => {
|
||||
log.push({ name: "call @@asyncIterator", args });
|
||||
return this;
|
||||
};
|
||||
},
|
||||
get [Symbol.iterator]() {
|
||||
log.push({ name: "get @@iterator" });
|
||||
return (...args) => {
|
||||
log.push({ name: "call @@iterator", args });
|
||||
return this;
|
||||
}
|
||||
},
|
||||
get next() {
|
||||
log.push({ name: "get next" });
|
||||
return (...args) => {
|
||||
log.push({ name: "call next", args });
|
||||
return {
|
||||
get then() {
|
||||
log.push({ name: "get then" });
|
||||
return null;
|
||||
},
|
||||
get value() {
|
||||
log.push({ name: "get value" });
|
||||
throw (exception = new MyError("AbruptValue!"));
|
||||
},
|
||||
get done() {
|
||||
log.push({ name: "get done" });
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
get return() {
|
||||
log.push({ name: "get return" });
|
||||
return (...args) => {
|
||||
log.push({ name: "call return", args });
|
||||
return { value: args[0], done: true };
|
||||
}
|
||||
},
|
||||
get throw() {
|
||||
log.push({ name: "get throw" });
|
||||
return (...args) => {
|
||||
log.push({ name: "call throw", args });
|
||||
throw args[0];
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
it = asyncGeneratorYieldStar1();
|
||||
assertThrowsAsync(() => it.next(), MyError);
|
||||
assertEquals([
|
||||
{ name: "get @@asyncIterator" },
|
||||
{ name: "call @@asyncIterator", args: [] },
|
||||
{ name: "get next" },
|
||||
{ name: "call next", args: [undefined] },
|
||||
{ name: "get then" },
|
||||
{ name: "get done" },
|
||||
{ name: "get value" },
|
||||
], log);
|
||||
assertEqualsAsync({ value: undefined, done: true }, () => it.next());
|
||||
|
@ -421,36 +421,6 @@
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=5601
|
||||
'intl402/PluralRules/*': [SKIP],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=5855
|
||||
'language/expressions/async-generators/*': ['--harmony-async-iteration'],
|
||||
'language/statements/async-generator/*': ['--harmony-async-iteration'],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=6226
|
||||
'language/expressions/async-generator/named-yield-star-async-next': [FAIL],
|
||||
'language/expressions/async-generator/named-yield-star-async-return': [FAIL],
|
||||
'language/expressions/async-generator/named-yield-star-async-throw': [FAIL],
|
||||
'language/expressions/async-generator/yield-star-async-next': [FAIL],
|
||||
'language/expressions/async-generator/yield-star-async-return': [FAIL],
|
||||
'language/expressions/async-generator/yield-star-async-throw': [FAIL],
|
||||
'language/expressions/class/async-gen-method-static-yield-star-async-next': [FAIL],
|
||||
'language/expressions/class/async-gen-method-static-yield-star-async-return': [FAIL],
|
||||
'language/expressions/class/async-gen-method-static-yield-star-async-throw': [FAIL],
|
||||
'language/expressions/class/async-gen-method-yield-star-async-next': [FAIL],
|
||||
'language/expressions/class/async-gen-method-yield-star-async-return': [FAIL],
|
||||
'language/expressions/class/async-gen-method-yield-star-async-throw': [FAIL],
|
||||
'language/expressions/object/method-definition/async-gen-yield-star-async-next': [FAIL],
|
||||
'language/expressions/object/method-definition/async-gen-yield-star-async-return': [FAIL],
|
||||
'language/expressions/object/method-definition/async-gen-yield-star-async-throw': [FAIL],
|
||||
'language/statements/async-generator/yield-star-async-next': [FAIL],
|
||||
'language/statements/async-generator/yield-star-async-return': [FAIL],
|
||||
'language/statements/async-generator/yield-star-async-throw': [FAIL],
|
||||
'language/statements/class/async-gen-method-static-yield-star-async-next': [FAIL],
|
||||
'language/statements/class/async-gen-method-static-yield-star-async-return': [FAIL],
|
||||
'language/statements/class/async-gen-method-static-yield-star-async-throw': [FAIL],
|
||||
'language/statements/class/async-gen-method-yield-star-async-next': [FAIL],
|
||||
'language/statements/class/async-gen-method-yield-star-async-return': [FAIL],
|
||||
'language/statements/class/async-gen-method-yield-star-async-throw': [FAIL],
|
||||
|
||||
# https://bugs.chromium.org/p/v8/issues/detail?id=6242
|
||||
'language/expressions/async-generator/named-yield-star-sync-next': [FAIL],
|
||||
'language/expressions/async-generator/named-yield-star-sync-return': [FAIL],
|
||||
|
Loading…
Reference in New Issue
Block a user