Chromium Code Reviews| Index: src/interpreter/bytecode-generator.cc |
| diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
| index 7257fd413422de3b43b4b146e3aa319b1e7b4264..79c30460e7d021d5c95078b4923bfe6275c97a12 100644 |
| --- a/src/interpreter/bytecode-generator.cc |
| +++ b/src/interpreter/bytecode-generator.cc |
| @@ -7,6 +7,7 @@ |
| #include <stack> |
| #include "src/compiler.h" |
| +#include "src/interpreter/control-flow-builders.h" |
| #include "src/objects.h" |
| #include "src/scopes.h" |
| #include "src/token.h" |
| @@ -15,8 +16,83 @@ namespace v8 { |
| namespace internal { |
| namespace interpreter { |
| + |
| +// Scoped class for tracking control statements entered by the |
| +// visitor. The pattern derives AstGraphBuilder::ControlScope. |
| +class BytecodeGenerator::ControlScope BASE_EMBEDDED { |
| + public: |
| + explicit ControlScope(BytecodeGenerator* generator) |
| + : generator_(generator), outer_(generator->control_scope()) { |
| + generator_->set_control_scope(this); |
| + } |
| + virtual ~ControlScope() {} |
|
Michael Starzinger
2015/09/30 13:27:36
Scope popping seems to be missing from destructor.
oth
2015/09/30 15:54:46
Done.
|
| + |
| + void Break(Statement* stmt) { PerformCommand(CMD_BREAK, stmt); } |
| + void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); } |
| + |
| + protected: |
| + enum Command { CMD_BREAK, CMD_CONTINUE }; |
| + void PerformCommand(Command command, Statement* statement); |
| + virtual bool Execute(Command command, Statement* statement) = 0; |
| + |
| + BytecodeGenerator* generator() const { return generator_; } |
| + ControlScope* outer() const { return outer_; } |
| + |
| + private: |
| + BytecodeGenerator* generator_; |
| + ControlScope* outer_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ControlScope); |
| +}; |
| + |
| + |
| +// Scoped class for enabling 'break' and 'continue' in iteration |
| +// constructs, e.g. do...while, while..., for... |
| +class BytecodeGenerator::ControlScopeForIteration |
| + : public BytecodeGenerator::ControlScope { |
| + public: |
| + ControlScopeForIteration(BytecodeGenerator* generator, |
| + IterationStatement* statement, |
| + LoopBuilder* loop_builder) |
| + : ControlScope(generator), |
| + statement_(statement), |
| + loop_builder_(loop_builder) {} |
| + |
| + protected: |
| + virtual bool Execute(Command command, Statement* statement) { |
| + if (statement != statement_) return false; |
| + switch (command) { |
| + case CMD_BREAK: |
| + loop_builder_->Break(); |
| + return true; |
| + case CMD_CONTINUE: |
| + loop_builder_->Continue(); |
| + return true; |
| + } |
| + return false; |
| + } |
| + |
| + private: |
| + Statement* statement_; |
| + LoopBuilder* loop_builder_; |
| +}; |
| + |
| + |
| +void BytecodeGenerator::ControlScope::PerformCommand(Command command, |
| + Statement* statement) { |
| + ControlScope* current = this; |
| + while (current != nullptr) { |
| + if (current->Execute(command, statement)) return; |
| + current = current->outer(); |
| + } |
| +} |
| + |
| + |
| BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
| - : builder_(isolate, zone) { |
| + : builder_(isolate, zone), |
| + info_(nullptr), |
| + scope_(nullptr), |
| + control_scope_(nullptr) { |
| InitializeAstVisitor(isolate, zone); |
| } |
| @@ -31,8 +107,8 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
| // This a temporary guard (oth). |
| DCHECK(scope()->is_function_scope()); |
| - builder().set_parameter_count(info->num_parameters_including_this()); |
| - builder().set_locals_count(scope()->num_stack_slots()); |
| + builder()->set_parameter_count(info->num_parameters_including_this()); |
| + builder()->set_locals_count(scope()->num_stack_slots()); |
| // Visit implicit declaration of the function name. |
| if (scope()->is_function_scope() && scope()->function() != NULL) { |
| @@ -52,7 +128,7 @@ Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
| void BytecodeGenerator::VisitBlock(Block* node) { |
| - builder().EnterBlock(); |
| + builder()->EnterBlock(); |
| if (node->scope() == NULL) { |
| // Visit statements in the same scope, no declarations. |
| VisitStatements(node->statements()); |
| @@ -65,7 +141,7 @@ void BytecodeGenerator::VisitBlock(Block* node) { |
| VisitStatements(node->statements()); |
| } |
| } |
| - builder().LeaveBlock(); |
| + builder()->LeaveBlock(); |
| } |
| @@ -114,20 +190,25 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { |
| void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { |
| - BytecodeLabel else_start, else_end; |
| // TODO(oth): Spot easy cases where there code would not need to |
| // emit the then block or the else block, e.g. condition is |
| // obviously true/1/false/0. |
| Visit(stmt->condition()); |
| - builder().CastAccumulatorToBoolean(); |
| - builder().JumpIfFalse(&else_start); |
| - |
| - Visit(stmt->then_statement()); |
| - builder().Jump(&else_end); |
| - builder().Bind(&else_start); |
| - |
| - Visit(stmt->else_statement()); |
| - builder().Bind(&else_end); |
| + builder()->CastAccumulatorToBoolean(); |
| + if (stmt->HasElseStatement()) { |
| + BytecodeLabel else_start, else_end; |
| + builder()->JumpIfFalse(&else_start); |
| + Visit(stmt->then_statement()); |
| + builder()->Jump(&else_end); |
| + builder()->Bind(&else_start); |
| + Visit(stmt->else_statement()); |
| + builder()->Bind(&else_end); |
| + } else { |
| + BytecodeLabel then_end; |
| + builder()->JumpIfFalse(&then_end); |
| + Visit(stmt->then_statement()); |
| + builder()->Bind(&then_end); |
| + } |
| } |
| @@ -138,18 +219,18 @@ void BytecodeGenerator::VisitSloppyBlockFunctionStatement( |
| void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { |
| - UNIMPLEMENTED(); |
| + control_scope()->Continue(stmt->target()); |
| } |
| void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
| - UNIMPLEMENTED(); |
| + control_scope()->Break(stmt->target()); |
| } |
| void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
| Visit(stmt->expression()); |
| - builder().Return(); |
| + builder()->Return(); |
| } |
| @@ -167,17 +248,63 @@ void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); } |
| void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| - UNIMPLEMENTED(); |
| + LoopBuilder loop_builder(builder()); |
| + ControlScopeForIteration(this, stmt, &loop_builder); |
| + |
| + BytecodeLabel body_start; |
| + builder()->Bind(&body_start); |
| + Visit(stmt->body()); |
| + builder()->Bind(loop_builder.continue_label()); |
| + Visit(stmt->cond()); |
| + builder()->JumpIfTrue(&body_start); |
| + builder()->Bind(loop_builder.break_label()); |
| } |
| void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
| - UNIMPLEMENTED(); |
| + LoopBuilder loop_builder(builder()); |
| + ControlScopeForIteration(this, stmt, &loop_builder); |
| + |
| + builder()->Jump(loop_builder.continue_label()); |
| + BytecodeLabel body_start; |
| + builder()->Bind(&body_start); |
| + Visit(stmt->body()); |
| + builder()->Bind(loop_builder.continue_label()); |
| + Visit(stmt->cond()); |
| + builder()->JumpIfTrue(&body_start); |
| + builder()->Bind(loop_builder.break_label()); |
| } |
| void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { |
| - UNIMPLEMENTED(); |
| + LoopBuilder loop_builder(builder()); |
| + ControlScopeForIteration(this, stmt, &loop_builder); |
| + |
| + if (stmt->init() != nullptr) { |
| + Visit(stmt->init()); |
| + } |
| + |
| + BytecodeLabel condition_start; |
| + if (stmt->cond() != nullptr) { |
| + builder()->Jump(&condition_start); |
| + } |
| + |
| + BytecodeLabel body_start; |
| + builder()->Bind(&body_start); |
| + Visit(stmt->body()); |
| + builder()->Bind(loop_builder.continue_label()); |
| + if (stmt->next() != nullptr) { |
| + Visit(stmt->next()); |
| + } |
| + |
| + builder()->Bind(&condition_start); |
| + if (stmt->cond()) { |
| + Visit(stmt->cond()); |
| + builder()->JumpIfTrue(&body_start); |
| + } else { |
| + builder()->Jump(&body_start); |
| + } |
| + builder()->Bind(loop_builder.break_label()); |
| } |
| @@ -228,19 +355,19 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) { UNIMPLEMENTED(); } |
| void BytecodeGenerator::VisitLiteral(Literal* expr) { |
| Handle<Object> value = expr->value(); |
| if (value->IsSmi()) { |
| - builder().LoadLiteral(Smi::cast(*value)); |
| + builder()->LoadLiteral(Smi::cast(*value)); |
| } else if (value->IsUndefined()) { |
| - builder().LoadUndefined(); |
| + builder()->LoadUndefined(); |
| } else if (value->IsTrue()) { |
| - builder().LoadTrue(); |
| + builder()->LoadTrue(); |
| } else if (value->IsFalse()) { |
| - builder().LoadFalse(); |
| + builder()->LoadFalse(); |
| } else if (value->IsNull()) { |
| - builder().LoadNull(); |
| + builder()->LoadNull(); |
| } else if (value->IsTheHole()) { |
| - builder().LoadTheHole(); |
| + builder()->LoadTheHole(); |
| } else { |
| - builder().LoadLiteral(value); |
| + builder()->LoadLiteral(value); |
| } |
| } |
| @@ -269,14 +396,14 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable) { |
| switch (variable->location()) { |
| case VariableLocation::LOCAL: { |
| Register source(variable->index()); |
| - builder().LoadAccumulatorWithRegister(source); |
| + builder()->LoadAccumulatorWithRegister(source); |
| break; |
| } |
| case VariableLocation::PARAMETER: { |
| // The parameter indices are shifted by 1 (receiver is variable |
| // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
| - Register source(builder().Parameter(variable->index() + 1)); |
| - builder().LoadAccumulatorWithRegister(source); |
| + Register source(builder()->Parameter(variable->index() + 1)); |
| + builder()->LoadAccumulatorWithRegister(source); |
| break; |
| } |
| case VariableLocation::GLOBAL: { |
| @@ -285,7 +412,7 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable) { |
| // a generic version of LoadGlobalViaContextStub rather than calling the |
| // runtime. |
| DCHECK(variable->IsStaticGlobalObjectProperty()); |
| - builder().LoadGlobal(variable->index()); |
| + builder()->LoadGlobal(variable->index()); |
| break; |
| } |
| case VariableLocation::UNALLOCATED: |
| @@ -314,17 +441,17 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
| object = temporary_register_scope.NewRegister(); |
| key = temporary_register_scope.NewRegister(); |
| Visit(property->obj()); |
| - builder().StoreAccumulatorInRegister(object); |
| - builder().LoadLiteral(property->key()->AsLiteral()->AsPropertyName()); |
| - builder().StoreAccumulatorInRegister(key); |
| + builder()->StoreAccumulatorInRegister(object); |
| + builder()->LoadLiteral(property->key()->AsLiteral()->AsPropertyName()); |
| + builder()->StoreAccumulatorInRegister(key); |
| break; |
| case KEYED_PROPERTY: |
| object = temporary_register_scope.NewRegister(); |
| key = temporary_register_scope.NewRegister(); |
| Visit(property->obj()); |
| - builder().StoreAccumulatorInRegister(object); |
| + builder()->StoreAccumulatorInRegister(object); |
| Visit(property->key()); |
| - builder().StoreAccumulatorInRegister(key); |
| + builder()->StoreAccumulatorInRegister(key); |
| break; |
| case NAMED_SUPER_PROPERTY: |
| case KEYED_SUPER_PROPERTY: |
| @@ -346,16 +473,16 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
| Variable* variable = expr->target()->AsVariableProxy()->var(); |
| DCHECK(variable->location() == VariableLocation::LOCAL); |
| Register destination(variable->index()); |
| - builder().StoreAccumulatorInRegister(destination); |
| + builder()->StoreAccumulatorInRegister(destination); |
| break; |
| } |
| case NAMED_PROPERTY: |
| - builder().StoreNamedProperty(object, key, feedback_index(slot), |
| - language_mode()); |
| + builder()->StoreNamedProperty(object, key, feedback_index(slot), |
| + language_mode()); |
| break; |
| case KEYED_PROPERTY: |
| - builder().StoreKeyedProperty(object, key, feedback_index(slot), |
| - language_mode()); |
| + builder()->StoreKeyedProperty(object, key, feedback_index(slot), |
| + language_mode()); |
| break; |
| case NAMED_SUPER_PROPERTY: |
| case KEYED_SUPER_PROPERTY: |
| @@ -377,13 +504,13 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { |
| case VARIABLE: |
| UNREACHABLE(); |
| case NAMED_PROPERTY: { |
| - builder().LoadLiteral(expr->key()->AsLiteral()->AsPropertyName()); |
| - builder().LoadNamedProperty(obj, feedback_index(slot), language_mode()); |
| + builder()->LoadLiteral(expr->key()->AsLiteral()->AsPropertyName()); |
| + builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode()); |
| break; |
| } |
| case KEYED_PROPERTY: { |
| Visit(expr->key()); |
| - builder().LoadKeyedProperty(obj, feedback_index(slot), language_mode()); |
| + builder()->LoadKeyedProperty(obj, feedback_index(slot), language_mode()); |
| break; |
| } |
| case NAMED_SUPER_PROPERTY: |
| @@ -397,7 +524,7 @@ void BytecodeGenerator::VisitProperty(Property* expr) { |
| TemporaryRegisterScope temporary_register_scope(&builder_); |
| Register obj = temporary_register_scope.NewRegister(); |
| Visit(expr->obj()); |
| - builder().StoreAccumulatorInRegister(obj); |
| + builder()->StoreAccumulatorInRegister(obj); |
| VisitPropertyLoad(obj, expr); |
| } |
| @@ -419,19 +546,19 @@ void BytecodeGenerator::VisitCall(Call* expr) { |
| UNIMPLEMENTED(); |
| } |
| Visit(property->obj()); |
| - builder().StoreAccumulatorInRegister(receiver); |
| + builder()->StoreAccumulatorInRegister(receiver); |
| // Perform a property load of the callee. |
| VisitPropertyLoad(receiver, property); |
| - builder().StoreAccumulatorInRegister(callee); |
| + builder()->StoreAccumulatorInRegister(callee); |
| break; |
| } |
| case Call::GLOBAL_CALL: { |
| // Receiver is undefined for global calls. |
| - builder().LoadUndefined().StoreAccumulatorInRegister(receiver); |
| + builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); |
| // Load callee as a global variable. |
| VariableProxy* proxy = callee_expr->AsVariableProxy(); |
| VisitVariableLoad(proxy->var()); |
| - builder().StoreAccumulatorInRegister(callee); |
| + builder()->StoreAccumulatorInRegister(callee); |
| break; |
| } |
| case Call::LOOKUP_SLOT_CALL: |
| @@ -448,12 +575,12 @@ void BytecodeGenerator::VisitCall(Call* expr) { |
| Visit(args->at(i)); |
| Register arg = temporary_register_scope.NewRegister(); |
| DCHECK(arg.index() - i == receiver.index() + 1); |
| - builder().StoreAccumulatorInRegister(arg); |
| + builder()->StoreAccumulatorInRegister(arg); |
| } |
| // TODO(rmcilroy): Deal with possible direct eval here? |
| // TODO(rmcilroy): Use CallIC to allow call type feedback. |
| - builder().Call(callee, receiver, args->length()); |
| + builder()->Call(callee, receiver, args->length()); |
| } |
| @@ -496,9 +623,9 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| Register temporary = temporary_register_scope.NewRegister(); |
| Visit(left); |
| - builder().StoreAccumulatorInRegister(temporary); |
| + builder()->StoreAccumulatorInRegister(temporary); |
| Visit(right); |
| - builder().CompareOperation(op, temporary, language_mode()); |
| + builder()->CompareOperation(op, temporary, language_mode()); |
| } |
| @@ -535,9 +662,9 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { |
| Register temporary = temporary_register_scope.NewRegister(); |
| Visit(left); |
| - builder().StoreAccumulatorInRegister(temporary); |
| + builder()->StoreAccumulatorInRegister(temporary); |
| Visit(right); |
| - builder().BinaryOperation(op, temporary); |
| + builder()->BinaryOperation(op, temporary); |
| } |