[generators] Improve yield* desugaring to save unnecessary try/catch and try/finally

Change-Id: Ia900c6c21d1ff330088a6566f8f6c7719c887ccf
Reviewed-on: https://chromium-review.googlesource.com/509256
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45466}
This commit is contained in:
Tobias Tebbi 2017-05-22 16:52:07 +02:00 committed by Commit Bot
parent a5449b0fd6
commit b9df000343
7 changed files with 421 additions and 134 deletions

View File

@ -2518,15 +2518,18 @@ class RewritableExpression final : public Expression {
// desired, must be done beforehand (see the parser).
class Suspend final : public Expression {
public:
enum OnException { kOnExceptionThrow, kOnExceptionRethrow };
// With {kNoControl}, the {Suspend} behaves like yield, except that it never
// throws and never causes the current generator to return. This is used to
// desugar yield*.
enum OnAbruptResume { kOnExceptionThrow, kOnExceptionRethrow, kNoControl };
Expression* generator_object() const { return generator_object_; }
Expression* expression() const { return expression_; }
OnException on_exception() const {
return OnExceptionField::decode(bit_field_);
OnAbruptResume on_abrupt_resume() const {
return OnAbruptResumeField::decode(bit_field_);
}
bool rethrow_on_exception() const {
return on_exception() == kOnExceptionRethrow;
return on_abrupt_resume() == kOnExceptionRethrow;
}
int suspend_id() const { return suspend_id_; }
@ -2563,23 +2566,23 @@ class Suspend final : public Expression {
friend class AstNodeFactory;
Suspend(Expression* generator_object, Expression* expression, int pos,
OnException on_exception, SuspendFlags flags)
OnAbruptResume on_abrupt_resume, SuspendFlags flags)
: Expression(pos, kSuspend),
suspend_id_(-1),
generator_object_(generator_object),
expression_(expression) {
bit_field_ |=
OnExceptionField::encode(on_exception) | FlagsField::encode(flags);
bit_field_ |= OnAbruptResumeField::encode(on_abrupt_resume) |
FlagsField::encode(flags);
}
int suspend_id_;
Expression* generator_object_;
Expression* expression_;
class OnExceptionField
: public BitField<OnException, Expression::kNextBitFieldIndex, 1> {};
class OnAbruptResumeField
: public BitField<OnAbruptResume, Expression::kNextBitFieldIndex, 2> {};
class FlagsField
: public BitField<SuspendFlags, OnExceptionField::kNext,
: public BitField<SuspendFlags, OnAbruptResumeField::kNext,
static_cast<int>(SuspendFlags::kBitWidth)> {};
};
@ -3564,11 +3567,11 @@ class AstNodeFactory final BASE_EMBEDDED {
}
Suspend* NewSuspend(Expression* generator_object, Expression* expression,
int pos, Suspend::OnException on_exception,
int pos, Suspend::OnAbruptResume on_abrupt_resume,
SuspendFlags flags) {
if (!expression) expression = NewUndefinedLiteral(pos);
return new (zone_)
Suspend(generator_object, expression, pos, on_exception, flags);
Suspend(generator_object, expression, pos, on_abrupt_resume, flags);
}
Throw* NewThrow(Expression* exception, int pos) {

View File

@ -2567,54 +2567,55 @@ void BytecodeGenerator::BuildGeneratorResume(Suspend* expr,
: Runtime::kInlineGeneratorGetInputOrDebugPos;
DCHECK(generator.is_valid());
builder()
->CallRuntime(get_generator_input, generator)
.StoreAccumulatorInRegister(input);
builder()->CallRuntime(get_generator_input, generator);
Register resume_mode = register_allocator()->NewRegister();
builder()
->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator)
.StoreAccumulatorInRegister(resume_mode);
if (expr->on_abrupt_resume() != Suspend::kNoControl) {
builder()->StoreAccumulatorInRegister(input);
// Now dispatch on resume mode.
BytecodeLabel resume_with_next;
BytecodeLabel resume_with_throw;
builder()
->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
.CompareOperation(Token::EQ_STRICT, resume_mode)
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_with_next)
.LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow))
.CompareOperation(Token::EQ_STRICT, resume_mode)
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_with_throw);
// Fall through for resuming with return.
if (expr->is_async_generator()) {
// Async generator methods will produce the iter result object.
builder()->LoadAccumulatorWithRegister(input);
execution_control()->AsyncReturnAccumulator();
} else {
RegisterList args = register_allocator()->NewRegisterList(2);
Register resume_mode = register_allocator()->NewRegister();
builder()
->MoveRegister(input, args[0])
.LoadTrue()
.StoreAccumulatorInRegister(args[1])
.CallRuntime(Runtime::kInlineCreateIterResultObject, args);
execution_control()->ReturnAccumulator();
}
->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator)
.StoreAccumulatorInRegister(resume_mode);
builder()->Bind(&resume_with_throw);
builder()->SetExpressionPosition(expr);
builder()->LoadAccumulatorWithRegister(input);
if (expr->rethrow_on_exception()) {
builder()->ReThrow();
} else {
builder()->Throw();
}
// Now dispatch on resume mode.
BytecodeLabel resume_with_next;
BytecodeLabel resume_with_throw;
builder()->Bind(&resume_with_next);
builder()->LoadAccumulatorWithRegister(input);
builder()
->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
.CompareOperation(Token::EQ_STRICT, resume_mode)
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_with_next)
.LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow))
.CompareOperation(Token::EQ_STRICT, resume_mode)
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_with_throw);
// Fall through for resuming with return.
if (expr->is_async_generator()) {
// Async generator methods will produce the iter result object.
builder()->LoadAccumulatorWithRegister(input);
execution_control()->AsyncReturnAccumulator();
} else {
RegisterList args = register_allocator()->NewRegisterList(2);
builder()
->MoveRegister(input, args[0])
.LoadTrue()
.StoreAccumulatorInRegister(args[1])
.CallRuntime(Runtime::kInlineCreateIterResultObject, args);
execution_control()->ReturnAccumulator();
}
builder()->Bind(&resume_with_throw);
builder()->SetExpressionPosition(expr);
builder()->LoadAccumulatorWithRegister(input);
if (expr->rethrow_on_exception()) {
builder()->ReThrow();
} else {
builder()->Throw();
}
builder()->Bind(&resume_with_next);
builder()->LoadAccumulatorWithRegister(input);
}
}
void BytecodeGenerator::VisitSuspend(Suspend* expr) {

View File

@ -1397,17 +1397,16 @@ class ParserBase {
return factory()->NewReturnStatement(expr, pos);
}
inline SuspendExpressionT BuildSuspend(ExpressionT generator,
ExpressionT expr, int pos,
Suspend::OnException on_exception,
SuspendFlags suspend_type) {
inline SuspendExpressionT BuildSuspend(
ExpressionT generator, ExpressionT expr, int pos,
Suspend::OnAbruptResume on_abrupt_resume, SuspendFlags suspend_type) {
DCHECK_EQ(0,
static_cast<int>(suspend_type & ~SuspendFlags::kSuspendTypeMask));
if (V8_UNLIKELY(is_async_generator())) {
suspend_type = static_cast<SuspendFlags>(suspend_type |
SuspendFlags::kAsyncGenerator);
}
return factory()->NewSuspend(generator, expr, pos, on_exception,
return factory()->NewSuspend(generator, expr, pos, on_abrupt_resume,
suspend_type);
}

View File

@ -4237,7 +4237,6 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name) {
}
}
// Desugaring of yield*
// ====================
//
@ -4282,17 +4281,9 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name) {
//
// // From the generator to its user:
// // Forward output, receive new input, and determine resume mode.
// mode = kReturn;
// try {
// try {
// RawYield(output); // See explanation above.
// mode = kNext;
// } catch (error) {
// mode = kThrow;
// }
// } finally {
// input = function.sent;
// continue;
// RawYield(output); // See explanation above.
// mode = %GeneratorGetResumeMode();
// input = function.sent;
// }
// }
//
@ -4509,48 +4500,31 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
property, break_loop, factory()->NewEmptyStatement(nopos), nopos);
}
// mode = kReturn;
Statement* set_mode_return;
{
Expression* mode_proxy = factory()->NewVariableProxy(var_mode);
Expression* kreturn =
factory()->NewSmiLiteral(JSGeneratorObject::kReturn, nopos);
Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, mode_proxy, kreturn, nopos);
set_mode_return = factory()->NewExpressionStatement(assignment, nopos);
}
// Yield(output);
Statement* yield_output;
{
Expression* output_proxy = factory()->NewVariableProxy(var_output);
Suspend* yield =
BuildSuspend(generator, output_proxy, nopos, Suspend::kOnExceptionThrow,
BuildSuspend(generator, output_proxy, nopos, Suspend::kNoControl,
SuspendFlags::kYieldStar);
yield_output = factory()->NewExpressionStatement(yield, nopos);
}
// mode = kNext;
Statement* set_mode_next;
// mode = %GeneratorGetResumeMode();
Statement* get_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);
set_mode_next = factory()->NewExpressionStatement(assignment, nopos);
}
// mode = kThrow;
Statement* set_mode_throw;
{
Expression* mode_proxy = factory()->NewVariableProxy(var_mode);
Expression* kthrow =
factory()->NewSmiLiteral(JSGeneratorObject::kThrow, nopos);
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
VariableProxy* generator = factory()->NewVariableProxy(
function_state_->generator_object_variable());
args->Add(generator, zone());
Expression* mode = factory()->NewCallRuntime(
Runtime::kInlineGeneratorGetResumeMode, args, pos);
Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, mode_proxy, kthrow, nopos);
set_mode_throw = factory()->NewExpressionStatement(assignment, nopos);
factory()->NewAssignment(Token::ASSIGN, mode_proxy, mode, nopos);
get_mode = factory()->NewExpressionStatement(assignment, nopos);
}
// input = function.sent;
@ -4596,36 +4570,6 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
// Now put things together.
// try { ... } catch(e) { ... }
Statement* try_catch;
{
Block* try_block = factory()->NewBlock(nullptr, 2, false, nopos);
try_block->statements()->Add(yield_output, zone());
try_block->statements()->Add(set_mode_next, zone());
Block* catch_block = factory()->NewBlock(nullptr, 1, false, nopos);
catch_block->statements()->Add(set_mode_throw, zone());
Scope* catch_scope = NewHiddenCatchScopeWithParent(scope());
try_catch = factory()->NewTryCatchStatementForDesugaring(
try_block, catch_scope, catch_block, nopos);
}
// try { ... } finally { ... }
Statement* try_finally;
{
Block* try_block = factory()->NewBlock(nullptr, 1, false, nopos);
try_block->statements()->Add(try_catch, zone());
Block* finally = factory()->NewBlock(nullptr, 2, false, nopos);
finally->statements()->Add(get_input, zone());
finally->statements()->Add(factory()->NewContinueStatement(loop, nopos),
zone());
try_finally = factory()->NewTryFinallyStatement(try_block, finally, nopos);
}
// switch (mode) { ... }
SwitchStatement* switch_mode = factory()->NewSwitchStatement(nullptr, nopos);
{
@ -4665,7 +4609,6 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
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,
@ -4682,7 +4625,9 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
factory()->NewExpressionStatement(assign, nopos), zone());
}
loop_body->statements()->Add(try_finally, 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);
}

