Author: [email protected]
Date: Tue Jan 13 00:58:33 2009
New Revision: 1058

Modified:
    branches/experimental/toiger/src/codegen-ia32.cc
    branches/experimental/toiger/src/register-allocator-ia32.h
    branches/experimental/toiger/src/virtual-frame-ia32.cc
    branches/experimental/toiger/src/virtual-frame-ia32.h

Log:
Experimental: use register allocation in the code for keyed property
loads.
Review URL: http://codereview.chromium.org/17615

Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc    (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc    Tue Jan 13 00:58:33  
2009
@@ -3237,9 +3237,9 @@
          ? ComputeCallInitializeInLoop(arg_count)
          : ComputeCallInitialize(arg_count);
      CodeForSourcePosition(node->position());
-    frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
-                           arg_count + 1);
-    Result result = allocator_->Allocate(eax);
+    Result result = frame_->CallCodeObject(stub,
+                                           RelocInfo::CODE_TARGET_CONTEXT,
+                                           arg_count + 1);
      frame_->RestoreContextRegister();

      // Replace the function on the stack with the result.
@@ -3288,8 +3288,9 @@
          ? ComputeCallInitializeInLoop(arg_count)
          : ComputeCallInitialize(arg_count);
        CodeForSourcePosition(node->position());
-      frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
-      Result result = allocator_->Allocate(eax);
+      Result result = frame_->CallCodeObject(stub,
+                                             RelocInfo::CODE_TARGET,
+                                             arg_count + 1);
        frame_->RestoreContextRegister();

        // Replace the function on the stack with the result.
@@ -3370,8 +3371,9 @@
    // constructor invocation.
    CodeForSourcePosition(node->position());
    Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
-  frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, args->length() +  
1);
-  Result result = allocator_->Allocate(eax);
+  Result result = frame_->CallCodeObject(ic,
+                                         RelocInfo::CONSTRUCT_CALL,
+                                         args->length() + 1);

    // Replace the function on the stack with the result.
    frame_->SetElementAt(0, &result);
@@ -4436,27 +4438,40 @@
    }

    virtual void Generate() {
-    // The argument are actually passed in edx and on top of the frame.
-    enter()->Bind();
-    VirtualFrame::SpilledScope spilled_scope(generator());
+    CodeGenerator* cgen = generator();
      Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+    Result receiver(cgen);
+    Result key(cgen);
+    enter()->Bind(&receiver, &key);
+    VirtualFrame* frame = generator()->frame();
+    frame->Push(&receiver);  // First IC argument.
+    frame->Push(&key);       // Second IC argument.
+
      // Calculate the delta from the IC call instruction to the map
      // check cmp instruction in the inlined version.  This delta is
      // stored in a test(eax, delta) instruction after the call so that
      // we can find it in the IC initialization code and patch the cmp
      // instruction.  This means that we cannot allow test instructions
      // after calls to KeyedLoadIC stubs in other places.
+    //
+    // The virtual frame should be spilled fully before the call so
+    // that the call itself does not generate extra code to spill
+    // values.
+    frame->SpillAll();
      int delta_to_patch_site = __ SizeOfCodeGeneratedSince(patch_site());
-    VirtualFrame* frame = generator()->frame();
+    Result value(cgen);
      if (is_global_) {
-      frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0);
+      value = frame->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, 0);
      } else {
-      frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
+      value = frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
      }
-    __ test(eax, Immediate(-delta_to_patch_site));
+    // The result needs to be specifically the eax register because
+    // the offset to the patch site will be expected in a test eax
+    // instruction.
+    ASSERT(value.is_register() && value.reg().is(eax));
+    __ test(value.reg(), Immediate(-delta_to_patch_site));
      __ IncrementCounter(&Counters::keyed_load_inline_miss, 1);
-    // The result is result is actually returned in eax.
-    exit()->Jump();
+    exit()->Jump(&value);
    }

    Label* patch_site() { return &patch_site_; }
@@ -4492,7 +4507,6 @@
    ASSERT(!is_illegal());
    ASSERT(!cgen_->has_cc());
    MacroAssembler* masm = cgen_->masm();
