Revision: 3955
Author: [email protected]
Date: Thu Feb 25 10:04:25 2010
Log: Change KeyedStoreIC interface to take value, key, and receiver in registers.
Review URL: http://codereview.chromium.org/608031
http://code.google.com/p/v8/source/detail?r=3955

Modified:
 /branches/bleeding_edge/src/ia32/codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
 /branches/bleeding_edge/src/ia32/ic-ia32.cc
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc
 /branches/bleeding_edge/src/ia32/virtual-frame-ia32.h

=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Feb 25 05:06:05 2010 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Feb 25 10:04:25 2010
@@ -6694,8 +6694,12 @@
  public:
   DeferredReferenceSetKeyedValue(Register value,
                                  Register key,
-                                 Register receiver)
-      : value_(value), key_(key), receiver_(receiver) {
+                                 Register receiver,
+                                 Register scratch)
+      : value_(value),
+        key_(key),
+        receiver_(receiver),
+        scratch_(scratch) {
     set_comment("[ DeferredReferenceSetKeyedValue");
   }

@@ -6707,17 +6711,65 @@
   Register value_;
   Register key_;
   Register receiver_;
+  Register scratch_;
   Label patch_site_;
 };


 void DeferredReferenceSetKeyedValue::Generate() {
   __ IncrementCounter(&Counters::keyed_store_inline_miss, 1);
-  // Push receiver and key arguments on the stack.
-  __ push(receiver_);
-  __ push(key_);
-  // Move value argument to eax as expected by the IC stub.
-  if (!value_.is(eax)) __ mov(eax, value_);
+  // Move value_ to eax, key_ to ecx, and receiver_ to edx.
+  Register old_value = value_;
+
+  // First, move value to eax.
+  if (!value_.is(eax)) {
+    if (key_.is(eax)) {
+      // Move key_ out of eax, preferably to ecx.
+      if (!value_.is(ecx) && !receiver_.is(ecx)) {
+        __ mov(ecx, key_);
+        key_ = ecx;
+      } else {
+        __ mov(scratch_, key_);
+        key_ = scratch_;
+      }
+    }
+    if (receiver_.is(eax)) {
+      // Move receiver_ out of eax, preferably to edx.
+      if (!value_.is(edx) && !key_.is(edx)) {
+        __ mov(edx, receiver_);
+        receiver_ = edx;
+      } else {
+ // Both moves to scratch are from eax, also, no valid path hits both.
+        __ mov(scratch_, receiver_);
+        receiver_ = scratch_;
+      }
+    }
+    __ mov(eax, value_);
+    value_ = eax;
+  }
+
+  // Now value_ is in eax.  Move the other two to the right positions.
+  // We do not update the variables key_ and receiver_ to ecx and edx.
+  if (key_.is(ecx)) {
+    if (!receiver_.is(edx)) {
+      __ mov(edx, receiver_);
+    }
+  } else if (key_.is(edx)) {
+    if (receiver_.is(ecx)) {
+      __ xchg(edx, ecx);
+    } else {
+      __ mov(ecx, key_);
+      if (!receiver_.is(edx)) {
+        __ mov(edx, receiver_);
+      }
+    }
+  } else {  // Key is not in edx or ecx.
+    if (!receiver_.is(edx)) {
+      __ mov(edx, receiver_);
+    }
+    __ mov(ecx, key_);
+  }
+
   // Call the IC stub.
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
   __ call(ic, RelocInfo::CODE_TARGET);
@@ -6730,11 +6782,8 @@
   // Here we use masm_-> instead of the __ macro because this is the
   // instruction that gets patched and coverage code gets in the way.
   masm_->test(eax, Immediate(-delta_to_patch_site));
-  // Restore value (returned from store IC), key and receiver
-  // registers.
-  if (!value_.is(eax)) __ mov(value_, eax);
-  __ pop(key_);
-  __ pop(receiver_);
+  // Restore value (returned from store IC) register.
+  if (!old_value.is(eax)) __ mov(old_value, eax);
 }