View File

@ -644,7 +644,7 @@ class PreParserFactory {
}
PreParserExpression NewSuspend(PreParserExpression generator_object,
PreParserExpression expression, int pos,
Suspend::OnException on_exception,
Suspend::OnAbruptResume on_abrupt_resume,
SuspendFlags flags) {
return PreParserExpression::Default();
}

View File

@ -569,3 +569,338 @@ handlers: [
[510, 526, 528],
]
---
snippet: "
function* g() { yield 42 }
function* f() { yield* g() }
f();
"
frame size: 12
parameter count: 1
bytecode array length: 679
bytecodes: [
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(25),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetContext), R(new_target), U8(1),
B(PushContext), R(3),
B(ResumeGenerator), R(new_target),
B(Star), R(2),
B(SwitchOnSmiNoFeedback), U8(0), U8(2), I8(0),
B(LdaSmi), I8(79),
B(Star), R(4),
B(CallRuntime), U16(Runtime::kAbort), R(4), U8(1),
B(LdaSmi), I8(-2),
B(Star), R(2),
B(CreateFunctionContext), U8(9),
B(PushContext), R(0),
B(Mov), R(closure), R(4),
B(Mov), R(this), R(5),
B(InvokeIntrinsic), U8(Runtime::k_CreateJSGeneratorObject), R(4), U8(2),
B(StaCurrentContextSlot), U8(4),
/* 38 E> */ B(StackCheck),
B(Mov), R(context), R(6),
B(LdaImmutableCurrentContextSlot), U8(4),
B(Star), R(7),
B(LdaImmutableCurrentContextSlot), U8(4),
B(Star), R(8),
B(LdaZero),
/* 38 E> */ B(SuspendGenerator), R(7), U8(0),
B(Ldar), R(8),
/* 54 S> */ B(Return),
B(LdaSmi), I8(-2),
B(Star), R(2),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(7), U8(1),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(7), U8(1),
B(Star), R(9),
B(LdaZero),
B(TestEqualStrictNoFeedback), R(9),
B(JumpIfTrue), U8(28),
B(LdaSmi), I8(2),
B(TestEqualStrictNoFeedback), R(9),
B(JumpIfTrue), U8(19),
B(LdaTrue),
B(Star), R(11),
B(Mov), R(8), R(10),
B(InvokeIntrinsic), U8(Runtime::k_CreateIterResultObject), R(10), U8(2),
B(Star), R(5),
B(LdaZero),
B(Star), R(4),
B(JumpConstant), U8(15),
B(Ldar), R(8),
/* 38 E> */ B(Throw),
/* 43 S> */ B(LdaUndefined),
B(StaCurrentContextSlot), U8(5),
B(LdaZero),
B(StaCurrentContextSlot), U8(6),
B(LdaUndefined),
B(StaCurrentContextSlot), U8(7),
B(LdaGlobal), U8(2), U8(5),
B(Star), R(9),
/* 50 E> */ B(CallUndefinedReceiver0), R(9), U8(3),
B(Star), R(7),
B(LdaNamedProperty), R(7), U8(3), U8(7),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(9),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(StaCurrentContextSlot), U8(8),
B(Ldar), R(2),
B(SwitchOnSmiNoFeedback), U8(4), U8(1), I8(1),
B(LdaSmi), I8(-2),
B(TestEqualStrictNoFeedback), R(2),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(79),
B(Star), R(7),
B(CallRuntime), U16(Runtime::kAbort), R(7), U8(1),
B(StackCheck),
B(LdaCurrentContextSlot), U8(6),
B(Star), R(7),
B(LdaZero),
B(TestEqualStrict), R(7), U8(15),
B(JumpIfTrue), U8(18),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(7), U8(19),
B(JumpIfTrue), U8(55),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(7), U8(28),
B(JumpIfTrue), U8(122),
B(JumpConstant), U8(11),
B(LdaCurrentContextSlot), U8(8),
B(Star), R(9),
B(LdaNamedProperty), R(9), U8(5), U8(13),
B(Star), R(8),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(10),
B(CallProperty1), R(8), R(9), R(10), U8(11),
B(StaCurrentContextSlot), U8(7),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(8), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(11),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(8),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
B(JumpConstant), U8(12),
B(LdaCurrentContextSlot), U8(8),
B(Star), R(8),
B(LdaNamedProperty), R(8), U8(6), U8(16),
B(StaCurrentContextSlot), U8(7),
B(LdaCurrentContextSlot), U8(7),
B(TestUndetectable),
B(JumpIfFalse), U8(20),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(8),
B(LdaTrue),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_CreateIterResultObject), R(8), U8(2),
B(Star), R(5),
B(LdaZero),
B(Star), R(4),
B(JumpConstant), U8(16),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(8),
B(LdaCurrentContextSlot), U8(8),
B(Star), R(9),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(10),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(8), U8(3),
B(StaCurrentContextSlot), U8(7),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(8), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(11),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(8),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
B(Jump), U8(197),
B(LdaCurrentContextSlot), U8(8),
B(Star), R(8),
B(LdaNamedProperty), R(8), U8(7), U8(20),
B(StaCurrentContextSlot), U8(9),
B(LdaCurrentContextSlot), U8(9),
B(TestUndetectable),
B(JumpIfFalse), U8(141),
B(LdaCurrentContextSlot), U8(8),
B(Star), R(8),
B(LdaNamedProperty), R(8), U8(6), U8(23),
B(StaCurrentContextSlot), U8(10),
B(LdaCurrentContextSlot), U8(10),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(108),
B(LdaZero),
B(Star), R(8),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(8), U8(26),
B(JumpIfFalse), U8(63),
B(LdaCurrentContextSlot), U8(10),
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(130),
B(Star), R(8),
B(LdaConstant), U8(8),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kNewTypeError), R(8), U8(2),
B(Throw),
B(Mov), R(context), R(8),
B(LdaCurrentContextSlot), U8(10),
B(Star), R(9),
B(LdaCurrentContextSlot), U8(8),
B(Star), R(10),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(9), U8(2),
B(Jump), U8(20),
B(Star), R(9),
B(Ldar), R(closure),
B(CreateCatchContext), R(9), U8(9), U8(10),
B(Star), R(8),
B(LdaTheHole),
B(SetPendingMessage),
B(Ldar), R(8),
B(PushContext), R(1),
B(PopContext), R(1),
B(Jump), U8(37),
B(LdaCurrentContextSlot), U8(10),
B(Star), R(8),
B(LdaCurrentContextSlot), U8(8),
B(Star), R(9),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(8), U8(2),
B(StaCurrentContextSlot), U8(11),
B(LdaCurrentContextSlot), U8(11),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(8), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(11),
B(LdaCurrentContextSlot), U8(11),
B(Star), R(8),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
B(Wide), B(LdaSmi), I16(144),
B(Star), R(8),
B(LdaConstant), U8(8),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kNewTypeError), R(8), U8(2),
B(Throw),
B(LdaCurrentContextSlot), U8(9),
B(Star), R(8),
B(LdaCurrentContextSlot), U8(8),
B(Star), R(9),
B(LdaCurrentContextSlot), U8(5),
B(Star), R(10),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(8), U8(3),
B(StaCurrentContextSlot), U8(7),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(8), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(11),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(8),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(8), U8(1),
B(Jump), U8(2),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(7),
B(LdaNamedProperty), R(7), U8(13), U8(29),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(52),
B(LdaImmutableCurrentContextSlot), U8(4),
B(Star), R(7),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(8),
B(LdaSmi), I8(1),
B(SuspendGenerator), R(7), U8(1),
B(Ldar), R(8),
/* 54 S> */ B(Return),
B(LdaSmi), I8(-2),
B(Star), R(2),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(7), U8(1),
B(LdaImmutableCurrentContextSlot), U8(4),
B(Star), R(7),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(7), U8(1),
B(StaCurrentContextSlot), U8(5),
B(LdaImmutableCurrentContextSlot), U8(4),
B(Star), R(7),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(7), U8(1),
B(StaCurrentContextSlot), U8(6),
B(Wide), B(JumpLoop), U16(418), I16(0),
B(LdaCurrentContextSlot), U8(6),
B(Star), R(7),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(7), U8(31),
B(JumpIfFalse), U8(26),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(7),
B(LdaNamedProperty), R(7), U8(14), U8(32),
B(Star), R(7),
B(LdaTrue),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_CreateIterResultObject), R(7), U8(2),
B(Star), R(5),
B(LdaZero),
B(Star), R(4),
B(Jump), U8(41),
B(LdaCurrentContextSlot), U8(7),
B(Star), R(7),
B(LdaNamedProperty), R(7), U8(14), U8(34),
B(StaCurrentContextSlot), U8(12),
B(LdaUndefined),
B(Star), R(7),
B(LdaTrue),
B(Star), R(8),
B(InvokeIntrinsic), U8(Runtime::k_CreateIterResultObject), R(7), U8(2),
B(Star), R(5),
B(LdaZero),
B(Star), R(4),
B(Jump), U8(14),
B(LdaSmi), I8(-1),
B(Star), R(4),
B(Jump), U8(8),
B(Star), R(5),
B(LdaSmi), I8(1),
B(Star), R(4),
B(LdaTheHole),
B(SetPendingMessage),
B(Star), R(6),
B(LdaImmutableCurrentContextSlot), U8(4),
B(Star), R(7),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorClose), R(7), U8(1),
B(Ldar), R(6),
B(SetPendingMessage),
B(Ldar), R(4),
B(SwitchOnSmiNoFeedback), U8(17), U8(2), I8(0),
B(Jump), U8(8),
B(Ldar), R(5),
/* 54 S> */ B(Return),
B(Ldar), R(5),
B(ReThrow),
B(LdaUndefined),
/* 54 S> */ B(Return),
]
constant pool: [
Smi [52],
Smi [137],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["g"],
SYMBOL_TYPE,
Smi [387],
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 [315],
Smi [271],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
Smi [540],
Smi [374],
Smi [6],
Smi [9],
]
handlers: [
[51, 636, 642],
[386, 398, 400],
]

View File

@ -2348,6 +2348,10 @@ TEST(Generators) {
"function* f() { for (let x of [42]) yield x }\n"
"f();\n",
"function* g() { yield 42 }\n"
"function* f() { yield* g() }\n"
"f();\n",
};
CHECK(CompareTexts(BuildActual(printer, snippets),