Author: [EMAIL PROTECTED]
Date: Tue Oct  7 04:19:44 2008
New Revision: 460

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

Log:
Move code generation for storing to a reference out of the AST nodes, and
onto the platform-specific Reference class defined in codegen-*.cc.  This
removes all of the static code generator functions.
Review URL: http://codereview.chromium.org/6527

Modified: branches/bleeding_edge/src/ast.h
==============================================================================
--- branches/bleeding_edge/src/ast.h    (original)
+++ branches/bleeding_edge/src/ast.h    Tue Oct  7 04:19:44 2008
@@ -140,9 +140,6 @@
  };


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


@@ -758,13 +744,6 @@
    // 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(CodeGenerator* cgen,
-                                 Reference* ref,
-                                 InitState init_state);
   protected:
    Handle<String> name_;
    Variable* var_;  // resolved variable, or NULL
@@ -840,13 +819,6 @@
    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(CodeGenerator* cgen,
-                                 Reference* ref,
-                                 InitState init_state);
   private:
    Variable* var_;
    Type type_;
@@ -874,13 +846,6 @@
    // 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(CodeGenerator* cgen,
-                                 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   Tue Oct  7 04:19:44 2008
@@ -50,6 +50,8 @@
  // For properties, we keep either one (named) or two (indexed) values
  // on the execution stack to represent the reference.

+enum InitState { CONST_INIT, NOT_CONST_INIT };
+
  class Reference BASE_EMBEDDED {
   public:
    // The values of the types is important, see size().
@@ -70,6 +72,8 @@
    bool is_slot() const { return type_ == SLOT; }
    bool is_property() const { return type_ == NAMED || type_ == KEYED; }

+  void SetValue(InitState init_state);
+
   private:
    ArmCodeGenerator* cgen_;
    Expression* expression_;
@@ -80,14 +84,10 @@
  //  
-------------------------------------------------------------------------
  // Code generation state

-// The state is passed down the AST by the code generator.  It is passed
-// implicitly (in a member variable) to the non-static code generator  
member
-// functions, and explicitly (as an argument) to the static member  
functions
-// and the AST node member functions.
-//
-// The state is threaded through the call stack.  Constructing a state
-// implicitly pushes it on the owning code generator's stack of states, and
-// destroying one implicitly pops it.
+// The state is passed down the AST by the code generator (and back up, in
+// the form of the state of the label pair).  It is threaded through the
+// call stack.  Constructing a state implicitly pushes it on the owning  
code
+// generator's stack of states, and destroying one implicitly pops it.

  class CodeGenState BASE_EMBEDDED {
   public:
@@ -190,12 +190,12 @@
      return ContextOperand(cp, Context::GLOBAL_INDEX);
    }

-  static MemOperand ContextOperand(Register context, int index) {
+  MemOperand ContextOperand(Register context, int index) const {
      return MemOperand(context, Context::SlotOffset(index));
    }

-  static MemOperand ParameterOperand(const CodeGenerator* cgen, int index)  
{
-    int num_parameters = cgen->scope()->num_parameters();
+  MemOperand ParameterOperand(int index) const {
+    int num_parameters = scope()->num_parameters();
      // index -2 corresponds to the activated closure, -1 corresponds
      // to the receiver
      ASSERT(-2 <= index && index < num_parameters);
@@ -203,21 +203,11 @@
      return MemOperand(fp, offset);
    }

-  MemOperand ParameterOperand(int index) const {
-    return ParameterOperand(this, index);
-  }
-
    MemOperand FunctionOperand() const {
      return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset);
    }

-  static MemOperand SlotOperand(CodeGenerator* cgen,
-                                Slot* slot,
-                                Register tmp);
-
-  MemOperand SlotOperand(Slot* slot, Register tmp) {
-    return SlotOperand(this, slot, tmp);
-  }
+  MemOperand SlotOperand(Slot* slot, Register tmp);

    void LoadCondition(Expression* x, CodeGenState::AccessType access,
                       Label* true_target, Label* false_target, bool  
force_cc);
@@ -246,38 +236,11 @@
      Visit(ref->expression());
    }

-  // 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(this, 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(this, 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(CodeGenerator* cgen,
-                                   Reference* ref,
-                                   Expression* key);
-
-
    void ToBoolean(Label* true_target, Label* false_target);

    void GenericBinaryOperation(Token::Value op);
