Author: [EMAIL PROTECTED]
Date: Wed Nov  5 00:44:54 2008
New Revision: 694

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

Log:
Initial port of VirtualFrame to the ARM architecture.  To reduce the
size of the change, the initial implementation provides read access to
the frame (eg, locals, parameters, and expression stack elements) but
no mutation.
Review URL: http://codereview.chromium.org/7302

Modified: branches/bleeding_edge/src/codegen-arm.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.cc   (original)
+++ branches/bleeding_edge/src/codegen-arm.cc   Wed Nov  5 00:44:54 2008
@@ -35,6 +35,20 @@

  namespace v8 { namespace internal {

+#define __ masm_->
+
+//  
-------------------------------------------------------------------------
+// VirtualFrame implementation.
+
+VirtualFrame::VirtualFrame(CodeGenerator* cgen) {
+  ASSERT(cgen->scope() != NULL);
+
+  masm_ = cgen->masm();
+  frame_local_count_ = cgen->scope()->num_stack_slots();
+  parameter_count_ = cgen->scope()->num_parameters();
+}
+
+
  //  
-------------------------------------------------------------------------
  // CodeGenState implementation.

@@ -67,11 +81,9 @@
  }


-//  
-----------------------------------------------------------------------------
+//  
-------------------------------------------------------------------------
  // CodeGenerator implementation

-#define __ masm_->
-
  CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
                               bool is_eval)
      : is_eval_(is_eval),
@@ -79,6 +91,7 @@
        deferred_(8),
        masm_(new MacroAssembler(NULL, buffer_size)),
        scope_(NULL),
