Remove some of the state-dependent behavior from the code generator.
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Sep 2008 08:44:32 +0000 (08:44 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 11 Sep 2008 08:44:32 +0000 (08:44 +0000)
Simplify the code generator by eliminating the access types STORE and
INIT_CONST and delegating code generation for stores to the appropriate AST
nodes.
Review URL: http://codereview.chromium.org/1889

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@265 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ast.h
src/codegen-arm.cc
src/codegen-ia32.cc

index ab7bc8d..8bece05 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -140,6 +140,9 @@ class Statement: public Node {
 };
 
 
+class Reference;
+enum InitState { CONST_INIT, NOT_CONST_INIT };
+
 class Expression: public Node {
  public:
   virtual Expression* AsExpression()  { return this; }
@@ -150,6 +153,18 @@ class Expression: public Node {
   // statement. This is used to transform postfix increments to
   // (faster) prefix increments.
   virtual void MarkAsStatement() { /* do nothing */ }
+
+  // Generate code to store into an expression evaluated as the left-hand
+  // side of an assignment.  The code will expect the stored value on top of
+  // the expression stack, and a reference containing the expression
+  // immediately below that.  This function is overridden for expression
+  // types that can be stored into.
+  virtual void GenerateStoreCode(MacroAssembler* masm,
+                                 Scope* scope,
+                                 Reference* ref,
+                                 InitState init_state) {
+    UNREACHABLE();
+  }
 };
 
 
@@ -753,6 +768,14 @@ class VariableProxy: public Expression {
   // Bind this proxy to the variable var.
   void BindTo(Variable* var);
 
+  // Generate code to store into an expression evaluated as the left-hand
+  // side of an assignment.  The code will expect the stored value on top of
+  // the expression stack, and a reference containing the expression
+  // immediately below that.
+  virtual void GenerateStoreCode(MacroAssembler* masm,
+                                 Scope* scope,
+                                 Reference* ref,
+                                 InitState init_state);
  protected:
   Handle<String> name_;
   Variable* var_;  // resolved variable, or NULL
@@ -828,6 +851,14 @@ class Slot: public Expression {
   Type type() const  { return type_; }
   int index() const  { return index_; }
 
+  // Generate code to store into an expression evaluated as the left-hand
+  // side of an assignment.  The code will expect the stored value on top of
+  // the expression stack, and a reference containing the expression
+  // immediately below that.
+  virtual void GenerateStoreCode(MacroAssembler* masm,
+                                 Scope* scope,
+                                 Reference* ref,
+                                 InitState init_state);
  private:
   Variable* var_;
   Type type_;
@@ -855,6 +886,14 @@ class Property: public Expression {
   // during preparsing.
   static Property* this_property() { return &this_property_; }
 
+  // Generate code to store into an expression evaluated as the left-hand
+  // side of an assignment.  The code will expect the stored value on top of
+  // the expression stack, and a reference containing the expression
+  // immediately below that.
+  virtual void GenerateStoreCode(MacroAssembler* masm,
+                                 Scope* scope,
+                                 Reference* ref,
+                                 InitState init_state);
  private:
   Expression* obj_;
   Expression* key_;
index fa58084..47d922d 100644 (file)
@@ -109,9 +109,7 @@ class CodeGenState BASE_EMBEDDED {
   enum AccessType {
     UNDEFINED,
     LOAD,
-    LOAD_TYPEOF_EXPR,
-    STORE,
-    INIT_CONST
+    LOAD_TYPEOF_EXPR
   };
 
   CodeGenState()
@@ -181,7 +179,6 @@ class ArmCodeGenerator: public CodeGenerator {
   // The following are used by class Reference.
   void LoadReference(Reference* ref);
   void UnloadReference(Reference* ref);
-  friend class Reference;
 
   // State
   bool has_cc() const  { return cc_reg_ != al; }
@@ -197,21 +194,32 @@ class ArmCodeGenerator: public CodeGenerator {
     return ContextOperand(cp, Context::GLOBAL_INDEX);
   }
 
-  MemOperand ContextOperand(Register context, int index) const {
+  static MemOperand ContextOperand(Register context, int index) {
     return MemOperand(context, Context::SlotOffset(index));
   }
 
-  MemOperand ParameterOperand(int index) const {
+  static MemOperand ParameterOperand(Scope* scope, int index) {
     // index -2 corresponds to the activated closure, -1 corresponds
     // to the receiver
-    ASSERT(-2 <= index && index < scope_->num_parameters());
+    ASSERT(-2 <= index && index < scope->num_parameters());
     int offset = JavaScriptFrameConstants::kParam0Offset - index * kPointerSize;
     return MemOperand(pp, offset);
   }
 
+  MemOperand ParameterOperand(int index) const {
+    return ParameterOperand(scope_, index);
+  }
+
   MemOperand FunctionOperand() const { return ParameterOperand(-2); }
 
-  MemOperand SlotOperand(Slot* slot, Register tmp);
+  static MemOperand SlotOperand(MacroAssembler* masm,
+                                Scope* scope,
+                                Slot* slot,
+                                Register tmp);
+
+  MemOperand SlotOperand(Slot* slot, Register tmp) {
+    return SlotOperand(masm_, scope_, slot, tmp);
+  }
 
   void LoadCondition(Expression* x, CodeGenState::AccessType access,
                      Label* true_target, Label* false_target, bool force_cc);
@@ -227,21 +235,47 @@ class ArmCodeGenerator: public CodeGenerator {
   // through the context chain.
   void LoadTypeofExpression(Expression* x);
 
+
   // References
-  void AccessReference(Reference* ref, CodeGenState::AccessType access);
 
-  void GetValue(Reference* ref)  { AccessReference(ref, CodeGenState::LOAD); }
-  void SetValue(Reference* ref)  { AccessReference(ref, CodeGenState::STORE); }
-  void InitConst(Reference* ref)  {
-    AccessReference(ref, CodeGenState::INIT_CONST);
+  // Generate code to fetch the value of a reference.  The reference is
+  // expected to be on top of the expression stack.  It is left in place and
+  // its value is pushed on top of it.
+  void GetValue(Reference* ref);
+
+  // Generate code to store a value in a reference.  The stored value is
+  // expected on top of the expression stack, with the reference immediately
+  // below it.  The expression stack is left unchanged.
+  void SetValue(Reference* ref) {
+    ASSERT(!has_cc());
+    ASSERT(!ref->is_illegal());
+    ref->expression()->GenerateStoreCode(masm_, scope_, ref, NOT_CONST_INIT);
   }
 
-  void ToBoolean(Label* true_target, Label* false_target);
+  // Generate code to store a value in a reference.  The stored value is
+  // expected on top of the expression stack, with the reference immediately
+  // below it.  The expression stack is left unchanged.
+  void InitConst(Reference* ref) {
+    ASSERT(!has_cc());
+    ASSERT(!ref->is_illegal());
+    ref->expression()->GenerateStoreCode(masm_, scope_, ref, CONST_INIT);
+  }
 
+  // Generate code to fetch a value from a property of a reference.  The
+  // reference is expected on top of the expression stack.  It is left in
+  // place and its value is pushed on top of it.
+  void GetReferenceProperty(Expression* key);
 
-  // Access property from the reference (must be at the TOS).
-  void AccessReferenceProperty(Expression* key,
-                               CodeGenState::AccessType access);
+  // Generate code to store a value in a property of a reference.  The
+  // stored value is expected on top of the expression stack, with the
+  // reference immediately below it.  The expression stack is left
+  // unchanged.
+  static void SetReferenceProperty(MacroAssembler* masm,
+                                   Reference* ref,
+                                   Expression* key);
+
+
+  void ToBoolean(Label* true_target, Label* false_target);
 
   void GenericBinaryOperation(Token::Value op);
   void Comparison(Condition cc, bool strict = false);
@@ -297,6 +331,11 @@ class ArmCodeGenerator: public CodeGenerator {
   virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
 
   virtual void GenerateObjectEquals(ZoneList<Expression*>* args);
+
+  friend class Reference;
+  friend class Property;
+  friend class VariableProxy;
+  friend class Slot;
 };
 
 
@@ -599,7 +638,10 @@ void ArmCodeGenerator::GenCode(FunctionLiteral* fun) {
 }
 
 
-MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) {
+MemOperand ArmCodeGenerator::SlotOperand(MacroAssembler* masm,
+                                         Scope* scope,
+                                         Slot* slot,
+                                         Register tmp) {
   // Currently, this assertion will fail if we try to assign to
   // a constant variable that is constant because it is read-only
   // (such as the variable referring to a named function expression).
@@ -612,11 +654,11 @@ MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) {
   int index = slot->index();
   switch (slot->type()) {
     case Slot::PARAMETER:
-      return ParameterOperand(index);
+      return ParameterOperand(scope, index);
 
     case Slot::LOCAL: {
       ASSERT(0 <= index &&
-             index < scope_->num_stack_slots() &&
+             index < scope->num_stack_slots() &&
              index >= 0);
       int local_offset = JavaScriptFrameConstants::kLocal0Offset -
                          index * kPointerSize;
@@ -627,15 +669,15 @@ MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) {
       // Follow the context chain if necessary.
       ASSERT(!tmp.is(cp));  // do not overwrite context register
       Register context = cp;
-      int chain_length = scope_->ContextChainLength(slot->var()->scope());
+      int chain_length = scope->ContextChainLength(slot->var()->scope());
       for (int i = chain_length; i-- > 0;) {
         // Load the closure.
         // (All contexts, even 'with' contexts, have a closure,
         // and it is the same for all contexts inside a function.
         // There is no need to go to the function context first.)
-        __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
+        masm->ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
         // Load the function context (which is the incoming, outer context).
-        __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
+        masm->ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
         context = tmp;
       }
       // We may have a 'with' context now. Get the function context.
@@ -645,7 +687,7 @@ MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) {
       // cause the function context of a function context is itself. Before
       // deleting this mov we should try to create a counter-example first,
       // though...)
-      __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
+      masm->ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
       return ContextOperand(tmp, index);
     }
 
@@ -822,18 +864,128 @@ void ArmCodeGenerator::UnloadReference(Reference* ref) {
 }
 
 
-void ArmCodeGenerator::AccessReference(Reference* ref,
-                                       CodeGenState::AccessType access) {
+void ArmCodeGenerator::GetValue(Reference* ref) {
   ASSERT(!has_cc());
-  ASSERT(ref->type() != Reference::ILLEGAL);
+  ASSERT(!ref->is_illegal());
   CodeGenState* old_state = state_;
-  CodeGenState new_state(access, ref, true_target(), false_target());
+  CodeGenState new_state(CodeGenState::LOAD, ref, true_target(),
+                         false_target());
   state_ = &new_state;
   Visit(ref->expression());
   state_ = old_state;
 }
 
 
+void Property::GenerateStoreCode(MacroAssembler* masm,
+                                 Scope* scope,
+                                 Reference* ref,
+                                 InitState init_state) {
+  Comment cmnt(masm, "[ Store to Property");
+  masm->RecordPosition(position());
+  ArmCodeGenerator::SetReferenceProperty(masm, ref, key());
+}
+
+
+void VariableProxy::GenerateStoreCode(MacroAssembler* masm,
+                                      Scope* scope,
+                                      Reference* ref,
+                                      InitState init_state) {
+  Comment cmnt(masm, "[ Store to VariableProxy");
+  Variable* node = var();
+
+  Expression* expr = node->rewrite();
+  if (expr != NULL) {
+    expr->GenerateStoreCode(masm, scope, ref, init_state);
+  } else {
+    ASSERT(node->is_global());
+    if (node->AsProperty() != NULL) {
+      masm->RecordPosition(node->AsProperty()->position());
+    }
+    ArmCodeGenerator::SetReferenceProperty(masm, ref,
+                                           new Literal(node->name()));
+  }
+}
+
+
+void Slot::GenerateStoreCode(MacroAssembler* masm,
+                             Scope* scope,
+                             Reference* ref,
+                             InitState init_state) {
+  Comment cmnt(masm, "[ Store to Slot");
+
+  if (type() == Slot::LOOKUP) {
+    ASSERT(var()->mode() == Variable::DYNAMIC);
+
+    // For now, just do a runtime call.
+    masm->push(cp);
+    masm->mov(r0, Operand(var()->name()));
+    masm->push(r0);
+
+    if (init_state == CONST_INIT) {
+      // Same as the case for a normal store, but ignores attribute
+      // (e.g. READ_ONLY) of context slot so that we can initialize const
+      // properties (introduced via eval("const foo = (some expr);")). Also,
+      // uses the current function context instead of the top context.
+      //
+      // Note that we must declare the foo upon entry of eval(), via a
+      // context slot declaration, but we cannot initialize it at the same
+      // time, because the const declaration may be at the end of the eval
+      // code (sigh...) and the const variable may have been used before
+      // (where its value is 'undefined'). Thus, we can only do the
+      // initialization when we actually encounter the expression and when
+      // the expression operands are defined and valid, and thus we need the
+      // split into 2 operations: declaration of the context slot followed
+      // by initialization.
+      masm->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+    } else {
+      masm->CallRuntime(Runtime::kStoreContextSlot, 3);
+    }
+    // Storing a variable must keep the (new) value on the expression
+    // stack. This is necessary for compiling assignment expressions.
+    masm->push(r0);
+
+  } else {
+    ASSERT(var()->mode() != Variable::DYNAMIC);
+
+    Label exit;
+    if (init_state == CONST_INIT) {
+      ASSERT(var()->mode() == Variable::CONST);
+      // Only the first const initialization must be executed (the slot
+      // still contains 'the hole' value). When the assignment is executed,
+      // the code is identical to a normal store (see below).
+      Comment cmnt(masm, "[ Init const");
+      masm->ldr(r2, ArmCodeGenerator::SlotOperand(masm, scope, this, r2));
+      masm->cmp(r2, Operand(Factory::the_hole_value()));
+      masm->b(ne, &exit);
+    }
+
+    // We must execute the store.
+    // r2 may be loaded with context; used below in RecordWrite.
+    // Storing a variable must keep the (new) value on the stack. This is
+    // necessary for compiling assignment expressions.
+    //
+    // Note: We will reach here even with var()->mode() == Variable::CONST
+    // because of const declarations which will initialize consts to 'the
+    // hole' value and by doing so, end up calling this code.  r2 may be
+    // loaded with context; used below in RecordWrite.
+    masm->pop(r0);
+    masm->str(r0, ArmCodeGenerator::SlotOperand(masm, scope, this, r2));
+    masm->push(r0);
+
+    if (type() == Slot::CONTEXT) {
+      // Skip write barrier if the written value is a smi.
+      masm->tst(r0, Operand(kSmiTagMask));
+      masm->b(eq, &exit);
+      // r2 is loaded with context when calling SlotOperand above.
+      int offset = FixedArray::kHeaderSize + index() * kPointerSize;
+      masm->mov(r3, Operand(offset));
+      masm->RecordWrite(r2, r3, r1);
+    }
+    masm->bind(&exit);
+  }
+}
+
+
 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given
 // register to a boolean in the condition code register. The code
 // may jump to 'false_target' in case the register converts to 'false'.
@@ -1836,42 +1988,29 @@ void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
 #define __  masm_->
 
 
-void ArmCodeGenerator::AccessReferenceProperty(
-    Expression* key,
-    CodeGenState::AccessType access) {
+void ArmCodeGenerator::GetReferenceProperty(Expression* key) {
+  ASSERT(!ref()->is_illegal());
   Reference::Type type = ref()->type();
-  ASSERT(type != Reference::ILLEGAL);
-
-  // TODO(1241834): Make sure that this is sufficient. If there is a chance
-  // that reference errors can be thrown below, we must distinguish
-  // between the 2 kinds of loads (typeof expression loads must not
-  // throw a reference error).
-  bool is_load = (access == CodeGenState::LOAD ||
-                  access == CodeGenState::LOAD_TYPEOF_EXPR);
 
+  // TODO(1241834): Make sure that this it is safe to ignore the distinction
+  // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance
+  // that reference errors can be thrown below, we must distinguish between
+  // the two kinds of loads (typeof expression loads must not throw a
+  // reference error).
   if (type == Reference::NAMED) {
     // Compute the name of the property.
     Literal* literal = key->AsLiteral();
     Handle<String> name(String::cast(*literal->handle()));
 
     // Call the appropriate IC code.
-    if (is_load) {
-      // Setup the name register.
-      __ mov(r2, Operand(name));
-      Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
-      Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
-      if (var != NULL) {
-        ASSERT(var->is_global());
-        __ Call(ic, code_target_context);
-      } else {
-        __ Call(ic, code_target);
-      }
-
+    // Setup the name register.
+    __ mov(r2, Operand(name));
+    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+    Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
+    if (var != NULL) {
+      ASSERT(var->is_global());
+      __ Call(ic, code_target_context);
     } else {
-      __ pop(r0);  // value
-      // Setup the name register.
-      __ mov(r2, Operand(name));
-      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
       __ Call(ic, code_target);
     }
 
@@ -1879,21 +2018,44 @@ void ArmCodeGenerator::AccessReferenceProperty(
     // Access keyed property.
     ASSERT(type == Reference::KEYED);
 
-    if (is_load) {
-      // TODO(1224671): Implement inline caching for keyed loads as on ia32.
-      GetPropertyStub stub;
-      __ CallStub(&stub);
-
-    } else {
-      __ pop(r0);  // value
-      SetPropertyStub stub;
-      __ CallStub(&stub);
-    }
+    // TODO(1224671): Implement inline caching for keyed loads as on ia32.
+    GetPropertyStub stub;
+    __ CallStub(&stub);
   }
   __ push(r0);
 }
 
 
+void ArmCodeGenerator::SetReferenceProperty(MacroAssembler* masm,
+                                            Reference* ref,
+                                            Expression* key) {
+  ASSERT(!ref->is_illegal());
+  Reference::Type type = ref->type();
+
+  if (type == Reference::NAMED) {
+    // Compute the name of the property.
+    Literal* literal = key->AsLiteral();
+    Handle<String> name(String::cast(*literal->handle()));
+
+    // Call the appropriate IC code.
+    masm->pop(r0);  // value
+    // Setup the name register.
+    masm->mov(r2, Operand(name));
+    Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+    masm->Call(ic, code_target);
+
+  } else {
+    // Access keyed property.
+    ASSERT(type == Reference::KEYED);
+
+    masm->pop(r0);  // value
+    SetPropertyStub stub;
+    masm->CallStub(&stub);
+  }
+  masm->push(r0);
+}
+
+
 void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) {
   // sp[0] : y
   // sp[1] : x
@@ -3116,6 +3278,7 @@ void ArmCodeGenerator::VisitConditional(Conditional* node) {
 
 
 void ArmCodeGenerator::VisitSlot(Slot* node) {
+  ASSERT(access() != CodeGenState::UNDEFINED);
   Comment cmnt(masm_, "[ Slot");
 
   if (node->type() == Slot::LOOKUP) {
@@ -3126,161 +3289,54 @@ void ArmCodeGenerator::VisitSlot(Slot* node) {
     __ mov(r0, Operand(node->var()->name()));
     __ push(r0);
 
-    switch (access()) {
-      case CodeGenState::UNDEFINED:
-        UNREACHABLE();
-        break;
-
-      case CodeGenState::LOAD:
-        __ CallRuntime(Runtime::kLoadContextSlot, 2);
-        __ push(r0);
-        break;
-
-      case CodeGenState::LOAD_TYPEOF_EXPR:
-        __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
-        __ push(r0);
-        break;
-
-      case CodeGenState::STORE:
-        // Storing a variable must keep the (new) value on the stack. This
-        // is necessary for compiling assignment expressions.
-        __ CallRuntime(Runtime::kStoreContextSlot, 3);
-        __ push(r0);
-        // result (TOS) is the value that was stored
-        break;
-
-      case CodeGenState::INIT_CONST:
-        // Same as STORE but ignores attribute (e.g. READ_ONLY) of
-        // context slot so that we can initialize const properties
-        // (introduced via eval("const foo = (some expr);")). Also,
-        // uses the current function context instead of the top
-        // context.
-        //
-        // Note that we must declare the foo upon entry of eval(),
-        // via a context slot declaration, but we cannot initialize
-        // it at the same time, because the const declaration may
-        // be at the end of the eval code (sigh...) and the const
-        // variable may have been used before (where its value is
-        // 'undefined'). Thus, we can only do the initialization
-        // when we actually encounter the expression and when the
-        // expression operands are defined and valid, and thus we
-        // need the split into 2 operations: declaration of the
-        // context slot followed by initialization.
-        __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
-        __ push(r0);
-        break;
+    if (access() == CodeGenState::LOAD) {
+      __ CallRuntime(Runtime::kLoadContextSlot, 2);
+    } else {
+      ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR);
+      __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
     }
+    __ push(r0);
 
   } else {
-    // Note: We would like to keep the assert below, but it fires because
-    // of some nasty code in LoadTypeofExpression() which should be removed...
+    // Note: We would like to keep the assert below, but it fires because of
+    // some nasty code in LoadTypeofExpression() which should be removed...
     // ASSERT(node->var()->mode() != Variable::DYNAMIC);
 
-    switch (access()) {
-      case CodeGenState::UNDEFINED:
-        UNREACHABLE();
-        break;
-
-      case CodeGenState::LOAD:  // fall through
-      case CodeGenState::LOAD_TYPEOF_EXPR:
-        // Special handling for locals allocated in registers.
-        __ ldr(r0, SlotOperand(node, r2));
-        __ push(r0);
-        if (node->var()->mode() == Variable::CONST) {
-          // Const slots may contain 'the hole' value (the constant hasn't
-          // been initialized yet) which needs to be converted into the
-          // 'undefined' value.
-          Comment cmnt(masm_, "[ Unhole const");
-          __ pop(r0);
-          __ cmp(r0, Operand(Factory::the_hole_value()));
-          __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
-          __ push(r0);
-        }
-        break;
-
-      case CodeGenState::INIT_CONST: {
-        ASSERT(node->var()->mode() == Variable::CONST);
-        // Only the first const initialization must be executed (the slot
-        // still contains 'the hole' value). When the assignment is executed,
-        // the code is identical to a normal store (see below).
-        { Comment cmnt(masm_, "[ Init const");
-          Label L;
-          __ ldr(r2, SlotOperand(node, r2));
-          __ cmp(r2, Operand(Factory::the_hole_value()));
-          __ b(ne, &L);
-          // We must execute the store.
-          // r2 may be loaded with context; used below in RecordWrite.
-          __ ldr(r0, MemOperand(sp, 0));
-          __ str(r0, SlotOperand(node, r2));
-          if (node->type() == Slot::CONTEXT) {
-            // Skip write barrier if the written value is a smi.
-            Label exit;
-            __ tst(r0, Operand(kSmiTagMask));
-            __ b(eq, &exit);
-            // r2 is loaded with context when calling SlotOperand above.
-            int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
-            __ mov(r3, Operand(offset));
-            __ RecordWrite(r2, r3, r1);
-            __ bind(&exit);
-          }
-          __ bind(&L);
-        }
-        break;
-      }
-
-      case CodeGenState::STORE: {
-        // Storing a variable must keep the (new) value on the stack. This
-        // is necessary for compiling assignment expressions.
-        // Special handling for locals allocated in registers.
-        //
-        // Note: We will reach here even with node->var()->mode() ==
-        // Variable::CONST because of const declarations which will
-        // initialize consts to 'the hole' value and by doing so, end
-        // up calling this code.
-        // r2 may be loaded with context; used below in RecordWrite.
-        __ pop(r0);
-        __ str(r0, SlotOperand(node, r2));
-        __ push(r0);
-        if (node->type() == Slot::CONTEXT) {
-          // Skip write barrier if the written value is a smi.
-          Label exit;
-          __ tst(r0, Operand(kSmiTagMask));
-          __ b(eq, &exit);
-          // r2 is loaded with context when calling SlotOperand above.
-          int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
-          __ mov(r3, Operand(offset));
-          __ RecordWrite(r2, r3, r1);
-          __ bind(&exit);
-        }
-        break;
-      }
+    // Special handling for locals allocated in registers.
+    __ ldr(r0, SlotOperand(node, r2));
+    __ push(r0);
+    if (node->var()->mode() == Variable::CONST) {
+      // Const slots may contain 'the hole' value (the constant hasn't been
+      // initialized yet) which needs to be converted into the 'undefined'
+      // value.
+      Comment cmnt(masm_, "[ Unhole const");
+      __ pop(r0);
+      __ cmp(r0, Operand(Factory::the_hole_value()));
+      __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
+      __ push(r0);
     }
   }
 }
 
 
-void ArmCodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) {
+void ArmCodeGenerator::VisitVariableProxy(VariableProxy* node) {
   Comment cmnt(masm_, "[ VariableProxy");
-  Variable* node = proxy_node->var();
-
-  Expression* x = node->rewrite();
-  if (x != NULL) {
-    Visit(x);
-    return;
-  }
-
-  ASSERT(node->is_global());
-  if (is_referenced()) {
-    if (node->AsProperty() != NULL) {
-      __ RecordPosition(node->AsProperty()->position());
-    }
-    AccessReferenceProperty(new Literal(node->name()), access());
+  Variable* var_node = node->var();
 
+  Expression* expr = var_node->rewrite();
+  if (expr != NULL) {
+    Visit(expr);
   } else {
-    // All stores are through references.
-    ASSERT(access() != CodeGenState::STORE);
-    Reference property(this, proxy_node);
-    GetValue(&property);
+    ASSERT(var_node->is_global());
+    if (is_referenced()) {
+      if (var_node->AsProperty() != NULL) {
+        __ RecordPosition(var_node->AsProperty()->position());
+      }
+      GetReferenceProperty(new Literal(var_node->name()));
+    } else {
+      Reference property(this, node);
+      GetValue(&property);
+    }
   }
 }
 
@@ -3541,13 +3597,11 @@ void ArmCodeGenerator::VisitThrow(Throw* node) {
 
 void ArmCodeGenerator::VisitProperty(Property* node) {
   Comment cmnt(masm_, "[ Property");
+
   if (is_referenced()) {
     __ RecordPosition(node->position());
-    AccessReferenceProperty(node->key(), access());
-
+    GetReferenceProperty(node->key());
   } else {
-    // All stores are through references.
-    ASSERT(access() != CodeGenState::STORE);
     Reference property(this, node);
     __ RecordPosition(node->position());
     GetValue(&property);
index 52f5a4e..786aa41 100644 (file)
@@ -115,9 +115,7 @@ class CodeGenState BASE_EMBEDDED {
   enum AccessType {
     UNDEFINED,
     LOAD,
-    LOAD_TYPEOF_EXPR,
-    STORE,
-    INIT_CONST
+    LOAD_TYPEOF_EXPR
   };
 
   CodeGenState()
@@ -187,7 +185,6 @@ class Ia32CodeGenerator: public CodeGenerator {
   // The following are used by class Reference.
   void LoadReference(Reference* ref);
   void UnloadReference(Reference* ref);
-  friend class Reference;
 
   // State
   bool has_cc() const  { return cc_reg_ >= 0; }
@@ -198,26 +195,39 @@ class Ia32CodeGenerator: public CodeGenerator {
   Label* false_target() const  { return state_->false_target(); }
 
   // Expressions
-  Operand GlobalObject() const  {
+  Operand GlobalObject() const {
     return ContextOperand(esi, Context::GLOBAL_INDEX);
   }
 
-  // Support functions for accessing parameters.
+  // Support functions for accessing parameters.  Static versions can
+  // require some code generator state to be passed in as arguments.
+  static Operand ParameterOperand(Scope* scope, int index) {
+    ASSERT(-2 <= index && index < scope->num_parameters());
+    return Operand(ebp, (1 + scope->num_parameters() - index) * kPointerSize);
+  }
+
   Operand ParameterOperand(int index) const {
-    ASSERT(-2 <= index && index < scope_->num_parameters());
-    return Operand(ebp, (1 + scope_->num_parameters() - index) * kPointerSize);
+    return ParameterOperand(scope_, index);
   }
 
   Operand ReceiverOperand() const { return ParameterOperand(-1); }
+
   Operand FunctionOperand() const {
     return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset);
   }
 
-  Operand ContextOperand(Register context, int index) const {
+  static Operand ContextOperand(Register context, int index) {
     return Operand(context, Context::SlotOffset(index));
   }
 
-  Operand SlotOperand(Slot* slot, Register tmp);
+  static Operand SlotOperand(MacroAssembler* masm,
+                             Scope* scope,
+                             Slot* slot,
+                             Register tmp);
+
+  Operand SlotOperand(Slot* slot, Register tmp) {
+    return SlotOperand(masm_, scope_, slot, tmp);
+  }
 
   void LoadCondition(Expression* x,
                      CodeGenState::AccessType access,
@@ -237,20 +247,42 @@ class Ia32CodeGenerator: public CodeGenerator {
   void LoadTypeofExpression(Expression* x);
 
   // References
-  void AccessReference(Reference* ref, CodeGenState::AccessType access);
 
-  void GetValue(Reference* ref) { AccessReference(ref, CodeGenState::LOAD); }
-  void SetValue(Reference* ref) { AccessReference(ref, CodeGenState::STORE); }
+  // Generate code to fetch the value of a reference.  The reference is
+  // expected to be on top of the expression stack.  It is left in place and
+  // its value is pushed on top of it.
+  void GetValue(Reference* ref);
+
+  // Generate code to store a value in a reference.  The stored value is
+  // expected on top of the expression stack, with the reference immediately
+  // below it.  The expression stack is left unchanged.
+  void SetValue(Reference* ref) {
+    ASSERT(!has_cc());
+    ASSERT(!ref->is_illegal());
+    ref->expression()->GenerateStoreCode(masm_, scope_, ref, NOT_CONST_INIT);
+  }
+
+  // Same as SetValue, used to set the initial value of a constant.
   void InitConst(Reference* ref) {
-    AccessReference(ref, CodeGenState::INIT_CONST);
+    ASSERT(!has_cc());
+    ASSERT(!ref->is_illegal());
+    ref->expression()->GenerateStoreCode(masm_, scope_, ref, CONST_INIT);
   }
 
-  void ToBoolean(Label* true_target, Label* false_target);
+  // Generate code to fetch a value from a property of a reference.  The
+  // reference is expected on top of the expression stack.  It is left in
+  // place and its value is pushed on top of it.
+  void GetReferenceProperty(Expression* key);
 
+  // Generate code to store a value in a property of a reference.  The
+  // stored value is expected on top of the expression stack, with the
+  // reference immediately below it.  The expression stack is left
+  // unchanged.
+  static void SetReferenceProperty(MacroAssembler* masm,
+                                   Reference* ref,
+                                   Expression* key);
 
-  // Access property from the reference (must be at the TOS).
-  void AccessReferenceProperty(Expression* key,
-                               CodeGenState::AccessType access);
+  void ToBoolean(Label* true_target, Label* false_target);
 
   void GenericBinaryOperation(
       Token::Value op,
@@ -316,6 +348,11 @@ class Ia32CodeGenerator: public CodeGenerator {
   virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args);
 
   virtual void GenerateObjectEquals(ZoneList<Expression*>* args);
+
+  friend class Reference;
+  friend class Property;
+  friend class VariableProxy;
+  friend class Slot;
 };
 
 
@@ -633,7 +670,10 @@ void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) {
 }
 
 
-Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
+Operand Ia32CodeGenerator::SlotOperand(MacroAssembler* masm,
+                                       Scope* scope,
+                                       Slot* slot,
+                                       Register tmp) {
   // Currently, this assertion will fail if we try to assign to
   // a constant variable that is constant because it is read-only
   // (such as the variable referring to a named function expression).
@@ -645,10 +685,10 @@ Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
   ASSERT(slot != NULL);
   int index = slot->index();
   switch (slot->type()) {
-    case Slot::PARAMETER: return ParameterOperand(index);
+    case Slot::PARAMETER: return ParameterOperand(scope, index);
 
     case Slot::LOCAL: {
-      ASSERT(0 <= index && index < scope_->num_stack_slots());
+      ASSERT(0 <= index && index < scope->num_stack_slots());
       const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
       return Operand(ebp, kLocal0Offset - index * kPointerSize);
     }
@@ -657,15 +697,15 @@ Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
       // Follow the context chain if necessary.
       ASSERT(!tmp.is(esi));  // do not overwrite context register
       Register context = esi;
-      int chain_length = scope_->ContextChainLength(slot->var()->scope());
+      int chain_length = scope->ContextChainLength(slot->var()->scope());
       for (int i = chain_length; i-- > 0;) {
         // Load the closure.
         // (All contexts, even 'with' contexts, have a closure,
         // and it is the same for all contexts inside a function.
         // There is no need to go to the function context first.)
-        __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
+        masm->mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
         // Load the function context (which is the incoming, outer context).
-        __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
+        masm->mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
         context = tmp;
       }
       // We may have a 'with' context now. Get the function context.
@@ -675,7 +715,7 @@ Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
       // cause the function context of a function context is itself. Before
       // deleting this mov we should try to create a counter-example first,
       // though...)
-      __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
+      masm->mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
       return ContextOperand(tmp, index);
     }
 
@@ -852,18 +892,123 @@ void Ia32CodeGenerator::UnloadReference(Reference* ref) {
 }
 
 
-void Ia32CodeGenerator::AccessReference(Reference* ref,
-                                        CodeGenState::AccessType access) {
+void Ia32CodeGenerator::GetValue(Reference* ref) {
   ASSERT(!has_cc());
   ASSERT(ref->type() != Reference::ILLEGAL);
   CodeGenState* old_state = state_;
-  CodeGenState new_state(access, ref, true_target(), false_target());
+  CodeGenState new_state(CodeGenState::LOAD, ref, true_target(),
+                         false_target());
   state_ = &new_state;
   Visit(ref->expression());
   state_ = old_state;
 }
 
 
+void Property::GenerateStoreCode(MacroAssembler* masm,
+                                 Scope* scope,
+                                 Reference* ref,
+                                 InitState init_state) {
+  Comment cmnt(masm, "[ Store to Property");
+  masm->RecordPosition(position());
+  Ia32CodeGenerator::SetReferenceProperty(masm, ref, key());
+}
+
+
+void VariableProxy::GenerateStoreCode(MacroAssembler* masm,
+                                      Scope* scope,
+                                      Reference* ref,
+                                      InitState init_state) {
+
+  Comment cmnt(masm, "[ Store to VariableProxy");
+  Variable* node = var();
+
+  Expression* expr = node->rewrite();
+  if (expr != NULL) {
+    expr->GenerateStoreCode(masm, scope, ref, init_state);
+  } else {
+    ASSERT(node->is_global());
+    if (node->AsProperty() != NULL) {
+      masm->RecordPosition(node->AsProperty()->position());
+    }
+    Ia32CodeGenerator::SetReferenceProperty(masm, ref,
+                                            new Literal(node->name()));
+  }
+}
+
+
+void Slot::GenerateStoreCode(MacroAssembler* masm,
+                             Scope* scope,
+                             Reference* ref,
+                             InitState init_state) {
+  Comment cmnt(masm, "[ Store to Slot");
+
+  if (type() == Slot::LOOKUP) {
+    ASSERT(var()->mode() == Variable::DYNAMIC);
+
+    // For now, just do a runtime call.
+    masm->push(Operand(esi));
+    masm->push(Immediate(var()->name()));
+
+    if (init_state == CONST_INIT) {
+      // Same as the case for a normal store, but ignores attribute
+      // (e.g. READ_ONLY) of context slot so that we can initialize const
+      // properties (introduced via eval("const foo = (some expr);")). Also,
+      // uses the current function context instead of the top context.
+      //
+      // Note that we must declare the foo upon entry of eval(), via a
+      // context slot declaration, but we cannot initialize it at the same
+      // time, because the const declaration may be at the end of the eval
+      // code (sigh...) and the const variable may have been used before
+      // (where its value is 'undefined'). Thus, we can only do the
+      // initialization when we actually encounter the expression and when
+      // the expression operands are defined and valid, and thus we need the
+      // split into 2 operations: declaration of the context slot followed
+      // by initialization.
+      masm->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+    } else {
+      masm->CallRuntime(Runtime::kStoreContextSlot, 3);
+    }
+    // Storing a variable must keep the (new) value on the expression
+    // stack. This is necessary for compiling assignment expressions.
+    masm->push(eax);
+
+  } else {
+    ASSERT(var()->mode() != Variable::DYNAMIC);
+
+    Label exit;
+    if (init_state == CONST_INIT) {
+      ASSERT(var()->mode() == Variable::CONST);
+      // Only the first const initialization must be executed (the slot
+      // still contains 'the hole' value). When the assignment is executed,
+      // the code is identical to a normal store (see below).
+      Comment cmnt(masm, "[ Init const");
+      masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx));
+      masm->cmp(eax, Factory::the_hole_value());
+      masm->j(not_equal, &exit);
+    }
+
+    // We must execute the store.
+    // Storing a variable must keep the (new) value on the stack. This is
+    // necessary for compiling assignment expressions.  ecx may be loaded
+    // with context; used below in RecordWrite.
+    //
+    // Note: We will reach here even with node->var()->mode() ==
+    // Variable::CONST because of const declarations which will initialize
+    // consts to 'the hole' value and by doing so, end up calling this
+    // code.
+    masm->pop(eax);
+    masm->mov(Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx), eax);
+    masm->push(eax);  // RecordWrite may destroy the value in eax.
+    if (type() == Slot::CONTEXT) {
+      // ecx is loaded with context when calling SlotOperand above.
+      int offset = FixedArray::kHeaderSize + index() * kPointerSize;
+      masm->RecordWrite(ecx, offset, eax, ebx);
+    }
+    masm->bind(&exit);
+  }
+}
+
+
 #undef __
 #define __  masm->
 
@@ -991,63 +1136,41 @@ void Ia32CodeGenerator::ToBoolean(Label* true_target, Label* false_target) {
 }
 
 
-void Ia32CodeGenerator::AccessReferenceProperty(
-    Expression* key,
-    CodeGenState::AccessType access) {
+void Ia32CodeGenerator::GetReferenceProperty(Expression* key) {
+  ASSERT(!ref()->is_illegal());
   Reference::Type type = ref()->type();
-  ASSERT(type != Reference::ILLEGAL);
-
-  // TODO(1241834): Make sure that this is sufficient. If there is a chance
-  // that reference errors can be thrown below, we must distinguish
-  // between the 2 kinds of loads (typeof expression loads must not
-  // throw a reference error).
-  bool is_load = (access == CodeGenState::LOAD ||
-                  access == CodeGenState::LOAD_TYPEOF_EXPR);
 
+  // TODO(1241834): Make sure that this it is safe to ignore the distinction
+  // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance
+  // that reference errors can be thrown below, we must distinguish between
+  // the two kinds of loads (typeof expression loads must not throw a
+  // reference error).
   if (type == Reference::NAMED) {
     // Compute the name of the property.
     Literal* literal = key->AsLiteral();
     Handle<String> name(String::cast(*literal->handle()));
 
-    // Call the appropriate IC code.
-    if (is_load) {
-      Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
-      Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
-      // Setup the name register.
-      __ Set(ecx, Immediate(name));
-      if (var != NULL) {
-        ASSERT(var->is_global());
-        __ call(ic, code_target_context);
-      } else {
-        __ call(ic, code_target);
-      }
+    Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
+    Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
+    // Setup the name register.
+    __ Set(ecx, Immediate(name));
+    if (var != NULL) {
+      ASSERT(var->is_global());
+      __ call(ic, code_target_context);
     } else {
-      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
-      // TODO(1222589): Make the IC grab the values from the stack.
-      __ pop(eax);
-      // Setup the name register.
-      __ Set(ecx, Immediate(name));
       __ call(ic, code_target);
     }
   } else {
     // Access keyed property.
     ASSERT(type == Reference::KEYED);
 
-    if (is_load) {
-      // Call IC code.
-      Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
-      Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
-      if (var != NULL) {
-        ASSERT(var->is_global());
-        __ call(ic, code_target_context);
-      } else {
-        __ call(ic, code_target);
-      }
+    // Call IC code.
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+    Variable* var = ref()->expression()->AsVariableProxy()->AsVariable();
+    if (var != NULL) {
+      ASSERT(var->is_global());
+      __ call(ic, code_target_context);
     } else {
-      // Call IC code.
-      Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
-      // TODO(1222589): Make the IC grab the values from the stack.
-      __ pop(eax);
       __ call(ic, code_target);
     }
   }
@@ -1055,6 +1178,38 @@ void Ia32CodeGenerator::AccessReferenceProperty(
 }
 
 
+void Ia32CodeGenerator::SetReferenceProperty(MacroAssembler* masm,
+                                             Reference* ref,
+                                             Expression* key) {
+  ASSERT(!ref->is_illegal());
+  Reference::Type type = ref->type();
+
+  if (type == Reference::NAMED) {
+    // Compute the name of the property.
+    Literal* literal = key->AsLiteral();
+    Handle<String> name(String::cast(*literal->handle()));
+
+    // Call the appropriate IC code.
+    Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+    // TODO(1222589): Make the IC grab the values from the stack.
+    masm->pop(eax);
+    // Setup the name register.
+    masm->Set(ecx, Immediate(name));
+    masm->call(ic, code_target);
+  } else {
+    // Access keyed property.
+    ASSERT(type == Reference::KEYED);
+
+    // Call IC code.
+    Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+    // TODO(1222589): Make the IC grab the values from the stack.
+    masm->pop(eax);
+    masm->call(ic, code_target);
+  }
+  masm->push(eax);  // IC call leaves result in eax, push it out
+}
+
+
 #undef __
 #define __  masm->
 
@@ -3325,6 +3480,7 @@ void Ia32CodeGenerator::VisitConditional(Conditional* node) {
 
 
 void Ia32CodeGenerator::VisitSlot(Slot* node) {
+  ASSERT(access() != CodeGenState::UNDEFINED);
   Comment cmnt(masm_, "[ Slot");
 
   if (node->type() == Slot::LOOKUP) {
@@ -3334,151 +3490,56 @@ void Ia32CodeGenerator::VisitSlot(Slot* node) {
     __ push(Operand(esi));
     __ push(Immediate(node->var()->name()));
 
-    switch (access()) {
-      case CodeGenState::UNDEFINED:
-        UNREACHABLE();
-        break;
-
-      case CodeGenState::LOAD:
-        __ CallRuntime(Runtime::kLoadContextSlot, 2);
-        __ push(eax);
-        // result (TOS) is the value that was loaded
-        break;
-
-      case CodeGenState::LOAD_TYPEOF_EXPR:
-        __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
-        __ push(eax);
-        // result (TOS) is the value that was loaded
-        break;
-
-      case CodeGenState::STORE:
-        // Storing a variable must keep the (new) value on the
-        // stack. This is necessary for compiling assignment
-        // expressions.
-        __ CallRuntime(Runtime::kStoreContextSlot, 3);
-        __ push(eax);
-        // result (TOS) is the value that was stored
-        break;
-
-      case CodeGenState::INIT_CONST:
-        // Same as STORE but ignores attribute (e.g. READ_ONLY) of
-        // context slot so that we can initialize const properties
-        // (introduced via eval("const foo = (some expr);")). Also,
-        // uses the current function context instead of the top
-        // context.
-        //
-        // Note that we must declare the foo upon entry of eval(),
-        // via a context slot declaration, but we cannot initialize
-        // it at the same time, because the const declaration may
-        // be at the end of the eval code (sigh...) and the const
-        // variable may have been used before (where its value is
-        // 'undefined'). Thus, we can only do the initialization
-        // when we actually encounter the expression and when the
-        // expression operands are defined and valid, and thus we
-        // need the split into 2 operations: declaration of the
-        // context slot followed by initialization.
-        //
-        __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
-        __ push(eax);
-        break;
+    if (access() == CodeGenState::LOAD) {
+      __ CallRuntime(Runtime::kLoadContextSlot, 2);
+    } else {
+      ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR);
+      __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
     }
+    __ push(eax);
 
   } else {
-    // Note: We would like to keep the assert below, but it fires because
-    // of some nasty code in LoadTypeofExpression() which should be removed...
+    // Note: We would like to keep the assert below, but it fires because of
+    // some nasty code in LoadTypeofExpression() which should be removed...
     // ASSERT(node->var()->mode() != Variable::DYNAMIC);
 
-    switch (access()) {
-      case CodeGenState::UNDEFINED:
-        UNREACHABLE();
-        break;
-
-      case CodeGenState::LOAD:  // fall through
-      case CodeGenState::LOAD_TYPEOF_EXPR:
-        if (node->var()->mode() == Variable::CONST) {
-          // Const slots may contain 'the hole' value (the constant hasn't
-          // been initialized yet) which needs to be converted into the
-          // 'undefined' value.
-          Comment cmnt(masm_, "[ Load const");
-          Label L;
-          __ mov(eax, SlotOperand(node, ecx));
-          __ cmp(eax, Factory::the_hole_value());
-          __ j(not_equal, &L);
-          __ mov(eax, Factory::undefined_value());
-          __ bind(&L);
-          __ push(eax);
-        } else {
-          __ push(SlotOperand(node, ecx));
-        }
-        break;
-
-      case CodeGenState::INIT_CONST:
-        ASSERT(node->var()->mode() == Variable::CONST);
-        // Only the first const initialization must be executed (the slot
-        // still contains 'the hole' value). When the assignment is executed,
-        // the code is identical to a normal store (see below).
-        { Comment cmnt(masm_, "[ Init const");
-          Label L;
-          __ mov(eax, SlotOperand(node, ecx));
-          __ cmp(eax, Factory::the_hole_value());
-          __ j(not_equal, &L);
-          // We must execute the store.
-          __ mov(eax, TOS);
-          __ mov(SlotOperand(node, ecx), eax);
-          if (node->type() == Slot::CONTEXT) {
-            // ecx is loaded with context when calling SlotOperand above.
-            int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
-            __ RecordWrite(ecx, offset, eax, ebx);
-          }
-          __ bind(&L);
-        }
-        break;
-
-      case CodeGenState::STORE:
-        // Storing a variable must keep the (new) value on the stack. This
-        // is necessary for compiling assignment expressions.
-        // ecx may be loaded with context; used below in RecordWrite.
-        //
-        // Note: We will reach here even with node->var()->mode() ==
-        // Variable::CONST because of const declarations which will
-        // initialize consts to 'the hole' value and by doing so, end
-        // up calling this code.
-        __ pop(eax);
-        __ mov(SlotOperand(node, ecx), eax);
-        __ push(eax);  // RecordWrite may destroy the value in eax.
-        if (node->type() == Slot::CONTEXT) {
-          // ecx is loaded with context when calling SlotOperand above.
-          int offset = FixedArray::kHeaderSize + node->index() * kPointerSize;
-          __ RecordWrite(ecx, offset, eax, ebx);
-        }
-        break;
+    if (node->var()->mode() == Variable::CONST) {
+      // Const slots may contain 'the hole' value (the constant hasn't been
+      // initialized yet) which needs to be converted into the 'undefined'
+      // value.
+      Comment cmnt(masm_, "[ Load const");
+      Label L;
+      __ mov(eax, SlotOperand(node, ecx));
+      __ cmp(eax, Factory::the_hole_value());
+      __ j(not_equal, &L);
+      __ mov(eax, Factory::undefined_value());
+      __ bind(&L);
+      __ push(eax);
+    } else {
+      __ push(SlotOperand(node, ecx));
     }
   }
 }
 
 
-void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) {
+void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) {
   Comment cmnt(masm_, "[ VariableProxy");
-  Variable* node = proxy_node->var();
-
-  Expression* x = node->rewrite();
-  if (x != NULL) {
-    Visit(x);
-    return;
-  }
-
-  ASSERT(node->is_global());
-  if (is_referenced()) {
-    if (node->AsProperty() != NULL) {
-      __ RecordPosition(node->AsProperty()->position());
-    }
-    AccessReferenceProperty(new Literal(node->name()), access());
+  Variable* var_node = node->var();
 
+  Expression* expr = var_node->rewrite();
+  if (expr != NULL) {
+    Visit(expr);
   } else {
-    // All stores are through references.
-    ASSERT(access() != CodeGenState::STORE);
-    Reference property(this, proxy_node);
-    GetValue(&property);
+    ASSERT(var_node->is_global());
+    if (is_referenced()) {
+      if (var_node->AsProperty() != NULL) {
+        __ RecordPosition(var_node->AsProperty()->position());
+      }
+      GetReferenceProperty(new Literal(var_node->name()));
+    } else {
+      Reference property(this, node);
+      GetValue(&property);
+    }
   }
 }
 
@@ -3784,10 +3845,8 @@ void Ia32CodeGenerator::VisitProperty(Property* node) {
 
   if (is_referenced()) {
     __ RecordPosition(node->position());
-    AccessReferenceProperty(node->key(), access());
+    GetReferenceProperty(node->key());
   } else {
-    // All stores are through references.
-    ASSERT(access() != CodeGenState::STORE);
     Reference property(this, node);
     __ RecordPosition(node->position());
     GetValue(&property);