@@ -601,9 +564,9 @@
            __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
            __ CallStub(&stub);
            __ push(r0);
-          SetValue(&arguments_ref);
+          arguments_ref.SetValue(NOT_CONST_INIT);
          }
-        SetValue(&shadow_ref);
+        shadow_ref.SetValue(NOT_CONST_INIT);
        }
        __ pop(r0);  // Value is no longer needed.
      }
@@ -685,6 +648,60 @@
  }


+MemOperand ArmCodeGenerator::SlotOperand(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).
+  // We need to implement assignments to read-only variables.
+  // Ideally, we should do this during AST generation (by converting
+  // such assignments into expression statements); however, in general
+  // we may not be able to make the decision until past AST generation,
+  // that is when the entire program is known.
+  ASSERT(slot != NULL);
+  int index = slot->index();
+  switch (slot->type()) {
+    case Slot::PARAMETER:
+      return ParameterOperand(index);
+
+    case Slot::LOCAL: {
+      ASSERT(0 <= index && index < scope()->num_stack_slots());
+      const int kLocalOffset = JavaScriptFrameConstants::kLocal0Offset;
+      return MemOperand(fp, kLocalOffset - index * kPointerSize);
+    }
+
+    case Slot::CONTEXT: {
+      // 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());
+      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));
+        // Load the function context (which is the incoming, outer  
context).
+        __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
+        context = tmp;
+      }
+      // We may have a 'with' context now. Get the function context.
+      // (In fact this mov may never be the needed, since the scope  
analysis
+      // may not permit a direct context access in this case and thus we  
are
+      // always at a function context. However it is safe to dereference  
be-
+      // 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));
+      return ContextOperand(tmp, index);
+    }
+
+    default:
+      UNREACHABLE();
+      return MemOperand(r0, 0);
+  }
+}
+
+
  // Loads a value on the stack. If it is a boolean value, the result may  
have
  // been (partially) translated into branches, or it may have set the  
condition
  // code register. If force_cc is set, the value is forced to set the  
condition
@@ -1469,7 +1486,7 @@
      Reference target(this, node->proxy());
      ASSERT(target.is_slot());
      Load(val);
-    SetValue(&target);
+    target.SetValue(NOT_CONST_INIT);
      // Get rid of the assigned value (declarations are statements).  It's
      // safe to pop the value lying on top of the reference before unloading
      // the reference itself (which preserves the top of stack) because we
@@ -1962,7 +1979,7 @@
        // If the reference was to a slot we rely on the convenient property
        // that it doesn't matter whether a value (eg, r3 pushed above) is
        // right on top of or right underneath a zero-sized reference.
-      SetValue(&each);
+      each.SetValue(NOT_CONST_INIT);
        if (each.size() > 0) {
          // It's safe to pop the value lying on top of the reference before
          // unloading the reference itself (which preserves the top of  
stack,
@@ -2007,7 +2024,7 @@
      // Here we make use of the convenient property that it doesn't matter
      // whether a value is immediately on top of or underneath a zero-sized
      // reference.
-    SetValue(&ref);
+    ref.SetValue(NOT_CONST_INIT);
    }

    // Remove the exception from the stack.
@@ -2564,9 +2581,9 @@
        // Dynamic constant initializations must use the function context
        // and initialize the actual constant declared. Dynamic variable
        // initializations are simply assignments and use SetValue.
-      InitConst(&target);
+      target.SetValue(CONST_INIT);
      } else {
-      SetValue(&target);
+      target.SetValue(NOT_CONST_INIT);
      }
    }
  }
@@ -3130,7 +3147,7 @@
      // Store the new value in the target if not const.
      __ bind(&exit);
      __ push(r0);
-    if (!is_const) SetValue(&target);
+    if (!is_const) target.SetValue(NOT_CONST_INIT);
    }

    // Postfix: Discard the new value and use the old.