-  VirtualFrame* frame = cgen_->frame();
    switch (type_) {
      case SLOT: {
        Comment cmnt(masm, "[ Load from Slot");
@@ -4510,6 +4524,7 @@
        // loads (typeof expression loads must not throw a reference
        // error).
        VirtualFrame::SpilledScope spilled_scope(cgen_);
+      VirtualFrame* frame = cgen_->frame();
        Comment cmnt(masm, "[ Load from named Property");
        Handle<String> name(GetName());
        Variable* var = expression_->AsVariableProxy()->AsVariable();
@@ -4529,9 +4544,7 @@
      case KEYED: {
        // TODO(1241834): Make sure that this it is safe to ignore the
        // distinction between expressions in a typeof and not in a typeof.
-      VirtualFrame::SpilledScope spilled_scope(cgen_);
        Comment cmnt(masm, "[ Load from keyed Property");
-      Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
        Variable* var = expression_->AsVariableProxy()->AsVariable();
        bool is_global = var != NULL;
        ASSERT(!is_global || var->is_global());
@@ -4543,43 +4556,79 @@
          Comment cmnt(masm, "[ Inlined array index load");
          DeferredReferenceGetKeyedValue* deferred =
              new DeferredReferenceGetKeyedValue(cgen_, is_global);
-        // Load receiver and check that it is not a smi (only needed
-        // if this is not a load from the global context) and that it
-        // has the expected map.
-        __ mov(edx, Operand(esp, kPointerSize));
+
+        Result key = cgen_->frame()->Pop();
+        Result receiver = cgen_->frame()->Pop();
+        key.ToRegister();
+        receiver.ToRegister();
+
+        // Check that the receiver is not a smi (only needed if this
+        // is not a load from the global context) and that it has the
+        // expected map.
          if (!is_global) {
-          __ test(edx, Immediate(kSmiTagMask));
-          deferred->enter()->Branch(zero, not_taken);
+          __ test(receiver.reg(), Immediate(kSmiTagMask));
+          deferred->enter()->Branch(zero, &receiver, &key, not_taken);
          }
+
          // Initially, use an invalid map. The map is patched in the IC
          // initialization code.
          __ bind(deferred->patch_site());
-        __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
+        __ cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
                 Immediate(Factory::null_value()));
-        deferred->enter()->Branch(not_equal, not_taken);
-        // Load key and check that it is a smi.
-        __ mov(eax, Operand(esp, 0));
-        __ test(eax, Immediate(kSmiTagMask));
-        deferred->enter()->Branch(not_zero, not_taken);
-        // Shift to get actual index value.
-        __ sar(eax, kSmiTagSize);
+        deferred->enter()->Branch(not_equal, &receiver, &key, not_taken);
+
+        // Check that the key is a smi.
+        __ test(key.reg(), Immediate(kSmiTagMask));
+        deferred->enter()->Branch(not_zero, &receiver, &key, not_taken);
+
          // Get the elements array from the receiver and check that it
          // is not a dictionary.
-        __ mov(edx, FieldOperand(edx, JSObject::kElementsOffset));
-        __ cmp(FieldOperand(edx, HeapObject::kMapOffset),
+        Result elements = cgen_->allocator()->Allocate();
+        ASSERT(elements.is_valid());
+        __ mov(elements.reg(),
+               FieldOperand(receiver.reg(), JSObject::kElementsOffset));
+        __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset),
                 Immediate(Factory::hash_table_map()));
-        deferred->enter()->Branch(equal, not_taken);
-        // Check that key is within bounds.
-        __ cmp(eax, FieldOperand(edx, Array::kLengthOffset));
-        deferred->enter()->Branch(above_equal, not_taken);
-        // Load and check that the result is not the hole.
-        __ mov(eax,
-               Operand(edx, eax, times_4, Array::kHeaderSize -  
kHeapObjectTag));
-        __ cmp(Operand(eax), Immediate(Factory::the_hole_value()));
-        deferred->enter()->Branch(equal, not_taken);
+        deferred->enter()->Branch(equal, &receiver, &key, not_taken);
+
+        // Shift the key to get the actual index value and check that
+        // it is within bounds.
+        Result index = cgen_->allocator()->Allocate();
+        ASSERT(index.is_valid());
+        __ mov(index.reg(), key.reg());
+        __ sar(index.reg(), kSmiTagSize);
+        __ cmp(index.reg(),
+               FieldOperand(elements.reg(), Array::kLengthOffset));
+        deferred->enter()->Branch(above_equal, &receiver, &key, not_taken);
+
+        // Load and check that the result is not the hole.  We could
+        // reuse the index or elements register for the value.
+        //
+        // TODO(): Consider whether it makes sense to try some
+        // heuristic about which register to reuse.  For example, if
+        // one is eax, the we can reuse that one because the value
+        // coming from the deferred code will be in eax.
+        Result value = index;
+        __ mov(value.reg(), Operand(elements.reg(),
+                                    index.reg(),
+                                    times_4,
+                                    Array::kHeaderSize - kHeapObjectTag));
+        elements.Unuse();
+        index.Unuse();
+        __ cmp(Operand(value.reg()), Immediate(Factory::the_hole_value()));
+        deferred->enter()->Branch(equal, &receiver, &key, not_taken);
          __ IncrementCounter(&Counters::keyed_load_inline, 1);
-        deferred->exit()->Bind();
+
+        // Restore the receiver and key to the frame and push the
+        // result on top of it.
+        cgen_->frame()->Push(&receiver);
+        cgen_->frame()->Push(&key);
+        deferred->exit()->Bind(&value);
+        cgen_->frame()->Push(&value);
+
        } else {
+        VirtualFrame::SpilledScope spilled_scope(cgen_);
+        VirtualFrame* frame = cgen_->frame();
          Comment cmnt(masm, "[ Load from keyed Property");
          Handle<Code>  
ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
          if (is_global) {
@@ -4593,8 +4642,8 @@
          // keyed load.  The explicit nop instruction is here because
          // the push that follows might be peep-hole optimized away.
          __ nop();
+        frame->EmitPush(eax);  // IC call leaves result in eax, push it out
        }
-      frame->EmitPush(eax);  // IC call leaves result in eax, push it out
        break;
      }