@@ -6933,7 +6982,8 @@
     DeferredReferenceSetKeyedValue* deferred =
         new DeferredReferenceSetKeyedValue(result.reg(),
                                            key.reg(),
-                                           receiver.reg());
+                                           receiver.reg(),
+                                           tmp.reg());

     // Check that the value is a smi if it is not a constant.  We can skip
     // the write barrier for smis and constants.
@@ -6993,7 +7043,6 @@
     // indicate that we have generated an inline version of the
     // keyed store.
     __ nop();
-    frame()->Drop(2);
   }
   ASSERT(frame()->height() == original_height - 3);
   return result;
@@ -7135,6 +7184,7 @@
       Comment cmnt(masm, "[ Store to keyed Property");
       Property* property = expression()->AsProperty();
       ASSERT(property != NULL);
+
       Result answer = cgen_->EmitKeyedStore(property->key()->type());
       cgen_->frame()->Push(&answer);
       set_unloaded();
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Tue Feb 23 04:40:36 2010 +++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Thu Feb 25 10:04:25 2010
@@ -741,23 +741,22 @@
       // We are declaring a function or constant that rewrites to a
       // property.  Use (keyed) IC to set the initial value.
       VisitForValue(prop->obj(), kStack);
-      VisitForValue(prop->key(), kStack);
-
       if (decl->fun() != NULL) {
+        VisitForValue(prop->key(), kStack);
         VisitForValue(decl->fun(), kAccumulator);
+        __ pop(ecx);
       } else {
+        VisitForValue(prop->key(), kAccumulator);
+        __ mov(ecx, result_register());
         __ mov(result_register(), Factory::the_hole_value());
       }
+      __ pop(edx);

Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
       __ call(ic, RelocInfo::CODE_TARGET);
       // Absence of a test eax instruction following the call
       // indicates that none of the load was inlined.
       __ nop();
-
-      // Value in eax is ignored (declarations are statements).  Receiver
-      // and key on stack are discarded.
-      __ Drop(2);
     }
   }
 }
@@ -1251,6 +1250,12 @@
     __ pop(result_register());
   }

+  __ pop(ecx);
+  if (expr->ends_initialization_block()) {
+ __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
+  } else {
+    __ pop(edx);
+  }
   // Record source code position before IC call.
   SetSourcePosition(expr->position());
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
@@ -1261,15 +1266,14 @@

   // If the assignment ends an initialization block, revert to fast case.
   if (expr->ends_initialization_block()) {
+    __ pop(edx);
     __ push(eax);  // Result of assignment, saved even if not needed.
-    // Receiver is under the key and value.
-    __ push(Operand(esp, 2 * kPointerSize));
+    __ push(edx);
     __ CallRuntime(Runtime::kToFastProperties, 1);
     __ pop(eax);
   }

-  // Receiver and key are still on stack.
-  DropAndApply(2, context_, eax);
+  Apply(context_, eax);
 }


@@ -1777,18 +1781,20 @@
       break;
     }
     case KEYED_PROPERTY: {
+      __ pop(ecx);
+      __ pop(edx);
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
       __ call(ic, RelocInfo::CODE_TARGET);
// This nop signals to the IC that there is no inlined code at the call
       // site for it to patch.
       __ nop();
       if (expr->is_postfix()) {
- __ Drop(2); // Result is on the stack under the key and the receiver.
+        // Result is on the stack
         if (context_ != Expression::kEffect) {
           ApplyTOS(context_);
         }
       } else {
-        DropAndApply(2, context_, eax);
+        Apply(context_, eax);
       }
       break;
     }
