| Index: src/interpreter/bytecode-generator.cc
|
| diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
|
| index 7257fd413422de3b43b4b146e3aa319b1e7b4264..5bca63d1fe79e2eb8104408908235e9489cfbfa7 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,84 @@ 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() { generator_->set_control_scope(outer()); }
|
| +
|
| + 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;
|
| + do {
|
| + if (current->Execute(command, statement)) return;
|
| + current = current->outer();
|
| + } while (current != nullptr);
|
| + UNREACHABLE();
|
| +}
|
| +
|
| +
|
| BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
|
| - : builder_(isolate, zone) {
|
| + : builder_(isolate, zone),
|
| + info_(nullptr),
|
| + scope_(nullptr),
|
| + control_scope_(nullptr) {
|
| InitializeAstVisitor(isolate, zone);
|
| }
|
|
|
| @@ -31,8 +108,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 +129,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 +142,7 @@ void BytecodeGenerator::VisitBlock(Block* node) {
|
| VisitStatements(node->statements());
|
| }
|
| }
|
| - builder().LeaveBlock();
|
| + builder()->LeaveBlock();
|
| }
|
|
|
|
|
| @@ -114,20 +191,24 @@ 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);
|
| + BytecodeLabel else_label, end_label;
|
|
|
| - Visit(stmt->else_statement());
|
| - builder().Bind(&else_end);
|
| + Visit(stmt->condition());
|
| + builder()->CastAccumulatorToBoolean();
|
| + builder()->JumpIfFalse(&else_label);
|
| + Visit(stmt->then_statement());
|
| + if (stmt->HasElseStatement()) {
|
| + builder()->Jump(&end_label);
|
| + builder()->Bind(&else_label);
|
| + Visit(stmt->else_statement());
|
| + } else {
|
| + builder()->Bind(&else_label);
|
| + }
|
| + builder()->Bind(&end_label);
|
| }
|
|
|
|
|
| @@ -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,69 @@ void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); }
|
|
|
|
|
| void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
| - UNIMPLEMENTED();
|
| + LoopBuilder loop_builder(builder());
|
| + ControlScopeForIteration control_scope(this, stmt, &loop_builder);
|
| +
|
| + BytecodeLabel body_label, condition_label, done_label;
|
| + builder()->Bind(&body_label);
|
| + Visit(stmt->body());
|
| + builder()->Bind(&condition_label);
|
| + Visit(stmt->cond());
|
| + builder()->JumpIfTrue(&body_label);
|
| + builder()->Bind(&done_label);
|
| +
|
| + loop_builder.SetBreakTarget(done_label);
|
| + loop_builder.SetContinueTarget(condition_label);
|
| }
|
|
|
|
|
| void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
|
| - UNIMPLEMENTED();
|
| + LoopBuilder loop_builder(builder());
|
| + ControlScopeForIteration control_scope(this, stmt, &loop_builder);
|
| +
|
| + BytecodeLabel body_label, condition_label, done_label;
|
| + builder()->Jump(&condition_label);
|
| + builder()->Bind(&body_label);
|
| + Visit(stmt->body());
|
| + builder()->Bind(&condition_label);
|
| + Visit(stmt->cond());
|
| + builder()->JumpIfTrue(&body_label);
|
| + builder()->Bind(&done_label);
|
| +
|
| + loop_builder.SetBreakTarget(done_label);
|
| + loop_builder.SetContinueTarget(condition_label);
|
| }
|
|
|
|
|
| void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
|
| - UNIMPLEMENTED();
|
| + LoopBuilder loop_builder(builder());
|
| + ControlScopeForIteration control_scope(this, stmt, &loop_builder);
|
| +
|
| + if (stmt->init() != nullptr) {
|
| + Visit(stmt->init());
|
| + }
|
| +
|
| + BytecodeLabel body_label, condition_label, next_label, done_label;
|
| + if (stmt->cond() != nullptr) {
|
| + builder()->Jump(&condition_label);
|
| + }
|
| + builder()->Bind(&body_label);
|
| + Visit(stmt->body());
|
| + builder()->Bind(&next_label);
|
| + if (stmt->next() != nullptr) {
|
| + Visit(stmt->next());
|
| + }
|
| + if (stmt->cond()) {
|
| + builder()->Bind(&condition_label);
|
| + Visit(stmt->cond());
|
| + builder()->JumpIfTrue(&body_label);
|
| + } else {
|
| + builder()->Jump(&body_label);
|
| + }
|
| + builder()->Bind(&done_label);
|
| +
|
| + loop_builder.SetBreakTarget(done_label);
|
| + loop_builder.SetContinueTarget(next_label);
|
| }
|
|
|
|
|
| @@ -228,19 +361,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 +402,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 +418,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 +447,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 +479,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 +510,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 +530,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 +552,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 +581,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 +629,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 +668,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);
|
| }
|
|
|
|
|
|
|