Commit b9df0003 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[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: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45466}
parent a5449b0f
...@@ -2518,15 +2518,18 @@ class RewritableExpression final : public Expression { ...@@ -2518,15 +2518,18 @@ class RewritableExpression final : public Expression {
// desired, must be done beforehand (see the parser). // desired, must be done beforehand (see the parser).
class Suspend final : public Expression { class Suspend final : public Expression {
public: 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* generator_object() const { return generator_object_; }
Expression* expression() const { return expression_; } Expression* expression() const { return expression_; }
OnException on_exception() const { OnAbruptResume on_abrupt_resume() const {
return OnExceptionField::decode(bit_field_); return OnAbruptResumeField::decode(bit_field_);
} }
bool rethrow_on_exception() const { bool rethrow_on_exception() const {
return on_exception() == kOnExceptionRethrow; return on_abrupt_resume() == kOnExceptionRethrow;
} }
int suspend_id() const { return suspend_id_; } int suspend_id() const { return suspend_id_; }
...@@ -2563,23 +2566,23 @@ class Suspend final : public Expression { ...@@ -2563,23 +2566,23 @@ class Suspend final : public Expression {
friend class AstNodeFactory; friend class AstNodeFactory;
Suspend(Expression* generator_object, Expression* expression, int pos, Suspend(Expression* generator_object, Expression* expression, int pos,
OnException on_exception, SuspendFlags flags) OnAbruptResume on_abrupt_resume, SuspendFlags flags)
: Expression(pos, kSuspend), : Expression(pos, kSuspend),
suspend_id_(-1), suspend_id_(-1),
generator_object_(generator_object), generator_object_(generator_object),
expression_(expression) { expression_(expression) {
bit_field_ |= bit_field_ |= OnAbruptResumeField::encode(on_abrupt_resume) |
OnExceptionField::encode(on_exception) | FlagsField::encode(flags); FlagsField::encode(flags);
} }
int suspend_id_; int suspend_id_;
Expression* generator_object_; Expression* generator_object_;
Expression* expression_; Expression* expression_;
class OnExceptionField class OnAbruptResumeField
: public BitField<OnException, Expression::kNextBitFieldIndex, 1> {}; : public BitField<OnAbruptResume, Expression::kNextBitFieldIndex, 2> {};
class FlagsField class FlagsField
: public BitField<SuspendFlags, OnExceptionField::kNext, : public BitField<SuspendFlags, OnAbruptResumeField::kNext,
static_cast<int>(SuspendFlags::kBitWidth)> {}; static_cast<int>(SuspendFlags::kBitWidth)> {};
}; };
...@@ -3564,11 +3567,11 @@ class AstNodeFactory final BASE_EMBEDDED { ...@@ -3564,11 +3567,11 @@ class AstNodeFactory final BASE_EMBEDDED {
} }
Suspend* NewSuspend(Expression* generator_object, Expression* expression, Suspend* NewSuspend(Expression* generator_object, Expression* expression,
int pos, Suspend::OnException on_exception, int pos, Suspend::OnAbruptResume on_abrupt_resume,
SuspendFlags flags) { SuspendFlags flags) {
if (!expression) expression = NewUndefinedLiteral(pos); if (!expression) expression = NewUndefinedLiteral(pos);
return new (zone_) 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) { Throw* NewThrow(Expression* exception, int pos) {
......
...@@ -2567,54 +2567,55 @@ void BytecodeGenerator::BuildGeneratorResume(Suspend* expr, ...@@ -2567,54 +2567,55 @@ void BytecodeGenerator::BuildGeneratorResume(Suspend* expr,
: Runtime::kInlineGeneratorGetInputOrDebugPos; : Runtime::kInlineGeneratorGetInputOrDebugPos;
DCHECK(generator.is_valid()); DCHECK(generator.is_valid());
builder() builder()->CallRuntime(get_generator_input, generator);
->CallRuntime(get_generator_input, generator)
.StoreAccumulatorInRegister(input);
Register resume_mode = register_allocator()->NewRegister(); if (expr->on_abrupt_resume() != Suspend::kNoControl) {
builder() builder()->StoreAccumulatorInRegister(input);
->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator)
.StoreAccumulatorInRegister(resume_mode);
// Now dispatch on resume mode. Register resume_mode = register_allocator()->NewRegister();
builder()
->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator)
.StoreAccumulatorInRegister(resume_mode);
BytecodeLabel resume_with_next; // Now dispatch on resume mode.
BytecodeLabel resume_with_throw; 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);
builder() builder()
->MoveRegister(input, args[0]) ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
.LoadTrue() .CompareOperation(Token::EQ_STRICT, resume_mode)
.StoreAccumulatorInRegister(args[1]) .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_with_next)
.CallRuntime(Runtime::kInlineCreateIterResultObject, args); .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow))
execution_control()->ReturnAccumulator(); .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()->Bind(&resume_with_throw);
builder()->SetExpressionPosition(expr); builder()->SetExpressionPosition(expr);
builder()->LoadAccumulatorWithRegister(input); builder()->LoadAccumulatorWithRegister(input);
if (expr->rethrow_on_exception()) { if (expr->rethrow_on_exception()) {
builder()->ReThrow(); builder()->ReThrow();
} else { } else {
builder()->Throw(); builder()->Throw();
} }
builder()->Bind(&resume_with_next); builder()->Bind(&resume_with_next);
builder()->LoadAccumulatorWithRegister(input); builder()->LoadAccumulatorWithRegister(input);
}
} }
void BytecodeGenerator::VisitSuspend(Suspend* expr) { void BytecodeGenerator::VisitSuspend(Suspend* expr) {
......
...@@ -1397,17 +1397,16 @@ class ParserBase { ...@@ -1397,17 +1397,16 @@ class ParserBase {
return factory()->NewReturnStatement(expr, pos); return factory()->NewReturnStatement(expr, pos);
} }
inline SuspendExpressionT BuildSuspend(ExpressionT generator, inline SuspendExpressionT BuildSuspend(
ExpressionT expr, int pos, ExpressionT generator, ExpressionT expr, int pos,
Suspend::OnException on_exception, Suspend::OnAbruptResume on_abrupt_resume, SuspendFlags suspend_type) {
SuspendFlags suspend_type) {
DCHECK_EQ(0, DCHECK_EQ(0,
static_cast<int>(suspend_type & ~SuspendFlags::kSuspendTypeMask)); static_cast<int>(suspend_type & ~SuspendFlags::kSuspendTypeMask));
if (V8_UNLIKELY(is_async_generator())) { if (V8_UNLIKELY(is_async_generator())) {
suspend_type = static_cast<SuspendFlags>(suspend_type | suspend_type = static_cast<SuspendFlags>(suspend_type |
SuspendFlags::kAsyncGenerator); SuspendFlags::kAsyncGenerator);
} }
return factory()->NewSuspend(generator, expr, pos, on_exception, return factory()->NewSuspend(generator, expr, pos, on_abrupt_resume,
suspend_type); suspend_type);
} }
......
...@@ -4237,7 +4237,6 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name) { ...@@ -4237,7 +4237,6 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name) {
} }
} }
// Desugaring of yield* // Desugaring of yield*
// ==================== // ====================
// //
...@@ -4282,17 +4281,9 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name) { ...@@ -4282,17 +4281,9 @@ void Parser::SetFunctionName(Expression* value, const AstRawString* name) {
// //
// // From the generator to its user: // // From the generator to its user:
// // Forward output, receive new input, and determine resume mode. // // Forward output, receive new input, and determine resume mode.
// mode = kReturn; // RawYield(output); // See explanation above.
// try { // mode = %GeneratorGetResumeMode();
// try { // input = function.sent;
// RawYield(output); // See explanation above.
// mode = kNext;
// } catch (error) {
// mode = kThrow;
// }
// } finally {
// input = function.sent;
// continue;
// } // }
// } // }
// //
...@@ -4509,48 +4500,31 @@ Expression* Parser::RewriteYieldStar(Expression* generator, ...@@ -4509,48 +4500,31 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
property, break_loop, factory()->NewEmptyStatement(nopos), nopos); 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); // Yield(output);
Statement* yield_output; Statement* yield_output;
{ {
Expression* output_proxy = factory()->NewVariableProxy(var_output); Expression* output_proxy = factory()->NewVariableProxy(var_output);
Suspend* yield = Suspend* yield =
BuildSuspend(generator, output_proxy, nopos, Suspend::kOnExceptionThrow, BuildSuspend(generator, output_proxy, nopos, Suspend::kNoControl,
SuspendFlags::kYieldStar); SuspendFlags::kYieldStar);
yield_output = factory()->NewExpressionStatement(yield, nopos); yield_output = factory()->NewExpressionStatement(yield, nopos);
} }
// mode = kNext; // mode = %GeneratorGetResumeMode();
Statement* set_mode_next; Statement* get_mode;
{ {
Expression* mode_proxy = factory()->NewVariableProxy(var_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; ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
Statement* set_mode_throw; VariableProxy* generator = factory()->NewVariableProxy(
{ function_state_->generator_object_variable());
Expression* mode_proxy = factory()->NewVariableProxy(var_mode); args->Add(generator, zone());
Expression* kthrow = Expression* mode = factory()->NewCallRuntime(
factory()->NewSmiLiteral(JSGeneratorObject::kThrow, nopos); Runtime::kInlineGeneratorGetResumeMode, args, pos);
Expression* assignment = Expression* assignment =
factory()->NewAssignment(Token::ASSIGN, mode_proxy, kthrow, nopos); factory()->NewAssignment(Token::ASSIGN, mode_proxy, mode, nopos);
set_mode_throw = factory()->NewExpressionStatement(assignment, nopos); get_mode = factory()->NewExpressionStatement(assignment, nopos);
} }
// input = function.sent; // input = function.sent;
...@@ -4596,36 +4570,6 @@ Expression* Parser::RewriteYieldStar(Expression* generator, ...@@ -4596,36 +4570,6 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
// Now put things together. // 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) { ... } // switch (mode) { ... }
SwitchStatement* switch_mode = factory()->NewSwitchStatement(nullptr, nopos); SwitchStatement* switch_mode = factory()->NewSwitchStatement(nullptr, nopos);
{ {
...@@ -4665,7 +4609,6 @@ Expression* Parser::RewriteYieldStar(Expression* generator, ...@@ -4665,7 +4609,6 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
Block* loop_body = factory()->NewBlock(nullptr, 5, false, nopos); Block* loop_body = factory()->NewBlock(nullptr, 5, false, nopos);
loop_body->statements()->Add(switch_mode, zone()); loop_body->statements()->Add(switch_mode, zone());
loop_body->statements()->Add(if_done, zone()); loop_body->statements()->Add(if_done, zone());
loop_body->statements()->Add(set_mode_return, zone());
if (is_async_generator()) { if (is_async_generator()) {
// AsyncGeneratorYield does not yield the original iterator result, // AsyncGeneratorYield does not yield the original iterator result,
...@@ -4682,7 +4625,9 @@ Expression* Parser::RewriteYieldStar(Expression* generator, ...@@ -4682,7 +4625,9 @@ Expression* Parser::RewriteYieldStar(Expression* generator,
factory()->NewExpressionStatement(assign, nopos), zone()); 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); loop->Initialize(factory()->NewBooleanLiteral(true, nopos), loop_body);
} }
......
...@@ -644,7 +644,7 @@ class PreParserFactory { ...@@ -644,7 +644,7 @@ class PreParserFactory {
} }
PreParserExpression NewSuspend(PreParserExpression generator_object, PreParserExpression NewSuspend(PreParserExpression generator_object,
PreParserExpression expression, int pos, PreParserExpression expression, int pos,
Suspend::OnException on_exception, Suspend::OnAbruptResume on_abrupt_resume,
SuspendFlags flags) { SuspendFlags flags) {
return PreParserExpression::Default(); return PreParserExpression::Default();
} }
......
...@@ -569,3 +569,338 @@ handlers: [ ...@@ -569,3 +569,338 @@ handlers: [
[510, 526, 528], [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],
]
...@@ -2348,6 +2348,10 @@ TEST(Generators) { ...@@ -2348,6 +2348,10 @@ TEST(Generators) {
"function* f() { for (let x of [42]) yield x }\n" "function* f() { for (let x of [42]) yield x }\n"
"f();\n", "f();\n",
"function* g() { yield 42 }\n"
"function* f() { yield* g() }\n"
"f();\n",
}; };
CHECK(CompareTexts(BuildActual(printer, snippets), CHECK(CompareTexts(BuildActual(printer, snippets),
......
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