Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

FPIIM-449

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
new file mode 100644
index 0000000..959e155
--- /dev/null
+++ b/src/interpreter/bytecode-generator.cc
@@ -0,0 +1,2182 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/interpreter/bytecode-generator.h"
+
+#include "src/ast/scopes.h"
+#include "src/compiler.h"
+#include "src/interpreter/bytecode-register-allocator.h"
+#include "src/interpreter/control-flow-builders.h"
+#include "src/objects.h"
+#include "src/parsing/parser.h"
+#include "src/parsing/token.h"
+
+namespace v8 {
+namespace internal {
+namespace interpreter {
+
+
+// Scoped class tracking context objects created by the visitor. Represents
+// mutations of the context chain within the function body, allowing pushing and
+// popping of the current {context_register} during visitation.
+class BytecodeGenerator::ContextScope BASE_EMBEDDED {
+ public:
+  ContextScope(BytecodeGenerator* generator, Scope* scope,
+               bool should_pop_context = true)
+      : generator_(generator),
+        scope_(scope),
+        outer_(generator_->execution_context()),
+        register_(generator_->NextContextRegister()),
+        depth_(0),
+        should_pop_context_(should_pop_context) {
+    if (outer_) {
+      depth_ = outer_->depth_ + 1;
+      generator_->builder()->PushContext(register_);
+    }
+    generator_->set_execution_context(this);
+  }
+
+  ~ContextScope() {
+    if (outer_ && should_pop_context_) {
+      generator_->builder()->PopContext(outer_->reg());
+    }
+    generator_->set_execution_context(outer_);
+  }
+
+  // Returns the depth of the given |scope| for the current execution context.
+  int ContextChainDepth(Scope* scope) {
+    return scope_->ContextChainLength(scope);
+  }
+
+  // Returns the execution context at |depth| in the current context chain if it
+  // is a function local execution context, otherwise returns nullptr.
+  ContextScope* Previous(int depth) {
+    if (depth > depth_) {
+      return nullptr;
+    }
+
+    ContextScope* previous = this;
+    for (int i = depth; i > 0; --i) {
+      previous = previous->outer_;
+    }
+    return previous;
+  }
+
+  Scope* scope() const { return scope_; }
+  Register reg() const { return register_; }
+
+ private:
+  BytecodeGenerator* generator_;
+  Scope* scope_;
+  ContextScope* outer_;
+  Register register_;
+  int depth_;
+  bool should_pop_context_;
+};
+
+
+// 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->execution_control()) {
+    generator_->set_execution_control(this);
+  }
+  virtual ~ControlScope() { generator_->set_execution_control(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 inside blocks and switch blocks.
+class BytecodeGenerator::ControlScopeForBreakable final
+    : public BytecodeGenerator::ControlScope {
+ public:
+  ControlScopeForBreakable(BytecodeGenerator* generator,
+                           BreakableStatement* statement,
+                           BreakableControlFlowBuilder* control_builder)
+      : ControlScope(generator),
+        statement_(statement),
+        control_builder_(control_builder) {}
+
+ protected:
+  virtual bool Execute(Command command, Statement* statement) {
+    if (statement != statement_) return false;
+    switch (command) {
+      case CMD_BREAK:
+        control_builder_->Break();
+        return true;
+      case CMD_CONTINUE:
+        break;
+    }
+    return false;
+  }
+
+ private:
+  Statement* statement_;
+  BreakableControlFlowBuilder* control_builder_;
+};
+
+
+// Scoped class for enabling 'break' and 'continue' in iteration
+// constructs, e.g. do...while, while..., for...
+class BytecodeGenerator::ControlScopeForIteration final
+    : 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();
+}
+
+
+class BytecodeGenerator::RegisterAllocationScope {
+ public:
+  explicit RegisterAllocationScope(BytecodeGenerator* generator)
+      : generator_(generator),
+        outer_(generator->register_allocator()),
+        allocator_(builder()) {
+    generator_->set_register_allocator(this);
+  }
+
+  virtual ~RegisterAllocationScope() {
+    generator_->set_register_allocator(outer_);
+  }
+
+  Register NewRegister() {
+    RegisterAllocationScope* current_scope = generator()->register_allocator();
+    if ((current_scope == this) ||
+        (current_scope->outer() == this &&
+         !current_scope->allocator_.HasConsecutiveAllocations())) {
+      // Regular case - Allocating registers in current or outer context.
+      // VisitForRegisterValue allocates register in outer context.
+      return allocator_.NewRegister();
+    } else {
+      // If it is required to allocate a register other than current or outer
+      // scopes, allocate a new temporary register. It might be expensive to
+      // walk the full context chain and compute the list of consecutive
+      // reservations in the innerscopes.
+      UNIMPLEMENTED();
+      return Register(-1);
+    }
+  }
+
+  void PrepareForConsecutiveAllocations(size_t count) {
+    allocator_.PrepareForConsecutiveAllocations(count);
+  }
+
+  Register NextConsecutiveRegister() {
+    return allocator_.NextConsecutiveRegister();
+  }
+
+  bool RegisterIsAllocatedInThisScope(Register reg) const {
+    return allocator_.RegisterIsAllocatedInThisScope(reg);
+  }
+
+  RegisterAllocationScope* outer() const { return outer_; }
+
+ private:
+  BytecodeGenerator* generator() const { return generator_; }
+  BytecodeArrayBuilder* builder() const { return generator_->builder(); }
+
+  BytecodeGenerator* generator_;
+  RegisterAllocationScope* outer_;
+  BytecodeRegisterAllocator allocator_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope);
+};
+
+
+// Scoped base class for determining where the result of an expression
+// is stored.
+class BytecodeGenerator::ExpressionResultScope {
+ public:
+  ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind)
+      : generator_(generator),
+        kind_(kind),
+        outer_(generator->execution_result()),
+        allocator_(generator),
+        result_identified_(false) {
+    generator_->set_execution_result(this);
+  }
+
+  virtual ~ExpressionResultScope() {
+    generator_->set_execution_result(outer_);
+    DCHECK(result_identified());
+  }
+
+  bool IsEffect() const { return kind_ == Expression::kEffect; }
+  bool IsValue() const { return kind_ == Expression::kValue; }
+
+  virtual void SetResultInAccumulator() = 0;
+  virtual void SetResultInRegister(Register reg) = 0;
+
+ protected:
+  ExpressionResultScope* outer() const { return outer_; }
+  BytecodeArrayBuilder* builder() const { return generator_->builder(); }
+  const RegisterAllocationScope* allocator() const { return &allocator_; }
+
+  void set_result_identified() {
+    DCHECK(!result_identified());
+    result_identified_ = true;
+  }
+
+  bool result_identified() const { return result_identified_; }
+
+ private:
+  BytecodeGenerator* generator_;
+  Expression::Context kind_;
+  ExpressionResultScope* outer_;
+  RegisterAllocationScope allocator_;
+  bool result_identified_;
+
+  DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope);
+};
+
+
+// Scoped class used when the result of the current expression is not
+// expected to produce a result.
+class BytecodeGenerator::EffectResultScope final
+    : public ExpressionResultScope {
+ public:
+  explicit EffectResultScope(BytecodeGenerator* generator)
+      : ExpressionResultScope(generator, Expression::kEffect) {
+    set_result_identified();
+  }
+
+  virtual void SetResultInAccumulator() {}
+  virtual void SetResultInRegister(Register reg) {}
+};
+
+
+// Scoped class used when the result of the current expression to be
+// evaluated should go into the interpreter's accumulator register.
+class BytecodeGenerator::AccumulatorResultScope final
+    : public ExpressionResultScope {
+ public:
+  explicit AccumulatorResultScope(BytecodeGenerator* generator)
+      : ExpressionResultScope(generator, Expression::kValue) {}
+
+  virtual void SetResultInAccumulator() { set_result_identified(); }
+
+  virtual void SetResultInRegister(Register reg) {
+    builder()->LoadAccumulatorWithRegister(reg);
+    set_result_identified();
+  }
+};
+
+
+// Scoped class used when the result of the current expression to be
+// evaluated should go into an interpreter register.
+class BytecodeGenerator::RegisterResultScope final
+    : public ExpressionResultScope {
+ public:
+  explicit RegisterResultScope(BytecodeGenerator* generator)
+      : ExpressionResultScope(generator, Expression::kValue) {}
+
+  virtual void SetResultInAccumulator() {
+    result_register_ = allocator()->outer()->NewRegister();
+    builder()->StoreAccumulatorInRegister(result_register_);
+    set_result_identified();
+  }
+
+  virtual void SetResultInRegister(Register reg) {
+    DCHECK(builder()->RegisterIsParameterOrLocal(reg) ||
+           (builder()->RegisterIsTemporary(reg) &&
+            !allocator()->RegisterIsAllocatedInThisScope(reg)));
+    result_register_ = reg;
+    set_result_identified();
+  }
+
+  Register ResultRegister() const { return result_register_; }
+
+ private:
+  Register result_register_;
+};
+
+
+BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
+    : isolate_(isolate),
+      zone_(zone),
+      builder_(isolate, zone),
+      info_(nullptr),
+      scope_(nullptr),
+      globals_(0, zone),
+      execution_control_(nullptr),
+      execution_context_(nullptr),
+      execution_result_(nullptr),
+      register_allocator_(nullptr) {
+  InitializeAstVisitor(isolate);
+}
+
+
+Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) {
+  set_info(info);
+  set_scope(info->scope());
+
+  // Initialize the incoming context.
+  ContextScope incoming_context(this, scope(), false);
+
+  builder()->set_parameter_count(info->num_parameters_including_this());
+  builder()->set_locals_count(scope()->num_stack_slots());
+  builder()->set_context_count(scope()->MaxNestedContextChainLength());
+
+  // Build function context only if there are context allocated variables.
+  if (scope()->NeedsContext()) {
+    // Push a new inner context scope for the function.
+    VisitNewLocalFunctionContext();
+    ContextScope local_function_context(this, scope(), false);
+    VisitBuildLocalActivationContext();
+    MakeBytecodeBody();
+  } else {
+    MakeBytecodeBody();
+  }
+
+  set_scope(nullptr);
+  set_info(nullptr);
+  return builder_.ToBytecodeArray();
+}
+
+
+void BytecodeGenerator::MakeBytecodeBody() {
+  // Build the arguments object if it is used.
+  VisitArgumentsObject(scope()->arguments());
+
+  // TODO(mythria): Build rest arguments array if it is used.
+  int rest_index;
+  if (scope()->rest_parameter(&rest_index)) {
+    UNIMPLEMENTED();
+  }
+
+  // Build assignment to {.this_function} variable if it is used.
+  VisitThisFunctionVariable(scope()->this_function_var());
+
+  // Build assignment to {new.target} variable if it is used.
+  VisitNewTargetVariable(scope()->new_target_var());
+
+  // TODO(rmcilroy): Emit tracing call if requested to do so.
+  if (FLAG_trace) {
+    UNIMPLEMENTED();
+  }
+
+  // Visit illegal re-declaration and bail out if it exists.
+  if (scope()->HasIllegalRedeclaration()) {
+    Visit(scope()->GetIllegalRedeclaration());
+    return;
+  }
+
+  // Visit declarations within the function scope.
+  VisitDeclarations(scope()->declarations());
+
+  // Visit statements in the function body.
+  VisitStatements(info()->literal()->body());
+}
+
+
+void BytecodeGenerator::VisitBlock(Block* stmt) {
+  BlockBuilder block_builder(this->builder());
+  ControlScopeForBreakable execution_control(this, stmt, &block_builder);
+
+  if (stmt->scope() == NULL) {
+    // Visit statements in the same scope, no declarations.
+    VisitStatements(stmt->statements());
+  } else {
+    // Visit declarations and statements in a block scope.
+    if (stmt->scope()->NeedsContext()) {
+      VisitNewLocalBlockContext(stmt->scope());
+      ContextScope scope(this, stmt->scope());
+      VisitDeclarations(stmt->scope()->declarations());
+      VisitStatements(stmt->statements());
+    } else {
+      VisitDeclarations(stmt->scope()->declarations());
+      VisitStatements(stmt->statements());
+    }
+  }
+  if (stmt->labels() != nullptr) block_builder.EndBlock();
+}
+
+
+void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
+  Variable* variable = decl->proxy()->var();
+  VariableMode mode = decl->mode();
+  // Const and let variables are initialized with the hole so that we can
+  // check that they are only assigned once.
+  bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET;
+  switch (variable->location()) {
+    case VariableLocation::GLOBAL:
+    case VariableLocation::UNALLOCATED: {
+      Handle<Oddball> value = variable->binding_needs_init()
+                                  ? isolate()->factory()->the_hole_value()
+                                  : isolate()->factory()->undefined_value();
+      globals()->push_back(variable->name());
+      globals()->push_back(value);
+      break;
+    }
+    case VariableLocation::LOCAL:
+      if (hole_init) {
+        Register destination(variable->index());
+        builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
+      }
+      break;
+    case VariableLocation::PARAMETER:
+      if (hole_init) {
+        // The parameter indices are shifted by 1 (receiver is variable
+        // index -1 but is parameter index 0 in BytecodeArrayBuilder).
+        Register destination(builder()->Parameter(variable->index() + 1));
+        builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
+      }
+      break;
+    case VariableLocation::CONTEXT:
+      if (hole_init) {
+        builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(),
+                                                  variable->index());
+      }
+      break;
+    case VariableLocation::LOOKUP:
+      UNIMPLEMENTED();
+      break;
+  }
+}
+
+
+void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
+  Variable* variable = decl->proxy()->var();
+  switch (variable->location()) {
+    case VariableLocation::GLOBAL:
+    case VariableLocation::UNALLOCATED: {
+      Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
+          decl->fun(), info()->script(), info());
+      // Check for stack-overflow exception.
+      if (function.is_null()) return SetStackOverflow();
+      globals()->push_back(variable->name());
+      globals()->push_back(function);
+      break;
+    }
+    case VariableLocation::PARAMETER:
+    case VariableLocation::LOCAL: {
+      VisitForAccumulatorValue(decl->fun());
+      VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid());
+      break;
+    }
+    case VariableLocation::CONTEXT: {
+      DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope()));
+      VisitForAccumulatorValue(decl->fun());
+      builder()->StoreContextSlot(execution_context()->reg(),
+                                  variable->index());
+      break;
+    }
+    case VariableLocation::LOOKUP:
+      UNIMPLEMENTED();
+  }
+}
+
+
+void BytecodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitDeclarations(
+    ZoneList<Declaration*>* declarations) {
+  RegisterAllocationScope register_scope(this);
+  DCHECK(globals()->empty());
+  AstVisitor::VisitDeclarations(declarations);
+  if (globals()->empty()) return;
+  int array_index = 0;
+  Handle<FixedArray> data = isolate()->factory()->NewFixedArray(
+      static_cast<int>(globals()->size()), TENURED);
+  for (Handle<Object> obj : *globals()) data->set(array_index++, *obj);
+  int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
+                      DeclareGlobalsNativeFlag::encode(info()->is_native()) |
+                      DeclareGlobalsLanguageMode::encode(language_mode());
+
+  Register pairs = register_allocator()->NewRegister();
+  builder()->LoadLiteral(data);
+  builder()->StoreAccumulatorInRegister(pairs);
+
+  Register flags = register_allocator()->NewRegister();
+  builder()->LoadLiteral(Smi::FromInt(encoded_flags));
+  builder()->StoreAccumulatorInRegister(flags);
+  DCHECK(flags.index() == pairs.index() + 1);
+
+  builder()->CallRuntime(Runtime::kDeclareGlobals, pairs, 2);
+  globals()->clear();
+}
+
+
+void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
+  for (int i = 0; i < statements->length(); i++) {
+    // Allocate an outer register allocations scope for the statement.
+    RegisterAllocationScope allocation_scope(this);
+    Statement* stmt = statements->at(i);
+    Visit(stmt);
+    if (stmt->IsJump()) break;
+  }
+}
+
+
+void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
+  VisitForEffect(stmt->expression());
+}
+
+
+void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
+}
+
+
+void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
+  BytecodeLabel else_label, end_label;
+  if (stmt->condition()->ToBooleanIsTrue()) {
+    // Generate then block unconditionally as always true.
+    Visit(stmt->then_statement());
+  } else if (stmt->condition()->ToBooleanIsFalse()) {
+    // Generate else block unconditionally if it exists.
+    if (stmt->HasElseStatement()) {
+      Visit(stmt->else_statement());
+    }
+  } else {
+    // TODO(oth): If then statement is BreakStatement or
+    // ContinueStatement we can reduce number of generated
+    // jump/jump_ifs here. See BasicLoops test.
+    VisitForAccumulatorValue(stmt->condition());
+    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);
+  }
+}
+
+
+void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
+    SloppyBlockFunctionStatement* stmt) {
+  Visit(stmt->statement());
+}
+
+
+void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
+  execution_control()->Continue(stmt->target());
+}
+
+
+void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
+  execution_control()->Break(stmt->target());
+}
+
+
+void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
+  VisitForAccumulatorValue(stmt->expression());
+  builder()->Return();
+}
+
+
+void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
+  // We need this scope because we visit for register values. We have to
+  // maintain a execution result scope where registers can be allocated.
+  ZoneList<CaseClause*>* clauses = stmt->cases();
+  SwitchBuilder switch_builder(builder(), clauses->length());
+  ControlScopeForBreakable scope(this, stmt, &switch_builder);
+  int default_index = -1;
+
+  // Keep the switch value in a register until a case matches.
+  Register tag = VisitForRegisterValue(stmt->tag());
+
+  // Iterate over all cases and create nodes for label comparison.
+  BytecodeLabel done_label;
+  for (int i = 0; i < clauses->length(); i++) {
+    CaseClause* clause = clauses->at(i);
+
+    // The default is not a test, remember index.
+    if (clause->is_default()) {
+      default_index = i;
+      continue;
+    }
+
+    // Perform label comparison as if via '===' with tag.
+    VisitForAccumulatorValue(clause->label());
+    builder()->CompareOperation(Token::Value::EQ_STRICT, tag,
+                                language_mode_strength());
+    switch_builder.Case(i);
+  }
+
+  if (default_index >= 0) {
+    // Emit default jump if there is a default case.
+    switch_builder.DefaultAt(default_index);
+  } else {
+    // Otherwise if we have reached here none of the cases matched, so jump to
+    // done.
+    builder()->Jump(&done_label);
+  }
+
+  // Iterate over all cases and create the case bodies.
+  for (int i = 0; i < clauses->length(); i++) {
+    CaseClause* clause = clauses->at(i);
+    switch_builder.SetCaseTarget(i);
+    VisitStatements(clause->statements());
+  }
+  builder()->Bind(&done_label);
+
+  switch_builder.SetBreakTarget(done_label);
+}
+
+
+void BytecodeGenerator::VisitCaseClause(CaseClause* clause) {
+  // Handled entirely in VisitSwitchStatement.
+  UNREACHABLE();
+}
+
+
+void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
+  LoopBuilder loop_builder(builder());
+  ControlScopeForIteration execution_control(this, stmt, &loop_builder);
+  loop_builder.LoopHeader();
+  if (stmt->cond()->ToBooleanIsFalse()) {
+    Visit(stmt->body());
+    loop_builder.Condition();
+  } else if (stmt->cond()->ToBooleanIsTrue()) {
+    loop_builder.Condition();
+    Visit(stmt->body());
+    loop_builder.JumpToHeader();
+  } else {
+    Visit(stmt->body());
+    loop_builder.Condition();
+    VisitForAccumulatorValue(stmt->cond());
+    loop_builder.JumpToHeaderIfTrue();
+  }
+  loop_builder.EndLoop();
+}
+
+
+void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
+  if (stmt->cond()->ToBooleanIsFalse()) {
+    // If the condition is false there is no need to generate the loop.
+    return;
+  }
+
+  LoopBuilder loop_builder(builder());
+  ControlScopeForIteration execution_control(this, stmt, &loop_builder);
+  loop_builder.LoopHeader();
+  loop_builder.Condition();
+  if (!stmt->cond()->ToBooleanIsTrue()) {
+    VisitForAccumulatorValue(stmt->cond());
+    loop_builder.BreakIfFalse();
+  }
+  Visit(stmt->body());
+  loop_builder.JumpToHeader();
+  loop_builder.EndLoop();
+}
+
+
+void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
+  if (stmt->init() != nullptr) {
+    Visit(stmt->init());
+  }
+  if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) {
+    // If the condition is known to be false there is no need to generate
+    // body, next or condition blocks. Init block should be generated.
+    return;
+  }
+
+  LoopBuilder loop_builder(builder());
+  ControlScopeForIteration execution_control(this, stmt, &loop_builder);
+
+  loop_builder.LoopHeader();
+  loop_builder.Condition();
+  if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
+    VisitForAccumulatorValue(stmt->cond());
+    loop_builder.BreakIfFalse();
+  }
+  Visit(stmt->body());
+  if (stmt->next() != nullptr) {
+    loop_builder.Next();
+    Visit(stmt->next());
+  }
+  loop_builder.JumpToHeader();
+  loop_builder.EndLoop();
+}
+
+
+void BytecodeGenerator::VisitForInAssignment(Expression* expr,
+                                             FeedbackVectorSlot slot) {
+  DCHECK(expr->IsValidReferenceExpression());
+
+  // Evaluate assignment starting with the value to be stored in the
+  // accumulator.
+  Property* property = expr->AsProperty();
+  LhsKind assign_type = Property::GetAssignType(property);
+  switch (assign_type) {
+    case VARIABLE: {
+      Variable* variable = expr->AsVariableProxy()->var();
+      VisitVariableAssignment(variable, slot);
+      break;
+    }
+    case NAMED_PROPERTY: {
+      RegisterAllocationScope register_scope(this);
+      Register value = register_allocator()->NewRegister();
+      builder()->StoreAccumulatorInRegister(value);
+      Register object = VisitForRegisterValue(property->obj());
+      Handle<String> name = property->key()->AsLiteral()->AsPropertyName();
+      builder()->LoadAccumulatorWithRegister(value);
+      builder()->StoreNamedProperty(object, name, feedback_index(slot),
+                                    language_mode());
+      break;
+    }
+    case KEYED_PROPERTY: {
+      RegisterAllocationScope register_scope(this);
+      Register value = register_allocator()->NewRegister();
+      builder()->StoreAccumulatorInRegister(value);
+      Register object = VisitForRegisterValue(property->obj());
+      Register key = VisitForRegisterValue(property->key());
+      builder()->LoadAccumulatorWithRegister(value);
+      builder()->StoreKeyedProperty(object, key, feedback_index(slot),
+                                    language_mode());
+      break;
+    }
+    case NAMED_SUPER_PROPERTY:
+    case KEYED_SUPER_PROPERTY:
+      UNIMPLEMENTED();
+  }
+}
+
+
+void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
+  if (stmt->subject()->IsNullLiteral() ||
+      stmt->subject()->IsUndefinedLiteral(isolate())) {
+    // ForIn generates lots of code, skip if it wouldn't produce any effects.
+    return;
+  }
+
+  LoopBuilder loop_builder(builder());
+  ControlScopeForIteration control_scope(this, stmt, &loop_builder);
+  BytecodeLabel subject_null_label, subject_undefined_label, not_object_label;
+
+  // Prepare the state for executing ForIn.
+  VisitForAccumulatorValue(stmt->subject());
+  builder()->JumpIfUndefined(&subject_undefined_label);
+  builder()->JumpIfNull(&subject_null_label);
+  Register receiver = register_allocator()->NewRegister();
+  builder()->CastAccumulatorToJSObject();
+  builder()->JumpIfNull(&not_object_label);
+  builder()->StoreAccumulatorInRegister(receiver);
+  Register cache_type = register_allocator()->NewRegister();
+  Register cache_array = register_allocator()->NewRegister();
+  Register cache_length = register_allocator()->NewRegister();
+  builder()->ForInPrepare(cache_type, cache_array, cache_length);
+
+  // Set up loop counter
+  Register index = register_allocator()->NewRegister();
+  builder()->LoadLiteral(Smi::FromInt(0));
+  builder()->StoreAccumulatorInRegister(index);
+
+  // The loop
+  loop_builder.LoopHeader();
+  loop_builder.Condition();
+  builder()->ForInDone(index, cache_length);
+  loop_builder.BreakIfTrue();
+  builder()->ForInNext(receiver, cache_type, cache_array, index);
+  loop_builder.ContinueIfUndefined();
+  VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot());
+  Visit(stmt->body());
+  loop_builder.Next();
+  builder()->ForInStep(index);
+  builder()->StoreAccumulatorInRegister(index);
+  loop_builder.JumpToHeader();
+  loop_builder.EndLoop();
+  builder()->Bind(&not_object_label);
+  builder()->Bind(&subject_null_label);
+  builder()->Bind(&subject_undefined_label);
+}
+
+
+void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
+  if (FLAG_ignition_fake_try_catch) {
+    Visit(stmt->try_block());
+    return;
+  }
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+  if (FLAG_ignition_fake_try_catch) {
+    Visit(stmt->try_block());
+    Visit(stmt->finally_block());
+    return;
+  }
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
+  // Find or build a shared function info.
+  Handle<SharedFunctionInfo> shared_info =
+      Compiler::GetSharedFunctionInfo(expr, info()->script(), info());
+  CHECK(!shared_info.is_null());  // TODO(rmcilroy): Set stack overflow?
+  builder()->CreateClosure(shared_info,
+                           expr->pretenure() ? TENURED : NOT_TENURED);
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitNativeFunctionLiteral(
+    NativeFunctionLiteral* expr) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitConditional(Conditional* expr) {
+  // TODO(rmcilroy): 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.
+
+  BytecodeLabel else_label, end_label;
+
+  VisitForAccumulatorValue(expr->condition());
+  builder()->JumpIfFalse(&else_label);
+
+  VisitForAccumulatorValue(expr->then_expression());
+  builder()->Jump(&end_label);
+
+  builder()->Bind(&else_label);
+  VisitForAccumulatorValue(expr->else_expression());
+  builder()->Bind(&end_label);
+
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitLiteral(Literal* expr) {
+  if (!execution_result()->IsEffect()) {
+    Handle<Object> value = expr->value();
+    if (value->IsSmi()) {
+      builder()->LoadLiteral(Smi::cast(*value));
+    } else if (value->IsUndefined()) {
+      builder()->LoadUndefined();
+    } else if (value->IsTrue()) {
+      builder()->LoadTrue();
+    } else if (value->IsFalse()) {
+      builder()->LoadFalse();
+    } else if (value->IsNull()) {
+      builder()->LoadNull();
+    } else if (value->IsTheHole()) {
+      builder()->LoadTheHole();
+    } else {
+      builder()->LoadLiteral(value);
+    }
+    execution_result()->SetResultInAccumulator();
+  }
+}
+
+
+void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
+  // Materialize a regular expression literal.
+  builder()->CreateRegExpLiteral(expr->pattern(), expr->literal_index(),
+                                 expr->flags());
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
+  // Deep-copy the literal boilerplate.
+  builder()->CreateObjectLiteral(expr->constant_properties(),
+                                 expr->literal_index(),
+                                 expr->ComputeFlags(true));
+  Register literal;
+
+  // Store computed values into the literal.
+  bool literal_in_accumulator = true;
+  int property_index = 0;
+  AccessorTable accessor_table(zone());
+  for (; property_index < expr->properties()->length(); property_index++) {
+    ObjectLiteral::Property* property = expr->properties()->at(property_index);
+    if (property->is_computed_name()) break;
+    if (property->IsCompileTimeValue()) continue;
+
+    if (literal_in_accumulator) {
+      literal = register_allocator()->NewRegister();
+      builder()->StoreAccumulatorInRegister(literal);
+      literal_in_accumulator = false;
+    }
+
+    RegisterAllocationScope inner_register_scope(this);
+    Literal* literal_key = property->key()->AsLiteral();
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+        UNREACHABLE();
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+        DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
+      // Fall through.
+      case ObjectLiteral::Property::COMPUTED: {
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
+        if (literal_key->value()->IsInternalizedString()) {
+          if (property->emit_store()) {
+            VisitForAccumulatorValue(property->value());
+            builder()->StoreNamedProperty(
+                literal, literal_key->AsPropertyName(),
+                feedback_index(property->GetSlot(0)), language_mode());
+          } else {
+            VisitForEffect(property->value());
+          }
+        } else {
+          register_allocator()->PrepareForConsecutiveAllocations(3);
+          Register key = register_allocator()->NextConsecutiveRegister();
+          Register value = register_allocator()->NextConsecutiveRegister();
+          Register language = register_allocator()->NextConsecutiveRegister();
+          // TODO(oth): This is problematic - can't assume contiguous here.
+          // literal is allocated in outer register scope, whereas key, value,
+          // language are in another.
+          DCHECK(Register::AreContiguous(literal, key, value, language));
+          VisitForAccumulatorValue(property->key());
+          builder()->StoreAccumulatorInRegister(key);
+          VisitForAccumulatorValue(property->value());
+          builder()->StoreAccumulatorInRegister(value);
+          if (property->emit_store()) {
+            builder()
+                ->LoadLiteral(Smi::FromInt(SLOPPY))
+                .StoreAccumulatorInRegister(language)
+                .CallRuntime(Runtime::kSetProperty, literal, 4);
+            VisitSetHomeObject(value, literal, property);
+          }
+        }
+        break;
+      }
+      case ObjectLiteral::Property::PROTOTYPE: {
+        register_allocator()->PrepareForConsecutiveAllocations(1);
+        DCHECK(property->emit_store());
+        Register value = register_allocator()->NextConsecutiveRegister();
+        DCHECK(Register::AreContiguous(literal, value));
+        VisitForAccumulatorValue(property->value());
+        builder()->StoreAccumulatorInRegister(value).CallRuntime(
+            Runtime::kInternalSetPrototype, literal, 2);
+        break;
+      }
+      case ObjectLiteral::Property::GETTER:
+        if (property->emit_store()) {
+          accessor_table.lookup(literal_key)->second->getter = property;
+        }
+        break;
+      case ObjectLiteral::Property::SETTER:
+        if (property->emit_store()) {
+          accessor_table.lookup(literal_key)->second->setter = property;
+        }
+        break;
+    }
+  }
+
+  // Define accessors, using only a single call to the runtime for each pair of
+  // corresponding getters and setters.
+  for (AccessorTable::Iterator it = accessor_table.begin();
+       it != accessor_table.end(); ++it) {
+    RegisterAllocationScope inner_register_scope(this);
+    register_allocator()->PrepareForConsecutiveAllocations(4);
+    Register name = register_allocator()->NextConsecutiveRegister();
+    Register getter = register_allocator()->NextConsecutiveRegister();
+    Register setter = register_allocator()->NextConsecutiveRegister();
+    Register attr = register_allocator()->NextConsecutiveRegister();
+    DCHECK(Register::AreContiguous(literal, name, getter, setter, attr));
+    VisitForAccumulatorValue(it->first);
+    builder()->StoreAccumulatorInRegister(name);
+    VisitObjectLiteralAccessor(literal, it->second->getter, getter);
+    VisitObjectLiteralAccessor(literal, it->second->setter, setter);
+    builder()
+        ->LoadLiteral(Smi::FromInt(NONE))
+        .StoreAccumulatorInRegister(attr)
+        .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, literal, 5);
+  }
+
+  // Object literals have two parts. The "static" part on the left contains no
+  // computed property names, and so we can compute its map ahead of time; see
+  // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts
+  // with the first computed property name and continues with all properties to
+  // its right. All the code from above initializes the static component of the
+  // object literal, and arranges for the map of the result to reflect the
+  // static order in which the keys appear. For the dynamic properties, we
+  // compile them into a series of "SetOwnProperty" runtime calls. This will
+  // preserve insertion order.
+  for (; property_index < expr->properties()->length(); property_index++) {
+    if (literal_in_accumulator) {
+      literal = register_allocator()->NewRegister();
+      builder()->StoreAccumulatorInRegister(literal);
+      literal_in_accumulator = false;
+    }
+
+    ObjectLiteral::Property* property = expr->properties()->at(property_index);
+    RegisterAllocationScope inner_register_scope(this);
+    if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
+      DCHECK(property->emit_store());
+      Register value = register_allocator()->NewRegister();
+      DCHECK(Register::AreContiguous(literal, value));
+      VisitForAccumulatorValue(property->value());
+      builder()->StoreAccumulatorInRegister(value).CallRuntime(
+          Runtime::kInternalSetPrototype, literal, 2);
+      continue;
+    }
+
+    register_allocator()->PrepareForConsecutiveAllocations(3);
+    Register key = register_allocator()->NextConsecutiveRegister();
+    Register value = register_allocator()->NextConsecutiveRegister();
+    Register attr = register_allocator()->NextConsecutiveRegister();
+    DCHECK(Register::AreContiguous(literal, key, value, attr));
+
+    VisitForAccumulatorValue(property->key());
+    builder()->CastAccumulatorToName().StoreAccumulatorInRegister(key);
+    VisitForAccumulatorValue(property->value());
+    builder()->StoreAccumulatorInRegister(value);
+    VisitSetHomeObject(value, literal, property);
+    builder()->LoadLiteral(Smi::FromInt(NONE)).StoreAccumulatorInRegister(attr);
+    Runtime::FunctionId function_id = static_cast<Runtime::FunctionId>(-1);
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+      case ObjectLiteral::Property::COMPUTED:
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+        function_id = Runtime::kDefineDataPropertyUnchecked;
+        break;
+      case ObjectLiteral::Property::PROTOTYPE:
+        UNREACHABLE();  // Handled specially above.
+        break;
+      case ObjectLiteral::Property::GETTER:
+        function_id = Runtime::kDefineGetterPropertyUnchecked;
+        break;
+      case ObjectLiteral::Property::SETTER:
+        function_id = Runtime::kDefineSetterPropertyUnchecked;
+        break;
+    }
+    builder()->CallRuntime(function_id, literal, 4);
+  }
+
+  // Transform literals that contain functions to fast properties.
+  if (expr->has_function()) {
+    DCHECK(!literal_in_accumulator);
+    builder()->CallRuntime(Runtime::kToFastProperties, literal, 1);
+  }
+
+  if (!literal_in_accumulator) {
+    // Restore literal array into accumulator.
+    builder()->LoadAccumulatorWithRegister(literal);
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
+  // Deep-copy the literal boilerplate.
+  builder()->CreateArrayLiteral(expr->constant_elements(),
+                                expr->literal_index(),
+                                expr->ComputeFlags(true));
+  Register index, literal;
+
+  // Evaluate all the non-constant subexpressions and store them into the
+  // newly cloned array.
+  bool literal_in_accumulator = true;
+  for (int array_index = 0; array_index < expr->values()->length();
+       array_index++) {
+    Expression* subexpr = expr->values()->at(array_index);
+    if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
+    if (subexpr->IsSpread()) {
+      // TODO(rmcilroy): Deal with spread expressions.
+      UNIMPLEMENTED();
+    }
+
+    if (literal_in_accumulator) {
+      index = register_allocator()->NewRegister();
+      literal = register_allocator()->NewRegister();
+      builder()->StoreAccumulatorInRegister(literal);
+      literal_in_accumulator = false;
+    }
+
+    FeedbackVectorSlot slot = expr->LiteralFeedbackSlot();
+    builder()
+        ->LoadLiteral(Smi::FromInt(array_index))
+        .StoreAccumulatorInRegister(index);
+    VisitForAccumulatorValue(subexpr);
+    builder()->StoreKeyedProperty(literal, index, feedback_index(slot),
+                                  language_mode());
+  }
+
+  if (!literal_in_accumulator) {
+    // Restore literal array into accumulator.
+    builder()->LoadAccumulatorWithRegister(literal);
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
+  VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot());
+}
+
+
+void BytecodeGenerator::VisitVariableLoad(Variable* variable,
+                                          FeedbackVectorSlot slot,
+                                          TypeofMode typeof_mode) {
+  switch (variable->location()) {
+    case VariableLocation::LOCAL: {
+      Register source(Register(variable->index()));
+      builder()->LoadAccumulatorWithRegister(source);
+      execution_result()->SetResultInAccumulator();
+      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);
+      execution_result()->SetResultInAccumulator();
+      break;
+    }
+    case VariableLocation::GLOBAL:
+    case VariableLocation::UNALLOCATED: {
+      builder()->LoadGlobal(variable->name(), feedback_index(slot),
+                            language_mode(), typeof_mode);
+      execution_result()->SetResultInAccumulator();
+      break;
+    }
+    case VariableLocation::CONTEXT: {
+      int depth = execution_context()->ContextChainDepth(variable->scope());
+      ContextScope* context = execution_context()->Previous(depth);
+      Register context_reg;
+      if (context) {
+        context_reg = context->reg();
+      } else {
+        context_reg = register_allocator()->NewRegister();
+        // Walk the context chain to find the context at the given depth.
+        // TODO(rmcilroy): Perform this work in a bytecode handler once we have
+        // a generic mechanism for performing jumps in interpreter.cc.
+        // TODO(mythria): Also update bytecode graph builder with correct depth
+        // when this changes.
+        builder()
+            ->LoadAccumulatorWithRegister(execution_context()->reg())
+            .StoreAccumulatorInRegister(context_reg);
+        for (int i = 0; i < depth; ++i) {
+          builder()
+              ->LoadContextSlot(context_reg, Context::PREVIOUS_INDEX)
+              .StoreAccumulatorInRegister(context_reg);
+        }
+      }
+      builder()->LoadContextSlot(context_reg, variable->index());
+      execution_result()->SetResultInAccumulator();
+      // TODO(rmcilroy): Perform check for uninitialized legacy const, const and
+      // let variables.
+      break;
+    }
+    case VariableLocation::LOOKUP: {
+      builder()->LoadLookupSlot(variable->name(), typeof_mode);
+      execution_result()->SetResultInAccumulator();
+      break;
+    }
+  }
+}
+
+
+void BytecodeGenerator::VisitVariableLoadForAccumulatorValue(
+    Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) {
+  AccumulatorResultScope accumulator_result(this);
+  VisitVariableLoad(variable, slot, typeof_mode);
+}
+
+
+Register BytecodeGenerator::VisitVariableLoadForRegisterValue(
+    Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) {
+  RegisterResultScope register_scope(this);
+  VisitVariableLoad(variable, slot, typeof_mode);
+  return register_scope.ResultRegister();
+}
+
+
+void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
+                                                FeedbackVectorSlot slot) {
+  switch (variable->location()) {
+    case VariableLocation::LOCAL: {
+      // TODO(rmcilroy): support const mode initialization.
+      Register destination(variable->index());
+      builder()->StoreAccumulatorInRegister(destination);
+      break;
+    }
+    case VariableLocation::PARAMETER: {
+      // The parameter indices are shifted by 1 (receiver is variable
+      // index -1 but is parameter index 0 in BytecodeArrayBuilder).
+      Register destination(builder()->Parameter(variable->index() + 1));
+      builder()->StoreAccumulatorInRegister(destination);
+      break;
+    }
+    case VariableLocation::GLOBAL:
+    case VariableLocation::UNALLOCATED: {
+      builder()->StoreGlobal(variable->name(), feedback_index(slot),
+                             language_mode());
+      break;
+    }
+    case VariableLocation::CONTEXT: {
+      // TODO(rmcilroy): support const mode initialization.
+      int depth = execution_context()->ContextChainDepth(variable->scope());
+      ContextScope* context = execution_context()->Previous(depth);
+      Register context_reg;
+      if (context) {
+        context_reg = context->reg();
+      } else {
+        Register value_temp = register_allocator()->NewRegister();
+        context_reg = register_allocator()->NewRegister();
+        // Walk the context chain to find the context at the given depth.
+        // TODO(rmcilroy): Perform this work in a bytecode handler once we have
+        // a generic mechanism for performing jumps in interpreter.cc.
+        // TODO(mythria): Also update bytecode graph builder with correct depth
+        // when this changes.
+        builder()
+            ->StoreAccumulatorInRegister(value_temp)
+            .LoadAccumulatorWithRegister(execution_context()->reg())
+            .StoreAccumulatorInRegister(context_reg);
+        for (int i = 0; i < depth; ++i) {
+          builder()
+              ->LoadContextSlot(context_reg, Context::PREVIOUS_INDEX)
+              .StoreAccumulatorInRegister(context_reg);
+        }
+        builder()->LoadAccumulatorWithRegister(value_temp);
+      }
+      builder()->StoreContextSlot(context_reg, variable->index());
+      break;
+    }
+    case VariableLocation::LOOKUP: {
+      builder()->StoreLookupSlot(variable->name(), language_mode());
+      break;
+    }
+  }
+}
+
+
+void BytecodeGenerator::VisitAssignment(Assignment* expr) {
+  DCHECK(expr->target()->IsValidReferenceExpression());
+  Register object, key;
+  Handle<String> name;
+
+  // Left-hand side can only be a property, a global or a variable slot.
+  Property* property = expr->target()->AsProperty();
+  LhsKind assign_type = Property::GetAssignType(property);
+
+  // Evaluate LHS expression.
+  switch (assign_type) {
+    case VARIABLE:
+      // Nothing to do to evaluate variable assignment LHS.
+      break;
+    case NAMED_PROPERTY: {
+      object = VisitForRegisterValue(property->obj());
+      name = property->key()->AsLiteral()->AsPropertyName();
+      break;
+    }
+    case KEYED_PROPERTY: {
+      object = VisitForRegisterValue(property->obj());
+      if (expr->is_compound()) {
+        // Use VisitForAccumulator and store to register so that the key is
+        // still in the accumulator for loading the old value below.
+        key = register_allocator()->NewRegister();
+        VisitForAccumulatorValue(property->key());
+        builder()->StoreAccumulatorInRegister(key);
+      } else {
+        key = VisitForRegisterValue(property->key());
+      }
+      break;
+    }
+    case NAMED_SUPER_PROPERTY:
+    case KEYED_SUPER_PROPERTY:
+      UNIMPLEMENTED();
+  }
+
+  // Evaluate the value and potentially handle compound assignments by loading
+  // the left-hand side value and performing a binary operation.
+  if (expr->is_compound()) {
+    Register old_value;
+    switch (assign_type) {
+      case VARIABLE: {
+        VariableProxy* proxy = expr->target()->AsVariableProxy();
+        old_value = VisitVariableLoadForRegisterValue(
+            proxy->var(), proxy->VariableFeedbackSlot());
+        break;
+      }
+      case NAMED_PROPERTY: {
+        FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
+        old_value = register_allocator()->NewRegister();
+        builder()
+            ->LoadNamedProperty(object, name, feedback_index(slot),
+                                language_mode())
+            .StoreAccumulatorInRegister(old_value);
+        break;
+      }
+      case KEYED_PROPERTY: {
+        // Key is already in accumulator at this point due to evaluating the
+        // LHS above.
+        FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
+        old_value = register_allocator()->NewRegister();
+        builder()
+            ->LoadKeyedProperty(object, feedback_index(slot), language_mode())
+            .StoreAccumulatorInRegister(old_value);
+        break;
+      }
+      case NAMED_SUPER_PROPERTY:
+      case KEYED_SUPER_PROPERTY:
+        UNIMPLEMENTED();
+        break;
+    }
+    VisitForAccumulatorValue(expr->value());
+    builder()->BinaryOperation(expr->binary_op(), old_value,
+                               language_mode_strength());
+  } else {
+    VisitForAccumulatorValue(expr->value());
+  }
+
+  // Store the value.
+  FeedbackVectorSlot slot = expr->AssignmentSlot();
+  switch (assign_type) {
+    case VARIABLE: {
+      // TODO(oth): The VisitVariableAssignment() call is hard to reason about.
+      // Is the value in the accumulator safe? Yes, but scary.
+      Variable* variable = expr->target()->AsVariableProxy()->var();
+      VisitVariableAssignment(variable, slot);
+      break;
+    }
+    case NAMED_PROPERTY:
+      builder()->StoreNamedProperty(object, name, feedback_index(slot),
+                                    language_mode());
+      break;
+    case KEYED_PROPERTY:
+      builder()->StoreKeyedProperty(object, key, feedback_index(slot),
+                                    language_mode());
+      break;
+    case NAMED_SUPER_PROPERTY:
+    case KEYED_SUPER_PROPERTY:
+      UNIMPLEMENTED();
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitYield(Yield* expr) { UNIMPLEMENTED(); }
+
+
+void BytecodeGenerator::VisitThrow(Throw* expr) {
+  VisitForAccumulatorValue(expr->exception());
+  builder()->Throw();
+}
+
+
+void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
+  LhsKind property_kind = Property::GetAssignType(expr);
+  FeedbackVectorSlot slot = expr->PropertyFeedbackSlot();
+  switch (property_kind) {
+    case VARIABLE:
+      UNREACHABLE();
+    case NAMED_PROPERTY: {
+      builder()->LoadNamedProperty(obj,
+                                   expr->key()->AsLiteral()->AsPropertyName(),
+                                   feedback_index(slot), language_mode());
+      break;
+    }
+    case KEYED_PROPERTY: {
+      VisitForAccumulatorValue(expr->key());
+      builder()->LoadKeyedProperty(obj, feedback_index(slot), language_mode());
+      break;
+    }
+    case NAMED_SUPER_PROPERTY:
+    case KEYED_SUPER_PROPERTY:
+      UNIMPLEMENTED();
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitPropertyLoadForAccumulator(Register obj,
+                                                        Property* expr) {
+  AccumulatorResultScope result_scope(this);
+  VisitPropertyLoad(obj, expr);
+}
+
+
+void BytecodeGenerator::VisitProperty(Property* expr) {
+  Register obj = VisitForRegisterValue(expr->obj());
+  VisitPropertyLoad(obj, expr);
+}
+
+
+Register BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args) {
+  if (args->length() == 0) {
+    return Register();
+  }
+
+  // Visit arguments and place in a contiguous block of temporary
+  // registers.  Return the first temporary register corresponding to
+  // the first argument.
+  //
+  // NB the caller may have already called
+  // PrepareForConsecutiveAllocations() with args->length() + N. The
+  // second call here will be a no-op provided there have been N or
+  // less calls to NextConsecutiveRegister(). Otherwise, the arguments
+  // here will be consecutive, but they will not be consecutive with
+  // earlier consecutive allocations made by the caller.
+  register_allocator()->PrepareForConsecutiveAllocations(args->length());
+
+  // Visit for first argument that goes into returned register
+  Register first_arg = register_allocator()->NextConsecutiveRegister();
+  VisitForAccumulatorValue(args->at(0));
+  builder()->StoreAccumulatorInRegister(first_arg);
+
+  // Visit remaining arguments
+  for (int i = 1; i < static_cast<int>(args->length()); i++) {
+    Register ith_arg = register_allocator()->NextConsecutiveRegister();
+    VisitForAccumulatorValue(args->at(i));
+    builder()->StoreAccumulatorInRegister(ith_arg);
+    DCHECK(ith_arg.index() - i == first_arg.index());
+  }
+  return first_arg;
+}
+
+
+void BytecodeGenerator::VisitCall(Call* expr) {
+  Expression* callee_expr = expr->expression();
+  Call::CallType call_type = expr->GetCallType(isolate());
+
+  // Prepare the callee and the receiver to the function call. This depends on
+  // the semantics of the underlying call type.
+
+  // The receiver and arguments need to be allocated consecutively for
+  // Call(). We allocate the callee and receiver consecutively for calls to
+  // kLoadLookupSlot. Future optimizations could avoid this there are no
+  // arguments or the receiver and arguments are already consecutive.
+  ZoneList<Expression*>* args = expr->arguments();
+  register_allocator()->PrepareForConsecutiveAllocations(args->length() + 2);
+  Register callee = register_allocator()->NextConsecutiveRegister();
+  Register receiver = register_allocator()->NextConsecutiveRegister();
+
+  switch (call_type) {
+    case Call::NAMED_PROPERTY_CALL:
+    case Call::KEYED_PROPERTY_CALL: {
+      Property* property = callee_expr->AsProperty();
+      VisitForAccumulatorValue(property->obj());
+      builder()->StoreAccumulatorInRegister(receiver);
+      VisitPropertyLoadForAccumulator(receiver, property);
+      builder()->StoreAccumulatorInRegister(callee);
+      break;
+    }
+    case Call::GLOBAL_CALL: {
+      // Receiver is undefined for global calls.
+      builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
+      // Load callee as a global variable.
+      VariableProxy* proxy = callee_expr->AsVariableProxy();
+      VisitVariableLoadForAccumulatorValue(proxy->var(),
+                                           proxy->VariableFeedbackSlot());
+      builder()->StoreAccumulatorInRegister(callee);
+      break;
+    }
+    case Call::LOOKUP_SLOT_CALL:
+    case Call::POSSIBLY_EVAL_CALL: {
+      if (callee_expr->AsVariableProxy()->var()->IsLookupSlot()) {
+        RegisterAllocationScope inner_register_scope(this);
+        register_allocator()->PrepareForConsecutiveAllocations(2);
+        Register context = register_allocator()->NextConsecutiveRegister();
+        Register name = register_allocator()->NextConsecutiveRegister();
+
+        // Call LoadLookupSlot to get the callee and receiver.
+        DCHECK(Register::AreContiguous(callee, receiver));
+        Variable* variable = callee_expr->AsVariableProxy()->var();
+        builder()
+            ->MoveRegister(Register::function_context(), context)
+            .LoadLiteral(variable->name())
+            .StoreAccumulatorInRegister(name)
+            .CallRuntimeForPair(Runtime::kLoadLookupSlot, context, 2, callee);
+        break;
+      }
+      // Fall through.
+      DCHECK_EQ(call_type, Call::POSSIBLY_EVAL_CALL);
+    }
+    case Call::OTHER_CALL: {
+      builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
+      VisitForAccumulatorValue(callee_expr);
+      builder()->StoreAccumulatorInRegister(callee);
+      break;
+    }
+    case Call::NAMED_SUPER_PROPERTY_CALL:
+    case Call::KEYED_SUPER_PROPERTY_CALL:
+    case Call::SUPER_CALL:
+      UNIMPLEMENTED();
+  }
+
+  // Evaluate all arguments to the function call and store in sequential
+  // registers.
+  Register arg = VisitArguments(args);
+  CHECK(args->length() == 0 || arg.index() == receiver.index() + 1);
+
+  // Resolve callee for a potential direct eval call. This block will mutate the
+  // callee value.
+  if (call_type == Call::POSSIBLY_EVAL_CALL && args->length() > 0) {
+    RegisterAllocationScope inner_register_scope(this);
+    register_allocator()->PrepareForConsecutiveAllocations(5);
+    Register callee_for_eval = register_allocator()->NextConsecutiveRegister();
+    Register source = register_allocator()->NextConsecutiveRegister();
+    Register function = register_allocator()->NextConsecutiveRegister();
+    Register language = register_allocator()->NextConsecutiveRegister();
+    Register position = register_allocator()->NextConsecutiveRegister();
+
+    // Set up arguments for ResolvePossiblyDirectEval by copying callee, source
+    // strings and function closure, and loading language and
+    // position.
+    builder()
+        ->MoveRegister(callee, callee_for_eval)
+        .MoveRegister(arg, source)
+        .MoveRegister(Register::function_closure(), function)
+        .LoadLiteral(Smi::FromInt(language_mode()))
+        .StoreAccumulatorInRegister(language)
+        .LoadLiteral(
+            Smi::FromInt(execution_context()->scope()->start_position()))
+        .StoreAccumulatorInRegister(position);
+
+    // Call ResolvePossiblyDirectEval and modify the callee.
+    builder()
+        ->CallRuntime(Runtime::kResolvePossiblyDirectEval, callee_for_eval, 5)
+        .StoreAccumulatorInRegister(callee);
+  }
+
+  // TODO(rmcilroy): Use CallIC to allow call type feedback.
+  builder()->Call(callee, receiver, args->length(),
+                  feedback_index(expr->CallFeedbackICSlot()));
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitCallNew(CallNew* expr) {
+  Register constructor = register_allocator()->NewRegister();
+  VisitForAccumulatorValue(expr->expression());
+  builder()->StoreAccumulatorInRegister(constructor);
+
+  ZoneList<Expression*>* args = expr->arguments();
+  Register first_arg = VisitArguments(args);
+  builder()->New(constructor, first_arg, args->length());
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  Register receiver;
+  if (expr->is_jsruntime()) {
+    // Allocate a register for the receiver and load it with undefined.
+    register_allocator()->PrepareForConsecutiveAllocations(args->length() + 1);
+    receiver = register_allocator()->NextConsecutiveRegister();
+    builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
+  }
+  // Evaluate all arguments to the runtime call.
+  Register first_arg = VisitArguments(args);
+
+  if (expr->is_jsruntime()) {
+    DCHECK(args->length() == 0 || first_arg.index() == receiver.index() + 1);
+    builder()->CallJSRuntime(expr->context_index(), receiver, args->length());
+  } else {
+    Runtime::FunctionId function_id = expr->function()->function_id;
+    builder()->CallRuntime(function_id, first_arg, args->length());
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
+  VisitForEffect(expr->expression());
+  builder()->LoadUndefined();
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
+  if (expr->expression()->IsVariableProxy()) {
+    // Typeof does not throw a reference error on global variables, hence we
+    // perform a non-contextual load in case the operand is a variable proxy.
+    VariableProxy* proxy = expr->expression()->AsVariableProxy();
+    VisitVariableLoadForAccumulatorValue(
+        proxy->var(), proxy->VariableFeedbackSlot(), INSIDE_TYPEOF);
+  } else {
+    VisitForAccumulatorValue(expr->expression());
+  }
+  builder()->TypeOf();
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
+  VisitForAccumulatorValue(expr->expression());
+  builder()->LogicalNot();
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
+  switch (expr->op()) {
+    case Token::Value::NOT:
+      VisitNot(expr);
+      break;
+    case Token::Value::TYPEOF:
+      VisitTypeOf(expr);
+      break;
+    case Token::Value::VOID:
+      VisitVoid(expr);
+      break;
+    case Token::Value::DELETE:
+      VisitDelete(expr);
+      break;
+    case Token::Value::BIT_NOT:
+    case Token::Value::ADD:
+    case Token::Value::SUB:
+      // These operators are converted to an equivalent binary operators in
+      // the parser. These operators are not expected to be visited here.
+      UNREACHABLE();
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
+  if (expr->expression()->IsProperty()) {
+    // Delete of an object property is allowed both in sloppy
+    // and strict modes.
+    Property* property = expr->expression()->AsProperty();
+    Register object = VisitForRegisterValue(property->obj());
+    VisitForAccumulatorValue(property->key());
+    builder()->Delete(object, language_mode());
+  } else if (expr->expression()->IsVariableProxy()) {
+    // Delete of an unqualified identifier is allowed in sloppy mode but is
+    // not allowed in strict mode. Deleting 'this' is allowed in both modes.
+    VariableProxy* proxy = expr->expression()->AsVariableProxy();
+    Variable* variable = proxy->var();
+    DCHECK(is_sloppy(language_mode()) || variable->HasThisName(isolate()));
+    switch (variable->location()) {
+      case VariableLocation::GLOBAL:
+      case VariableLocation::UNALLOCATED: {
+        // Global var, let, const or variables not explicitly declared.
+        Register native_context = register_allocator()->NewRegister();
+        Register global_object = register_allocator()->NewRegister();
+        builder()
+            ->LoadContextSlot(execution_context()->reg(),
+                              Context::NATIVE_CONTEXT_INDEX)
+            .StoreAccumulatorInRegister(native_context)
+            .LoadContextSlot(native_context, Context::EXTENSION_INDEX)
+            .StoreAccumulatorInRegister(global_object)
+            .LoadLiteral(variable->name())
+            .Delete(global_object, language_mode());
+        break;
+      }
+      case VariableLocation::PARAMETER:
+      case VariableLocation::LOCAL:
+      case VariableLocation::CONTEXT: {
+        // Deleting local var/let/const, context variables, and arguments
+        // does not have any effect.
+        if (variable->HasThisName(isolate())) {
+          builder()->LoadTrue();
+        } else {
+          builder()->LoadFalse();
+        }
+        break;
+      }
+      case VariableLocation::LOOKUP: {
+        builder()->LoadLiteral(variable->name()).DeleteLookupSlot();
+        break;
+      }
+      default:
+        UNREACHABLE();
+    }
+  } else {
+    // Delete of an unresolvable reference returns true.
+    VisitForEffect(expr->expression());
+    builder()->LoadTrue();
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
+  DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
+
+  // Left-hand side can only be a property, a global or a variable slot.
+  Property* property = expr->expression()->AsProperty();
+  LhsKind assign_type = Property::GetAssignType(property);
+
+  // TODO(rmcilroy): Set is_postfix to false if visiting for effect.
+  bool is_postfix = expr->is_postfix();
+
+  // Evaluate LHS expression and get old value.
+  Register obj, key, old_value;
+  Handle<String> name;
+  switch (assign_type) {
+    case VARIABLE: {
+      VariableProxy* proxy = expr->expression()->AsVariableProxy();
+      VisitVariableLoadForAccumulatorValue(proxy->var(),
+                                           proxy->VariableFeedbackSlot());
+      break;
+    }
+    case NAMED_PROPERTY: {
+      FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
+      obj = VisitForRegisterValue(property->obj());
+      name = property->key()->AsLiteral()->AsPropertyName();
+      builder()->LoadNamedProperty(obj, name, feedback_index(slot),
+                                   language_mode());
+      break;
+    }
+    case KEYED_PROPERTY: {
+      FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
+      obj = VisitForRegisterValue(property->obj());
+      // Use visit for accumulator here since we need the key in the accumulator
+      // for the LoadKeyedProperty.
+      key = register_allocator()->NewRegister();
+      VisitForAccumulatorValue(property->key());
+      builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty(
+          obj, feedback_index(slot), language_mode());
+      break;
+    }
+    case NAMED_SUPER_PROPERTY:
+    case KEYED_SUPER_PROPERTY:
+      UNIMPLEMENTED();
+  }
+
+  // Convert old value into a number.
+  if (!is_strong(language_mode())) {
+    builder()->CastAccumulatorToNumber();
+  }
+
+  // Save result for postfix expressions.
+  if (is_postfix) {
+    old_value = register_allocator()->outer()->NewRegister();
+    builder()->StoreAccumulatorInRegister(old_value);
+  }
+
+  // Perform +1/-1 operation.
+  builder()->CountOperation(expr->binary_op(), language_mode_strength());
+
+  // Store the value.
+  FeedbackVectorSlot feedback_slot = expr->CountSlot();
+  switch (assign_type) {
+    case VARIABLE: {
+      Variable* variable = expr->expression()->AsVariableProxy()->var();
+      VisitVariableAssignment(variable, feedback_slot);
+      break;
+    }
+    case NAMED_PROPERTY: {
+      builder()->StoreNamedProperty(obj, name, feedback_index(feedback_slot),
+                                    language_mode());
+      break;
+    }
+    case KEYED_PROPERTY: {
+      builder()->StoreKeyedProperty(obj, key, feedback_index(feedback_slot),
+                                    language_mode());
+      break;
+    }
+    case NAMED_SUPER_PROPERTY:
+    case KEYED_SUPER_PROPERTY:
+      UNIMPLEMENTED();
+  }
+
+  // Restore old value for postfix expressions.
+  if (is_postfix) {
+    execution_result()->SetResultInRegister(old_value);
+  } else {
+    execution_result()->SetResultInAccumulator();
+  }
+}
+
+
+void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
+  switch (binop->op()) {
+    case Token::COMMA:
+      VisitCommaExpression(binop);
+      break;
+    case Token::OR:
+      VisitLogicalOrExpression(binop);
+      break;
+    case Token::AND:
+      VisitLogicalAndExpression(binop);
+      break;
+    default:
+      VisitArithmeticExpression(binop);
+      break;
+  }
+}
+
+
+void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
+  Register lhs = VisitForRegisterValue(expr->left());
+  VisitForAccumulatorValue(expr->right());
+  builder()->CompareOperation(expr->op(), lhs, language_mode_strength());
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
+  Register lhs = VisitForRegisterValue(expr->left());
+  VisitForAccumulatorValue(expr->right());
+  builder()->BinaryOperation(expr->op(), lhs, language_mode_strength());
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); }
+
+
+void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
+  UNREACHABLE();
+}
+
+
+void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
+  execution_result()->SetResultInRegister(Register::function_closure());
+}
+
+
+void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitSuperPropertyReference(
+    SuperPropertyReference* expr) {
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
+  VisitForEffect(binop->left());
+  Visit(binop->right());
+}
+
+
+void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
+  Expression* left = binop->left();
+  Expression* right = binop->right();
+
+  // Short-circuit evaluation- If it is known that left is always true,
+  // no need to visit right
+  if (left->ToBooleanIsTrue()) {
+    VisitForAccumulatorValue(left);
+  } else {
+    BytecodeLabel end_label;
+    VisitForAccumulatorValue(left);
+    builder()->JumpIfTrue(&end_label);
+    VisitForAccumulatorValue(right);
+    builder()->Bind(&end_label);
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
+  Expression* left = binop->left();
+  Expression* right = binop->right();
+
+  // Short-circuit evaluation- If it is known that left is always false,
+  // no need to visit right
+  if (left->ToBooleanIsFalse()) {
+    VisitForAccumulatorValue(left);
+  } else {
+    BytecodeLabel end_label;
+    VisitForAccumulatorValue(left);
+    builder()->JumpIfFalse(&end_label);
+    VisitForAccumulatorValue(right);
+    builder()->Bind(&end_label);
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitRewritableAssignmentExpression(
+    RewritableAssignmentExpression* expr) {
+  Visit(expr->expression());
+}
+
+
+void BytecodeGenerator::VisitNewLocalFunctionContext() {
+  AccumulatorResultScope accumulator_execution_result(this);
+  Scope* scope = this->scope();
+
+  // Allocate a new local context.
+  if (scope->is_script_scope()) {
+    RegisterAllocationScope register_scope(this);
+    Register closure = register_allocator()->NewRegister();
+    Register scope_info = register_allocator()->NewRegister();
+    DCHECK(Register::AreContiguous(closure, scope_info));
+    builder()
+        ->LoadAccumulatorWithRegister(Register::function_closure())
+        .StoreAccumulatorInRegister(closure)
+        .LoadLiteral(scope->GetScopeInfo(isolate()))
+        .StoreAccumulatorInRegister(scope_info)
+        .CallRuntime(Runtime::kNewScriptContext, closure, 2);
+  } else {
+    builder()->CallRuntime(Runtime::kNewFunctionContext,
+                           Register::function_closure(), 1);
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitBuildLocalActivationContext() {
+  Scope* scope = this->scope();
+
+  if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
+    Variable* variable = scope->receiver();
+    Register receiver(builder()->Parameter(0));
+    // Context variable (at bottom of the context chain).
+    DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
+    builder()->LoadAccumulatorWithRegister(receiver).StoreContextSlot(
+        execution_context()->reg(), variable->index());
+  }
+
+  // Copy parameters into context if necessary.
+  int num_parameters = scope->num_parameters();
+  for (int i = 0; i < num_parameters; i++) {
+    Variable* variable = scope->parameter(i);
+    if (!variable->IsContextSlot()) continue;
+
+    // The parameter indices are shifted by 1 (receiver is variable
+    // index -1 but is parameter index 0 in BytecodeArrayBuilder).
+    Register parameter(builder()->Parameter(i + 1));
+    // Context variable (at bottom of the context chain).
+    DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
+    builder()->LoadAccumulatorWithRegister(parameter)
+        .StoreContextSlot(execution_context()->reg(), variable->index());
+  }
+}
+
+
+void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) {
+  AccumulatorResultScope accumulator_execution_result(this);
+  DCHECK(scope->is_block_scope());
+
+  // Allocate a new local block context.
+  register_allocator()->PrepareForConsecutiveAllocations(2);
+  Register scope_info = register_allocator()->NextConsecutiveRegister();
+  Register closure = register_allocator()->NextConsecutiveRegister();
+
+  builder()
+      ->LoadLiteral(scope->GetScopeInfo(isolate()))
+      .StoreAccumulatorInRegister(scope_info);
+  VisitFunctionClosureForContext();
+  builder()
+      ->StoreAccumulatorInRegister(closure)
+      .CallRuntime(Runtime::kPushBlockContext, scope_info, 2);
+  execution_result()->SetResultInAccumulator();
+}
+
+
+void BytecodeGenerator::VisitObjectLiteralAccessor(
+    Register home_object, ObjectLiteralProperty* property, Register value_out) {
+  // TODO(rmcilroy): Replace value_out with VisitForRegister();
+  if (property == nullptr) {
+    builder()->LoadNull().StoreAccumulatorInRegister(value_out);
+  } else {
+    VisitForAccumulatorValue(property->value());
+    builder()->StoreAccumulatorInRegister(value_out);
+    VisitSetHomeObject(value_out, home_object, property);
+  }
+}
+
+
+void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
+                                           ObjectLiteralProperty* property,
+                                           int slot_number) {
+  Expression* expr = property->value();
+  if (!FunctionLiteral::NeedsHomeObject(expr)) return;
+
+  UNIMPLEMENTED();
+}
+
+
+void BytecodeGenerator::VisitArgumentsObject(Variable* variable) {
+  if (variable == nullptr) return;
+
+  DCHECK(variable->IsContextSlot() || variable->IsStackAllocated());
+
+  // Allocate and initialize a new arguments object and assign to the
+  // {arguments} variable.
+  CreateArgumentsType type =
+      is_strict(language_mode()) || !info()->has_simple_parameters()
+          ? CreateArgumentsType::kUnmappedArguments
+          : CreateArgumentsType::kMappedArguments;
+  builder()->CreateArguments(type);
+  VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid());
+}
+
+
+void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) {
+  if (variable == nullptr) return;
+
+  // TODO(rmcilroy): Remove once we have tests which exercise this code path.
+  UNIMPLEMENTED();
+
+  // Store the closure we were called with in the given variable.
+  builder()->LoadAccumulatorWithRegister(Register::function_closure());
+  VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid());
+}
+
+
+void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
+  if (variable == nullptr) return;
+
+  // Store the new target we were called with in the given variable.
+  builder()->LoadAccumulatorWithRegister(Register::new_target());
+  VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid());
+}
+
+
+void BytecodeGenerator::VisitFunctionClosureForContext() {
+  AccumulatorResultScope accumulator_execution_result(this);
+  Scope* closure_scope = execution_context()->scope()->ClosureScope();
+  if (closure_scope->is_script_scope() ||
+      closure_scope->is_module_scope()) {
+    // Contexts nested in the native context have a canonical empty function as
+    // their closure, not the anonymous closure containing the global code.
+    Register native_context = register_allocator()->NewRegister();
+    builder()
+        ->LoadContextSlot(execution_context()->reg(),
+                          Context::NATIVE_CONTEXT_INDEX)
+        .StoreAccumulatorInRegister(native_context)
+        .LoadContextSlot(native_context, Context::CLOSURE_INDEX);
+  } else {
+    DCHECK(closure_scope->is_function_scope());
+    builder()->LoadAccumulatorWithRegister(Register::function_closure());
+  }
+  execution_result()->SetResultInAccumulator();
+}
+
+
+// Visits the expression |expr| and places the result in the accumulator.
+void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) {
+  AccumulatorResultScope accumulator_scope(this);
+  Visit(expr);
+}
+
+
+// Visits the expression |expr| and discards the result.
+void BytecodeGenerator::VisitForEffect(Expression* expr) {
+  EffectResultScope effect_scope(this);
+  Visit(expr);
+}
+
+
+// Visits the expression |expr| and returns the register containing
+// the expression result.
+Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) {
+  RegisterResultScope register_scope(this);
+  Visit(expr);
+  return register_scope.ResultRegister();
+}
+
+
+Register BytecodeGenerator::NextContextRegister() const {
+  if (execution_context() == nullptr) {
+    // Return the incoming function context for the outermost execution context.
+    return Register::function_context();
+  }
+  Register previous = execution_context()->reg();
+  if (previous == Register::function_context()) {
+    // If the previous context was the incoming function context, then the next
+    // context register is the first local context register.
+    return builder_.first_context_register();
+  } else {
+    // Otherwise use the next local context register.
+    DCHECK_LT(previous.index(), builder_.last_context_register().index());
+    return Register(previous.index() + 1);
+  }
+}
+
+
+LanguageMode BytecodeGenerator::language_mode() const {
+  return info()->language_mode();
+}
+
+
+Strength BytecodeGenerator::language_mode_strength() const {
+  return strength(language_mode());
+}
+
+
+int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const {
+  return info()->feedback_vector()->GetIndex(slot);
+}
+
+}  // namespace interpreter
+}  // namespace internal
+}  // namespace v8