[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:
parent
a5449b0fd6
commit
b9df000343
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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],
|
||||
]
|
||||
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user