=======================================
--- /branches/bleeding_edge/src/ia32/ic-ia32.cc Wed Feb 24 00:33:51 2010
+++ /branches/bleeding_edge/src/ia32/ic-ia32.cc Thu Feb 25 10:04:25 2010
@@ -622,54 +622,41 @@
 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------
   Label slow, fast, array, extra, check_pixel_array;

-  // Get the receiver from the stack.
-  __ mov(edx, Operand(esp, 2 * kPointerSize));  // 2 ~ return address, key
   // Check that the object isn't a smi.
   __ test(edx, Immediate(kSmiTagMask));
   __ j(zero, &slow, not_taken);
   // Get the map from the receiver.
-  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
   // Check that the receiver does not require access checks.  We need
   // to do this because this generic stub does not perform map checks.
-  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
+  __ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
   __ j(not_zero, &slow, not_taken);
-  // Get the key from the stack.
-  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
   // Check that the key is a smi.
-  __ test(ebx, Immediate(kSmiTagMask));
+  __ test(ecx, Immediate(kSmiTagMask));
   __ j(not_zero, &slow, not_taken);
-  // Get the instance type from the map of the receiver.
-  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
-  // Check if the object is a JS array or not.
-  __ cmp(ecx, JS_ARRAY_TYPE);
+  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
   __ j(equal, &array);
   // Check that the object is some kind of JS object.
-  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
-  __ j(less, &slow, not_taken);
+  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
+  __ j(below, &slow, not_taken);

   // Object case: Check key against length in the elements array.
   // eax: value
   // edx: JSObject
-  // ebx: index (as a smi)
-  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
+  // ecx: key (a smi)
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
   // Check that the object is in fast mode (not dictionary).
-  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
-         Immediate(Factory::fixed_array_map()));
-  __ j(not_equal, &check_pixel_array, not_taken);
- // Untag the key (for checking against untagged length in the fixed array).
-  __ mov(edx, Operand(ebx));
- __ sar(edx, kSmiTagSize); // untag the index and use it for the comparison
-  __ cmp(edx, FieldOperand(ecx, Array::kLengthOffset));
-  // eax: value
-  // ecx: FixedArray
-  // ebx: index (as a smi)
+  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
+  __ mov(ebx, Operand(ecx));
+  __ SmiUntag(ebx);
+  __ cmp(ebx, FieldOperand(edi, Array::kLengthOffset));
   __ j(below, &fast, taken);

   // Slow case: call runtime.
@@ -677,52 +664,51 @@
   GenerateRuntimeSetProperty(masm);

   // Check whether the elements is a pixel array.
-  // eax: value
-  // ecx: elements array
-  // ebx: index (as a smi)
   __ bind(&check_pixel_array);
-  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
-         Immediate(Factory::pixel_array_map()));
-  __ j(not_equal, &slow);
+  // eax: value
+  // ecx: key
+  // edx: receiver
+  // edi: elements array
+  __ CheckMap(edi, Factory::pixel_array_map(), &slow, true);
   // Check that the value is a smi. If a conversion is needed call into the
   // runtime to convert and clamp.
   __ test(eax, Immediate(kSmiTagMask));
   __ j(not_zero, &slow);
-  __ sar(ebx, kSmiTagSize);  // Untag the index.
-  __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
+  __ mov(ebx, ecx);
+  __ SmiUntag(ebx);
+  __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset));
   __ j(above_equal, &slow);
-  __ mov(edx, eax);  // Save the value.
-  __ sar(eax, kSmiTagSize);  // Untag the value.
+  __ mov(ecx, eax);  // Save the value. Key is not longer needed.
+  __ SmiUntag(ecx);
   {  // Clamp the value to [0..255].
     Label done;
-    __ test(eax, Immediate(0xFFFFFF00));
+    __ test(ecx, Immediate(0xFFFFFF00));
     __ j(zero, &done);
-    __ setcc(negative, eax);  // 1 if negative, 0 if positive.
-    __ dec_b(eax);  // 0 if negative, 255 if positive.
+    __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
+    __ dec_b(ecx);  // 0 if negative, 255 if positive.
     __ bind(&done);
   }
