Index: src/x64/stub-cache-x64.cc |
=================================================================== |
--- src/x64/stub-cache-x64.cc (revision 9531) |
+++ src/x64/stub-cache-x64.cc (working copy) |
@@ -645,7 +645,7 @@ |
scratch1, scratch2, scratch3, name, |
miss_label); |
- __ EnterInternalFrame(); |
+ FrameScope scope(masm, StackFrame::INTERNAL); |
// Save the name_ register across the call. |
__ push(name_); |
@@ -662,7 +662,8 @@ |
// Restore the name_ register. |
__ pop(name_); |
- __ LeaveInternalFrame(); |
+ |
+ // Leave the internal frame. |
} |
void LoadWithInterceptor(MacroAssembler* masm, |
@@ -670,19 +671,21 @@ |
Register holder, |
JSObject* holder_obj, |
Label* interceptor_succeeded) { |
- __ EnterInternalFrame(); |
- __ push(holder); // Save the holder. |
- __ push(name_); // Save the name. |
+ { |
+ FrameScope scope(masm, StackFrame::INTERNAL); |
+ __ push(holder); // Save the holder. |
+ __ push(name_); // Save the name. |
- CompileCallLoadPropertyWithInterceptor(masm, |
- receiver, |
- holder, |
- name_, |
- holder_obj); |
+ CompileCallLoadPropertyWithInterceptor(masm, |
+ receiver, |
+ holder, |
+ name_, |
+ holder_obj); |
- __ pop(name_); // Restore the name. |
- __ pop(receiver); // Restore the holder. |
- __ LeaveInternalFrame(); |
+ __ pop(name_); // Restore the name. |
+ __ pop(receiver); // Restore the holder. |
+ // Leave the internal frame. |
+ } |
__ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); |
__ j(not_equal, interceptor_succeeded); |
@@ -781,7 +784,8 @@ |
// Update the write barrier for the array address. |
// Pass the value being stored in the now unused name_reg. |
__ movq(name_reg, rax); |
- __ RecordWrite(receiver_reg, offset, name_reg, scratch); |
+ __ RecordWriteField( |
+ receiver_reg, offset, name_reg, scratch, kDontSaveFPRegs); |
} else { |
// Write to the properties array. |
int offset = index * kPointerSize + FixedArray::kHeaderSize; |
@@ -792,7 +796,8 @@ |
// Update the write barrier for the array address. |
// Pass the value being stored in the now unused name_reg. |
__ movq(name_reg, rax); |
- __ RecordWrite(scratch, offset, name_reg, receiver_reg); |
+ __ RecordWriteField( |
+ scratch, offset, name_reg, receiver_reg, kDontSaveFPRegs); |
} |
// Return the value (register rax). |
@@ -1139,41 +1144,43 @@ |
// Save necessary data before invoking an interceptor. |
// Requires a frame to make GC aware of pushed pointers. |
- __ EnterInternalFrame(); |
+ { |
+ FrameScope frame_scope(masm(), StackFrame::INTERNAL); |
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
- // CALLBACKS case needs a receiver to be passed into C++ callback. |
- __ push(receiver); |
- } |
- __ push(holder_reg); |
- __ push(name_reg); |
+ if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
+ // CALLBACKS case needs a receiver to be passed into C++ callback. |
+ __ push(receiver); |
+ } |
+ __ push(holder_reg); |
+ __ push(name_reg); |
- // Invoke an interceptor. Note: map checks from receiver to |
- // interceptor's holder has been compiled before (see a caller |
- // of this method.) |
- CompileCallLoadPropertyWithInterceptor(masm(), |
- receiver, |
- holder_reg, |
- name_reg, |
- interceptor_holder); |
+ // Invoke an interceptor. Note: map checks from receiver to |
+ // interceptor's holder has been compiled before (see a caller |
+ // of this method.) |
+ CompileCallLoadPropertyWithInterceptor(masm(), |
+ receiver, |
+ holder_reg, |
+ name_reg, |
+ interceptor_holder); |
- // Check if interceptor provided a value for property. If it's |
- // the case, return immediately. |
- Label interceptor_failed; |
- __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); |
- __ j(equal, &interceptor_failed); |
- __ LeaveInternalFrame(); |
- __ ret(0); |
+ // Check if interceptor provided a value for property. If it's |
+ // the case, return immediately. |
+ Label interceptor_failed; |
+ __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); |
+ __ j(equal, &interceptor_failed); |
+ frame_scope.GenerateLeaveFrame(); |
+ __ ret(0); |
- __ bind(&interceptor_failed); |
- __ pop(name_reg); |
- __ pop(holder_reg); |
- if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
- __ pop(receiver); |
+ __ bind(&interceptor_failed); |
+ __ pop(name_reg); |
+ __ pop(holder_reg); |
+ if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
+ __ pop(receiver); |
+ } |
+ |
+ // Leave the internal frame. |
} |
- __ LeaveInternalFrame(); |
- |
// Check that the maps from interceptor's holder to lookup's holder |
// haven't changed. And load lookup's holder into |holder| register. |
if (interceptor_holder != lookup->holder()) { |
@@ -1421,7 +1428,7 @@ |
__ j(not_equal, &call_builtin); |
if (argc == 1) { // Otherwise fall through to call builtin. |
- Label exit, with_write_barrier, attempt_to_grow_elements; |
+ Label attempt_to_grow_elements, with_write_barrier; |
// Get the array's length into rax and calculate new length. |
__ SmiToInteger32(rax, FieldOperand(rdx, JSArray::kLengthOffset)); |
@@ -1435,30 +1442,42 @@ |
__ cmpl(rax, rcx); |
__ j(greater, &attempt_to_grow_elements); |
+ // Check if value is a smi. |
+ __ movq(rcx, Operand(rsp, argc * kPointerSize)); |
+ __ JumpIfNotSmi(rcx, &with_write_barrier); |
+ |
// Save new length. |
__ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); |
// Push the element. |
- __ movq(rcx, Operand(rsp, argc * kPointerSize)); |
__ lea(rdx, FieldOperand(rbx, |
rax, times_pointer_size, |
FixedArray::kHeaderSize - argc * kPointerSize)); |
__ movq(Operand(rdx, 0), rcx); |
- // Check if value is a smi. |
__ Integer32ToSmi(rax, rax); // Return new length as smi. |
- |
- __ JumpIfNotSmi(rcx, &with_write_barrier); |
- |
- __ bind(&exit); |
__ ret((argc + 1) * kPointerSize); |
__ bind(&with_write_barrier); |
- __ InNewSpace(rbx, rcx, equal, &exit); |
+ if (FLAG_smi_only_arrays) { |
+ __ movq(rdi, FieldOperand(rdx, HeapObject::kMapOffset)); |
+ __ CheckFastObjectElements(rdi, &call_builtin); |
+ } |
- __ RecordWriteHelper(rbx, rdx, rcx); |
+ // Save new length. |
+ __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rax); |
+ // Push the element. |
+ __ lea(rdx, FieldOperand(rbx, |
+ rax, times_pointer_size, |
+ FixedArray::kHeaderSize - argc * kPointerSize)); |
+ __ movq(Operand(rdx, 0), rcx); |
+ |
+ __ RecordWrite( |
+ rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
+ |
+ __ Integer32ToSmi(rax, rax); // Return new length as smi. |
__ ret((argc + 1) * kPointerSize); |
__ bind(&attempt_to_grow_elements); |
@@ -1466,6 +1485,17 @@ |
__ jmp(&call_builtin); |
} |
+ __ movq(rdi, Operand(rsp, argc * kPointerSize)); |
+ if (FLAG_smi_only_arrays) { |
+ // Growing elements that are SMI-only requires special handling in case |
+ // the new element is non-Smi. For now, delegate to the builtin. |
+ Label no_fast_elements_check; |
+ __ JumpIfSmi(rdi, &no_fast_elements_check); |
+ __ movq(rsi, FieldOperand(rdx, HeapObject::kMapOffset)); |
+ __ CheckFastObjectElements(rsi, &call_builtin, Label::kFar); |
+ __ bind(&no_fast_elements_check); |
+ } |
+ |
ExternalReference new_space_allocation_top = |
ExternalReference::new_space_allocation_top_address(isolate()); |
ExternalReference new_space_allocation_limit = |
@@ -1489,16 +1519,22 @@ |
// We fit and could grow elements. |
__ Store(new_space_allocation_top, rcx); |
- __ movq(rcx, Operand(rsp, argc * kPointerSize)); |
// Push the argument... |
- __ movq(Operand(rdx, 0), rcx); |
+ __ movq(Operand(rdx, 0), rdi); |
// ... and fill the rest with holes. |
__ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
for (int i = 1; i < kAllocationDelta; i++) { |
__ movq(Operand(rdx, i * kPointerSize), kScratchRegister); |
} |
+ // We know the elements array is in new space so we don't need the |
+ // remembered set, but we just pushed a value onto it so we may have to |
+ // tell the incremental marker to rescan the object that we just grew. We |
+ // don't need to worry about the holes because they are in old space and |
+ // already marked black. |
+ __ RecordWrite(rbx, rdx, rdi, kDontSaveFPRegs, OMIT_REMEMBERED_SET); |
+ |
// Restore receiver to rdx as finish sequence assumes it's here. |
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
@@ -1510,7 +1546,6 @@ |
__ Integer32ToSmi(rax, rax); |
__ movq(FieldOperand(rdx, JSArray::kLengthOffset), rax); |
- // Elements are in new space, so write barrier is not required. |
__ ret((argc + 1) * kPointerSize); |
} |
@@ -2463,19 +2498,36 @@ |
Handle<Map>(object->map())); |
__ j(not_equal, &miss); |
+ // Compute the cell operand to use. |
+ __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); |
+ Operand cell_operand = FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset); |
+ |
// Check that the value in the cell is not the hole. If it is, this |
// cell could have been deleted and reintroducing the global needs |
// to update the property details in the property dictionary of the |
// global object. We bail out to the runtime system to do that. |
- __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); |
- __ CompareRoot(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), |
- Heap::kTheHoleValueRootIndex); |
+ __ CompareRoot(cell_operand, Heap::kTheHoleValueRootIndex); |
__ j(equal, &miss); |
// Store the value in the cell. |
- __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rax); |
+ __ movq(cell_operand, rax); |
+ Label done; |
+ __ JumpIfSmi(rax, &done); |
+ __ movq(rcx, rax); |
+ __ lea(rdx, cell_operand); |
+ // Cells are always in the remembered set. |
+ __ RecordWrite(rbx, // Object. |
+ rdx, // Address. |
+ rcx, // Value. |
+ kDontSaveFPRegs, |
+ OMIT_REMEMBERED_SET, |
+ OMIT_SMI_CHECK); |
+ |
+ |
// Return the value (register rax). |
+ __ bind(&done); |
+ |
Counters* counters = isolate()->counters(); |
__ IncrementCounter(counters->named_store_global_inline(), 1); |
__ ret(0); |
@@ -3436,6 +3488,7 @@ |
__ movsd(Operand(rbx, rdi, times_8, 0), xmm0); |
break; |
case FAST_ELEMENTS: |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: |
case DICTIONARY_ELEMENTS: |
case NON_STRICT_ARGUMENTS_ELEMENTS: |
@@ -3503,6 +3556,7 @@ |
case EXTERNAL_FLOAT_ELEMENTS: |
case EXTERNAL_DOUBLE_ELEMENTS: |
case FAST_ELEMENTS: |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: |
case DICTIONARY_ELEMENTS: |
case NON_STRICT_ARGUMENTS_ELEMENTS: |
@@ -3634,8 +3688,10 @@ |
} |
-void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, |
- bool is_js_array) { |
+void KeyedStoreStubCompiler::GenerateStoreFastElement( |
+ MacroAssembler* masm, |
+ bool is_js_array, |
+ ElementsKind elements_kind) { |
// ----------- S t a t e ------------- |
// -- rax : value |
// -- rcx : key |
@@ -3665,13 +3721,22 @@ |
__ j(above_equal, &miss_force_generic); |
} |
- // Do the store and update the write barrier. Make sure to preserve |
- // the value in register eax. |
- __ movq(rdx, rax); |
- __ SmiToInteger32(rcx, rcx); |
- __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), |
- rax); |
- __ RecordWrite(rdi, 0, rdx, rcx); |
+ // Do the store and update the write barrier. |
+ if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
+ __ JumpIfNotSmi(rax, &miss_force_generic); |
+ __ SmiToInteger32(rcx, rcx); |
+ __ movq(FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize), |
+ rax); |
+ } else { |
+ ASSERT(elements_kind == FAST_ELEMENTS); |
+ __ SmiToInteger32(rcx, rcx); |
+ __ lea(rcx, |
+ FieldOperand(rdi, rcx, times_pointer_size, FixedArray::kHeaderSize)); |
+ __ movq(Operand(rcx, 0), rax); |
+ // Make sure to preserve the value in register rax. |
+ __ movq(rdx, rax); |
+ __ RecordWrite(rdi, rcx, rdx, kDontSaveFPRegs); |
+ } |
// Done. |
__ ret(0); |
@@ -3693,8 +3758,7 @@ |
// -- rdx : receiver |
// -- rsp[0] : return address |
// ----------------------------------- |
- Label miss_force_generic, smi_value, is_nan, maybe_nan; |
- Label have_double_value, not_nan; |
+ Label miss_force_generic; |
// This stub is meant to be tail-jumped to, the receiver must already |
// have been verified by the caller to not be a smi. |
@@ -3715,52 +3779,10 @@ |
__ j(above_equal, &miss_force_generic); |
// Handle smi values specially |
- __ JumpIfSmi(rax, &smi_value, Label::kNear); |
- |
- __ CheckMap(rax, |
- masm->isolate()->factory()->heap_number_map(), |
- &miss_force_generic, |
- DONT_DO_SMI_CHECK); |
- |
- // Double value, canonicalize NaN. |
- uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); |
- __ cmpl(FieldOperand(rax, offset), |
- Immediate(kNaNOrInfinityLowerBoundUpper32)); |
- __ j(greater_equal, &maybe_nan, Label::kNear); |
- |
- __ bind(¬_nan); |
- __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); |
- __ bind(&have_double_value); |
__ SmiToInteger32(rcx, rcx); |
- __ movsd(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize), |
- xmm0); |
+ __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0, &miss_force_generic); |
__ ret(0); |
- __ bind(&maybe_nan); |
- // Could be NaN or Infinity. If fraction is not zero, it's NaN, otherwise |
- // it's an Infinity, and the non-NaN code path applies. |
- __ j(greater, &is_nan, Label::kNear); |
- __ cmpl(FieldOperand(rax, HeapNumber::kValueOffset), Immediate(0)); |
- __ j(zero, ¬_nan); |
- __ bind(&is_nan); |
- // Convert all NaNs to the same canonical NaN value when they are stored in |
- // the double array. |
- __ Set(kScratchRegister, BitCast<uint64_t>( |
- FixedDoubleArray::canonical_not_the_hole_nan_as_double())); |
- __ movq(xmm0, kScratchRegister); |
- __ jmp(&have_double_value, Label::kNear); |
- |
- __ bind(&smi_value); |
- // Value is a smi. convert to a double and store. |
- // Preserve original value. |
- __ SmiToInteger32(rdx, rax); |
- __ push(rdx); |
- __ fild_s(Operand(rsp, 0)); |
- __ pop(rdx); |
- __ SmiToInteger32(rcx, rcx); |
- __ fstp_d(FieldOperand(rdi, rcx, times_8, FixedDoubleArray::kHeaderSize)); |
- __ ret(0); |
- |
// Handle store cache miss, replacing the ic with the generic stub. |
__ bind(&miss_force_generic); |
Handle<Code> ic_force_generic = |