Commit 31b88650 authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[ignition] desugar yield* in the BytecodeGenerator

Async generator yield* is still desugared in the parser, to be moved to the BytecodeGenerator in a future CL.

Bug: v8:6472
Change-Id: I8b33e2f9e931949f7375540099cd8ec3a6b27cf1
Reviewed-on: https://chromium-review.googlesource.com/539335
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46165}
parent b00de2a9
......@@ -270,6 +270,9 @@ void AstExpressionRewriter::VisitSuspend(Suspend* node) {
AST_REWRITE_PROPERTY(Expression, node, expression);
}
void AstExpressionRewriter::VisitYieldStar(YieldStar* node) {
VisitSuspend(node);
}
void AstExpressionRewriter::VisitThrow(Throw* node) {
REWRITE_THIS(node);
......
......@@ -240,6 +240,10 @@ void AstNumberingVisitor::VisitSuspend(Suspend* node) {
Visit(node->expression());
}
void AstNumberingVisitor::VisitYieldStar(YieldStar* node) {
VisitSuspend(node);
ReserveFeedbackSlots(node);
}
void AstNumberingVisitor::VisitThrow(Throw* node) {
IncrementNodeCount();
......
......@@ -362,6 +362,12 @@ void AstTraversalVisitor<Subclass>::VisitSuspend(Suspend* expr) {
RECURSE_EXPRESSION(Visit(expr->expression()));
}
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitYieldStar(YieldStar* expr) {
PROCESS_EXPRESSION(expr);
RECURSE_EXPRESSION(Visit(expr->expression()));
}
template <class Subclass>
void AstTraversalVisitor<Subclass>::VisitThrow(Throw* expr) {
PROCESS_EXPRESSION(expr);
......
......@@ -92,6 +92,7 @@ namespace internal {
V(VariableProxy) \
V(Literal) \
V(Suspend) \
V(YieldStar) \
V(Throw) \
V(CallRuntime) \
V(UnaryOperation) \
......@@ -2250,7 +2251,7 @@ class RewritableExpression final : public Expression {
// Our Yield is different from the JS yield in that it "returns" its argument as
// is, without wrapping it in an iterator result object. Such wrapping, if
// desired, must be done beforehand (see the parser).
class Suspend final : public Expression {
class Suspend : public Expression {
public:
// With {kNoControl}, the {Suspend} behaves like yield, except that it never
// throws and never causes the current generator to return. This is used to
......@@ -2300,10 +2301,11 @@ class Suspend final : public Expression {
private:
friend class AstNodeFactory;
friend class YieldStar;
Suspend(Expression* expression, int pos, OnAbruptResume on_abrupt_resume,
SuspendFlags flags)
: Expression(pos, kSuspend), suspend_id_(-1), expression_(expression) {
Suspend(NodeType node_type, Expression* expression, int pos,
OnAbruptResume on_abrupt_resume, SuspendFlags flags)
: Expression(pos, node_type), suspend_id_(-1), expression_(expression) {
bit_field_ |= OnAbruptResumeField::encode(on_abrupt_resume) |
FlagsField::encode(flags);
}
......@@ -2318,6 +2320,74 @@ class Suspend final : public Expression {
static_cast<int>(SuspendFlags::kBitWidth)> {};
};
class YieldStar final : public Suspend {
public:
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
FeedbackSlotCache* cache) {
load_iterable_iterator_slot_ = spec->AddLoadICSlot();
load_iterator_return_slot_ = spec->AddLoadICSlot();
load_iterator_next_slot_ = spec->AddLoadICSlot();
load_iterator_throw_slot_ = spec->AddLoadICSlot();
load_output_done_slot_ = spec->AddLoadICSlot();
load_output_value_slot_ = spec->AddLoadICSlot();
call_iterable_iterator_slot_ = spec->AddCallICSlot();
call_iterator_return_slot1_ = spec->AddCallICSlot();
call_iterator_return_slot2_ = spec->AddCallICSlot();
call_iterator_next_slot_ = spec->AddCallICSlot();
call_iterator_throw_slot_ = spec->AddCallICSlot();
}
FeedbackSlot load_iterable_iterator_slot() const {
return load_iterable_iterator_slot_;
}
FeedbackSlot load_iterator_return_slot() const {
return load_iterator_return_slot_;
}
FeedbackSlot load_iterator_next_slot() const {
return load_iterator_next_slot_;
}
FeedbackSlot load_iterator_throw_slot() const {
return load_iterator_throw_slot_;
}
FeedbackSlot load_output_done_slot() const { return load_output_done_slot_; }
FeedbackSlot load_output_value_slot() const {
return load_output_value_slot_;
}
FeedbackSlot call_iterable_iterator_slot() const {
return call_iterable_iterator_slot_;
}
FeedbackSlot call_iterator_return_slot1() const {
return call_iterator_return_slot1_;
}
FeedbackSlot call_iterator_return_slot2() const {
return call_iterator_return_slot2_;
}
FeedbackSlot call_iterator_next_slot() const {
return call_iterator_next_slot_;
}
FeedbackSlot call_iterator_throw_slot() const {
return call_iterator_throw_slot_;
}
private:
friend class AstNodeFactory;
YieldStar(Expression* expression, int pos, SuspendFlags flags)
: Suspend(kYieldStar, expression, pos,
Suspend::OnAbruptResume::kNoControl, flags) {}
FeedbackSlot load_iterable_iterator_slot_;
FeedbackSlot load_iterator_return_slot_;
FeedbackSlot load_iterator_next_slot_;
FeedbackSlot load_iterator_throw_slot_;
FeedbackSlot load_output_done_slot_;
FeedbackSlot load_output_value_slot_;
FeedbackSlot call_iterable_iterator_slot_;
FeedbackSlot call_iterator_return_slot1_;
FeedbackSlot call_iterator_return_slot2_;
FeedbackSlot call_iterator_next_slot_;
FeedbackSlot call_iterator_throw_slot_;
};
class Throw final : public Expression {
public:
......@@ -3312,7 +3382,13 @@ class AstNodeFactory final BASE_EMBEDDED {
Suspend::OnAbruptResume on_abrupt_resume,
SuspendFlags flags) {
if (!expression) expression = NewUndefinedLiteral(pos);
return new (zone_) Suspend(expression, pos, on_abrupt_resume, flags);
return new (zone_)
Suspend(AstNode::kSuspend, expression, pos, on_abrupt_resume, flags);
}
YieldStar* NewYieldStar(Expression* expression, int pos, SuspendFlags flags) {
if (!expression) expression = NewUndefinedLiteral(pos);
return new (zone_) YieldStar(expression, pos, flags);
}
Throw* NewThrow(Expression* exception, int pos) {
......
......@@ -256,6 +256,8 @@ void CallPrinter::VisitAssignment(Assignment* node) {
void CallPrinter::VisitSuspend(Suspend* node) { Find(node->expression()); }
void CallPrinter::VisitYieldStar(YieldStar* node) { Find(node->expression()); }
void CallPrinter::VisitThrow(Throw* node) { Find(node->exception()); }
......@@ -1119,6 +1121,12 @@ void AstPrinter::VisitSuspend(Suspend* node) {
Visit(node->expression());
}
void AstPrinter::VisitYieldStar(YieldStar* node) {
EmbeddedVector<char, 128> buf;
SNPrintF(buf, "YIELD_STAR id %d", node->suspend_id());
IndentedScope indent(this, buf.start(), node->position());
Visit(node->expression());
}
void AstPrinter::VisitThrow(Throw* node) {
IndentedScope indent(this, "THROW", node->position());
......
......@@ -1377,6 +1377,10 @@ void AstGraphBuilder::VisitSuspend(Suspend* expr) {
UNREACHABLE();
}
void AstGraphBuilder::VisitYieldStar(YieldStar* expr) {
// Generator functions are supported only by going through Ignition first.
UNREACHABLE();
}
void AstGraphBuilder::VisitThrow(Throw* expr) {
VisitForValue(expr->exception());
......
......@@ -149,10 +149,9 @@ void ALAA::VisitObjectLiteral(ObjectLiteral* e) {
void ALAA::VisitArrayLiteral(ArrayLiteral* e) { VisitExpressions(e->values()); }
void ALAA::VisitSuspend(Suspend* stmt) {
Visit(stmt->expression());
}
void ALAA::VisitSuspend(Suspend* e) { Visit(e->expression()); }
void ALAA::VisitYieldStar(YieldStar* e) { Visit(e->expression()); }
void ALAA::VisitThrow(Throw* stmt) { Visit(stmt->exception()); }
......
......@@ -1357,6 +1357,10 @@ void FullCodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
Visit(expr->expression());
}
void FullCodeGenerator::VisitYieldStar(YieldStar* expr) {
// Resumable functions are not supported.
UNREACHABLE();
}
bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) {
Expression* sub_expr;
......
......@@ -962,14 +962,20 @@ void BytecodeGenerator::GenerateBytecodeBody() {
void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt,
LoopBuilder* loop_builder) {
// Recall that stmt->yield_count() is always zero inside ordinary
// (i.e. non-generator) functions.
if (stmt->suspend_count() == 0) {
VisitIterationHeader(stmt->first_suspend_id(), stmt->suspend_count(),
loop_builder);
}
void BytecodeGenerator::VisitIterationHeader(int first_suspend_id,
int suspend_count,
LoopBuilder* loop_builder) {
// Recall that suspend_count is always zero inside ordinary (i.e.
// non-generator) functions.
if (suspend_count == 0) {
loop_builder->LoopHeader();
} else {
loop_builder->LoopHeaderInGenerator(
&generator_jump_table_, static_cast<int>(stmt->first_suspend_id()),
static_cast<int>(stmt->suspend_count()));
loop_builder->LoopHeaderInGenerator(&generator_jump_table_,
first_suspend_id, suspend_count);
// Perform state dispatch on the generator state, assuming this is a resume.
builder()
......@@ -2572,13 +2578,10 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
}
}
void BytecodeGenerator::BuildGeneratorSuspend(Suspend* expr,
void BytecodeGenerator::BuildGeneratorSuspend(Suspend* expr, Register value,
RegisterList registers_to_save) {
RegisterAllocationScope register_scope(this);
builder()->SetExpressionPosition(expr);
Register value = VisitForRegisterValue(expr->expression());
// Save context, registers, and state. Then return.
builder()
->LoadLiteral(Smi::FromInt(expr->suspend_id()))
......@@ -2624,8 +2627,6 @@ void BytecodeGenerator::BuildGeneratorResume(
->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
.StoreAccumulatorInRegister(generator_state_);
Register input = register_allocator()->NewRegister();
// When resuming an Async Generator from an Await expression, the sent
// value is in the [[await_input_or_debug_pos]] slot. Otherwise, the sent
// value is in the [[input_or_debug_pos]] slot.
......@@ -2635,8 +2636,12 @@ void BytecodeGenerator::BuildGeneratorResume(
: Runtime::kInlineGeneratorGetInputOrDebugPos;
builder()->CallRuntime(get_generator_input, generator_object_);
}
if (expr->on_abrupt_resume() != Suspend::kNoControl) {
void BytecodeGenerator::BuildAbruptResume(Suspend* expr) {
RegisterAllocationScope register_scope(this);
Register input = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(input);
builder()->CallRuntime(Runtime::kInlineGeneratorGetResumeMode,
......@@ -2679,15 +2684,256 @@ void BytecodeGenerator::BuildGeneratorResume(
builder()->Bind(jump_table, JSGeneratorObject::kNext);
builder()->LoadAccumulatorWithRegister(input);
}
}
}
void BytecodeGenerator::VisitSuspend(Suspend* expr) {
RegisterList registers(0, register_allocator()->next_register_index());
BuildGeneratorSuspend(expr, registers);
{
RegisterAllocationScope scope(this);
builder()->SetExpressionPosition(expr);
Register value = VisitForRegisterValue(expr->expression());
BuildGeneratorSuspend(expr, value, registers);
}
builder()->Bind(generator_jump_table_, static_cast<int>(expr->suspend_id()));
// Upon resume, we continue here.
BuildGeneratorResume(expr, registers);
if (expr->on_abrupt_resume() != Suspend::kNoControl) BuildAbruptResume(expr);
}
// Desugaring of (yield* iterable)
//
// do {
// const kNext = 0;
// const kReturn = 1;
// const kThrow = 2;
//
// let output; // uninitialized
//
// let iterator = GetIterator(iterable);
// let input = undefined;
// let resumeMode = kNext;
//
// while (true) {
// // From the generator to the iterator:
// // Forward input according to resumeMode and obtain output.
// switch (resumeMode) {
// case kNext:
// output = iterator.next(input);
// break;
// case kReturn:
// let iteratorReturn = iterator.return;
// if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
// output = %_Call(iteratorReturn, iterator, input);
// break;
// case kThrow:
// let iteratorThrow = iterator.throw;
// if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
// let iteratorReturn = iterator.return;
// if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
// output = %_Call(iteratorReturn, iterator);
// if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
// }
// throw MakeTypeError(kThrowMethodMissing);
// }
// output = %_Call(iteratorThrow, iterator, input);
// break;
// }
// 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.
// input = Suspend(output);
// resumeMode = %GeneratorGetResumeMode();
// }
//
// if (resumeMode === kReturn) {
// return output.value;
// }
// output.value
// }
void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
// TODO(tebbi): Also desugar async generator yield* in the BytecodeGenerator.
DCHECK(!expr->is_async_generator());
Register output = register_allocator()->NewRegister();
Register resume_mode = register_allocator()->NewRegister();
{
RegisterAllocationScope register_scope(this);
RegisterList iterator_and_input = register_allocator()->NewRegisterList(2);
Register iterator = iterator_and_input[0];
BuildGetIterator(expr->expression(), IteratorType::kNormal,
expr->load_iterable_iterator_slot(),
expr->call_iterable_iterator_slot(),
FeedbackSlot::Invalid(), FeedbackSlot::Invalid());
builder()->StoreAccumulatorInRegister(iterator);
Register input = iterator_and_input[1];
builder()->LoadUndefined().StoreAccumulatorInRegister(input);
builder()
->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
.StoreAccumulatorInRegister(resume_mode);
{
LoopBuilder loop(builder());
VisitIterationHeader(expr->suspend_id(), 1, &loop);
{
BytecodeLabels after_switch(zone());
BytecodeJumpTable* switch_jump_table =
builder()->AllocateJumpTable(2, 1);
builder()
->LoadAccumulatorWithRegister(resume_mode)
.SwitchOnSmiNoFeedback(switch_jump_table);
// Fallthrough to default case.
// TODO(tebbi): Add debug code to check that {resume_mode} really is
// {JSGeneratorObject::kNext} in this case.
STATIC_ASSERT(JSGeneratorObject::kNext == 0);
{
RegisterAllocationScope register_scope(this);
// output = iterator.next(input);
Register iterator_next = register_allocator()->NewRegister();
builder()
->LoadNamedProperty(
iterator, ast_string_constants()->next_string(),
feedback_index(expr->load_iterator_next_slot()))
.StoreAccumulatorInRegister(iterator_next)
.CallProperty(iterator_next, iterator_and_input,
feedback_index(expr->call_iterator_next_slot()))
.Jump(after_switch.New());
}
STATIC_ASSERT(JSGeneratorObject::kReturn == 1);
builder()->Bind(switch_jump_table, JSGeneratorObject::kReturn);
{
RegisterAllocationScope register_scope(this);
BytecodeLabels return_input(zone());
// Trigger return from within the inner iterator.
Register iterator_return = register_allocator()->NewRegister();
builder()
->LoadNamedProperty(
iterator, ast_string_constants()->return_string(),
feedback_index(expr->load_iterator_return_slot()))
.JumpIfUndefined(return_input.New())
.JumpIfNull(return_input.New())
.StoreAccumulatorInRegister(iterator_return)
.CallProperty(iterator_return, iterator_and_input,
feedback_index(expr->call_iterator_return_slot1()))
.Jump(after_switch.New());
return_input.Bind(builder());
{
builder()->LoadAccumulatorWithRegister(input);
execution_control()->ReturnAccumulator();
}
}
STATIC_ASSERT(JSGeneratorObject::kThrow == 2);
builder()->Bind(switch_jump_table, JSGeneratorObject::kThrow);
{
BytecodeLabels iterator_throw_is_undefined(zone());
{
RegisterAllocationScope register_scope(this);
// If the inner iterator has a throw method, use it to trigger an
// exception inside.
Register iterator_throw = register_allocator()->NewRegister();
builder()
->LoadNamedProperty(
iterator, ast_string_constants()->throw_string(),
feedback_index(expr->load_iterator_throw_slot()))
.JumpIfUndefined(iterator_throw_is_undefined.New())
.JumpIfNull(iterator_throw_is_undefined.New())
.StoreAccumulatorInRegister(iterator_throw);
builder()
->CallProperty(iterator_throw, iterator_and_input,
feedback_index(expr->call_iterator_throw_slot()))
.Jump(after_switch.New());
}
iterator_throw_is_undefined.Bind(builder());
{
RegisterAllocationScope register_scope(this);
BytecodeLabels throw_throw_method_missing(zone());
Register iterator_return = register_allocator()->NewRegister();
// If iterator.throw does not exist, try to use iterator.return to
// inform the iterator that it should stop.
builder()
->LoadNamedProperty(
iterator, ast_string_constants()->return_string(),
feedback_index(expr->load_iterator_return_slot()))
.StoreAccumulatorInRegister(iterator_return);
builder()
->JumpIfUndefined(throw_throw_method_missing.New())
.JumpIfNull(throw_throw_method_missing.New())
.CallProperty(
iterator_return, RegisterList(iterator),
feedback_index(expr->call_iterator_return_slot2()))
.JumpIfJSReceiver(throw_throw_method_missing.New())
.CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output);
throw_throw_method_missing.Bind(builder());
builder()->CallRuntime(Runtime::kThrowThrowMethodMissing);
}
}
after_switch.Bind(builder());
}
// Check that output is an object.
BytecodeLabel check_if_done;
builder()
->StoreAccumulatorInRegister(output)
.JumpIfJSReceiver(&check_if_done)
.CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output);
builder()->Bind(&check_if_done);
// Break once output.done is true.
builder()->LoadNamedProperty(
output, ast_string_constants()->done_string(),
feedback_index(expr->load_output_done_slot()));
loop.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
// Suspend the current generator.
RegisterList registers(0, register_allocator()->next_register_index());
BuildGeneratorSuspend(expr, output, registers);
builder()->Bind(generator_jump_table_,
static_cast<int>(expr->suspend_id()));
// Upon resume, we continue here.
BuildGeneratorResume(expr, registers);
builder()->StoreAccumulatorInRegister(input);
builder()
->CallRuntime(Runtime::kInlineGeneratorGetResumeMode,
generator_object_)
.StoreAccumulatorInRegister(resume_mode);
loop.BindContinueTarget();
loop.JumpToHeader(loop_depth_);
}
}
// Decide if we trigger a return or if the yield* expression should just
// produce a value.
BytecodeLabel completion_is_output_value;
Register output_value = register_allocator()->NewRegister();
builder()
->LoadNamedProperty(output, ast_string_constants()->value_string(),
feedback_index(expr->load_output_value_slot()))
.StoreAccumulatorInRegister(output_value)
.LoadLiteral(Smi::FromInt(JSGeneratorObject::kReturn))
.CompareOperation(Token::EQ_STRICT, resume_mode)
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &completion_is_output_value)
.LoadAccumulatorWithRegister(output_value);
execution_control()->ReturnAccumulator();
builder()->Bind(&completion_is_output_value);
builder()->LoadAccumulatorWithRegister(output_value);
}
void BytecodeGenerator::VisitThrow(Throw* expr) {
......@@ -3438,21 +3684,19 @@ void BytecodeGenerator::VisitImportCallExpression(ImportCallExpression* expr) {
.CallRuntime(Runtime::kDynamicImportCall, args);
}
void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
builder()->SetExpressionPosition(expr);
FeedbackSlot load_slot = expr->IteratorPropertyFeedbackSlot();
FeedbackSlot call_slot = expr->IteratorCallFeedbackSlot();
void BytecodeGenerator::BuildGetIterator(Expression* iterable,
IteratorType hint,
FeedbackSlot load_slot,
FeedbackSlot call_slot,
FeedbackSlot async_load_slot,
FeedbackSlot async_call_slot) {
RegisterList args = register_allocator()->NewRegisterList(1);
Register method = register_allocator()->NewRegister();
Register obj = args[0];
VisitForAccumulatorValue(expr->iterable());
if (expr->hint() == IteratorType::kAsync) {
FeedbackSlot async_load_slot = expr->AsyncIteratorPropertyFeedbackSlot();
FeedbackSlot async_call_slot = expr->AsyncIteratorCallFeedbackSlot();
VisitForAccumulatorValue(iterable);
if (hint == IteratorType::kAsync) {
// Set method to GetMethod(obj, @@asyncIterator)
builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty(
obj, feedback_index(async_load_slot));
......@@ -3506,6 +3750,15 @@ void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
}
}
void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
builder()->SetExpressionPosition(expr);
BuildGetIterator(expr->iterable(), expr->hint(),
expr->IteratorPropertyFeedbackSlot(),
expr->IteratorCallFeedbackSlot(),
expr->AsyncIteratorPropertyFeedbackSlot(),
expr->AsyncIteratorCallFeedbackSlot());
}
void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
builder()->LoadAccumulatorWithRegister(Register::function_closure());
}
......
......@@ -137,8 +137,14 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildNewLocalWithContext(Scope* scope);
void BuildGeneratorPrologue();
void BuildGeneratorSuspend(Suspend* expr, RegisterList registers_to_save);
void BuildGeneratorSuspend(Suspend* expr, Register value,
RegisterList registers_to_save);
void BuildGeneratorResume(Suspend* expr, RegisterList registers_to_restore);
void BuildAbruptResume(Suspend* expr);
void BuildGetIterator(Expression* iterable, IteratorType hint,
FeedbackSlot load_slot, FeedbackSlot call_slot,
FeedbackSlot async_load_slot,
FeedbackSlot async_call_slot);
void VisitArgumentsObject(Variable* variable);
void VisitRestArgumentsArray(Variable* rest);
......@@ -175,6 +181,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
// Visit the header/body of a loop iteration.
void VisitIterationHeader(IterationStatement* stmt,
LoopBuilder* loop_builder);
void VisitIterationHeader(int first_suspend_id, int suspend_count,
LoopBuilder* loop_builder);
void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder);
// Visit a statement and switch scopes, the context is in the accumulator.
......
......@@ -103,6 +103,7 @@ class RegisterList {
RegisterList() : first_reg_index_(Register().index()), register_count_(0) {}
RegisterList(int first_reg_index, int register_count)
: first_reg_index_(first_reg_index), register_count_(register_count) {}
explicit RegisterList(Register r) : RegisterList(r.index(), 1) {}
// Increases/decreases the size of the register list by one.
void IncrementRegisterCount() { register_count_++; }
......
......@@ -4315,6 +4315,11 @@ Expression* Parser::RewriteYieldStar(Expression* iterable, int pos) {
IteratorType type =
is_async_generator() ? IteratorType::kAsync : IteratorType::kNormal;
if (type == IteratorType::kNormal) {
return factory()->NewYieldStar(iterable, pos,
SuspendFlags::kGeneratorYieldStar);
}
// Forward definition for break/continue statements.
WhileStatement* loop = factory()->NewWhileStatement(nullptr, nopos);
......@@ -4506,7 +4511,7 @@ Expression* Parser::RewriteYieldStar(Expression* iterable, int pos) {
{
Expression* output_proxy = factory()->NewVariableProxy(var_output);
Suspend* yield = BuildSuspend(output_proxy, nopos, Suspend::kNoControl,
SuspendFlags::kYieldStar);
SuspendFlags::kYield);
yield_output = factory()->NewExpressionStatement(yield, nopos);
}
......
......@@ -768,6 +768,7 @@ NOT_A_PATTERN(VariableDeclaration)
NOT_A_PATTERN(WhileStatement)
NOT_A_PATTERN(WithStatement)
NOT_A_PATTERN(Suspend)
NOT_A_PATTERN(YieldStar)
#undef NOT_A_PATTERN
} // namespace internal
......
......@@ -29,7 +29,6 @@ RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_ExportFromRuntime) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......@@ -42,7 +41,6 @@ RUNTIME_FUNCTION(Runtime_ExportFromRuntime) {
return *container;
}
RUNTIME_FUNCTION(Runtime_InstallToContext) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......@@ -67,21 +65,18 @@ RUNTIME_FUNCTION(Runtime_InstallToContext) {
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_Throw) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
return isolate->Throw(args[0]);
}
RUNTIME_FUNCTION(Runtime_ReThrow) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
return isolate->ReThrow(args[0]);
}
RUNTIME_FUNCTION(Runtime_ThrowStackOverflow) {
SealHandleScope shs(isolate);
DCHECK_LE(0, args.length());
......@@ -166,14 +161,12 @@ RUNTIME_FUNCTION(Runtime_UnwindAndFindExceptionHandler) {
return isolate->UnwindAndFindHandler();
}
RUNTIME_FUNCTION(Runtime_PromoteScheduledException) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
return isolate->PromoteScheduledException();
}
RUNTIME_FUNCTION(Runtime_ThrowReferenceError) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......@@ -182,7 +175,6 @@ RUNTIME_FUNCTION(Runtime_ThrowReferenceError) {
isolate, NewReferenceError(MessageTemplate::kNotDefined, name));
}
RUNTIME_FUNCTION(Runtime_NewTypeError) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
......@@ -193,7 +185,6 @@ RUNTIME_FUNCTION(Runtime_NewTypeError) {
return *isolate->factory()->NewTypeError(message_template, arg0);
}
RUNTIME_FUNCTION(Runtime_NewReferenceError) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
......@@ -204,7 +195,6 @@ RUNTIME_FUNCTION(Runtime_NewReferenceError) {
return *isolate->factory()->NewReferenceError(message_template, arg0);
}
RUNTIME_FUNCTION(Runtime_NewSyntaxError) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
......@@ -260,6 +250,13 @@ RUNTIME_FUNCTION(Runtime_ThrowIteratorResultNotAnObject) {
NewTypeError(MessageTemplate::kIteratorResultNotAnObject, value));
}
RUNTIME_FUNCTION(Runtime_ThrowThrowMethodMissing) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kThrowMethodMissing));
}
RUNTIME_FUNCTION(Runtime_ThrowSymbolIteratorInvalid) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
......@@ -316,14 +313,12 @@ RUNTIME_FUNCTION(Runtime_StackGuard) {
return isolate->stack_guard()->HandleInterrupts();
}
RUNTIME_FUNCTION(Runtime_Interrupt) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
return isolate->stack_guard()->HandleInterrupts();
}
RUNTIME_FUNCTION(Runtime_AllocateInNewSpace) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......@@ -334,7 +329,6 @@ RUNTIME_FUNCTION(Runtime_AllocateInNewSpace) {
return *isolate->factory()->NewFillerObject(size, false, NEW_SPACE);
}
RUNTIME_FUNCTION(Runtime_AllocateInTargetSpace) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
......@@ -370,12 +364,10 @@ RUNTIME_FUNCTION(Runtime_AllocateSeqTwoByteString) {
return *result;
}
RUNTIME_FUNCTION(Runtime_IS_VAR) {
UNREACHABLE(); // implemented as macro in the parser
}
namespace {
bool ComputeLocation(Isolate* isolate, MessageLocation* target) {
......@@ -400,7 +392,6 @@ bool ComputeLocation(Isolate* isolate, MessageLocation* target) {
return false;
}
Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object) {
MessageLocation location;
if (ComputeLocation(isolate, &location)) {
......@@ -475,7 +466,6 @@ RUNTIME_FUNCTION(Runtime_CreateListFromArrayLike) {
isolate, object, ElementTypes::kAll));
}
RUNTIME_FUNCTION(Runtime_IncrementUseCounter) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -333,6 +333,7 @@ namespace internal {
F(ThrowInvalidStringLength, 0, 1) \
F(ThrowInvalidTypedArrayAlignment, 2, 1) \
F(ThrowIteratorResultNotAnObject, 1, 1) \
F(ThrowThrowMethodMissing, 0, 1) \
F(ThrowSymbolIteratorInvalid, 0, 1) \
F(ThrowNonCallableInInstanceOfCheck, 0, 1) \
F(ThrowNonObjectInInstanceOfCheck, 0, 1) \
......
......@@ -357,214 +357,138 @@ snippet: "
function* f() { yield* g() }
f();
"
frame size: 15
frame size: 10
parameter count: 1
bytecode array length: 476
bytecode array length: 293
bytecodes: [
B(Mov), R(new_target), R(9),
B(Mov), R(new_target), R(1),
B(Ldar), R(new_target),
B(JumpIfUndefined), U8(25),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetContext), R(9), U8(1),
B(PushContext), R(11),
B(RestoreGeneratorState), R(9),
B(Star), R(10),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetContext), R(1), U8(1),
B(PushContext), R(3),
B(RestoreGeneratorState), R(1),
B(Star), R(2),
B(SwitchOnSmiNoFeedback), U8(0), U8(2), I8(0),
B(LdaSmi), I8(81),
B(Star), R(11),
B(CallRuntime), U16(Runtime::kAbort), R(11), U8(1),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kAbort), R(3), U8(1),
B(LdaSmi), I8(-2),
B(Star), R(10),
B(Mov), R(closure), R(11),
B(Mov), R(this), R(12),
B(InvokeIntrinsic), U8(Runtime::k_CreateJSGeneratorObject), R(11), U8(2),
B(Star), R(2),
B(Mov), R(closure), R(3),
B(Mov), R(this), R(4),
B(InvokeIntrinsic), U8(Runtime::k_CreateJSGeneratorObject), R(3), U8(2),
B(Star), R(0),
/* 38 E> */ B(StackCheck),
B(LdaZero),
B(Mov), R(0), R(9),
B(Mov), R(0), R(11),
/* 38 E> */ B(SuspendGenerator), R(9), R(0), U8(11), U8(0),
B(Ldar), R(11),
B(Mov), R(0), R(1),
B(Mov), R(0), R(3),
/* 38 E> */ B(SuspendGenerator), R(1), R(0), U8(3), U8(0),
B(Ldar), R(3),
/* 54 S> */ B(Return),
B(RestoreGeneratorRegisters), R(9), R(0), U8(11),
B(RestoreGeneratorRegisters), R(1), R(0), U8(3),
B(LdaSmi), I8(-2),
B(Star), R(10),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(9), U8(1),
B(Star), R(11),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(9), U8(1),
B(Star), R(2),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(1), U8(1),
B(Star), R(3),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(1), U8(1),
B(SwitchOnSmiNoFeedback), U8(2), U8(2), I8(0),
B(Ldar), R(11),
B(Ldar), R(3),
/* 38 E> */ B(Throw),
B(Ldar), R(11),
B(Ldar), R(3),
/* 54 S> */ B(Return),
/* 43 S> */ B(LdaUndefined),
B(Star), R(1),
B(LdaZero),
B(Star), R(2),
B(LdaUndefined),
B(Star), R(3),
B(LdaGlobal), U8(4), U8(5),
B(Star), R(13),
/* 50 E> */ B(CallUndefinedReceiver0), R(13), U8(3),
B(Star), R(11),
B(LdaNamedProperty), R(11), U8(5), U8(7),
B(Star), R(12),
B(CallProperty0), R(12), R(11), U8(9),
/* 43 S> */ B(LdaGlobal), U8(4), U8(5),
B(Star), R(9),
/* 50 E> */ B(CallUndefinedReceiver0), R(9), U8(3),
B(Star), R(7),
B(LdaNamedProperty), R(7), U8(5), U8(7),
B(Star), R(8),
B(CallProperty0), R(8), R(7), U8(19),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star), R(5),
B(LdaUndefined),
B(Star), R(6),
B(LdaZero),
B(Star), R(4),
B(Ldar), R(10),
B(Ldar), R(2),
B(SwitchOnSmiNoFeedback), U8(6), U8(1), I8(1),
B(LdaSmi), I8(-2),
B(TestEqualStrictNoFeedback), R(10),
B(TestEqualStrictNoFeedback), R(2),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(81),
B(Star), R(11),
B(CallRuntime), U16(Runtime::kAbort), R(11), U8(1),
B(StackCheck),
B(LdaZero),
B(TestEqualStrict), R(2), U8(15),
B(Mov), R(2), R(11),
B(JumpIfTrue), U8(18),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(11), U8(19),
B(JumpIfTrue), U8(39),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(11), U8(28),
B(JumpIfTrue), U8(74),
B(Jump), U8(232),
B(LdaNamedProperty), R(4), U8(7), U8(13),
B(Star), R(12),
B(CallProperty1), R(12), R(4), R(1), U8(11),
B(Star), R(3),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(3), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(3), U8(1),
B(Jump), U8(204),
B(LdaNamedProperty), R(4), U8(8), U8(16),
B(Star), R(3),
B(TestUndetectable),
B(JumpIfFalse), U8(5),
B(Ldar), R(1),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kAbort), R(9), U8(1),
B(Ldar), R(4),
B(SwitchOnSmiNoFeedback), U8(7), U8(2), I8(1),
B(LdaNamedProperty), R(5), U8(9), U8(11),
B(Star), R(9),
B(CallProperty1), R(9), R(5), R(6), U8(25),
B(Jump), U8(65),
B(LdaNamedProperty), R(5), U8(10), U8(9),
B(JumpIfUndefined), U8(13),
B(JumpIfNull), U8(11),
B(Star), R(9),
B(CallProperty1), R(9), R(5), R(6), U8(21),
B(Jump), U8(48),
B(Ldar), R(6),
/* 54 S> */ B(Return),
B(Mov), R(3), R(12),
B(Mov), R(4), R(13),
B(Mov), R(1), R(14),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(12), U8(3),
B(Star), R(3),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(3), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(LdaNamedProperty), R(5), U8(11), U8(13),
B(JumpIfUndefined), U8(13),
B(JumpIfNull), U8(11),
B(Star), R(9),
B(CallProperty1), R(9), R(5), R(6), U8(27),
B(Jump), U8(28),
B(LdaNamedProperty), R(5), U8(10), U8(9),
B(Star), R(9),
B(JumpIfUndefined), U8(15),
B(JumpIfNull), U8(13),
B(CallProperty0), R(9), R(5), U8(23),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(3), U8(1),
B(Jump), U8(162),
B(LdaNamedProperty), R(4), U8(9), U8(20),
B(Star), R(5),
B(TestUndetectable),
B(JumpIfFalse), U8(123),
B(LdaNamedProperty), R(4), U8(8), U8(23),
B(Star), R(6),
B(TestUndetectable),
B(JumpIfFalse), U8(4),
B(Jump), U8(96),
B(LdaZero),
B(Star), R(12),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(12), U8(26),
B(JumpIfFalse), U8(61),
B(Ldar), R(6),
B(TestTypeOf), U8(5),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(131),
B(Star), R(12),
B(LdaConstant), U8(10),
B(Star), R(13),
B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2),
B(Throw),
B(Mov), R(context), R(12),
B(Mov), R(6), R(13),
B(Mov), R(4), R(14),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(13), U8(2),
B(Jump), U8(20),
B(Star), R(13),
B(Ldar), R(closure),
B(CreateCatchContext), R(13), U8(11), U8(12),
B(Star), R(12),
B(LdaTheHole),
B(SetPendingMessage),
B(Ldar), R(12),
B(PushContext), R(13),
B(PopContext), R(13),
B(Jump), U8(27),
B(Mov), R(6), R(12),
B(Mov), R(4), R(13),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(12), U8(2),
B(Star), R(7),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(7), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(7), U8(1),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(12),
B(LdaConstant), U8(10),
B(Star), R(13),
B(CallRuntime), U16(Runtime::kNewTypeError), R(12), U8(2),
B(Throw),
B(Mov), R(5), R(12),
B(Mov), R(4), R(13),
B(Mov), R(1), R(14),
B(InvokeIntrinsic), U8(Runtime::k_Call), R(12), U8(3),
B(CallRuntime), U16(Runtime::kThrowThrowMethodMissing), R(0), U8(0),
B(Star), R(3),
B(InvokeIntrinsic), U8(Runtime::k_IsJSReceiver), R(3), U8(1),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(7),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(3), U8(1),
B(Jump), U8(2),
B(LdaNamedProperty), R(3), U8(13), U8(29),
B(JumpIfToBooleanFalse), U8(4),
B(Jump), U8(45),
B(LdaNamedProperty), R(3), U8(12), U8(15),
B(JumpIfToBooleanTrue), U8(35),
B(LdaSmi), I8(1),
B(Mov), R(3), R(11),
B(SuspendGenerator), R(9), R(0), U8(11), U8(1),
B(Ldar), R(11),
B(SuspendGenerator), R(1), R(0), U8(9), U8(1),
B(Ldar), R(3),
/* 54 S> */ B(Return),
B(RestoreGeneratorRegisters), R(9), R(0), U8(11),
B(RestoreGeneratorRegisters), R(1), R(0), U8(9),
B(LdaSmi), I8(-2),
B(Star), R(10),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(9), 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(323), I16(0),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetInputOrDebugPos), R(1), U8(1),
B(Star), R(6),
B(InvokeIntrinsic), U8(Runtime::k_GeneratorGetResumeMode), R(1), U8(1),
B(Star), R(4),
B(JumpLoop), U8(148), I8(0),
B(LdaNamedProperty), R(3), U8(13), U8(17),
B(Star), R(5),
B(LdaSmi), I8(1),
B(TestEqualStrict), R(2), U8(31),
B(JumpIfFalse), U8(7),
B(LdaNamedProperty), R(3), U8(14), U8(32),
B(TestEqualStrictNoFeedback), R(4),
B(JumpIfFalse), U8(5),
B(Ldar), R(5),
/* 54 S> */ B(Return),
B(LdaNamedProperty), R(3), U8(14), U8(34),
B(Star), R(8),
B(LdaUndefined),
/* 54 S> */ B(Return),
]
constant pool: [
Smi [45],
Smi [111],
Smi [108],
Smi [10],
Smi [7],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["g"],
SYMBOL_TYPE,
Smi [296],
Smi [126],
Smi [17],
Smi [37],
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,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
]
handlers: [
[302, 312, 314],
]
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