-  __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
-  __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
-  __ mov(eax, edx);  // Return the original value.
-  __ ret(0);
+  __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset));
+  __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
+  __ ret(0);  // Return value in eax.

   // Extra capacity case: Check if there is extra capacity to
   // perform the store and update the length. Used for adding one
   // element to the array by writing to array[array.length].
   __ bind(&extra);
   // eax: value
-  // edx: JSArray
-  // ecx: FixedArray
-  // ebx: index (as a smi)
-  // flags: compare (ebx, edx.length())
+  // edx: receiver, a JSArray
+  // ecx: key, a smi.
+  // edi: receiver->elements, a FixedArray
+  // flags: compare (ecx, edx.length())
   __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
-  __ sar(ebx, kSmiTagSize);  // untag
-  __ cmp(ebx, FieldOperand(ecx, Array::kLengthOffset));
+  __ mov(ebx, ecx);
+  __ SmiUntag(ebx);  // untag
+  __ cmp(ebx, FieldOperand(edi, Array::kLengthOffset));
   __ j(above_equal, &slow, not_taken);
-  // Restore tag and increment.
-  __ lea(ebx, Operand(ebx, times_2, 1 << kSmiTagSize));
-  __ mov(FieldOperand(edx, JSArray::kLengthOffset), ebx);
- __ sub(Operand(ebx), Immediate(1 << kSmiTagSize)); // decrement ebx again
+  // Add 1 to receiver->length, and go to fast array write.
+  __ add(FieldOperand(edx, JSArray::kLengthOffset),
+         Immediate(1 << kSmiTagSize));
   __ jmp(&fast);

   // Array case: Get the length and the elements array from the JS
@@ -730,28 +716,26 @@
   // length is always a smi.
   __ bind(&array);
   // eax: value
-  // edx: JSArray
-  // ebx: index (as a smi)
-  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
-  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
-         Immediate(Factory::fixed_array_map()));
-  __ j(not_equal, &check_pixel_array);
+  // edx: receiver, a JSArray
+  // ecx: key, a smi.
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);

   // Check the key against the length in the array, compute the
   // address to store into and fall through to fast case.
-  __ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset));
+  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
   __ j(above_equal, &extra, not_taken);

   // Fast case: Do the store.
   __ bind(&fast);
   // eax: value
-  // ecx: FixedArray
-  // ebx: index (as a smi)
- __ mov(Operand(ecx, ebx, times_2, FixedArray::kHeaderSize - kHeapObjectTag),
-         eax);
+  // ecx: key (a smi)
+  // edx: receiver
+  // edi: FixedArray receiver->elements
+  __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
   // Update write barrier for the elements array address.
   __ mov(edx, Operand(eax));
-  __ RecordWrite(ecx, 0, edx, ebx);
+  __ RecordWrite(edi, 0, edx, ecx);
   __ ret(0);
 }

@@ -760,92 +744,91 @@
                                          ExternalArrayType array_type) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------
   Label slow, check_heap_number;

-  // Get the receiver from the stack.
-  __ mov(edx, Operand(esp, 2 * kPointerSize));
   // Check that the object isn't a smi.
   __ test(edx, Immediate(kSmiTagMask));
   __ j(zero, &slow);
   // Get the map from the receiver.
-  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
+  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
   // Check that the receiver does not require access checks.  We need
   // to do this because this generic stub does not perform map checks.
-  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
+  __ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
   __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
   __ j(not_zero, &slow);
-  // Get the key from the stack.
-  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
   // Check that the key is a smi.
-  __ test(ebx, Immediate(kSmiTagMask));
+  __ test(ecx, Immediate(kSmiTagMask));
   __ j(not_zero, &slow);
   // Get the instance type from the map of the receiver.
