Change KeyedStoreIC interface to take value, key, and receiver in registers.
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 25 Feb 2010 18:04:25 +0000 (18:04 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 25 Feb 2010 18:04:25 +0000 (18:04 +0000)
Review URL: http://codereview.chromium.org/608031

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3955 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ia32/codegen-ia32.cc
src/ia32/full-codegen-ia32.cc
src/ia32/ic-ia32.cc
src/ia32/stub-cache-ia32.cc
src/ia32/virtual-frame-ia32.cc
src/ia32/virtual-frame-ia32.h

index d8c317f61ac6cd2aea9f07557e3db274461bddfc..58f5aa03d661818887de958deb9806502ec9b0bb 100644 (file)
@@ -6694,8 +6694,12 @@ class DeferredReferenceSetKeyedValue: public DeferredCode {
  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 @@ class DeferredReferenceSetKeyedValue: public DeferredCode {
   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 @@ void DeferredReferenceSetKeyedValue::Generate() {
   // 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 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
     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 @@ Result CodeGenerator::EmitKeyedStore(StaticType* key_type) {
     // 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 @@ void Reference::SetValue(InitState init_state) {
       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();
index a7773d81d16abb08d6b7146beff69345cb010db5..299d4f7a97693a1d183e4afd7654aefd0b478f11 100644 (file)
@@ -741,23 +741,22 @@ void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
       // 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 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
     __ 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 @@ void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
 
   // 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 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
       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;
     }
index d6f7881253094956c9558d467ae4262912490ad3..555cd1bf9b6a22839e2478134dec20a53cb2641d 100644 (file)
@@ -622,54 +622,41 @@ void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
 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 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   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 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
   // 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 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
                                          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 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
   // +/-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 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
     __ 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);
+      __ pop(ecx);
+      __ add(Operand(esp), Immediate(kPointerSize));
     }
-    // eax: untagged integer value
+    // 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 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
         // 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 @@ void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
     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 @@ Object* KeyedStoreIC_Miss(Arguments args);
 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::GenerateRuntimeSetProperty(MacroAssembler* masm) {
 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));
index f00eac6d122f9840f6248d1859ca0828e51241c6..a7e9a69a046b7fcbcb554803b6c9dc3f287ab957 100644 (file)
@@ -1691,23 +1691,18 @@ Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
                                                   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,
index 7df028e946bdfc7bc175ed0593648c258635ec53..e7e40f66bb6717f0330c4e8ba3993e3b05e023d6 100644 (file)
@@ -895,30 +895,39 @@ Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
 }
 
 
+// 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 VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
   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 @@ Result VirtualFrame::CallStoreIC(Handle<String> name, bool is_contextual) {
     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);
 }
 
index 7be593cc58f934ef46d6189046c3507a6f246ca5..ba8a071e3beb46699dae186bef73a74a72626f25 100644 (file)
@@ -573,6 +573,14 @@ class VirtualFrame: public ZoneObject {
   // 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);