@@ -3500,177 +3517,134 @@
  #undef __
  #define __ masm->

-MemOperand ArmCodeGenerator::SlotOperand(CodeGenerator* cgen,
-                                         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).
-  // We need to implement assignments to read-only variables.
-  // Ideally, we should do this during AST generation (by converting
-  // such assignments into expression statements); however, in general
-  // we may not be able to make the decision until past AST generation,
-  // that is when the entire program is known.
-  ASSERT(slot != NULL);
-  int index = slot->index();
-  switch (slot->type()) {
-    case Slot::PARAMETER:
-      return ParameterOperand(cgen, index);
-
-    case Slot::LOCAL: {
-      ASSERT(0 <= index &&
-             index < cgen->scope()->num_stack_slots() &&
-             index >= 0);
-      int local_offset = JavaScriptFrameConstants::kLocal0Offset -
-                         index * kPointerSize;
-      return MemOperand(fp, local_offset);
-    }
-
-    case Slot::CONTEXT: {
-      MacroAssembler* masm = cgen->masm();
-      // Follow the context chain if necessary.
-      ASSERT(!tmp.is(cp));  // do not overwrite context register
-      Register context = cp;
-      int chain_length =
-          cgen->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));
-        // Load the function context (which is the incoming, outer  
context).
-        __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
-        context = tmp;
-      }
-      // We may have a 'with' context now. Get the function context.
-      // (In fact this mov may never be the needed, since the scope  
analysis
-      // may not permit a direct context access in this case and thus we  
are
-      // always at a function context. However it is safe to dereference  
be-
-      // 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));
-      return ContextOperand(tmp, index);
-    }
-
-    default:
-      UNREACHABLE();
-      return MemOperand(r0, 0);
-  }
-}
+void Reference::SetValue(InitState init_state) {
+  ASSERT(!is_illegal());
+  ASSERT(!cgen_->has_cc());
+  MacroAssembler* masm = cgen_->masm();
+  switch (type_) {
+    case SLOT: {
+      Comment cmnt(masm, "[ Store to Slot");
+      Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
+      ASSERT(slot != NULL);
+      if (slot->type() == Slot::LOOKUP) {
+        ASSERT(slot->var()->mode() == Variable::DYNAMIC);

+        // For now, just do a runtime call.
+        __ push(cp);
+        __ mov(r0, Operand(slot->var()->name()));
+        __ push(r0);

-void Property::GenerateStoreCode(CodeGenerator* cgen,
-                                 Reference* ref,
-                                 InitState init_state) {
-  MacroAssembler* masm = cgen->masm();
-  Comment cmnt(masm, "[ Store to Property");
-  __ RecordPosition(position());
-  ArmCodeGenerator::SetReferenceProperty(cgen, ref, key());
-}
+        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.
+          __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+        } else {
+          __ CallRuntime(Runtime::kStoreContextSlot, 3);
+        }
+        // Storing a variable must keep the (new) value on the expression
+        // stack. This is necessary for compiling assignment expressions.
+        __ push(r0);

+      } else {
+        ASSERT(slot->var()->mode() != Variable::DYNAMIC);

-void VariableProxy::GenerateStoreCode(CodeGenerator* cgen,
-                                      Reference* ref,
-                                      InitState init_state) {
-  MacroAssembler* masm = cgen->masm();
-  Comment cmnt(masm, "[ Store to VariableProxy");
-  Variable* node = var();
+        Label exit;
+        if (init_state == CONST_INIT) {
+          ASSERT(slot->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");
+          __ ldr(r2, cgen_->SlotOperand(slot, r2));
+          __ cmp(r2, Operand(Factory::the_hole_value()));
+          __ b(ne, &exit);
+        }

-  Expression* expr = node->rewrite();
-  if (expr != NULL) {
-    expr->GenerateStoreCode(cgen, ref, init_state);
-  } else {
-    ASSERT(node->is_global());
-    if (node->AsProperty() != NULL) {
-      __ RecordPosition(node->AsProperty()->position());
+        // We must execute the store.  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 slot->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, cgen_->SlotOperand(slot, r2));
+        __ push(r0);
+        if (slot->type() == Slot::CONTEXT) {
+          // Skip write barrier if the written value is a smi.
+          __ tst(r0, Operand(kSmiTagMask));
+          __ b(eq, &exit);
+          // r2 is loaded with context when calling SlotOperand above.
+          int offset = FixedArray::kHeaderSize + slot->index() *  
kPointerSize;
+          __ mov(r3, Operand(offset));
+          __ RecordWrite(r2, r3, r1);
+        }
+        // If we definitely did not jump over the assignment, we do not  
need
+        // to bind the exit label.  Doing so can defeat peephole
+        // optimization.
+        if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) {
+          __ bind(&exit);
+        }
+      }
+      break;
      }
-    Expression* key = new Literal(node->name());
-    ArmCodeGenerator::SetReferenceProperty(cgen, ref, key);
-  }
-}
-
-
-void Slot::GenerateStoreCode(CodeGenerator* cgen,
-                             Reference* ref,
-                             InitState init_state) {
-  MacroAssembler* masm = cgen->masm();
-  Comment cmnt(masm, "[ Store to Slot");

-  if (type() == Slot::LOOKUP) {
-    ASSERT(var()->mode() == Variable::DYNAMIC);
-
-    // For now, just do a runtime call.
-    __ push(cp);
-    __ mov(r0, Operand(var()->name()));
-    __ push(r0);
+    case NAMED: {
+      Comment cmnt(masm, "[ Store to named Property");
+      Property* property = expression_->AsProperty();
+      Handle<String> name;
+      if (property == NULL) {
+        // Global variable reference treated as named property access.
+        VariableProxy* proxy = expression_->AsVariableProxy();
+        ASSERT(proxy->AsVariable() != NULL);
+        ASSERT(proxy->AsVariable()->is_global());
+        name = proxy->name();
+      } else {
+        Literal* raw_name = property->key()->AsLiteral();
+        ASSERT(raw_name != NULL);
+        name = Handle<String>(String::cast(*raw_name->handle()));
+        __ RecordPosition(property->position());
+      }

-    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.
-      __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
-    } else {
-      __ CallRuntime(Runtime::kStoreContextSlot, 3);
+      // Call the appropriate IC code.
+      __ pop(r0);  // value
+      // Setup the name register.
+      __ mov(r2, Operand(name));
+      Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
+      __ Call(ic, RelocInfo::CODE_TARGET);
+      __ push(r0);
+      break;
      }
-    // Storing a variable must keep the (new) value on the expression
-    // stack. This is necessary for compiling assignment expressions.
-    __ 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");
-      __ ldr(r2, ArmCodeGenerator::SlotOperand(cgen, this, r2));
-      __ cmp(r2, Operand(Factory::the_hole_value()));
-      __ b(ne, &exit);
+    case KEYED: {
+      Comment cmnt(masm, "[ Store to keyed Property");
+      Property* property = expression_->AsProperty();
+      ASSERT(property != NULL);
+      __ RecordPosition(property->position());
+      __ pop(r0);  // value
+      SetPropertyStub stub;
+      __ CallStub(&stub);
+      __ push(r0);
+      break;
      }

-    // 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.
-    __ pop(r0);
-    __ str(r0, ArmCodeGenerator::SlotOperand(cgen, this, r2));
-    __ push(r0);
-
-    if (type() == Slot::CONTEXT) {
-      // Skip write barrier if the written value is a smi.
-      __ tst(r0, Operand(kSmiTagMask));
-      __ b(eq, &exit);
-      // r2 is loaded with context when calling SlotOperand above.
-      int offset = FixedArray::kHeaderSize + index() * kPointerSize;
-      __ mov(r3, Operand(offset));
-      __ RecordWrite(r2, r3, r1);
-    }
-    // If we definitely did not jump over the assignment, we do not need to
-    // bind the exit label.  Doing so can defeat peephole optimization.
-    if (init_state == CONST_INIT || type() == Slot::CONTEXT) {
-      __ bind(&exit);
-    }
+    default:
+      UNREACHABLE();
    }
  }

@@ -4514,36 +4488,6 @@
    // Do the runtime call to allocate the arguments object.
    __ bind(&runtime);
    __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
-}
-
-
-void ArmCodeGenerator::SetReferenceProperty(CodeGenerator* cgen,
-                                            Reference* ref,
-                                            Expression* key) {
-  ASSERT(!ref->is_illegal());
-  MacroAssembler* masm = cgen->masm();
-
-  if (ref->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.
-    __ pop(r0);  // value
-    // Setup the name register.
-    __ mov(r2, Operand(name));
-    Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
-    __ Call(ic, RelocInfo::CODE_TARGET);
-
-  } else {
-    // Access keyed property.
-    ASSERT(ref->type() == Reference::KEYED);
-
-    __ pop(r0);  // value
-    SetPropertyStub stub;
-    __ CallStub(&stub);
-  }
-  __ push(r0);
  }



Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc  (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc  Tue Oct  7 04:19:44 2008
@@ -56,6 +56,8 @@
  // For properties, we keep either one (named) or two (indexed) values
  // on the execution stack to represent the reference.

+enum InitState { CONST_INIT, NOT_CONST_INIT };
+
  class Reference BASE_EMBEDDED {
   public:
    // The values of the types is important, see size().
@@ -77,6 +79,8 @@
    bool is_slot() const { return type_ == SLOT; }
    bool is_property() const { return type_ == NAMED || type_ == KEYED; }

+  void SetValue(InitState init_state);
+
   private:
    Ia32CodeGenerator* cgen_;
    Expression* expression_;
@@ -87,14 +91,10 @@
  //  
-------------------------------------------------------------------------
  // Code generation state

-// The state is passed down the AST by the code generator.  It is passed
-// implicitly (in a member variable) to the non-static code generator  
member
-// functions, and explicitly (as an argument) to the static member  
functions
-// and the AST node member functions.
-//
-// The state is threaded through the call stack.  Constructing a state
-// implicitly pushes it on the owning code generator's stack of states, and
-// destroying one implicitly pops it.
+// The state is passed down the AST by the code generator (and back up, in
+// the form of the state of the label pair).  It is threaded through the
+// call stack.  Constructing a state implicitly pushes it on the owning  
code
+// generator's stack of states, and destroying one implicitly pops it.

  class CodeGenState BASE_EMBEDDED {
   public:
@@ -196,35 +196,24 @@
      return ContextOperand(esi, Context::GLOBAL_INDEX);
    }

-  // Support functions for accessing parameters.  Static versions can
-  // require some code generator state to be passed in as arguments.
-  static Operand ParameterOperand(const CodeGenerator* cgen, int index) {
-    int num_parameters = cgen->scope()->num_parameters();
+  // Support functions for accessing parameters.
+  Operand ParameterOperand(int index) const {
+    int num_parameters = scope()->num_parameters();
      ASSERT(-2 <= index && index < num_parameters);
      return Operand(ebp, (1 + num_parameters - index) * kPointerSize);
    }

-  Operand ParameterOperand(int index) const {
-    return ParameterOperand(this, index);
-  }
-
    Operand ReceiverOperand() const { return ParameterOperand(-1); }

    Operand FunctionOperand() const {
      return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset);
    }

-  static Operand ContextOperand(Register context, int index) {
+  Operand ContextOperand(Register context, int index) const {
      return Operand(context, Context::SlotOffset(index));
    }

-  static Operand SlotOperand(CodeGenerator* cgen,
-                             Slot* slot,
-                             Register tmp);
-
-  Operand SlotOperand(Slot* slot, Register tmp) {
-    return SlotOperand(this, slot, tmp);
-  }
+  Operand SlotOperand(Slot* slot, Register tmp);

    void LoadCondition(Expression* x,
                       CodeGenState::AccessType access,
@@ -255,35 +244,11 @@
      Visit(ref->expression());
    }

-  // 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(this, ref, NOT_CONST_INIT);
-  }
-
-  // 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(this, 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(CodeGenerator* cgen,
-                                   Reference* ref,
-                                   Expression* key);
-
    void ToBoolean(Label* true_target, Label* false_target);

    void GenericBinaryOperation(
@@ -673,9 +638,9 @@
            if (!arguments_object_saved) {
              __ push(ecx);
            }
-          SetValue(&arguments_ref);
+          arguments_ref.SetValue(NOT_CONST_INIT);
          }
-        SetValue(&shadow_ref);
+        shadow_ref.SetValue(NOT_CONST_INIT);
        }
        __ pop(eax);  // Value is no longer needed.
      }