-  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
-  // Check that the object is a JS object.
-  __ cmp(ecx, JS_OBJECT_TYPE);
+  __ CmpInstanceType(edi, JS_OBJECT_TYPE);
   __ j(not_equal, &slow);

   // Check that the elements array is the appropriate type of
   // ExternalArray.
   // eax: value
-  // edx: JSObject
-  // ebx: index (as a smi)
-  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
-  Handle<Map> map(Heap::MapForExternalArrayType(array_type));
-  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
-         Immediate(map));
-  __ j(not_equal, &slow);
+  // edx: receiver, a JSObject
+  // ecx: key, a smi
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+  __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)),
+              &slow, true);

   // Check that the index is in range.
-  __ sar(ebx, kSmiTagSize);  // Untag the index.
-  __ cmp(ebx, FieldOperand(ecx, ExternalArray::kLengthOffset));
+  __ mov(ebx, ecx);
+  __ SmiUntag(ebx);
+  __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
   // Unsigned comparison catches both negative and too-large values.
   __ j(above_equal, &slow);

   // Handle both smis and HeapNumbers in the fast path. Go to the
   // runtime for all other kinds of values.
   // eax: value
-  // ecx: elements array
+  // edx: receiver
+  // ecx: key
+  // edi: elements array
   // ebx: untagged index
   __ test(eax, Immediate(kSmiTagMask));
   __ j(not_equal, &check_heap_number);
   // smi case
-  __ mov(edx, eax);  // Save the value.
-  __ sar(eax, kSmiTagSize);  // Untag the value.
-  __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset));
+ __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed.
+  __ SmiUntag(ecx);
+  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
   // ecx: base pointer of external storage
   switch (array_type) {
     case kExternalByteArray:
     case kExternalUnsignedByteArray:
-      __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
+      __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
       break;
     case kExternalShortArray:
     case kExternalUnsignedShortArray:
-      __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
+      __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
       break;
     case kExternalIntArray:
     case kExternalUnsignedIntArray:
-      __ mov(Operand(ecx, ebx, times_4, 0), eax);
+      __ mov(Operand(edi, ebx, times_4, 0), ecx);
       break;
     case kExternalFloatArray:
       // Need to perform int-to-float conversion.
-      __ push(eax);
+      __ push(ecx);
       __ fild_s(Operand(esp, 0));
-      __ pop(eax);
-      __ fstp_s(Operand(ecx, ebx, times_4, 0));
+      __ pop(ecx);
+      __ fstp_s(Operand(edi, ebx, times_4, 0));
       break;
     default:
       UNREACHABLE();
       break;
   }
-  __ mov(eax, edx);  // Return the original value.
-  __ ret(0);
+  __ ret(0);  // Return the original value.

   __ bind(&check_heap_number);
+  // eax: value
+  // edx: receiver
+  // ecx: key
+  // edi: elements array
+  // ebx: untagged index
   __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
          Immediate(Factory::heap_number_map()));
   __ j(not_equal, &slow);
@@ -854,14 +837,12 @@
   // +/-Infinity into integer arrays basically undefined. For more
   // reproducible behavior, convert these to zero.
   __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
-  __ mov(edx, eax);  // Save the value.
-  __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset));
+  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
   // ebx: untagged index