+      frame_(NULL),
        cc_reg_(al),
        state_(NULL),
        break_stack_height_(0) {
@@ -94,13 +107,17 @@
  // cp: callee's context

  void CodeGenerator::GenCode(FunctionLiteral* fun) {
-  Scope* scope = fun->scope();
    ZoneList<Statement*>* body = fun->body();

    // Initialize state.
-  { CodeGenState state(this);
-    scope_ = scope;
-    cc_reg_ = al;
+  ASSERT(scope_ == NULL);
+  scope_ = fun->scope();
+  ASSERT(frame_ == NULL);
+  VirtualFrame virtual_frame(this);
+  frame_ = &virtual_frame;
+  cc_reg_ = al;
+  {
+    CodeGenState state(this);

      // Entry
      // stack: function, receiver, arguments, return address
@@ -122,19 +139,19 @@
  #endif

      // Allocate space for locals and initialize them.
-    if (scope->num_stack_slots() > 0) {
+    if (scope_->num_stack_slots() > 0) {
        Comment cmnt(masm_, "[ allocate space for locals");
        // Initialize stack slots with 'undefined' value.
        __ mov(ip, Operand(Factory::undefined_value()));
-      for (int i = 0; i < scope->num_stack_slots(); i++) {
+      for (int i = 0; i < scope_->num_stack_slots(); i++) {
          __ push(ip);
        }
      }

-    if (scope->num_heap_slots() > 0) {
+    if (scope_->num_heap_slots() > 0) {
        // Allocate local context.
        // Get outer context and create a new context based on it.
-      __ ldr(r0, FunctionOperand());
+      __ ldr(r0, frame_->Function());
        __ push(r0);
        __ CallRuntime(Runtime::kNewContext, 1);  // r0 holds the result

@@ -146,7 +163,7 @@
          __ bind(&verified_true);
        }
        // Update context local.
-      __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ str(cp, frame_->Context());
      }

      // TODO(1241774): Improve this code!!!
@@ -164,12 +181,12 @@
        // order: such a parameter is copied repeatedly into the same
        // context location and thus the last value is what is seen inside
        // the function.
-      for (int i = 0; i < scope->num_parameters(); i++) {
-        Variable* par = scope->parameter(i);
+      for (int i = 0; i < scope_->num_parameters(); i++) {
+        Variable* par = scope_->parameter(i);
          Slot* slot = par->slot();
          if (slot != NULL && slot->type() == Slot::CONTEXT) {
-          ASSERT(!scope->is_global_scope());  // no parameters in global  
scope
-          __ ldr(r1, ParameterOperand(i));
+          ASSERT(!scope_->is_global_scope());  // no parameters in global  
scope
+          __ ldr(r1, frame_->Parameter(i));
            // Loads r2 with context; used below in RecordWrite.
            __ str(r1, SlotOperand(slot, r2));
            // Load the offset into r3.
@@ -184,18 +201,18 @@
      // Store the arguments object.
      // This must happen after context initialization because
      // the arguments array may be stored in the context!
-    if (scope->arguments() != NULL) {
-      ASSERT(scope->arguments_shadow() != NULL);
+    if (scope_->arguments() != NULL) {
+      ASSERT(scope_->arguments_shadow() != NULL);
        Comment cmnt(masm_, "[ allocate arguments object");
-      { Reference shadow_ref(this, scope->arguments_shadow());
-        { Reference arguments_ref(this, scope->arguments());
+      { Reference shadow_ref(this, scope_->arguments_shadow());
+        { Reference arguments_ref(this, scope_->arguments());
            ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
-          __ ldr(r2, FunctionOperand());
+          __ ldr(r2, frame_->Function());
            // The receiver is below the arguments, the return address,
            // and the frame pointer on the stack.
-          const int kReceiverDisplacement = 2 + scope->num_parameters();
+          const int kReceiverDisplacement = 2 + scope_->num_parameters();
            __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
-          __ mov(r0, Operand(Smi::FromInt(scope->num_parameters())));
+          __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
            __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
            __ CallStub(&stub);
            __ push(r0);
@@ -210,13 +227,13 @@
      // functions (source elements). In case of an illegal
      // redeclaration we need to handle that instead of processing the
      // declarations.
-    if (scope->HasIllegalRedeclaration()) {
+    if (scope_->HasIllegalRedeclaration()) {
        Comment cmnt(masm_, "[ illegal redeclarations");
-      scope->VisitIllegalRedeclaration(this);
+      scope_->VisitIllegalRedeclaration(this);
      } else {
        Comment cmnt(masm_, "[ declarations");
        // ProcessDeclarations calls DeclareGlobals indirectly
-      ProcessDeclarations(scope->declarations());
+      ProcessDeclarations(scope_->declarations());

        // Bail out if a stack-overflow exception occurred when
        // processing declarations.
@@ -233,7 +250,7 @@
      // Compile the body of the function in a vanilla state. Don't
      // bother compiling all the code if the scope has an illegal
      // redeclaration.
-    if (!scope->HasIllegalRedeclaration()) {
+    if (!scope_->HasIllegalRedeclaration()) {
        Comment cmnt(masm_, "[ function body");
  #ifdef DEBUG
        bool is_builtin = Bootstrapper::IsActive();
@@ -272,6 +289,7 @@

    // Code generation state must be reset.
    scope_ = NULL;
+  frame_ = NULL;
    ASSERT(!has_cc());
    ASSERT(state_ == NULL);
  }
@@ -290,13 +308,10 @@
    int index = slot->index();
    switch (slot->type()) {
      case Slot::PARAMETER:
-      return ParameterOperand(index);
+      return frame_->Parameter(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::LOCAL:
+      return frame_->Local(index);

      case Slot::CONTEXT: {
        // Follow the context chain if necessary.
@@ -979,7 +994,7 @@
    __ CallStub(&call_function);

    // Restore context and pop function from the stack.
-  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ ldr(cp, frame_->Context());
    __ pop();  // discard the TOS
  }

@@ -1214,7 +1229,7 @@
      __ bind(&verified_true);
    }
    // Update context local.
-  __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ str(cp, frame_->Context());
  }


@@ -1223,7 +1238,7 @@
    // Pop context.
    __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
    // Update context local.
-  __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ str(cp, frame_->Context());
  }


@@ -1324,7 +1339,7 @@
      } else {
        __ bind(&next);
        next.Unuse();
-      __ ldr(r0, MemOperand(sp, 0));
+      __ ldr(r0, frame_->Top());
        __ push(r0);  // duplicate TOS
        Load(clause->label());
        Comparison(eq, true);
@@ -1543,29 +1558,29 @@
    // sp[2] : array or enum cache
    // sp[3] : 0 or map
    // sp[4] : enumerable
-  __ ldr(r0, MemOperand(sp, 0 * kPointerSize));  // load the current count
-  __ ldr(r1, MemOperand(sp, 1 * kPointerSize));  // load the length
+  __ ldr(r0, frame_->Element(0));  // load the current count
+  __ ldr(r1, frame_->Element(1));  // load the length
    __ cmp(r0, Operand(r1));  // compare to the array length
    __ b(hs, &cleanup);

-  __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
+  __ ldr(r0, frame_->Element(0));

    // Get the i'th entry of the array.
-  __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
+  __ ldr(r2, frame_->Element(2));
    __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
    __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));

    // Get Map or 0.
-  __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
+  __ ldr(r2, frame_->Element(3));
    // Check if this (still) matches the map of the enumerable.
    // If not, we have to filter the key.
-  __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
+  __ ldr(r1, frame_->Element(4));
    __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
    __ cmp(r1, Operand(r2));
    __ b(eq, &end_del_check);

    // Convert the entry to a string (or null if it isn't a property  
anymore).
-  __ ldr(r0, MemOperand(sp, 4 * kPointerSize));  // push enumerable
+  __ ldr(r0, frame_->Element(4));  // push enumerable
    __ push(r0);
    __ push(r3);  // push entry
    __ mov(r0, Operand(1));
@@ -1585,7 +1600,7 @@
    { Reference each(this, node->each());
      if (!each.is_illegal()) {
        if (each.size() > 0) {
-        __ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
+        __ ldr(r0, frame_->Element(each.size()));
          __ push(r0);
        }
        // If the reference was to a slot we rely on the convenient property
@@ -1680,9 +1695,10 @@

    // Unlink from try chain.
    // TOS contains code slot
-  const int kNextOffset = StackHandlerConstants::kNextOffset +
-      StackHandlerConstants::kAddressDisplacement;
-  __ ldr(r1, MemOperand(sp, kNextOffset));  // read next_sp
+  const int kNextIndex = (StackHandlerConstants::kNextOffset
+                          + StackHandlerConstants::kAddressDisplacement)
+                       / kPointerSize;
+  __ ldr(r1, frame_->Element(kNextIndex));  // read next_sp
    __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
    __ str(r1, MemOperand(r3));
    ASSERT(StackHandlerConstants::kCodeOffset == 0);  // first field is code
@@ -1702,7 +1718,7 @@
        __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
        __ ldr(sp, MemOperand(r3));

-      __ ldr(r1, MemOperand(sp, kNextOffset));
+      __ ldr(r1, frame_->Element(kNextIndex));
        __ str(r1, MemOperand(r3));
        ASSERT(StackHandlerConstants::kCodeOffset == 0);  // first field is  
code
        __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
@@ -1797,9 +1813,10 @@
    // break from (eg, for...in) may have left stuff on the stack.
    __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
    __ ldr(sp, MemOperand(r3));
-  const int kNextOffset = StackHandlerConstants::kNextOffset +
-      StackHandlerConstants::kAddressDisplacement;
-  __ ldr(r1, MemOperand(sp, kNextOffset));
+  const int kNextIndex = (StackHandlerConstants::kNextOffset
+                          + StackHandlerConstants::kAddressDisplacement)
+                       / kPointerSize;
+  __ ldr(r1, frame_->Element(kNextIndex));
    __ str(r1, MemOperand(r3));
    ASSERT(StackHandlerConstants::kCodeOffset == 0);  // first field is code
    __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
@@ -1982,7 +1999,7 @@
    // Retrieve the literal array and check the allocated entry.

    // Load the function of this activation.
-  __ ldr(r1, FunctionOperand());
+  __ ldr(r1, frame_->Function());

    // Load the literals array of the function.
    __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
@@ -2055,7 +2072,7 @@
    // Retrieve the literal array and check the allocated entry.

    // Load the function of this activation.
-  __ ldr(r1, FunctionOperand());
+  __ ldr(r1, frame_->Function());

    // Load the literals array of the function.
    __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
@@ -2092,7 +2109,7 @@
          Load(value);
          __ CallRuntime(Runtime::kSetProperty, 3);
          // restore r0
-        __ ldr(r0, MemOperand(sp, 0));
+        __ ldr(r0, frame_->Top());
          break;
        }
        case ObjectLiteral::Property::SETTER: {
@@ -2102,7 +2119,7 @@
          __ push(r0);
          Load(value);
          __ CallRuntime(Runtime::kDefineAccessor, 4);
-        __ ldr(r0, MemOperand(sp, 0));
+        __ ldr(r0, frame_->Top());
          break;
        }
        case ObjectLiteral::Property::GETTER: {
@@ -2112,7 +2129,7 @@
          __ push(r0);
          Load(value);
          __ CallRuntime(Runtime::kDefineAccessor, 4);
-        __ ldr(r0, MemOperand(sp, 0));
+        __ ldr(r0, frame_->Top());
          break;
        }
      }
@@ -2127,7 +2144,7 @@
    __ mov(r0, Operand(node->literals()));
    __ push(r0);
    // Load the function of this frame.
-  __ ldr(r0, FunctionOperand());
+  __ ldr(r0, frame_->Function());
    __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
    __ push(r0);
    __ CallRuntime(Runtime::kCreateArrayLiteral, 2);
@@ -2148,7 +2165,7 @@
        __ pop(r0);

        // Fetch the object literal
-      __ ldr(r1, MemOperand(sp, 0));
+      __ ldr(r1, frame_->Top());
          // Get the elements array.
        __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));

@@ -2271,7 +2288,7 @@
      Handle<Code> stub = ComputeCallInitialize(args->length());
      __ RecordPosition(node->position());
      __ Call(stub, RelocInfo::CODE_TARGET_CONTEXT);
-    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    __ ldr(cp, frame_->Context());
      // Remove the function from the stack.
      __ pop();
      __ push(r0);
@@ -2318,7 +2335,7 @@
        Handle<Code> stub = ComputeCallInitialize(args->length());
        __ RecordPosition(node->position());
        __ Call(stub, RelocInfo::CODE_TARGET);
-      __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ ldr(cp, frame_->Context());

        // Remove the function from the stack.
        __ pop();
@@ -2335,7 +2352,7 @@
        ref.GetValue(NOT_INSIDE_TYPEOF);  // receiver

        // Pass receiver to called function.
-      __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
+      __ ldr(r0, frame_->Element(ref.size()));
        __ push(r0);
        // Call the function.
        CallWithArguments(args, node->position());
@@ -2383,7 +2400,7 @@
    __ mov(r0, Operand(args->length()));

    // Load the function into r1 as per calling convention.
-  __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize));
+  __ ldr(r1, frame_->Element(args->length() + 1));

    // Call the construct call builtin that handles allocation and
    // constructor invocation.
@@ -2392,7 +2409,7 @@
            RelocInfo::CONSTRUCT_CALL);

    // Discard old TOS value and push r0 on the stack (same as Pop(),  
push(r0)).
-  __ str(r0, MemOperand(sp, 0 * kPointerSize));
+  __ str(r0, frame_->Top());
  }


@@ -2565,7 +2582,7 @@
      // Call the JS runtime function.
      Handle<Code> stub = ComputeCallInitialize(args->length());
      __ Call(stub, RelocInfo::CODE_TARGET);
-    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    __ ldr(cp, frame_->Context());
      __ pop();
      __ push(r0);
    }
@@ -2727,7 +2744,9 @@
      __ b(ne, &slow);

      // Postfix: Store the old value as the result.
-    if (is_postfix) __ str(r0, MemOperand(sp, target.size() *  
kPointerSize));
+    if (is_postfix) {
+      __ str(r0, frame_->Element(target.size()));
+    }

      // Perform optimistic increment/decrement.
      if (is_increment) {
@@ -2754,7 +2773,7 @@
        InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
        __ CallStub(&stub);
        // Store to result (on the stack).
-      __ str(r0, MemOperand(sp, target.size() * kPointerSize));
+      __ str(r0, frame_->Element(target.size()));
      }

      // Compute the new value by calling the right JavaScript native.
@@ -2814,7 +2833,7 @@
      } else {
        Label pop_and_continue, exit;

-      __ ldr(r0, MemOperand(sp, 0));  // dup the stack top
+      __ ldr(r0, frame_->Top());  // dup the stack top
        __ push(r0);
        // Avoid popping the result if it converts to 'false' using the
        // standard ToBoolean() conversion as described in ECMA-262,
@@ -2855,7 +2874,7 @@
      } else {
        Label pop_and_continue, exit;

-      __ ldr(r0, MemOperand(sp, 0));
+      __ ldr(r0, frame_->Top());
        __ push(r0);
        // Avoid popping the result if it converts to 'true' using the
        // standard ToBoolean() conversion as described in ECMA-262,
@@ -2900,7 +2919,7 @@


  void CodeGenerator::VisitThisFunction(ThisFunction* node) {
-  __ ldr(r0, FunctionOperand());
+  __ ldr(r0, frame_->Function());
    __ push(r0);
  }


Modified: branches/bleeding_edge/src/codegen-arm.h
==============================================================================
--- branches/bleeding_edge/src/codegen-arm.h    (original)
+++ branches/bleeding_edge/src/codegen-arm.h    Wed Nov  5 00:44:54 2008
@@ -38,8 +38,50 @@
  // Mode to overwrite BinaryExpression values.
  enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };

+enum InitState { CONST_INIT, NOT_CONST_INIT };
+enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
+
+
+//  
-------------------------------------------------------------------------
+// Virtual frame
+
+class VirtualFrame BASE_EMBEDDED {
+ public:
+  explicit VirtualFrame(CodeGenerator* cgen);
+
+  MemOperand Top() const { return MemOperand(sp, 0); }

-//  
-----------------------------------------------------------------------------
+  MemOperand Element(int index) const {
+    return MemOperand(sp, index * kPointerSize);
+  }
+
+  MemOperand Local(int index) const {
+    ASSERT(0 <= index && index < frame_local_count_);
+    return MemOperand(fp, kLocal0Offset - index * kPointerSize);
+  }
+
+  MemOperand Function() const { return MemOperand(fp, kFunctionOffset); }
+
+  MemOperand Context() const { return MemOperand(fp, kContextOffset); }
+
+  MemOperand Parameter(int index) const {
+    // Index -1 corresponds to the receiver.
+    ASSERT(-1 <= index && index <= parameter_count_);
+    return MemOperand(fp, (1 + parameter_count_ - index) * kPointerSize);
+  }
+
+ private:
+  static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
+  static const int kFunctionOffset =  
JavaScriptFrameConstants::kFunctionOffset;
+  static const int kContextOffset = StandardFrameConstants::kContextOffset;
+
+  MacroAssembler* masm_;
+  int frame_local_count_;
+  int parameter_count_;
+};
+
+
+//  
-------------------------------------------------------------------------
  // Reference support

  // A reference is a C++ stack-allocated object that keeps an ECMA
@@ -49,9 +91,6 @@
  // 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 };
-enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
-
  class Reference BASE_EMBEDDED {
   public:
    // The values of the types is important, see size().
@@ -133,7 +172,7 @@
  };


-//  
-----------------------------------------------------------------------------
+//  
-------------------------------------------------------------------------
  // CodeGenerator

  class CodeGenerator: public Visitor {
@@ -193,20 +232,6 @@
    void LoadReference(Reference* ref);
    void UnloadReference(Reference* ref);

-  // Support functions for accessing parameters and other operands.
-  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);
-    int offset = (1 + num_parameters - index) * kPointerSize;
-    return MemOperand(fp, offset);
-  }
-
-  MemOperand FunctionOperand() const {
-    return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset);
-  }
-
    MemOperand ContextOperand(Register context, int index) const {
      return MemOperand(context, Context::SlotOffset(index));
    }
@@ -355,6 +380,7 @@

    // Code generation state
    Scope* scope_;
+  VirtualFrame* frame_;
    Condition cc_reg_;
    CodeGenState* state_;
    bool is_inside_try_;
@@ -363,10 +389,8 @@
    // Labels
    Label function_return_;

+  friend class VirtualFrame;
    friend class Reference;
-  friend class Property;
-  friend class VariableProxy;
-  friend class Slot;

    DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
  };

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

Reply via email to