@@ -734,6 +699,60 @@
  }


+Operand Ia32CodeGenerator::SlotOperand(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).
+  // We need to implement assignments to read-only variables.
+  // Ideally, we should do this during AST generation (by converting
+  // such assignments into expression statements); however, in general
+  // we may not be able to make the decision until past AST generation,
+  // that is when the entire program is known.
+  ASSERT(slot != NULL);
+  int index = slot->index();
+  switch (slot->type()) {
+    case Slot::PARAMETER:
+      return ParameterOperand(index);
+
+    case Slot::LOCAL: {
+      ASSERT(0 <= index && index < scope()->num_stack_slots());
+      const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
+      return Operand(ebp, kLocal0Offset - index * kPointerSize);
+    }
+
+    case Slot::CONTEXT: {
+      // 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());
+      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));
+        // Load the function context (which is the incoming, outer  
context).
+        __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
+        context = tmp;
+      }
+      // We may have a 'with' context now. Get the function context.
+      // (In fact this mov may never be the needed, since the scope  
analysis
+      // may not permit a direct context access in this case and thus we  
are
+      // always at a function context. However it is safe to dereference  
be-
+      // 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));
+      return ContextOperand(tmp, index);
+    }
+
+    default:
+      UNREACHABLE();
+      return Operand(eax);
+  }
+}
+
+
  // Loads a value on TOS. If it is a boolean value, the result may have been
  // (partially) translated into branches, or it may have set the condition  