-  // ecx: base pointer of external storage
+  // edi: base pointer of external storage
   // top of FPU stack: value
   if (array_type == kExternalFloatArray) {
-    __ fstp_s(Operand(ecx, ebx, times_4, 0));
-    __ mov(eax, edx);  // Return the original value.
+    __ fstp_s(Operand(edi, ebx, times_4, 0));
     __ ret(0);
   } else {
     // Need to perform float-to-int conversion.
@@ -871,29 +852,27 @@
     __ j(parity_even, &is_nan);

     if (array_type != kExternalUnsignedIntArray) {
-      __ push(eax);  // Make room on stack
+      __ push(ecx);  // Make room on stack
       __ fistp_s(Operand(esp, 0));
-      __ pop(eax);
+      __ pop(ecx);
     } else {
       // fistp stores values as signed integers.
       // To represent the entire range, we need to store as a 64-bit
       // int and discard the high 32 bits.
-      __ push(eax);  // Make room on stack
-      __ push(eax);  // Make room on stack
+      __ sub(Operand(esp), Immediate(2 * kPointerSize));
       __ fistp_d(Operand(esp, 0));
-      __ pop(eax);
-      __ mov(Operand(esp, 0), eax);
-      __ pop(eax);
-    }
-    // eax: untagged integer value
+      __ pop(ecx);
+      __ add(Operand(esp), Immediate(kPointerSize));
+    }
+    // ecx: untagged integer value
     switch (array_type) {
       case kExternalByteArray:
       case kExternalUnsignedByteArray:
-        __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
+        __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
         break;
       case kExternalShortArray:
       case kExternalUnsignedShortArray:
-        __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
+        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
         break;
       case kExternalIntArray:
       case kExternalUnsignedIntArray: {
@@ -904,21 +883,20 @@
         // This test would apparently detect both NaN and Infinity,
         // but we've already checked for NaN using the FPU hardware
         // above.
-        __ mov_w(edi, FieldOperand(edx, HeapNumber::kValueOffset + 6));
-        __ and_(edi, 0x7FF0);
-        __ cmp(edi, 0x7FF0);
+        __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6));
+        __ and_(edx, 0x7FF0);
+        __ cmp(edx, 0x7FF0);
         __ j(not_equal, &not_infinity);
-        __ mov(eax, 0);
+        __ mov(ecx, 0);
         __ bind(&not_infinity);
-        __ mov(Operand(ecx, ebx, times_4, 0), eax);
+        __ mov(Operand(edi, ebx, times_4, 0), ecx);
         break;
       }
       default:
         UNREACHABLE();
         break;
     }
-    __ mov(eax, edx);  // Return the original value.
-    __ ret(0);
+    __ ret(0);  // Return original value.

     __ bind(&is_nan);
     __ ffree();
@@ -926,23 +904,22 @@
     switch (array_type) {
       case kExternalByteArray:
       case kExternalUnsignedByteArray:
-        __ mov_b(Operand(ecx, ebx, times_1, 0), 0);
+        __ mov_b(Operand(edi, ebx, times_1, 0), 0);
         break;
       case kExternalShortArray:
       case kExternalUnsignedShortArray:
-        __ mov(eax, 0);
-        __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
+        __ xor_(ecx, Operand(ecx));
+        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
         break;
       case kExternalIntArray:
       case kExternalUnsignedIntArray:
-        __ mov(Operand(ecx, ebx, times_4, 0), Immediate(0));
+        __ mov(Operand(edi, ebx, times_4, 0), Immediate(0));
         break;
       default:
         UNREACHABLE();
         break;
     }
-    __ mov(eax, edx);  // Return the original value.
-    __ ret(0);
+    __ ret(0);  // Return the original value.
   }

   // Slow case: call runtime.
@@ -1497,16 +1474,16 @@
 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------

-  __ pop(ecx);
-  __ push(Operand(esp, 1 * kPointerSize));
-  __ push(Operand(esp, 1 * kPointerSize));
-  __ push(eax);
+  __ pop(ebx);
+  __ push(edx);
   __ push(ecx);
+  __ push(eax);
+  __ push(ebx);

   // Do tail-call to runtime routine.
   __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
@@ -1516,16 +1493,16 @@
 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------

-  __ pop(ecx);
-  __ push(Operand(esp, 1 * kPointerSize));
-  __ push(Operand(esp, 1 * kPointerSize));
-  __ push(eax);
+  __ pop(ebx);
+  __ push(edx);
   __ push(ecx);
