Index: src/x64/codegen-x64.cc |
=================================================================== |
--- src/x64/codegen-x64.cc (revision 5112) |
+++ src/x64/codegen-x64.cc (working copy) |
@@ -4840,8 +4840,13 @@ |
// Duplicate the object as the IC receiver. |
frame_->Dup(); |
Load(property->value()); |
- frame_->Push(key); |
- Result ignored = frame_->CallStoreIC(); |
+ Result ignored = |
+ frame_->CallStoreIC(Handle<String>::cast(key), false); |
+ // A test rax instruction following the store IC call would |
+ // indicate the presence of an inlined version of the |
+ // store. Add a nop to indicate that there is no such |
+ // inlined version. |
+ __ nop(); |
break; |
} |
// Fall through |
@@ -7992,12 +7997,101 @@ |
int expected_height = frame()->height() - (is_contextual ? 1 : 2); |
#endif |
- Result result = frame()->CallStoreIC(name, is_contextual); |
- // A test rax instruction following the call signals that the inobject |
- // property case was inlined. Ensure that there is not a test rax |
- // instruction here. |
- __ nop(); |
+ Result result; |
+ if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) { |
+ result = frame()->CallStoreIC(name, is_contextual); |
+ // A test rax instruction following the call signals that the inobject |
+ // property case was inlined. Ensure that there is not a test rax |
+ // instruction here. |
+ __ nop(); |
+ } else { |
+ // Inline the in-object property case. |
+ JumpTarget slow, done; |
+ Label patch_site; |
+ // Get the value and receiver from the stack. |
+ Result value = frame()->Pop(); |
+ value.ToRegister(); |
+ Result receiver = frame()->Pop(); |
+ receiver.ToRegister(); |
+ |
+ // Allocate result register. |
+ result = allocator()->Allocate(); |
+ ASSERT(result.is_valid() && receiver.is_valid() && value.is_valid()); |
+ |
+ // Check that the receiver is a heap object. |
+ Condition is_smi = __ CheckSmi(receiver.reg()); |
+ slow.Branch(is_smi, &value, &receiver); |
+ |
+ // This is the map check instruction that will be patched. |
+ // Initially use an invalid map to force a failure. The exact |
+ // instruction sequence is important because we use the |
+ // kOffsetToStoreInstruction constant for patching. We avoid using |
+ // the __ macro for the following two instructions because it |
+ // might introduce extra instructions. |
+ __ bind(&patch_site); |
+ masm()->Move(kScratchRegister, Factory::null_value()); |
+ masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
+ kScratchRegister); |
+ // This branch is always a forwards branch so it's always a fixed size |
+ // which allows the assert below to succeed and patching to work. |
+ slow.Branch(not_equal, &value, &receiver); |
+ |
+ // The delta from the patch label to the store offset must be |
+ // statically known. |
+ ASSERT(masm()->SizeOfCodeGeneratedSince(&patch_site) == |
+ StoreIC::kOffsetToStoreInstruction); |
+ |
+ // The initial (invalid) offset has to be large enough to force a 32-bit |
+ // instruction encoding to allow patching with an arbitrary offset. Use |
+ // kMaxInt (minus kHeapObjectTag). |
+ int offset = kMaxInt; |
+ __ movq(FieldOperand(receiver.reg(), offset), value.reg()); |
+ __ movq(result.reg(), value.reg()); |
+ |
+ // Allocate scratch register for write barrier. |
+ Result scratch = allocator()->Allocate(); |
+ ASSERT(scratch.is_valid() && |
+ result.is_valid() && |
+ receiver.is_valid() && |
+ value.is_valid()); |
+ |
+ // The write barrier clobbers all input registers, so spill the |
+ // receiver and the value. |
+ frame_->Spill(receiver.reg()); |
+ frame_->Spill(value.reg()); |
+ |
+ // Update the write barrier. To save instructions in the inlined |
+ // version we do not filter smis. |
+ Label skip_write_barrier; |
+ __ InNewSpace(receiver.reg(), value.reg(), equal, &skip_write_barrier); |
+ int delta_to_record_write = masm_->SizeOfCodeGeneratedSince(&patch_site); |
+ __ lea(scratch.reg(), Operand(receiver.reg(), offset)); |
+ __ RecordWriteHelper(receiver.reg(), scratch.reg(), value.reg()); |
+ if (FLAG_debug_code) { |
+ __ movq(receiver.reg(), Immediate(BitCast<int64_t>(kZapValue))); |
+ __ movq(value.reg(), Immediate(BitCast<int64_t>(kZapValue))); |
+ __ movq(scratch.reg(), Immediate(BitCast<int64_t>(kZapValue))); |
+ } |
+ __ bind(&skip_write_barrier); |
+ value.Unuse(); |
+ scratch.Unuse(); |
+ receiver.Unuse(); |
+ done.Jump(&result); |
+ |
+ slow.Bind(&value, &receiver); |
+ frame()->Push(&receiver); |
+ frame()->Push(&value); |
+ result = frame()->CallStoreIC(name, is_contextual); |
+ // Encode the offset to the map check instruction and the offset |
+ // to the write barrier store address computation in a test rax |
+ // instruction. |
+ int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site); |
+ __ testl(rax, |
+ Immediate((delta_to_record_write << 16) | delta_to_patch_site)); |
+ done.Bind(&result); |
+ } |
+ |
ASSERT_EQ(expected_height, frame()->height()); |
return result; |
} |
@@ -9598,7 +9692,7 @@ |
__ bind(&arg2_is_object); |
__ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); |
__ j(not_equal, &check_undefined_arg2); |
- // Get the untagged integer version of the eax heap number in ecx. |
+ // Get the untagged integer version of the rax heap number in rcx. |
IntegerConvert(masm, rcx, rax); |
__ bind(&done); |
__ movl(rax, rdx); |
@@ -10054,8 +10148,8 @@ |
__ movq(rax, FieldOperand(rax, ConsString::kFirstOffset)); |
__ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
// String is a cons string with empty second part. |
- // eax: first part of cons string. |
- // ebx: map of first part of cons string. |
+ // rax: first part of cons string. |
+ // rbx: map of first part of cons string. |
// Is first part a flat two byte string? |
__ testb(FieldOperand(rbx, Map::kInstanceTypeOffset), |
Immediate(kStringRepresentationMask | kStringEncodingMask)); |