code
  // register. If force_cc is set, the value is forced to set the condition  
code
@@ -1763,7 +1782,7 @@
      Reference target(this, node->proxy());
      ASSERT(target.is_slot());
      Load(val);
-    SetValue(&target);
+    target.SetValue(NOT_CONST_INIT);
      // Get rid of the assigned value (declarations are statements).  It's
      // safe to pop the value lying on top of the reference before unloading
      // the reference itself (which preserves the top of stack) because we
@@ -2290,7 +2309,7 @@
        // If the reference was to a slot we rely on the convenient property
        // that it doesn't matter whether a value (eg, ebx pushed above) is
        // right on top of or right underneath a zero-sized reference.
-      SetValue(&each);
+      each.SetValue(NOT_CONST_INIT);
        if (each.size() > 0) {
          // It's safe to pop the value lying on top of the reference before
          // unloading the reference itself (which preserves the top of  
stack,
@@ -2334,7 +2353,7 @@
      // Load the exception to the top of the stack.  Here we make use of the
      // convenient property that it doesn't matter whether a value is
      // immediately on top of or underneath a zero-sized reference.
-    SetValue(&ref);
+    ref.SetValue(NOT_CONST_INIT);
    }

    // Remove the exception from the stack.
@@ -2944,9 +2963,9 @@
        // Dynamic constant initializations must use the function context
        // and initialize the actual constant declared. Dynamic variable
        // initializations are simply assignments and use SetValue.