+  __ push(eax);
+  __ push(ebx);

   // Do tail-call to runtime routine.
ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Feb 24 11:26:10 2010 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Thu Feb 25 10:04:25 2010
@@ -1691,23 +1691,18 @@
                                                   String* name) {
   // ----------- S t a t e -------------
   //  -- eax    : value
+  //  -- ecx    : key
+  //  -- edx    : receiver
   //  -- esp[0] : return address
-  //  -- esp[4] : key
-  //  -- esp[8] : receiver
   // -----------------------------------
   Label miss;

   __ IncrementCounter(&Counters::keyed_store_field, 1);

-  // Get the name from the stack.
-  __ mov(ecx, Operand(esp, 1 * kPointerSize));
   // Check that the name has not changed.
   __ cmp(Operand(ecx), Immediate(Handle<String>(name)));
   __ j(not_equal, &miss, not_taken);

-  // Get the object from the stack.
-  __ mov(edx, Operand(esp, 2 * kPointerSize));
-
   // Generate store field code.  Trashes the name register.
   GenerateStoreField(masm(),
                      object,
=======================================
--- /branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc Fri Feb 19 07:04:16 2010 +++ /branches/bleeding_edge/src/ia32/virtual-frame-ia32.cc Thu Feb 25 10:04:25 2010
@@ -893,32 +893,41 @@
   ASSERT(result.is_valid());
   return result;
 }
+
+
+// This function assumes that the only results that could be in a_reg or b_reg +// are a and b. Other results can be live, but must not be in a_reg or b_reg.
+void VirtualFrame::MoveResultsToRegisters(Result* a,
+                                          Result* b,
+                                          Register a_reg,
+                                          Register b_reg) {
+  if (a->is_register() && a->reg().is(a_reg)) {
+    b->ToRegister(b_reg);
+  } else if (!cgen()->allocator()->is_used(a_reg)) {
+    a->ToRegister(a_reg);
+    b->ToRegister(b_reg);
+  } else if (cgen()->allocator()->is_used(b_reg)) {
+    // a must be in b_reg, b in a_reg.
+    __ xchg(a_reg, b_reg);
+ // Results a and b will be invalidated, so it is ok if they are switched.
+  } else {
+    b->ToRegister(b_reg);
+    a->ToRegister(a_reg);
+  }
+  a->Unuse();
+  b->Unuse();
+}


 Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
   // Name and receiver are on the top of the frame.  The IC expects
   // name in ecx and receiver in eax.
-  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
   Result name = Pop();
   Result receiver = Pop();
   PrepareForCall(0, 0);  // No stack arguments.
-  // Move results to the right registers:
-  if (name.is_register() && name.reg().is(eax)) {
-    if (receiver.is_register() && receiver.reg().is(ecx)) {
-      // Wrong registers.
-      __ xchg(eax, ecx);
-    } else {
-      // Register ecx is free for name, which frees eax for receiver.
-      name.ToRegister(ecx);
-      receiver.ToRegister(eax);
-    }
-  } else {
-    // Register eax is free for receiver, which frees ecx for name.
-    receiver.ToRegister(eax);
-    name.ToRegister(ecx);
-  }
-  name.Unuse();
-  receiver.Unuse();
+  MoveResultsToRegisters(&name, &receiver, ecx, eax);
+
+  Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
   return RawCallCodeObject(ic, mode);
 }

@@ -928,20 +937,7 @@
   Result key = Pop();
   Result receiver = Pop();
   PrepareForCall(0, 0);
-
-  if (!key.is_register() || !key.reg().is(edx)) {
-    // Register edx is available for receiver.
-    receiver.ToRegister(edx);
-    key.ToRegister(eax);
-  } else if (!receiver.is_register() || !receiver.reg().is(eax)) {
-    // Register eax is available for key.
-    key.ToRegister(eax);
-    receiver.ToRegister(edx);
-  } else {
-    __ xchg(edx, eax);
-  }
-  key.Unuse();
-  receiver.Unuse();
+  MoveResultsToRegisters(&key, &receiver, eax, edx);

   Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
   return RawCallCodeObject(ic, mode);
