| Index: src/x64/ic-x64.cc
|
| ===================================================================
|
| --- src/x64/ic-x64.cc (revision 4691)
|
| +++ src/x64/ic-x64.cc (working copy)
|
| @@ -780,16 +780,16 @@
|
| void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
|
| // ----------- S t a t e -------------
|
| // -- rax : value
|
| + // -- rcx : key
|
| + // -- rdx : receiver
|
| // -- rsp[0] : return address
|
| - // -- rsp[8] : key
|
| - // -- rsp[16] : receiver
|
| // -----------------------------------
|
|
|
| - __ pop(rcx);
|
| - __ push(Operand(rsp, 1 * kPointerSize)); // receiver
|
| - __ push(Operand(rsp, 1 * kPointerSize)); // key
|
| + __ pop(rbx);
|
| + __ push(rdx); // receiver
|
| + __ push(rcx); // key
|
| __ push(rax); // value
|
| - __ push(rcx); // return address
|
| + __ push(rbx); // return address
|
|
|
| // Do tail-call to runtime routine.
|
| ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
|
| @@ -800,16 +800,16 @@
|
| void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
|
| // ----------- S t a t e -------------
|
| // -- rax : value
|
| + // -- rcx : key
|
| + // -- rdx : receiver
|
| // -- rsp[0] : return address
|
| - // -- rsp[8] : key
|
| - // -- rsp[16] : receiver
|
| // -----------------------------------
|
|
|
| - __ pop(rcx);
|
| - __ push(Operand(rsp, 1 * kPointerSize)); // receiver
|
| - __ push(Operand(rsp, 1 * kPointerSize)); // key
|
| + __ pop(rbx);
|
| + __ push(rdx); // receiver
|
| + __ push(rcx); // key
|
| __ push(rax); // value
|
| - __ push(rcx); // return address
|
| + __ push(rbx); // return address
|
|
|
| // Do tail-call to runtime routine.
|
| __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
|
| @@ -818,50 +818,46 @@
|
|
|
| void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
|
| // ----------- S t a t e -------------
|
| - // -- rax : value
|
| - // -- rsp[0] : return address
|
| - // -- rsp[8] : key
|
| - // -- rsp[16] : receiver
|
| + // -- rax : value
|
| + // -- rcx : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| // -----------------------------------
|
| Label slow, fast, array, extra, check_pixel_array;
|
|
|
| - // Get the receiver from the stack.
|
| - __ movq(rdx, Operand(rsp, 2 * kPointerSize)); // 2 ~ return address, key
|
| // Check that the object isn't a smi.
|
| __ JumpIfSmi(rdx, &slow);
|
| // Get the map from the receiver.
|
| - __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
|
| + __ movq(rbx, FieldOperand(rdx, 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.
|
| - __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
|
| + __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
|
| Immediate(1 << Map::kIsAccessCheckNeeded));
|
| __ j(not_zero, &slow);
|
| - // Get the key from the stack.
|
| - __ movq(rbx, Operand(rsp, 1 * kPointerSize)); // 1 ~ return address
|
| // Check that the key is a smi.
|
| - __ JumpIfNotSmi(rbx, &slow);
|
| + __ JumpIfNotSmi(rcx, &slow);
|
|
|
| - __ CmpInstanceType(rcx, JS_ARRAY_TYPE);
|
| + __ CmpInstanceType(rbx, JS_ARRAY_TYPE);
|
| __ j(equal, &array);
|
| // Check that the object is some kind of JS object.
|
| - __ CmpInstanceType(rcx, FIRST_JS_OBJECT_TYPE);
|
| + __ CmpInstanceType(rbx, FIRST_JS_OBJECT_TYPE);
|
| __ j(below, &slow);
|
|
|
| // Object case: Check key against length in the elements array.
|
| // rax: value
|
| // rdx: JSObject
|
| - // rbx: index (as a smi)
|
| - __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| + // rcx: index (as a smi)
|
| + __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| // Check that the object is in fast mode (not dictionary).
|
| - __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
|
| + __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
|
| Heap::kFixedArrayMapRootIndex);
|
| __ j(not_equal, &check_pixel_array);
|
| // Untag the key (for checking against untagged length in the fixed array).
|
| - __ SmiToInteger32(rdx, rbx);
|
| - __ cmpl(rdx, FieldOperand(rcx, Array::kLengthOffset));
|
| + __ SmiToInteger32(rdi, rcx);
|
| + __ cmpl(rdi, FieldOperand(rbx, Array::kLengthOffset));
|
| // rax: value
|
| - // rcx: FixedArray
|
| - // rbx: index (as a smi)
|
| + // rbx: FixedArray
|
| + // rcx: index (as a smi)
|
| __ j(below, &fast);
|
|
|
| // Slow case: call runtime.
|
| @@ -870,31 +866,31 @@
|
|
|
| // Check whether the elements is a pixel array.
|
| // rax: value
|
| - // rcx: elements array
|
| - // rbx: index (as a smi), zero-extended.
|
| + // rdx: receiver
|
| + // rbx: receiver's elements array
|
| + // rcx: index (as a smi), zero-extended.
|
| __ bind(&check_pixel_array);
|
| - __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
|
| + __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
|
| Heap::kPixelArrayMapRootIndex);
|
| __ j(not_equal, &slow);
|
| // Check that the value is a smi. If a conversion is needed call into the
|
| // runtime to convert and clamp.
|
| __ JumpIfNotSmi(rax, &slow);
|
| - __ SmiToInteger32(rbx, rbx);
|
| - __ cmpl(rbx, FieldOperand(rcx, PixelArray::kLengthOffset));
|
| + __ SmiToInteger32(rdi, rcx);
|
| + __ cmpl(rdi, FieldOperand(rbx, PixelArray::kLengthOffset));
|
| __ j(above_equal, &slow);
|
| - __ movq(rdx, rax); // Save the value.
|
| - __ SmiToInteger32(rax, rax);
|
| + // No more bailouts to slow case on this path, so key not needed.
|
| + __ SmiToInteger32(rcx, rax);
|
| { // Clamp the value to [0..255].
|
| Label done;
|
| - __ testl(rax, Immediate(0xFFFFFF00));
|
| + __ testl(rcx, Immediate(0xFFFFFF00));
|
| __ j(zero, &done);
|
| - __ setcc(negative, rax); // 1 if negative, 0 if positive.
|
| - __ decb(rax); // 0 if negative, 255 if positive.
|
| + __ setcc(negative, rcx); // 1 if negative, 0 if positive.
|
| + __ decb(rcx); // 0 if negative, 255 if positive.
|
| __ bind(&done);
|
| }
|
| - __ movq(rcx, FieldOperand(rcx, PixelArray::kExternalPointerOffset));
|
| - __ movb(Operand(rcx, rbx, times_1, 0), rax);
|
| - __ movq(rax, rdx); // Return the original value.
|
| + __ movq(rbx, FieldOperand(rbx, PixelArray::kExternalPointerOffset));
|
| + __ movb(Operand(rbx, rdi, times_1, 0), rcx);
|
| __ ret(0);
|
|
|
| // Extra capacity case: Check if there is extra capacity to
|
| @@ -902,18 +898,17 @@
|
| // element to the array by writing to array[array.length].
|
| __ bind(&extra);
|
| // rax: value
|
| - // rdx: JSArray
|
| - // rcx: FixedArray
|
| - // rbx: index (as a smi)
|
| + // rdx: receiver (a JSArray)
|
| + // rbx: receiver's elements array (a FixedArray)
|
| + // rcx: index (as a smi)
|
| // flags: smicompare (rdx.length(), rbx)
|
| __ j(not_equal, &slow); // do not leave holes in the array
|
| - __ SmiToInteger64(rbx, rbx);
|
| - __ cmpl(rbx, FieldOperand(rcx, FixedArray::kLengthOffset));
|
| + __ SmiToInteger64(rdi, rcx);
|
| + __ cmpl(rdi, FieldOperand(rbx, FixedArray::kLengthOffset));
|
| __ j(above_equal, &slow);
|
| // Increment and restore smi-tag.
|
| - __ Integer64PlusConstantToSmi(rbx, rbx, 1);
|
| - __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rbx);
|
| - __ SmiSubConstant(rbx, rbx, Smi::FromInt(1));
|
| + __ Integer64PlusConstantToSmi(rdi, rdi, 1);
|
| + __ movq(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
|
| __ jmp(&fast);
|
|
|
| // Array case: Get the length and the elements array from the JS
|
| @@ -921,39 +916,39 @@
|
| // length is always a smi.
|
| __ bind(&array);
|
| // rax: value
|
| - // rdx: JSArray
|
| - // rbx: index (as a smi)
|
| - __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| - __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
|
| + // rdx: receiver (a JSArray)
|
| + // rcx: index (as a smi)
|
| + __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| + __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
|
| Heap::kFixedArrayMapRootIndex);
|
| __ j(not_equal, &slow);
|
|
|
| // Check the key against the length in the array, compute the
|
| // address to store into and fall through to fast case.
|
| - __ SmiCompare(FieldOperand(rdx, JSArray::kLengthOffset), rbx);
|
| + __ SmiCompare(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
|
| __ j(below_equal, &extra);
|
|
|
| // Fast case: Do the store.
|
| __ bind(&fast);
|
| // rax: value
|
| - // rcx: FixedArray
|
| - // rbx: index (as a smi)
|
| + // rbx: receiver's elements array (a FixedArray)
|
| + // rcx: index (as a smi)
|
| Label non_smi_value;
|
| __ JumpIfNotSmi(rax, &non_smi_value);
|
| - SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2);
|
| - __ movq(Operand(rcx, index.reg, index.scale,
|
| + SmiIndex index = masm->SmiToIndex(rcx, rcx, kPointerSizeLog2);
|
| + __ movq(Operand(rbx, index.reg, index.scale,
|
| FixedArray::kHeaderSize - kHeapObjectTag),
|
| rax);
|
| __ ret(0);
|
| __ bind(&non_smi_value);
|
| - // Slow case that needs to retain rbx for use by RecordWrite.
|
| + // Slow case that needs to retain rcx for use by RecordWrite.
|
| // Update write barrier for the elements array address.
|
| - SmiIndex index2 = masm->SmiToIndex(kScratchRegister, rbx, kPointerSizeLog2);
|
| - __ movq(Operand(rcx, index2.reg, index2.scale,
|
| + SmiIndex index2 = masm->SmiToIndex(kScratchRegister, rcx, kPointerSizeLog2);
|
| + __ movq(Operand(rbx, index2.reg, index2.scale,
|
| FixedArray::kHeaderSize - kHeapObjectTag),
|
| rax);
|
| __ movq(rdx, rax);
|
| - __ RecordWriteNonSmi(rcx, 0, rdx, rbx);
|
| + __ RecordWriteNonSmi(rbx, 0, rdx, rcx);
|
| __ ret(0);
|
| }
|
|
|
| @@ -961,102 +956,103 @@
|
| void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
|
| ExternalArrayType array_type) {
|
| // ----------- S t a t e -------------
|
| - // -- rax : value
|
| - // -- rsp[0] : return address
|
| - // -- rsp[8] : key
|
| - // -- rsp[16] : receiver
|
| + // -- rax : value
|
| + // -- rcx : key
|
| + // -- rdx : receiver
|
| + // -- rsp[0] : return address
|
| // -----------------------------------
|
| Label slow, check_heap_number;
|
|
|
| - // Get the receiver from the stack.
|
| - __ movq(rdx, Operand(rsp, 2 * kPointerSize));
|
| // Check that the object isn't a smi.
|
| __ JumpIfSmi(rdx, &slow);
|
| // Get the map from the receiver.
|
| - __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
|
| + __ movq(rbx, FieldOperand(rdx, 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.
|
| - __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
|
| + __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
|
| Immediate(1 << Map::kIsAccessCheckNeeded));
|
| __ j(not_zero, &slow);
|
| - // Get the key from the stack.
|
| - __ movq(rbx, Operand(rsp, 1 * kPointerSize)); // 1 ~ return address
|
| // Check that the key is a smi.
|
| - __ JumpIfNotSmi(rbx, &slow);
|
| + __ JumpIfNotSmi(rcx, &slow);
|
|
|
| // Check that the object is a JS object.
|
| - __ CmpInstanceType(rcx, JS_OBJECT_TYPE);
|
| + __ CmpInstanceType(rbx, JS_OBJECT_TYPE);
|
| __ j(not_equal, &slow);
|
|
|
| // Check that the elements array is the appropriate type of
|
| // ExternalArray.
|
| // rax: value
|
| - // rdx: JSObject
|
| - // rbx: index (as a smi)
|
| - __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| - __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
|
| + // rcx: key (a smi)
|
| + // rdx: receiver (a JSObject)
|
| + __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
|
| + __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
|
| Heap::RootIndexForExternalArrayType(array_type));
|
| __ j(not_equal, &slow);
|
|
|
| // Check that the index is in range.
|
| - __ SmiToInteger32(rbx, rbx); // Untag the index.
|
| - __ cmpl(rbx, FieldOperand(rcx, ExternalArray::kLengthOffset));
|
| + __ SmiToInteger32(rdi, rcx); // Untag the index.
|
| + __ cmpl(rdi, FieldOperand(rbx, 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.
|
| // rax: value
|
| - // rcx: elements array
|
| - // rbx: untagged index
|
| + // rcx: key (a smi)
|
| + // rdx: receiver (a JSObject)
|
| + // rbx: elements array
|
| + // rdi: untagged key
|
| __ JumpIfNotSmi(rax, &check_heap_number);
|
| - __ movq(rdx, rax); // Save the value.
|
| - __ SmiToInteger32(rax, rax);
|
| - __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset));
|
| - // rcx: base pointer of external storage
|
| + // No more branches to slow case on this path. Key and receiver not needed.
|
| + __ SmiToInteger32(rdx, rax);
|
| + __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
|
| + // rbx: base pointer of external storage
|
| switch (array_type) {
|
| case kExternalByteArray:
|
| case kExternalUnsignedByteArray:
|
| - __ movb(Operand(rcx, rbx, times_1, 0), rax);
|
| + __ movb(Operand(rbx, rdi, times_1, 0), rdx);
|
| break;
|
| case kExternalShortArray:
|
| case kExternalUnsignedShortArray:
|
| - __ movw(Operand(rcx, rbx, times_2, 0), rax);
|
| + __ movw(Operand(rbx, rdi, times_2, 0), rdx);
|
| break;
|
| case kExternalIntArray:
|
| case kExternalUnsignedIntArray:
|
| - __ movl(Operand(rcx, rbx, times_4, 0), rax);
|
| + __ movl(Operand(rbx, rdi, times_4, 0), rdx);
|
| break;
|
| case kExternalFloatArray:
|
| // Need to perform int-to-float conversion.
|
| - __ push(rax);
|
| + __ push(rdx);
|
| __ fild_s(Operand(rsp, 0));
|
| - __ pop(rax);
|
| - __ fstp_s(Operand(rcx, rbx, times_4, 0));
|
| + __ pop(rdx);
|
| + __ fstp_s(Operand(rbx, rdi, times_4, 0));
|
| break;
|
| default:
|
| UNREACHABLE();
|
| break;
|
| }
|
| - __ movq(rax, rdx); // Return the original value.
|
| __ ret(0);
|
|
|
| __ bind(&check_heap_number);
|
| - __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rdx);
|
| + // rax: value
|
| + // rcx: key (a smi)
|
| + // rdx: receiver (a JSObject)
|
| + // rbx: elements array
|
| + // rdi: untagged key
|
| + __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
|
| __ j(not_equal, &slow);
|
| + // No more branches to slow case on this path.
|
|
|
| // The WebGL specification leaves the behavior of storing NaN and
|
| // +/-Infinity into integer arrays basically undefined. For more
|
| // reproducible behavior, convert these to zero.
|
| __ fld_d(FieldOperand(rax, HeapNumber::kValueOffset));
|
| - __ movq(rdx, rax); // Save the value.
|
| - __ movq(rcx, FieldOperand(rcx, ExternalArray::kExternalPointerOffset));
|
| - // rbx: untagged index
|
| - // rcx: base pointer of external storage
|
| + __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
|
| + // rdi: untagged index
|
| + // rbx: base pointer of external storage
|
| // top of FPU stack: value
|
| if (array_type == kExternalFloatArray) {
|
| - __ fstp_s(Operand(rcx, rbx, times_4, 0));
|
| - __ movq(rax, rdx); // Return the original value.
|
| + __ fstp_s(Operand(rbx, rdi, times_4, 0));
|
| __ ret(0);
|
| } else {
|
| // Need to perform float-to-int conversion.
|
| @@ -1065,66 +1061,70 @@
|
| __ fucomi(0);
|
| __ j(parity_even, &is_nan);
|
|
|
| - __ push(rax); // Make room on stack
|
| + __ push(rdx); // Make room on the stack. Receiver is no longer needed.
|
| __ fistp_d(Operand(rsp, 0));
|
| - __ pop(rax);
|
| - // rax: untagged integer value
|
| + __ pop(rdx);
|
| + // rdx: value (converted to an untagged integer)
|
| + // rdi: untagged index
|
| + // rbx: base pointer of external storage
|
| switch (array_type) {
|
| case kExternalByteArray:
|
| case kExternalUnsignedByteArray:
|
| - __ movb(Operand(rcx, rbx, times_1, 0), rax);
|
| + __ movb(Operand(rbx, rdi, times_1, 0), rdx);
|
| break;
|
| case kExternalShortArray:
|
| case kExternalUnsignedShortArray:
|
| - __ movw(Operand(rcx, rbx, times_2, 0), rax);
|
| + __ movw(Operand(rbx, rdi, times_2, 0), rdx);
|
| break;
|
| case kExternalIntArray:
|
| case kExternalUnsignedIntArray: {
|
| // We also need to explicitly check for +/-Infinity. These are
|
| // converted to MIN_INT, but we need to be careful not to
|
| - // confuse with legal uses of MIN_INT.
|
| + // confuse with legal uses of MIN_INT. Since MIN_INT truncated
|
| + // to 8 or 16 bits is zero, we only perform this test when storing
|
| + // 32-bit ints.
|
| Label not_infinity;
|
| // This test would apparently detect both NaN and Infinity,
|
| // but we've already checked for NaN using the FPU hardware
|
| // above.
|
| - __ movzxwq(rdi, FieldOperand(rdx, HeapNumber::kValueOffset + 6));
|
| - __ and_(rdi, Immediate(0x7FF0));
|
| - __ cmpw(rdi, Immediate(0x7FF0));
|
| + __ movzxwq(rcx, FieldOperand(rax, HeapNumber::kValueOffset + 6));
|
| + __ and_(rcx, Immediate(0x7FF0));
|
| + __ cmpw(rcx, Immediate(0x7FF0));
|
| __ j(not_equal, ¬_infinity);
|
| - __ movq(rax, Immediate(0));
|
| + __ movq(rdx, Immediate(0));
|
| __ bind(¬_infinity);
|
| - __ movl(Operand(rcx, rbx, times_4, 0), rax);
|
| + __ movl(Operand(rbx, rdi, times_4, 0), rdx);
|
| break;
|
| }
|
| default:
|
| UNREACHABLE();
|
| break;
|
| }
|
| - __ movq(rax, rdx); // Return the original value.
|
| __ ret(0);
|
|
|
| __ bind(&is_nan);
|
| + // rdi: untagged index
|
| + // rbx: base pointer of external storage
|
| __ ffree();
|
| __ fincstp();
|
| - __ movq(rax, Immediate(0));
|
| + __ movq(rdx, Immediate(0));
|
| switch (array_type) {
|
| case kExternalByteArray:
|
| case kExternalUnsignedByteArray:
|
| - __ movb(Operand(rcx, rbx, times_1, 0), rax);
|
| + __ movb(Operand(rbx, rdi, times_1, 0), rdx);
|
| break;
|
| case kExternalShortArray:
|
| case kExternalUnsignedShortArray:
|
| - __ movw(Operand(rcx, rbx, times_2, 0), rax);
|
| + __ movw(Operand(rbx, rdi, times_2, 0), rdx);
|
| break;
|
| case kExternalIntArray:
|
| case kExternalUnsignedIntArray:
|
| - __ movl(Operand(rcx, rbx, times_4, 0), rax);
|
| + __ movl(Operand(rbx, rdi, times_4, 0), rdx);
|
| break;
|
| default:
|
| UNREACHABLE();
|
| break;
|
| }
|
| - __ movq(rax, rdx); // Return the original value.
|
| __ ret(0);
|
| }
|
|
|
|
|