-      InitConst(&target);
+      target.SetValue(CONST_INIT);
      } else {
-      SetValue(&target);
+      target.SetValue(NOT_CONST_INIT);
      }
    }
  }
@@ -3687,7 +3706,7 @@
      // Store the new value in the target if not const.
      __ bind(deferred->exit());
      __ push(eax);  // Push the new value to TOS
-    if (!is_const) SetValue(&target);
+    if (!is_const) target.SetValue(NOT_CONST_INIT);
    }

    // Postfix: Discard the new value and use the old.
@@ -4071,165 +4090,130 @@
  #undef __
  #define __ masm->

-Operand Ia32CodeGenerator::SlotOperand(CodeGenerator* cgen,
-                                       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).
-  // We need to implement assignments to read-only variables.
-  // Ideally, we should do this during AST generation (by converting
-  // such assignments into expression statements); however, in general
-  // we may not be able to make the decision until past AST generation,
-  // that is when the entire program is known.
-  ASSERT(slot != NULL);
-  int index = slot->index();
-  switch (slot->type()) {
-    case Slot::PARAMETER: return ParameterOperand(cgen, index);
-
-    case Slot::LOCAL: {
-      ASSERT(0 <= index && index < cgen->scope()->num_stack_slots());
-      const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
-      return Operand(ebp, kLocal0Offset - index * kPointerSize);
-    }
-
-    case Slot::CONTEXT: {
-      MacroAssembler* masm = cgen->masm();
-      // Follow the context chain if necessary.
-      ASSERT(!tmp.is(esi));  // do not overwrite context register
-      Register context = esi;
-      int chain_length =
-          cgen->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));
-        // Load the function context (which is the incoming, outer  
context).
-        __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
-        context = tmp;
-      }
-      // We may have a 'with' context now. Get the function context.
-      // (In fact this mov may never be the needed, since the scope  
analysis
-      // may not permit a direct context access in this case and thus we  
are
-      // always at a function context. However it is safe to dereference  
be-
-      // 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));
-      return ContextOperand(tmp, index);
-    }
-
-    default:
-      UNREACHABLE();
-      return Operand(eax);
-  }
-}
-
-
-void Property::GenerateStoreCode(CodeGenerator* cgen,
-                                 Reference* ref,
-                                 InitState init_state) {
-  MacroAssembler* masm = cgen->masm();
-  Comment cmnt(masm, "[ Store to Property");
-  __ RecordPosition(position());
-  Ia32CodeGenerator::SetReferenceProperty(cgen, ref, key());
-}
+void Reference::SetValue(InitState init_state) {
+  ASSERT(!is_illegal());
+  ASSERT(!cgen_->has_cc());
+  MacroAssembler* masm = cgen_->masm();
+  switch (type_) {
+    case SLOT: {
+      Comment cmnt(masm, "[ Store to Slot");
+      Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
+      ASSERT(slot != NULL);
+      if (slot->type() == Slot::LOOKUP) {
+        ASSERT(slot->var()->mode() == Variable::DYNAMIC);
+
+        // For now, just do a runtime call.
+        __ push(esi);
+        __ push(Immediate(slot->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.
+          __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
+        } else {
+          __ CallRuntime(Runtime::kStoreContextSlot, 3);
+        }
+        // Storing a variable must keep the (new) value on the expression
+        // stack. This is necessary for compiling chained assignment
+        // expressions.
+        __ push(eax);

+      } else {
+        ASSERT(slot->var()->mode() != Variable::DYNAMIC);

-void VariableProxy::GenerateStoreCode(CodeGenerator* cgen,
-                                      Reference* ref,
-                                      InitState init_state) {
-  MacroAssembler* masm = cgen->masm();
-  Comment cmnt(masm, "[ Store to VariableProxy");
-  Variable* node = var();
+        Label exit;
+        if (init_state == CONST_INIT) {
+          ASSERT(slot->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");
+          __ mov(eax, cgen_->SlotOperand(slot, ecx));
+          __ cmp(eax, Factory::the_hole_value());
+          __ j(not_equal, &exit);
+        }

-  Expression* expr = node->rewrite();
-  if (expr != NULL) {
-    expr->GenerateStoreCode(cgen, ref, init_state);
-  } else {
-    ASSERT(node->is_global());
-    if (node->AsProperty() != NULL) {
-      __ RecordPosition(node->AsProperty()->position());
+        // We must execute the store.  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 slot->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(cgen_->SlotOperand(slot, ecx), eax);
+        __ push(eax);  // RecordWrite may destroy the value in eax.
+        if (slot->type() == Slot::CONTEXT) {
+          // ecx is loaded with context when calling SlotOperand above.
+          int offset = FixedArray::kHeaderSize + slot->index() *  
kPointerSize;
+          __ RecordWrite(ecx, offset, eax, ebx);
+        }
+        // If we definitely did not jump over the assignment, we do not  
need
+        // to bind the exit label.  Doing so can defeat peephole
+        // optimization.
+        if (init_state == CONST_INIT) __ bind(&exit);
+      }
+      break;
      }
-    Expression* key = new Literal(node->name());
-    Ia32CodeGenerator::SetReferenceProperty(cgen, ref, key);
-  }
-}
-

-void Slot::GenerateStoreCode(CodeGenerator* cgen,
-                             Reference* ref,
-                             InitState init_state) {
-  MacroAssembler* masm = cgen->masm();
-  Comment cmnt(masm, "[ Store to Slot");
-
-  if (type() == Slot::LOOKUP) {
-    ASSERT(var()->mode() == Variable::DYNAMIC);
-
-    // For now, just do a runtime call.
-    __ push(esi);
-    __ push(Immediate(var()->name()));
+    case NAMED: {
+      Comment cmnt(masm, "[ Store to named Property");
+      Property* property = expression_->AsProperty();
+      Handle<String> name;
+      if (property == NULL) {
+        // Global variable reference treated as named property access.
+        VariableProxy* proxy = expression_->AsVariableProxy();
+        ASSERT(proxy->AsVariable() != NULL);
+        ASSERT(proxy->AsVariable()->is_global());
+        name = proxy->name();
+      } else {
+        Literal* raw_name = property->key()->AsLiteral();
+        ASSERT(raw_name != NULL);
+        name = Handle<String>(String::cast(*raw_name->handle()));
+        __ RecordPosition(property->position());
+      }

-    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.
-      __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
-    } else {
-      __ CallRuntime(Runtime::kStoreContextSlot, 3);
+      // Call the appropriate IC code.
+      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.
+      __ mov(ecx, name);
+      __ call(ic, RelocInfo::CODE_TARGET);
+      __ push(eax);  // IC call leaves result in eax, push it out
+      break;
      }
-    // Storing a variable must keep the (new) value on the expression
-    // stack. This is necessary for compiling assignment expressions.
-    __ 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");
-      __ mov(eax, Ia32CodeGenerator::SlotOperand(cgen, this, ecx));
-      __ cmp(eax, Factory::the_hole_value());
-      __ j(not_equal, &exit);
+    case KEYED: {
+      Comment cmnt(masm, "[ Store to keyed Property");
+      Property* property = expression_->AsProperty();
+      ASSERT(property != NULL);
+      __ RecordPosition(property->position());
+      // 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, RelocInfo::CODE_TARGET);
+      __ push(eax);  // IC call leaves result in eax, push it out
+      break;
      }

-    // 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.
-    __ pop(eax);
-    __ mov(Ia32CodeGenerator::SlotOperand(cgen, this, ecx), eax);
-    __ 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;
-      __ RecordWrite(ecx, offset, eax, ebx);
-    }
-    // If we definitely did not jump over the assignment, we do not need to
-    // bind the exit label.  Doing so can defeat peephole optimization.
-    if (init_state == CONST_INIT) __ bind(&exit);
+    default:
+      UNREACHABLE();
    }
  }

@@ -4288,38 +4272,6 @@
    __ bind(&false_result);
    __ mov(eax, 0);
    __ ret(1 * kPointerSize);
-}
-
-
-void Ia32CodeGenerator::SetReferenceProperty(CodeGenerator* cgen,
-                                             Reference* ref,
-                                             Expression* key) {
-  ASSERT(!ref->is_illegal());
-  MacroAssembler* masm = cgen->masm();
-
-  if (ref->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.
-    __ pop(eax);
-    // Setup the name register.
-    __ Set(ecx, Immediate(name));
-    __ call(ic, RelocInfo::CODE_TARGET);
-  } else {
-    // Access keyed property.
-    ASSERT(ref->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.
-    __ pop(eax);
-    __ call(ic, RelocInfo::CODE_TARGET);
-  }
-  __ push(eax);  // IC call leaves result in eax, push it out
  }



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

Reply via email to