Index: src/ia32/ic-ia32.cc |
=================================================================== |
--- src/ia32/ic-ia32.cc (revision 3954) |
+++ src/ia32/ic-ia32.cc (working copy) |
@@ -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); |
+ __ 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 @@ |
// 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, ¬_infinity); |
- __ mov(eax, 0); |
+ __ mov(ecx, 0); |
__ bind(¬_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)); |