Commit fbb46475 authored by Caitlin Potter's avatar Caitlin Potter Committed by Commit Bot

[ignition] desugar AsyncGenerator yield* in BytecodeGenerator

Move the desugaring into BytecodeGenerator per TODOs.

BUG=v8:6472
R=tebbi@chromium.org, rmcilroy@chromium.org, jgruber@chromium.org

Change-Id: Ic482bee18d6e6fe73de4c5f9abaf4feda7be2dd5
Reviewed-on: https://chromium-review.googlesource.com/550396Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Cr-Commit-Position: refs/heads/master@{#47403}
parent 7707e12b
......@@ -62,7 +62,7 @@ class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> {
template <typename Node>
void ReserveFeedbackSlots(Node* node) {
node->AssignFeedbackSlots(properties_.get_spec(), language_mode_,
&slot_cache_);
function_kind_, &slot_cache_);
}
class LanguageModeScope {
......@@ -198,7 +198,12 @@ void AstNumberingVisitor::VisitSuspend(Suspend* node) {
void AstNumberingVisitor::VisitYield(Yield* node) { VisitSuspend(node); }
void AstNumberingVisitor::VisitYieldStar(YieldStar* node) {
VisitSuspend(node);
node->set_suspend_id(suspend_count_++);
if (IsAsyncGeneratorFunction(function_kind_)) {
node->set_await_iterator_close_suspend_id(suspend_count_++);
node->set_await_delegated_iterator_output_suspend_id(suspend_count_++);
}
Visit(node->expression());
ReserveFeedbackSlots(node);
}
......
......@@ -246,6 +246,7 @@ static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec,
void ForInStatement::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
FunctionKind kind,
FeedbackSlotCache* cache) {
AssignVectorSlots(each(), spec, language_mode, &each_slot_);
for_in_feedback_slot_ = spec->AddGeneralSlot();
......@@ -261,12 +262,14 @@ Assignment::Assignment(NodeType node_type, Token::Value op, Expression* target,
void Assignment::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
FunctionKind kind,
FeedbackSlotCache* cache) {
AssignVectorSlots(target(), spec, language_mode, &slot_);
}
void CountOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
FunctionKind kind,
FeedbackSlotCache* cache) {
AssignVectorSlots(expression(), spec, language_mode, &slot_);
// Assign a slot to collect feedback about binary operations. Used only in
......@@ -375,6 +378,7 @@ ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value,
void ClassLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
FunctionKind kind,
FeedbackSlotCache* cache) {
// This logic that computes the number of slots needed for vector store
// ICs must mirror BytecodeGenerator::VisitClassLiteral.
......@@ -412,8 +416,9 @@ bool ObjectLiteral::Property::emit_store() const { return emit_store_; }
void ObjectLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
FunctionKind kind,
FeedbackSlotCache* cache) {
MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, cache);
MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, kind, cache);
// This logic that computes the number of slots needed for vector store
// ics must mirror FullCodeGenerator::VisitObjectLiteral.
......@@ -770,8 +775,9 @@ void ArrayLiteral::RewindSpreads() {
void ArrayLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
FunctionKind kind,
FeedbackSlotCache* cache) {
MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, cache);
MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, kind, cache);
// This logic that computes the number of slots needed for vector store
// ics must mirror FullCodeGenerator::VisitArrayLiteral.
......@@ -835,6 +841,7 @@ void MaterializedLiteral::BuildConstants(Isolate* isolate) {
void BinaryOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
FunctionKind kind,
FeedbackSlotCache* cache) {
// Feedback vector slot is only used by interpreter for binary operations.
// Full-codegen uses AstId to record type feedback.
......@@ -881,6 +888,7 @@ static bool IsTypeof(Expression* expr) {
void CompareOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
FunctionKind kind,
FeedbackSlotCache* cache_) {
// Feedback vector slot is only used by interpreter for binary operations.
// Full-codegen uses AstId to record type feedback.
......@@ -1022,7 +1030,7 @@ bool Expression::IsMonomorphic() const {
}
void Call::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
LanguageMode language_mode, FunctionKind kind,
FeedbackSlotCache* cache) {
ic_slot_ = spec->AddCallICSlot();
}
......@@ -1060,6 +1068,7 @@ CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements,
void CaseClause::AssignFeedbackSlots(FeedbackVectorSpec* spec,
LanguageMode language_mode,
FunctionKind kind,
FeedbackSlotCache* cache) {
feedback_slot_ = spec->AddInterpreterCompareICSlot();
}
......
......@@ -614,7 +614,7 @@ class ForInStatement final : public ForEachStatement {
// Type feedback information.
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
FeedbackSlot EachFeedbackSlot() const { return each_slot_; }
FeedbackSlot ForInFeedbackSlot() {
DCHECK(!for_in_feedback_slot_.IsInvalid());
......@@ -826,7 +826,7 @@ class CaseClause final : public Expression {
ZoneList<Statement*>* statements() const { return statements_; }
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
FeedbackSlot CompareOperationFeedbackSlot() { return feedback_slot_; }
......@@ -1086,7 +1086,7 @@ class Literal final : public Expression {
class MaterializedLiteral : public Expression {
public:
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache) {
FunctionKind kind, FeedbackSlotCache* cache) {
literal_slot_ = spec->AddLiteralSlot();
}
......@@ -1365,7 +1365,7 @@ class ObjectLiteral final : public AggregateLiteral {
// Object literals need one feedback slot for each non-trivial value, as well
// as some slots for home objects.
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
private:
friend class AstNodeFactory;
......@@ -1481,7 +1481,7 @@ class ArrayLiteral final : public AggregateLiteral {
void RewindSpreads();
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
FeedbackSlot LiteralFeedbackSlot() const { return literal_slot_; }
private:
......@@ -1658,7 +1658,7 @@ class Property final : public Expression {
bool IsSuperAccess() { return obj()->IsSuperPropertyReference(); }
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache) {
FunctionKind kind, FeedbackSlotCache* cache) {
if (key()->IsPropertyName()) {
property_feedback_slot_ = spec->AddLoadICSlot();
} else {
......@@ -1712,7 +1712,7 @@ class Call final : public Expression {
// Type feedback information.
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
FeedbackSlot CallFeedbackICSlot() const { return ic_slot_; }
......@@ -1810,7 +1810,7 @@ class CallNew final : public Expression {
// Type feedback information.
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache) {
FunctionKind kind, FeedbackSlotCache* cache) {
// CallNew stores feedback in the exact same way as Call. We can
// piggyback on the type feedback infrastructure for calls.
callnew_feedback_slot_ = spec->AddCallICSlot();
......@@ -1932,7 +1932,7 @@ class BinaryOperation final : public Expression {
void set_right(Expression* e) { right_ = e; }
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
FeedbackSlot BinaryOperationFeedbackSlot() const { return feedback_slot_; }
......@@ -1990,7 +1990,7 @@ class CountOperation final : public Expression {
}
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
FeedbackSlot CountSlot() const { return slot_; }
private:
......@@ -2027,7 +2027,7 @@ class CompareOperation final : public Expression {
void set_right(Expression* e) { right_ = e; }
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
FeedbackSlot CompareOperationFeedbackSlot() const { return feedback_slot_; }
......@@ -2145,7 +2145,7 @@ class Assignment : public Expression {
}
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
FeedbackSlot AssignmentSlot() const { return slot_; }
protected:
......@@ -2288,8 +2288,39 @@ class Yield final : public Suspend {
class YieldStar final : public Suspend {
public:
// In addition to the normal suspend for yield*, a yield* in an async
// generator has 2 additional suspends:
// - One for awaiting the iterator result of closing the generator when
// resumed with a "throw" completion, and a throw method is not present
// on the delegated iterator (await_iterator_close_suspend_id)
// - One for awaiting the iterator result yielded by the delegated iterator
// (await_delegated_iterator_output_suspend_id)
int await_iterator_close_suspend_id() const {
DCHECK_NE(-1, await_iterator_close_suspend_id_);
return await_iterator_close_suspend_id_;
}
void set_await_iterator_close_suspend_id(int id) {
await_iterator_close_suspend_id_ = id;
}
int await_delegated_iterator_output_suspend_id() const {
DCHECK_NE(-1, await_delegated_iterator_output_suspend_id_);
return await_delegated_iterator_output_suspend_id_;
}
void set_await_delegated_iterator_output_suspend_id(int id) {
await_delegated_iterator_output_suspend_id_ = id;
}
inline int suspend_count() const {
if (await_iterator_close_suspend_id_ != -1) {
DCHECK_NE(-1, await_delegated_iterator_output_suspend_id_);
return 3;
}
return 1;
}
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache) {
FunctionKind kind, FeedbackSlotCache* cache) {
load_iterable_iterator_slot_ = spec->AddLoadICSlot();
load_iterator_return_slot_ = spec->AddLoadICSlot();
load_iterator_next_slot_ = spec->AddLoadICSlot();
......@@ -2301,6 +2332,10 @@ class YieldStar final : public Suspend {
call_iterator_return_slot2_ = spec->AddCallICSlot();
call_iterator_next_slot_ = spec->AddCallICSlot();
call_iterator_throw_slot_ = spec->AddCallICSlot();
if (IsAsyncGeneratorFunction(kind)) {
load_iterable_async_iterator_slot_ = spec->AddLoadICSlot();
call_iterable_async_iterator_slot_ = spec->AddCallICSlot();
}
}
FeedbackSlot load_iterable_iterator_slot() const {
......@@ -2334,13 +2369,21 @@ class YieldStar final : public Suspend {
FeedbackSlot call_iterator_throw_slot() const {
return call_iterator_throw_slot_;
}
FeedbackSlot load_iterable_async_iterator_slot() const {
return load_iterable_async_iterator_slot_;
}
FeedbackSlot call_iterable_async_iterator_slot() const {
return call_iterable_async_iterator_slot_;
}
private:
friend class AstNodeFactory;
YieldStar(Expression* expression, int pos)
: Suspend(kYieldStar, expression, pos,
Suspend::OnAbruptResume::kNoControl) {}
Suspend::OnAbruptResume::kNoControl),
await_iterator_close_suspend_id_(-1),
await_delegated_iterator_output_suspend_id_(-1) {}
FeedbackSlot load_iterable_iterator_slot_;
FeedbackSlot load_iterator_return_slot_;
......@@ -2353,6 +2396,12 @@ class YieldStar final : public Suspend {
FeedbackSlot call_iterator_return_slot2_;
FeedbackSlot call_iterator_next_slot_;
FeedbackSlot call_iterator_throw_slot_;
FeedbackSlot load_iterable_async_iterator_slot_;
FeedbackSlot call_iterable_async_iterator_slot_;
int await_iterator_close_suspend_id_;
int await_delegated_iterator_output_suspend_id_;
};
class Await final : public Suspend {
......@@ -2420,7 +2469,7 @@ class FunctionLiteral final : public Expression {
LanguageMode language_mode() const;
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache) {
FunctionKind kind, FeedbackSlotCache* cache) {
literal_feedback_slot_ = spec->AddCreateClosureSlot();
}
......@@ -2660,7 +2709,7 @@ class ClassLiteral final : public Expression {
// Object literals need one feedback slot for each non-trivial value, as well
// as some slots for home objects.
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache);
FunctionKind kind, FeedbackSlotCache* cache);
bool NeedsProxySlot() const {
return class_variable_proxy() != nullptr &&
......@@ -2715,7 +2764,7 @@ class NativeFunctionLiteral final : public Expression {
FeedbackSlot LiteralFeedbackSlot() const { return literal_feedback_slot_; }
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache) {
FunctionKind kind, FeedbackSlotCache* cache) {
// TODO(mvstanton): The FeedbackSlotCache can be adapted
// to always return the same slot for this case.
literal_feedback_slot_ = spec->AddCreateClosureSlot();
......@@ -2833,7 +2882,7 @@ class GetIterator final : public Expression {
void set_iterable(Expression* iterable) { iterable_ = iterable; }
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache) {
FunctionKind kind, FeedbackSlotCache* cache) {
iterator_property_feedback_slot_ = spec->AddLoadICSlot();
iterator_call_feedback_slot_ = spec->AddCallICSlot();
if (hint() == IteratorType::kAsync) {
......
......@@ -2727,6 +2727,7 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
// let iteratorReturn = iterator.return;
// if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
// output = %_Call(iteratorReturn, iterator);
// if (IS_ASYNC_GENERATOR) output = await output;
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
// }
// throw MakeTypeError(kThrowMethodMissing);
......@@ -2734,11 +2735,18 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
// output = %_Call(iteratorThrow, iterator, input);
// break;
// }
//
// if (IS_ASYNC_GENERATOR) output = await output;
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
// if (output.done) break;
//
// // From the generator to its user:
// // Forward output, receive new input, and determine resume mode.
// if (IS_ASYNC_GENERATOR) {
// // AsyncGeneratorYield abstract operation awaits the operand before
// // resolving the promise for the current AsyncGeneratorRequest.
// %_AsyncGeneratorYield(output.value)
// }
// input = Suspend(output);
// resumeMode = %GeneratorGetResumeMode();
// }
......@@ -2749,11 +2757,11 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
// output.value
// }
void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
// TODO(tebbi): Also desugar async generator yield* in the BytecodeGenerator.
DCHECK(!IsAsyncGeneratorFunction(function_kind()));
Register output = register_allocator()->NewRegister();
Register resume_mode = register_allocator()->NewRegister();
IteratorType iterator_type = IsAsyncGeneratorFunction(function_kind())
? IteratorType::kAsync
: IteratorType::kNormal;
{
RegisterAllocationScope register_scope(this);
......@@ -2761,10 +2769,12 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
RegisterList iterator_and_input = register_allocator()->NewRegisterList(2);
Register iterator = iterator_and_input[0];
BuildGetIterator(expr->expression(), IteratorType::kNormal,
BuildGetIterator(expr->expression(), iterator_type,
expr->load_iterable_iterator_slot(),
expr->call_iterable_iterator_slot(),
FeedbackSlot::Invalid(), FeedbackSlot::Invalid());
expr->load_iterable_async_iterator_slot(),
expr->call_iterable_async_iterator_slot());
builder()->StoreAccumulatorInRegister(iterator);
Register input = iterator_and_input[1];
builder()->LoadUndefined().StoreAccumulatorInRegister(input);
......@@ -2776,8 +2786,11 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
// This loop builder does not construct counters as the loop is not
// visible to the user, and we therefore neither pass the block coverage
// builder nor the expression.
//
// YieldStar in AsyncGenerator functions includes 3 suspend points, rather
// than 1. These are documented in the YieldStar AST node.
LoopBuilder loop(builder(), nullptr, nullptr);
VisitIterationHeader(expr->suspend_id(), 1, &loop);
VisitIterationHeader(expr->suspend_id(), expr->suspend_count(), &loop);
{
BytecodeLabels after_switch(zone());
......@@ -2827,7 +2840,11 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
return_input.Bind(builder());
{
builder()->LoadAccumulatorWithRegister(input);
execution_control()->ReturnAccumulator();
if (iterator_type == IteratorType::kAsync) {
execution_control()->AsyncReturnAccumulator();
} else {
execution_control()->ReturnAccumulator();
}
}
}
......@@ -2870,8 +2887,16 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
.JumpIfNull(throw_throw_method_missing.New())
.CallProperty(
iterator_return, RegisterList(iterator),
feedback_index(expr->call_iterator_return_slot2()))
.JumpIfJSReceiver(throw_throw_method_missing.New())
feedback_index(expr->call_iterator_return_slot2()));
if (iterator_type == IteratorType::kAsync) {
// For async generators, await the result of the .return() call.
BuildAwait(expr->await_iterator_close_suspend_id());
builder()->StoreAccumulatorInRegister(output);
}
builder()
->JumpIfJSReceiver(throw_throw_method_missing.New())
.CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output);
throw_throw_method_missing.Bind(builder());
......@@ -2882,6 +2907,11 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
after_switch.Bind(builder());
}
if (iterator_type == IteratorType::kAsync) {
// Await the result of the method invocation.
BuildAwait(expr->await_delegated_iterator_output_suspend_id());
}
// Check that output is an object.
BytecodeLabel check_if_done;
builder()
......@@ -2898,7 +2928,27 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
loop.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
// Suspend the current generator.
builder()->LoadAccumulatorWithRegister(output);
if (iterator_type == IteratorType::kNormal) {
builder()->LoadAccumulatorWithRegister(output);
} else {
RegisterAllocationScope register_scope(this);
DCHECK(iterator_type == IteratorType::kAsync);
// If generatorKind is async, perform AsyncGeneratorYield(output.value),
// which will await `output.value` before resolving the current
// AsyncGeneratorRequest's promise.
builder()->LoadNamedProperty(
output, ast_string_constants()->value_string(),
feedback_index(expr->load_output_value_slot()));
RegisterList args = register_allocator()->NewRegisterList(3);
builder()
->MoveRegister(generator_object(), args[0]) // generator
.StoreAccumulatorInRegister(args[1]) // value
.LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT)
.StoreAccumulatorInRegister(args[2]) // is_caught
.CallRuntime(Runtime::kInlineAsyncGeneratorYield, args);
}
BuildSuspendPoint(expr->suspend_id());
builder()->StoreAccumulatorInRegister(input);
builder()
......@@ -2923,7 +2973,11 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
.CompareOperation(Token::EQ_STRICT, resume_mode)
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &completion_is_output_value)
.LoadAccumulatorWithRegister(output_value);
execution_control()->ReturnAccumulator();
if (iterator_type == IteratorType::kAsync) {
execution_control()->AsyncReturnAccumulator();
} else {
execution_control()->ReturnAccumulator();
}
builder()->Bind(&completion_is_output_value);
BuildIncrementBlockCoverageCounterIfEnabled(expr,
......
......@@ -2952,7 +2952,9 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
}
if (delegating) {
return impl()->RewriteYieldStar(expression, pos);
ExpressionT yieldstar = factory()->NewYieldStar(expression, pos);
impl()->RecordSuspendSourceRange(yieldstar, PositionAfterSemicolon());
return yieldstar;
}
// Hackily disambiguate o from o.next and o [Symbol.iterator]().
......
......@@ -4098,439 +4098,6 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name,
}
}
// Desugaring of yield*
// ====================
//
// With the help of do-expressions and function.sent, we desugar yield* into a
// loop containing a "raw" yield (a yield that doesn't wrap an iterator result
// object around its argument). Concretely, "yield* iterable" turns into
// roughly the following code:
//
// do {
// const kNext = 0;
// const kReturn = 1;
// const kThrow = 2;
//
// let input = undefined;
// let mode = kNext;
// let output = undefined;
//
// let iterator = GetIterator(iterable);
//
// while (true) {
// // From the generator to the iterator:
// // Forward input according to resume mode and obtain output.
// switch (mode) {
// case kNext:
// output = iterator.next(input);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
// break;
// case kReturn:
// IteratorClose(iterator, input, output); // See below.
// break;
// case kThrow:
// let iteratorThrow = iterator.throw;
// if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
// IteratorClose(iterator); // See below.
// throw MakeTypeError(kThrowMethodMissing);
// }
// output = %_Call(iteratorThrow, iterator, input);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
// break;
// }
// if (output.done) break;
//
// // From the generator to its user:
// // Forward output, receive new input, and determine resume mode.
// RawYield(output); // See explanation above.
// mode = %GeneratorGetResumeMode();
// input = function.sent;
// }
// }
//
// if (mode === kReturn) {
// return {value: output.value, done: true};
// }
// output.value
// }
//
// IteratorClose(iterator) expands to the following:
//
// let iteratorReturn = iterator.return;
// if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
// let output = %_Call(iteratorReturn, iterator);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
// }
//
// IteratorClose(iterator, input, output) expands to the following:
//
// let iteratorReturn = iterator.return;
// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
// output = %_Call(iteratorReturn, iterator, input);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
Expression* Parser::RewriteYieldStar(Expression* iterable, int pos) {
const int nopos = kNoSourcePosition;
IteratorType type =
is_async_generator() ? IteratorType::kAsync : IteratorType::kNormal;
if (type == IteratorType::kNormal) {
Expression* expr = factory()->NewYieldStar(iterable, pos);
RecordSuspendSourceRange(expr, PositionAfterSemicolon());
return expr;
}
// Forward definition for break/continue statements.
WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
// let input = undefined;
Variable* var_input = NewTemporary(ast_value_factory()->empty_string());
Statement* initialize_input;
{
Expression* input_proxy = factory()->NewVariableProxy(var_input);
Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, input_proxy,
factory()->NewUndefinedLiteral(nopos), nopos);
initialize_input = factory()->NewExpressionStatement(assignment, nopos);
}
// let mode = kNext;
Variable* var_mode = NewTemporary(ast_value_factory()->empty_string());
Statement* initialize_mode;
{
Expression* mode_proxy = factory()->NewVariableProxy(var_mode);
Expression* knext =
factory()->NewSmiLiteral(JSGeneratorObject::kNext, nopos);
Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, mode_proxy, knext, nopos);
initialize_mode = factory()->NewExpressionStatement(assignment, nopos);
}
// let output = undefined;
Variable* var_output = NewTemporary(ast_value_factory()->empty_string());
Statement* initialize_output;
{
Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, output_proxy,
factory()->NewUndefinedLiteral(nopos), nopos);
initialize_output = factory()->NewExpressionStatement(assignment, nopos);
}
// let iterator = GetIterator(iterable);
Variable* var_iterator = NewTemporary(ast_value_factory()->empty_string());
Statement* get_iterator;
{
Expression* iterator = factory()->NewGetIterator(iterable, type, nopos);
Expression* iterator_proxy = factory()->NewVariableProxy(var_iterator);
Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, iterator_proxy, iterator, nopos);
get_iterator = factory()->NewExpressionStatement(assignment, nopos);
}
// output = iterator.next(input);
Statement* call_next;
{
Expression* iterator_proxy = factory()->NewVariableProxy(var_iterator);
Expression* literal =
factory()->NewStringLiteral(ast_value_factory()->next_string(), nopos);
Expression* next_property =
factory()->NewProperty(iterator_proxy, literal, nopos);
Expression* input_proxy = factory()->NewVariableProxy(var_input);
auto args = new (zone()) ZoneList<Expression*>(1, zone());
args->Add(input_proxy, zone());
Expression* call = factory()->NewCall(next_property, args, nopos);
if (type == IteratorType::kAsync) {
call = factory()->NewAwait(call, nopos);
}
Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, output_proxy, call, nopos);
call_next = factory()->NewExpressionStatement(assignment, nopos);
}
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
Statement* validate_next_output;
{
Expression* is_receiver_call;
{
auto args = new (zone()) ZoneList<Expression*>(1, zone());
args->Add(factory()->NewVariableProxy(var_output), zone());
is_receiver_call =
factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
}
Statement* throw_call;
{
auto args = new (zone()) ZoneList<Expression*>(1, zone());
args->Add(factory()->NewVariableProxy(var_output), zone());
Expression* call = factory()->NewCallRuntime(
Runtime::kThrowIteratorResultNotAnObject, args, nopos);
throw_call = factory()->NewExpressionStatement(call, nopos);
}
validate_next_output = factory()->NewIfStatement(
is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
nopos);
}
// let iteratorThrow = iterator.throw;
Variable* var_throw = NewTemporary(ast_value_factory()->empty_string());
Statement* get_throw;
{
Expression* iterator_proxy = factory()->NewVariableProxy(var_iterator);
Expression* literal =
factory()->NewStringLiteral(ast_value_factory()->throw_string(), nopos);
Expression* property =
factory()->NewProperty(iterator_proxy, literal, nopos);
Expression* throw_proxy = factory()->NewVariableProxy(var_throw);
Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, throw_proxy, property, nopos);
get_throw = factory()->NewExpressionStatement(assignment, nopos);
}
// if (IS_NULL_OR_UNDEFINED(iteratorThrow) {
// IteratorClose(iterator);
// throw MakeTypeError(kThrowMethodMissing);
// }
Statement* check_throw;
{
Expression* condition = factory()->NewCompareOperation(
Token::EQ, factory()->NewVariableProxy(var_throw),
factory()->NewNullLiteral(nopos), nopos);
Expression* call =
NewThrowTypeError(MessageTemplate::kThrowMethodMissing,
ast_value_factory()->empty_string(), nopos);
Statement* throw_call = factory()->NewExpressionStatement(call, nopos);
Block* then = factory()->NewBlock(nullptr, 4 + 1, false, nopos);
BuildIteratorCloseForCompletion(
scope(), then->statements(), var_iterator,
factory()->NewSmiLiteral(Parser::kNormalCompletion, nopos), type);
then->statements()->Add(throw_call, zone());
check_throw = factory()->NewIfStatement(
condition, then, factory()->NewEmptyStatement(nopos), nopos);
}
// output = %_Call(iteratorThrow, iterator, input);
Statement* call_throw;
{
auto args = new (zone()) ZoneList<Expression*>(3, zone());
args->Add(factory()->NewVariableProxy(var_throw), zone());
args->Add(factory()->NewVariableProxy(var_iterator), zone());
args->Add(factory()->NewVariableProxy(var_input), zone());
Expression* call =
factory()->NewCallRuntime(Runtime::kInlineCall, args, nopos);
if (type == IteratorType::kAsync) {
call = factory()->NewAwait(call, nopos);
}
Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(var_output), call, nopos);
call_throw = factory()->NewExpressionStatement(assignment, nopos);
}
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
Statement* validate_throw_output;
{
Expression* is_receiver_call;
{
auto args = new (zone()) ZoneList<Expression*>(1, zone());
args->Add(factory()->NewVariableProxy(var_output), zone());
is_receiver_call =
factory()->NewCallRuntime(Runtime::kInlineIsJSReceiver, args, nopos);
}
Statement* throw_call;
{
auto args = new (zone()) ZoneList<Expression*>(1, zone());
args->Add(factory()->NewVariableProxy(var_output), zone());
Expression* call = factory()->NewCallRuntime(
Runtime::kThrowIteratorResultNotAnObject, args, nopos);
throw_call = factory()->NewExpressionStatement(call, nopos);
}
validate_throw_output = factory()->NewIfStatement(
is_receiver_call, factory()->NewEmptyStatement(nopos), throw_call,
nopos);
}
// if (output.done) break;
Statement* if_done;
{
Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* literal =
factory()->NewStringLiteral(ast_value_factory()->done_string(), nopos);
Expression* property = factory()->NewProperty(output_proxy, literal, nopos);
BreakStatement* break_loop = factory()->NewBreakStatement(loop, nopos);
if_done = factory()->NewIfStatement(
property, break_loop, factory()->NewEmptyStatement(nopos), nopos);
}
// Yield(output);
Statement* yield_output;
{
Expression* output_proxy = factory()->NewVariableProxy(var_output);
Suspend* yield =
factory()->NewYield(output_proxy, nopos, Suspend::kNoControl);
yield_output = factory()->NewExpressionStatement(yield, nopos);
}
// mode = %GeneratorGetResumeMode();
Statement* get_mode;
{
Expression* mode_proxy = factory()->NewVariableProxy(var_mode);
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
VariableProxy* generator = factory()->NewVariableProxy(
function_state_->scope()->generator_object_var());
args->Add(generator, zone());
Expression* mode = factory()->NewCallRuntime(
Runtime::kInlineGeneratorGetResumeMode, args, pos);
Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, mode_proxy, mode, nopos);
get_mode = factory()->NewExpressionStatement(assignment, nopos);
}
// input = function.sent;
Statement* get_input;
{
Expression* function_sent = FunctionSentExpression(nopos);
Expression* input_proxy = factory()->NewVariableProxy(var_input);
Expression* assignment = factory()->NewAssignment(
Token::ASSIGN, input_proxy, function_sent, nopos);
get_input = factory()->NewExpressionStatement(assignment, nopos);
}
// if (mode === kReturn) {
// return {value: output.value, done: true};
// }
Statement* maybe_return_value;
{
Expression* mode_proxy = factory()->NewVariableProxy(var_mode);
Expression* kreturn =
factory()->NewSmiLiteral(JSGeneratorObject::kReturn, nopos);
Expression* condition = factory()->NewCompareOperation(
Token::EQ_STRICT, mode_proxy, kreturn, nopos);
Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* literal =
factory()->NewStringLiteral(ast_value_factory()->value_string(), nopos);
Expression* property = factory()->NewProperty(output_proxy, literal, nopos);
Statement* return_value = BuildReturnStatement(property, nopos);
maybe_return_value = factory()->NewIfStatement(
condition, return_value, factory()->NewEmptyStatement(nopos), nopos);
}
// output.value
Statement* get_value;
{
Expression* output_proxy = factory()->NewVariableProxy(var_output);
Expression* literal =
factory()->NewStringLiteral(ast_value_factory()->value_string(), nopos);
Expression* property = factory()->NewProperty(output_proxy, literal, nopos);
get_value = factory()->NewExpressionStatement(property, nopos);
}
// Now put things together.
// switch (mode) { ... }
SwitchStatement* switch_mode = factory()->NewSwitchStatement(nullptr, nopos);
{
auto case_next = new (zone()) ZoneList<Statement*>(3, zone());
case_next->Add(call_next, zone());
case_next->Add(validate_next_output, zone());
case_next->Add(factory()->NewBreakStatement(switch_mode, nopos), zone());
auto case_return = new (zone()) ZoneList<Statement*>(5, zone());
BuildIteratorClose(case_return, var_iterator, var_input, var_output, type);
case_return->Add(factory()->NewBreakStatement(switch_mode, nopos), zone());
auto case_throw = new (zone()) ZoneList<Statement*>(5, zone());
case_throw->Add(get_throw, zone());
case_throw->Add(check_throw, zone());
case_throw->Add(call_throw, zone());
case_throw->Add(validate_throw_output, zone());
case_throw->Add(factory()->NewBreakStatement(switch_mode, nopos), zone());
auto cases = new (zone()) ZoneList<CaseClause*>(3, zone());
Expression* knext =
factory()->NewSmiLiteral(JSGeneratorObject::kNext, nopos);
Expression* kreturn =
factory()->NewSmiLiteral(JSGeneratorObject::kReturn, nopos);
Expression* kthrow =
factory()->NewSmiLiteral(JSGeneratorObject::kThrow, nopos);
cases->Add(factory()->NewCaseClause(knext, case_next, nopos), zone());
cases->Add(factory()->NewCaseClause(kreturn, case_return, nopos), zone());
cases->Add(factory()->NewCaseClause(kthrow, case_throw, nopos), zone());
switch_mode->Initialize(factory()->NewVariableProxy(var_mode), cases);
}
// while (true) { ... }
// Already defined earlier: WhileStatement* loop = ...
{
Block* loop_body = factory()->NewBlock(nullptr, 5, false, nopos);
loop_body->statements()->Add(switch_mode, zone());
loop_body->statements()->Add(if_done, 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);
Expression* value = factory()->NewAwait(
factory()->NewProperty(factory()->NewVariableProxy(var_output),
literal, nopos),
nopos);
Assignment* assign =
factory()->NewAssignment(Token::ASSIGN, output_proxy, value, nopos);
loop_body->statements()->Add(
factory()->NewExpressionStatement(assign, nopos), zone());
}
loop_body->statements()->Add(yield_output, zone());
loop_body->statements()->Add(get_input, zone());
loop_body->statements()->Add(get_mode, zone());
loop->Initialize(factory()->NewBooleanLiteral(true, nopos), loop_body);
}
// do { ... }
DoExpression* yield_star;
{
// The rewriter needs to process the get_value statement only, hence we
// put the preceding statements into an init block.
Block* do_block_ = factory()->NewBlock(nullptr, 6, true, nopos);
do_block_->statements()->Add(initialize_input, zone());
do_block_->statements()->Add(initialize_mode, zone());
do_block_->statements()->Add(initialize_output, zone());
do_block_->statements()->Add(get_iterator, zone());
do_block_->statements()->Add(loop, zone());
do_block_->statements()->Add(maybe_return_value, zone());
Block* do_block = factory()->NewBlock(nullptr, 2, false, nopos);
do_block->statements()->Add(do_block_, zone());
do_block->statements()->Add(get_value, zone());
// TODO(jgruber): Collect source ranges for YieldStar within async
// generators. The main issue is that we don't have a good dedicated node
// to attach to - the DoExpression seems a bit too generic.
Variable* dot_result =
NewTemporary(ast_value_factory()->dot_result_string());
yield_star = factory()->NewDoExpression(do_block, dot_result, nopos);
Rewriter::Rewrite(this, GetClosureScope(), yield_star, ast_value_factory());
}
return yield_star;
}
Statement* Parser::CheckCallable(Variable* var, Expression* error, int pos) {
const int nopos = kNoSourcePosition;
Statement* validate_var;
......
......@@ -599,8 +599,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Block* block,
Expression* return_value, bool* ok);
Expression* RewriteYieldStar(Expression* expression, int pos);
void AddArrowFunctionFormalParameters(ParserFormalParameters* parameters,
Expression* params, int end_pos,
bool* ok);
......
......@@ -653,6 +653,9 @@ class PreParserFactory {
PreParserExpression NewAwait(PreParserExpression expression, int pos) {
return PreParserExpression::Default();
}
PreParserExpression NewYieldStar(PreParserExpression iterable, int pos) {
return PreParserExpression::Default();
}
PreParserExpression NewConditional(PreParserExpression condition,
PreParserExpression then_expression,
PreParserExpression else_expression,
......@@ -1031,10 +1034,6 @@ class PreParser : public ParserBase<PreParser> {
PreParserStatement block,
PreParserExpression return_value,
bool* ok) {}
V8_INLINE PreParserExpression RewriteYieldStar(PreParserExpression expression,
int pos) {
return PreParserExpression::Default();
}
V8_INLINE void RewriteNonPattern(bool* ok) { ValidateExpression(ok); }
void DeclareAndInitializeVariables(
......
......@@ -582,460 +582,270 @@ snippet: "
async function* f() { yield* g() }
f();
"
frame size: 18
frame size: 17
parameter count: 1
bytecode array length: 1015
bytecode array length: 575
bytecodes: [
B(Ldar), R(0),
B(JumpIfUndefined), U8(25),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetContext), R(0), U8(1),
B(PushContext), R(10),
B(PushContext), R(2),
B(RestoreGeneratorState), R(0),
B(Star), R(9),
B(SwitchOnSmiNoFeedback), U8(0), U8(11), I8(0),
B(Star), R(1),
B(SwitchOnSmiNoFeedback), U8(0), U8(5), I8(0),
B(LdaSmi), I8(45),
B(Star), R(10),
B(CallRuntime), U16(Runtime::kAbort), R(10), U8(1),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kAbort), R(2), U8(1),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(Mov), R(closure), R(10),
B(Mov), R(this), R(11),
B(InvokeIntrinsic), U8(Runtime::k_CreateJSGeneratorObject), R(10), U8(2),
B(Star), R(1),
B(Mov), R(closure), R(2),
B(Mov), R(this), R(3),
B(InvokeIntrinsic), U8(Runtime::k_CreateJSGeneratorObject), R(2), U8(2),
B(Star), R(0),
/* 44 E> */ B(StackCheck),
B(Mov), R(context), R(12),
B(Mov), R(context), R(13),
B(Mov), R(context), R(4),
B(Mov), R(context), R(5),
B(Ldar), R(0),
/* 44 E> */ B(SuspendGenerator), R(0), R(0), U8(14), U8(0),
/* 44 E> */ B(SuspendGenerator), R(0), R(0), U8(6), U8(0),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(14),
B(RestoreGeneratorRegisters), R(0), R(0), U8(6),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(Star), R(1),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(14),
B(Star), R(6),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(SwitchOnSmiNoFeedback), U8(11), U8(2), I8(0),
B(Ldar), R(14),
B(SwitchOnSmiNoFeedback), U8(5), U8(2), I8(0),
B(Ldar), R(6),
/* 44 E> */ B(Throw),
B(LdaZero),
B(Star), R(10),
B(Mov), R(14), R(11),
B(JumpConstant), U8(36),
/* 49 S> */ B(LdaUndefined),
B(Star), R(1),
B(LdaZero),
B(Star), R(2),
B(LdaUndefined),
B(Star), R(3),
B(LdaGlobal), U8(13), U8(2),
B(Star), R(16),
/* 56 E> */ B(CallUndefinedReceiver0), R(16), U8(0),
B(Star), R(14),
B(LdaNamedProperty), R(14), U8(14), U8(8),
B(Mov), R(6), R(3),
B(JumpConstant), U8(22),
/* 49 S> */ B(LdaGlobal), U8(7), U8(2),
B(Star), R(12),
/* 56 E> */ B(CallUndefinedReceiver0), R(12), U8(0),
B(Star), R(10),
B(LdaNamedProperty), R(10), U8(8), U8(26),
B(JumpIfUndefined), U8(17),
B(JumpIfNull), U8(15),
B(Star), R(15),
B(CallProperty0), R(15), R(14), U8(10),
B(Star), R(11),
B(CallProperty0), R(11), R(10), U8(28),
B(JumpIfJSReceiver), U8(23),
B(CallRuntime), U16(Runtime::kThrowSymbolAsyncIteratorInvalid), R(0), U8(0),
B(LdaNamedProperty), R(14), U8(15), U8(4),
B(Star), R(15),
B(CallProperty0), R(15), R(14), U8(6),
B(Star), R(15),
B(InvokeIntrinsic), U8(Runtime::k_CreateAsyncFromSyncIterator), R(15), U8(1),
B(Star), R(4),
B(Ldar), R(9),
B(SwitchOnSmiNoFeedback), U8(16), U8(8), I8(1),
B(LdaSmi), I8(-2),
B(TestEqualStrictNoFeedback), R(9),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(45),
B(Star), R(14),
B(CallRuntime), U16(Runtime::kAbort), R(14), U8(1),
B(StackCheck),
B(LdaZero),
B(TestEqualStrict), R(2), U8(16),
B(Mov), R(2), R(14),
B(JumpIfTrue), U8(18),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(14), U8(20),
B(JumpIfTrue), U8(83),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(14), U8(29),
B(JumpIfTrue), U8(211),
B(JumpConstant), U8(30),
B(LdaNamedProperty), R(4), U8(24), U8(14),
B(Star), R(15),
B(CallProperty1), R(15), R(4), R(1), U8(12),
B(Star), R(16),
B(Mov), R(0), R(15),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(15), U8(2),
B(SuspendGenerator), R(0), R(0), U8(15), U8(1),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(15),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(15),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(16),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(16),
B(JumpIfTrue), U8(5),
B(Ldar), R(15),
B(ReThrow),
B(Mov), R(15), R(3),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(15), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(3), U8(1),
B(JumpConstant), U8(31),
B(LdaNamedProperty), R(4), U8(25), U8(17),
B(Star), R(3),
B(TestUndetectable),
B(JumpIfFalse), U8(54),
B(Mov), R(0), R(15),
B(Mov), R(1), R(16),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(15), U8(2),
B(SuspendGenerator), R(0), R(0), U8(15), U8(2),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(15),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(15),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(16),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(16),
B(JumpIfTrue), U8(5),
B(Ldar), R(15),
B(ReThrow),
B(LdaZero),
B(Star), R(10),
B(Mov), R(15), R(11),
B(JumpConstant), U8(37),
B(Mov), R(3), R(15),
B(Mov), R(4), R(16),
B(Mov), R(1), R(17),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(15), U8(3),
B(Star), R(16),
B(Mov), R(0), R(15),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(15), U8(2),
B(SuspendGenerator), R(0), R(0), U8(15), U8(3),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(15),
B(LdaSmi), I8(-2),
B(LdaNamedProperty), R(10), U8(9), U8(4),
B(Star), R(11),
B(CallProperty0), R(11), R(10), U8(16),
B(Star), R(11),
B(InvokeIntrinsic), U8(Runtime::k_CreateAsyncFromSyncIterator), R(11), U8(1),
B(Star), R(8),
B(LdaUndefined),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(15),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(16),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(16),
B(JumpIfTrue), U8(5),
B(Ldar), R(15),
B(ReThrow),
B(Mov), R(15), R(3),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(15), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(3), U8(1),
B(JumpConstant), U8(32),
B(LdaNamedProperty), R(4), U8(26), U8(21),
B(Star), R(5),
B(TestUndetectable),
B(JumpIfFalse), U8(212),
B(LdaNamedProperty), R(4), U8(25), U8(24),
B(Star), R(6),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(185),
B(LdaZero),
B(Star), R(15),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(15), U8(27),
B(JumpIfFalse), U8(106),
B(Ldar), R(6),
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(134),
B(Star), R(15),
B(LdaConstant), U8(27),
B(Star), R(16),
B(CallRuntime), U16(Runtime::kNewTypeError), R(15), U8(2),
B(Throw),
B(Mov), R(context), R(15),
B(Mov), R(6), R(16),
B(Mov), R(4), R(17),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(16), U8(2),
B(Star), R(17),
B(Mov), R(0), R(16),
B(CallJSRuntime), U8(%async_generator_await_caught), R(16), U8(2),
B(SuspendGenerator), R(0), R(0), U8(16), U8(4),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(16),
B(Star), R(7),
B(Ldar), R(1),
B(SwitchOnSmiNoFeedback), U8(10), U8(3), I8(1),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(16),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(17),
B(TestEqualStrictNoFeedback), R(1),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(45),
B(Star), R(12),
B(CallRuntime), U16(Runtime::kAbort), R(12), U8(1),
B(Ldar), R(7),
B(SwitchOnSmiNoFeedback), U8(13), U8(2), I8(1),
B(LdaNamedProperty), R(8), U8(15), U8(8),
B(Star), R(12),
B(CallProperty1), R(12), R(8), R(9), U8(22),
B(Jump), U8(118),
B(LdaNamedProperty), R(8), U8(16), U8(6),
B(JumpIfUndefined), U8(13),
B(JumpIfNull), U8(11),
B(Star), R(12),
B(CallProperty1), R(12), R(8), R(9), U8(18),
B(Jump), U8(101),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(17),
B(JumpIfTrue), U8(5),
B(Ldar), R(16),
B(ReThrow),
B(Ldar), R(16),
B(Jump), U8(20),
B(Star), R(16),
B(Ldar), R(closure),
B(CreateCatchContext), R(16), U8(28), U8(29),
B(Star), R(15),
B(LdaTheHole),
B(SetPendingMessage),
B(Ldar), R(15),
B(PushContext), R(16),
B(PopContext), R(16),
B(Jump), U8(71),
B(Mov), R(6), R(15),
B(Mov), R(4), R(16),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(15), U8(2),
B(Star), R(16),
B(Mov), R(0), R(15),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(15), U8(2),
B(SuspendGenerator), R(0), R(0), U8(15), U8(5),
B(Star), R(2),
B(Mov), R(9), R(3),
B(JumpConstant), U8(23),
B(LdaNamedProperty), R(8), U8(17), U8(10),
B(JumpIfUndefined), U8(13),
B(JumpIfNull), U8(11),
B(Star), R(12),
B(CallProperty1), R(12), R(8), R(9), U8(24),
B(Jump), U8(76),
B(LdaNamedProperty), R(8), U8(16), U8(6),
B(Star), R(12),
B(JumpIfUndefined), U8(63),
B(JumpIfNull), U8(61),
B(CallProperty0), R(12), R(8), U8(20),
B(Star), R(14),
B(Mov), R(0), R(13),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(13), U8(2),
B(SuspendGenerator), R(0), R(0), U8(13), U8(2),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(15),
B(RestoreGeneratorRegisters), R(0), R(0), U8(13),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(Star), R(1),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(15),
B(Star), R(13),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(16),
B(Star), R(14),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(16),
B(TestEqualStrictNoFeedback), R(14),
B(JumpIfTrue), U8(5),
B(Ldar), R(15),
B(Ldar), R(13),
B(ReThrow),
B(Mov), R(15), R(7),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(15), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(7), U8(1),
B(Wide), B(LdaSmi), I16(147),
B(Star), R(15),
B(LdaConstant), U8(27),
B(Star), R(16),
B(CallRuntime), U16(Runtime::kNewTypeError), R(15), U8(2),
B(Throw),
B(Mov), R(5), R(15),
B(Mov), R(4), R(16),
B(Mov), R(1), R(17),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(15), U8(3),
B(Star), R(16),
B(Mov), R(0), R(15),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(15), U8(2),
B(SuspendGenerator), R(0), R(0), U8(15), U8(6),
B(Ldar), R(13),
B(Mov), R(13), R(6),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(CallRuntime), U16(Runtime::kThrowThrowMethodMissing), R(0), U8(0),
B(Star), R(13),
B(Mov), R(0), R(12),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(12), U8(2),
B(SuspendGenerator), R(0), R(0), U8(12), U8(3),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(15),
B(RestoreGeneratorRegisters), R(0), R(0), U8(12),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(Star), R(1),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(15),
B(Star), R(12),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(16),
B(Star), R(13),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(16),
B(TestEqualStrictNoFeedback), R(13),
B(JumpIfTrue), U8(5),
B(Ldar), R(15),
B(Ldar), R(12),
B(ReThrow),
B(Mov), R(15), R(3),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(15), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(3), U8(1),
B(Jump), U8(2),
B(LdaNamedProperty), R(3), U8(33), U8(30),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(101),
B(LdaNamedProperty), R(3), U8(34), U8(32),
B(Star), R(15),
B(Mov), R(0), R(14),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(14), U8(2),
B(SuspendGenerator), R(0), R(0), U8(14), U8(7),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(14),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(14),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Ldar), R(12),
B(Mov), R(12), R(6),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(LdaNamedProperty), R(6), U8(18), U8(12),
B(JumpIfToBooleanTrue), U8(50),
B(LdaNamedProperty), R(6), U8(19), U8(14),
B(Star), R(15),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(15),
B(JumpIfTrue), U8(5),
B(Ldar), R(14),
B(ReThrow),
B(Mov), R(14), R(3),
B(LdaFalse),
B(Star), R(16),
B(Mov), R(0), R(14),
B(Mov), R(3), R(15),
B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorYield), R(14), U8(3),
B(SuspendGenerator), R(0), R(0), U8(14), U8(8),
B(SuspendGenerator), R(0), R(0), U8(14), U8(1),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(14),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(1),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(2),
B(Wide), B(JumpLoop), U16(649), I16(0),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(2), U8(34),
B(JumpIfFalse), U8(57),
B(LdaNamedProperty), R(3), U8(34), U8(35),
B(Star), R(15),
B(Mov), R(0), R(14),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(14), U8(2),
B(SuspendGenerator), R(0), R(0), U8(14), U8(9),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(14),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(14),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(15),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(15),
B(JumpIfTrue), U8(5),
B(Ldar), R(14),
B(ReThrow),
B(LdaZero),
B(Star), R(10),
B(Mov), R(14), R(11),
B(Jump), U8(111),
B(LdaNamedProperty), R(3), U8(34), U8(37),
B(Star), R(7),
B(Wide), B(JumpLoop), U16(260), I16(0),
B(LdaNamedProperty), R(6), U8(19), U8(14),
B(Star), R(8),
B(LdaSmi), I8(1),
B(TestEqualStrictNoFeedback), R(7),
B(JumpIfFalse), U8(10),
B(LdaZero),
B(Star), R(2),
B(Mov), R(8), R(3),
B(Jump), U8(105),
B(LdaUndefined),
B(Star), R(15),
B(Mov), R(0), R(14),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(14), U8(2),
B(SuspendGenerator), R(0), R(0), U8(14), U8(10),
B(Star), R(7),
B(Mov), R(0), R(6),
B(CallJSRuntime), U8(%async_generator_await_uncaught), R(6), U8(2),
B(SuspendGenerator), R(0), R(0), U8(6), U8(4),
/* 60 S> */ B(Return),
B(RestoreGeneratorRegisters), R(0), R(0), U8(14),
B(RestoreGeneratorRegisters), R(0), R(0), U8(6),
B(LdaSmi), I8(-2),
B(Star), R(9),
B(Star), R(1),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(0), U8(1),
B(Star), R(14),
B(Star), R(6),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(0), U8(1),
B(Star), R(15),
B(Star), R(7),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(15),
B(TestEqualStrictNoFeedback), R(7),
B(JumpIfTrue), U8(5),
B(Ldar), R(14),
B(Ldar), R(6),
B(ReThrow),
B(LdaZero),
B(Star), R(10),
B(Mov), R(14), R(11),
B(Star), R(2),
B(Mov), R(6), R(3),
B(Jump), U8(53),
B(Jump), U8(39),
B(Star), R(14),
B(Star), R(6),
B(Ldar), R(closure),
B(CreateCatchContext), R(14), U8(28), U8(35),
B(Star), R(13),
B(CreateCatchContext), R(6), U8(20), U8(21),
B(Star), R(5),
B(LdaTheHole),
B(SetPendingMessage),
B(Ldar), R(13),
B(PushContext), R(14),
B(Ldar), R(5),
B(PushContext), R(6),
B(LdaImmutableCurrentContextSlot), U8(4),
B(Star), R(16),
B(Mov), R(0), R(15),
B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorReject), R(15), U8(2),
B(PopContext), R(14),
B(Star), R(11),
B(Star), R(8),
B(Mov), R(0), R(7),
B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorReject), R(7), U8(2),
B(PopContext), R(6),
B(Star), R(3),
B(LdaSmi), I8(1),
B(Star), R(10),
B(Star), R(2),
B(Jump), U8(14),
B(LdaSmi), I8(-1),
B(Star), R(10),
B(Star), R(2),
B(Jump), U8(8),
B(Star), R(11),
B(Star), R(3),
B(LdaSmi), I8(2),
B(Star), R(10),
B(Star), R(2),
B(LdaTheHole),
B(SetPendingMessage),
B(Star), R(12),
B(Star), R(4),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorClose), R(0), U8(1),
B(Ldar), R(12),
B(Ldar), R(4),
B(SetPendingMessage),
B(Ldar), R(10),
B(SwitchOnSmiNoFeedback), U8(38), U8(3), I8(0),
B(Ldar), R(2),
B(SwitchOnSmiNoFeedback), U8(24), U8(3), I8(0),
B(Jump), U8(22),
B(LdaTrue),
B(Star), R(15),
B(Mov), R(0), R(13),
B(Mov), R(11), R(14),
B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorResolve), R(13), U8(3),
B(Star), R(7),
B(Mov), R(0), R(5),
B(Mov), R(3), R(6),
B(InvokeIntrinsic), U8(Runtime::k_AsyncGeneratorResolve), R(5), U8(3),
/* 60 S> */ B(Return),
B(Ldar), R(11),
B(Ldar), R(3),
/* 60 S> */ B(Return),
B(Ldar), R(11),
B(Ldar), R(3),
B(ReThrow),
B(LdaUndefined),
/* 60 S> */ B(Return),
]
constant pool: [
Smi [44],
Smi [135],
Smi [135],
Smi [135],
Smi [135],
Smi [135],
Smi [135],
Smi [135],
Smi [135],
Smi [815],
Smi [873],
Smi [132],
Smi [132],
Smi [132],
Smi [433],
Smi [15],
Smi [7],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["g"],
SYMBOL_TYPE,
SYMBOL_TYPE,
Smi [71],
Smi [142],
Smi [206],
Smi [334],
Smi [411],
Smi [499],
Smi [572],
Smi [622],
Smi [237],
Smi [109],
Smi [169],
Smi [17],
Smi [42],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["throw"],
ONE_BYTE_INTERNALIZED_STRING_TYPE [""],
ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"],
FIXED_ARRAY_TYPE,
Smi [502],
Smi [430],
Smi [295],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"],
FIXED_ARRAY_TYPE,
Smi [885],
Smi [647],
Smi [445],
Smi [325],
Smi [6],
Smi [20],
Smi [23],
]
handlers: [
[47, 962, 968],
[50, 923, 925],
[460, 515, 517],
[47, 522, 528],
[50, 483, 485],
]
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