From a3a3a1f0be458edc65cd13b7155f62fe526d12f5 Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Thu, 25 Feb 2010 18:04:25 +0000 Subject: [PATCH] Change KeyedStoreIC interface to take value, key, and receiver in registers. 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 | 78 ++++++++-- src/ia32/full-codegen-ia32.cc | 30 ++-- src/ia32/ic-ia32.cc | 255 +++++++++++++++------------------ src/ia32/stub-cache-ia32.cc | 9 +- src/ia32/virtual-frame-ia32.cc | 122 +++++++++------- src/ia32/virtual-frame-ia32.h | 8 ++ 6 files changed, 275 insertions(+), 227 deletions(-) diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index d8c317f61..58f5aa03d 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -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 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(); diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc index a7773d81d..299d4f7a9 100644 --- a/src/ia32/full-codegen-ia32.cc +++ b/src/ia32/full-codegen-ia32.cc @@ -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 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 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 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; } diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc index d6f788125..555cd1bf9 100644 --- a/src/ia32/ic-ia32.cc +++ b/src/ia32/ic-ia32.cc @@ -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(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(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, ¬_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 @@ 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)); diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index f00eac6d1..a7e9a69a0 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -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(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, diff --git a/src/ia32/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc index 7df028e94..e7e40f66b 100644 --- a/src/ia32/virtual-frame-ia32.cc +++ b/src/ia32/virtual-frame-ia32.cc @@ -895,30 +895,39 @@ Result VirtualFrame::RawCallCodeObject(Handle 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 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 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 ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); return RawCallCodeObject(ic, mode); @@ -958,41 +954,57 @@ Result VirtualFrame::CallStoreIC(Handle 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 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 ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); return RawCallCodeObject(ic, RelocInfo::CODE_TARGET); } diff --git a/src/ia32/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h index 7be593cc5..ba8a071e3 100644 --- a/src/ia32/virtual-frame-ia32.h +++ b/src/ia32/virtual-frame-ia32.h @@ -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); -- 2.34.1