Author: [EMAIL PROTECTED]
Date: Thu Sep 11 01:44:32 2008
New Revision: 265

Modified:
    branches/bleeding_edge/src/ast.h
    branches/bleeding_edge/src/codegen-arm.cc
    branches/bleeding_edge/src/codegen-ia32.cc

Log:
Remove some of the state-dependent behavior from the code generator.
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

Modified: branches/bleeding_edge/src/ast.h
==============================================================================
--- branches/bleeding_edge/src/ast.h    (original)
+++ branches/bleeding_edge/src/ast.h    Thu Sep 11 01:44:32 2008
@@ -140,6 +140,9 @@
  };


+class Reference;
+enum InitState { CONST_INIT, NOT_CONST_INIT };
+
  class Expression: public Node {
   public:
    virtual Expression* AsExpression()  { return this; }
@@ -150,6 +153,18 @@
    // 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 @@
    // 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 @@
    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 @@
    // 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_;

Modified: branches/bleeding_edge/src/codegen-arm.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.cc   (original)
+++ branches/bleeding_edge/src/codegen-arm.cc   Thu Sep 11 01:44:32 2008
@@ -109,9 +109,7 @@
    enum AccessType {
      UNDEFINED,
      LOAD,
-    LOAD_TYPEOF_EXPR,
-    STORE,
-    INIT_CONST
+    LOAD_TYPEOF_EXPR
    };

    CodeGenState()
@@ -181,7 +179,6 @@
    // 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 @@
      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 @@
    // 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);
-  }
+  // References

-  void ToBoolean(Label* true_target, Label* false_target);
+  // 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);
+  }
+
+  // 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);
+
+  // 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);
    void Comparison(Condition cc, bool strict = false);
@@ -297,6 +331,11 @@
    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 @@
  }


-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 @@
    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 @@
        // 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 @@
        // 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::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 @@
  #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 @@
      // 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::VisitSlot(Slot* node) {
+  ASSERT(access() != CodeGenState::UNDEFINED);
    Comment cmnt(masm_, "[ Slot");

    if (node->type() == Slot::LOOKUP) {
@@ -3126,161 +3289,54 @@
      __ 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::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);

Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc  (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc  Thu Sep 11 01:44:32 2008
@@ -115,9 +115,7 @@
    enum AccessType {
      UNDEFINED,
      LOAD,
-    LOAD_TYPEOF_EXPR,
-    STORE,
-    INIT_CONST
+    LOAD_TYPEOF_EXPR
    };

    CodeGenState()
@@ -187,7 +185,6 @@
    // 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 @@
    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 @@
    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);
-
+  // Same as SetValue, used to set the initial value of a constant.
+  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);
+
+  // 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 @@
    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 @@
  }


-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 @@
    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 @@
        // 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 @@
        // 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::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::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::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::VisitSlot(Slot* node) {
+  ASSERT(access() != CodeGenState::UNDEFINED);
    Comment cmnt(masm_, "[ Slot");

    if (node->type() == Slot::LOOKUP) {
@@ -3334,151 +3490,56 @@
      __ 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 @@

    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);

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to