Modified: branches/experimental/toiger/src/register-allocator-ia32.h
==============================================================================
--- branches/experimental/toiger/src/register-allocator-ia32.h  (original)
+++ branches/experimental/toiger/src/register-allocator-ia32.h  Tue Jan 13  
00:58:33 2009
@@ -70,7 +70,6 @@
      if (this != &other) {
        Unuse();
        other.CopyTo(this);
-      // other.Unuse();
      }
      return *this;
    }

Modified: branches/experimental/toiger/src/virtual-frame-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-ia32.cc      (original)
+++ branches/experimental/toiger/src/virtual-frame-ia32.cc      Tue Jan 13  
00:58:33 2009
@@ -918,12 +918,15 @@
  }


-void VirtualFrame::CallCodeObject(Handle<Code> code,
-                                  RelocInfo::Mode rmode,
-                                  int frame_arg_count) {
+Result VirtualFrame::CallCodeObject(Handle<Code> code,
+                                    RelocInfo::Mode rmode,
+                                    int frame_arg_count) {
    ASSERT(cgen_->HasValidEntryRegisters());
    PrepareForCall(frame_arg_count);
    __ call(code, rmode);
+  Result result = cgen_->allocator()->Allocate(eax);
+  ASSERT(result.is_valid());
+  return result;
  }



Modified: branches/experimental/toiger/src/virtual-frame-ia32.h
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-ia32.h       (original)
+++ branches/experimental/toiger/src/virtual-frame-ia32.h       Tue Jan 13  
00:58:33 2009
@@ -347,9 +347,9 @@

    // Call into a JS code object, given the number of arguments it expects  
on
    // (and removes from) the top of the physical frame.
-  void CallCodeObject(Handle<Code> ic,
-                      RelocInfo::Mode rmode,
-                      int frame_arg_count);
+  Result CallCodeObject(Handle<Code> ic,
+                        RelocInfo::Mode rmode,
+                        int frame_arg_count);

    // Drop a number of elements from the top of the expression stack.  May
    // emit code to affect the physical frame.  Does not clobber any  
registers

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

Reply via email to