@@ -958,41 +954,57 @@
     value.ToRegister(eax);
     __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
     __ mov(ecx, name);
+    value.Unuse();
   } else {
     Result receiver = Pop();
     PrepareForCall(0, 0);
-
-    if (value.is_register() && value.reg().is(edx)) {
-      if (receiver.is_register() && receiver.reg().is(eax)) {
-        // Wrong registers.
-        __ xchg(eax, edx);
-      } else {
-        // Register eax is free for value, which frees edx for receiver.
-        value.ToRegister(eax);
-        receiver.ToRegister(edx);
-      }
-    } else {
- // Register edx is free for receiver, which guarantees eax is free for
-      // value.
-      receiver.ToRegister(edx);
-      value.ToRegister(eax);
-    }
+    MoveResultsToRegisters(&value, &receiver, eax, edx);
   }
   __ mov(ecx, name);
-  value.Unuse();
   return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
 }


 Result VirtualFrame::CallKeyedStoreIC() {
   // Value, key, and receiver are on the top of the frame.  The IC
-  // expects value in eax and key and receiver on the stack.  It does
-  // not drop the key and receiver.
-  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+  // expects value in eax, key in ecx, and receiver in edx.
   Result value = Pop();
-  PrepareForCall(2, 0);  // Two stack args, neither callee-dropped.
-  value.ToRegister(eax);
-  value.Unuse();
+  Result key = Pop();
+  Result receiver = Pop();
+  PrepareForCall(0, 0);
+  if (!cgen()->allocator()->is_used(eax) ||
+      (value.is_register() && value.reg().is(eax))) {
+    value.ToRegister(eax);  // No effect if value is in eax already.
+    MoveResultsToRegisters(&key, &receiver, ecx, edx);
+    value.Unuse();
+  } else if (!cgen()->allocator()->is_used(ecx) ||
+             (key.is_register() && key.reg().is(ecx))) {
+    // Receiver and/or key are in eax.
+    key.ToRegister(ecx);
+    MoveResultsToRegisters(&value, &receiver, eax, edx);
+    key.Unuse();
+  } else if (!cgen()->allocator()->is_used(edx) ||
+             (receiver.is_register() && receiver.reg().is(edx))) {
+    receiver.ToRegister(edx);
+    MoveResultsToRegisters(&key, &value, ecx, eax);
+    receiver.Unuse();
+  } else {
+    // All three registers are used, and no value is in the correct place.
+    // We have one of the two circular permutations of eax, ecx, edx.
+    ASSERT(value.is_register());
+    if (value.reg().is(ecx)) {
+      __ xchg(eax, edx);
+      __ xchg(eax, ecx);
+    } else {
+      __ xchg(eax, ecx);
+      __ xchg(eax, edx);
+    }
+    value.Unuse();
+    key.Unuse();
+    receiver.Unuse();
+  }
+
+  Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
   return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
 }

=======================================
--- /branches/bleeding_edge/src/ia32/virtual-frame-ia32.h Fri Feb 19 07:04:16 2010 +++ /branches/bleeding_edge/src/ia32/virtual-frame-ia32.h Thu Feb 25 10:04:25 2010
@@ -573,6 +573,14 @@
   // Register counts are correctly updated.
   int InvalidateFrameSlotAt(int index);

+ // This function assumes that a and b are the only results that could be in
+  // the registers a_reg or b_reg.  Other results can be live, but must not
+ // be in the registers a_reg or b_reg. The results a and b are invalidated.
+  void MoveResultsToRegisters(Result* a,
+                              Result* b,
+                              Register a_reg,
+                              Register b_reg);
+
   // Call a code stub that has already been prepared for calling (via
   // PrepareForCall).
   Result RawCallStub(CodeStub* stub);

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

Reply via email to