Index: src/ia32/stub-cache-ia32.cc |
=================================================================== |
--- src/ia32/stub-cache-ia32.cc (revision 9531) |
+++ src/ia32/stub-cache-ia32.cc (working copy) |
@@ -66,8 +66,8 @@ |
__ j(not_equal, &miss); |
// Jump to the first instruction in the code stub. |
- __ add(Operand(extra), Immediate(Code::kHeaderSize - kHeapObjectTag)); |
- __ jmp(Operand(extra)); |
+ __ add(extra, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
+ __ jmp(extra); |
__ bind(&miss); |
} else { |
@@ -92,8 +92,8 @@ |
__ mov(offset, Operand::StaticArray(offset, times_2, value_offset)); |
// Jump to the first instruction in the code stub. |
- __ add(Operand(offset), Immediate(Code::kHeaderSize - kHeapObjectTag)); |
- __ jmp(Operand(offset)); |
+ __ add(offset, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
+ __ jmp(offset); |
// Pop at miss. |
__ bind(&miss); |
@@ -204,8 +204,8 @@ |
__ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); |
__ xor_(scratch, flags); |
__ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); |
- __ sub(scratch, Operand(name)); |
- __ add(Operand(scratch), Immediate(flags)); |
+ __ sub(scratch, name); |
+ __ add(scratch, Immediate(flags)); |
__ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize); |
// Probe the secondary table. |
@@ -318,7 +318,7 @@ |
Register scratch2, |
Label* miss_label) { |
__ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); |
- __ mov(eax, Operand(scratch1)); |
+ __ mov(eax, scratch1); |
__ ret(0); |
} |
@@ -406,7 +406,7 @@ |
// frame. |
// ----------------------------------- |
__ pop(scratch); |
- __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments)); |
+ __ add(esp, Immediate(kPointerSize * kFastApiCallArguments)); |
__ push(scratch); |
} |
@@ -462,7 +462,7 @@ |
__ PrepareCallApiFunction(kApiArgc + kApiStackSpace); |
__ mov(ApiParameterOperand(1), eax); // v8::Arguments::implicit_args_. |
- __ add(Operand(eax), Immediate(argc * kPointerSize)); |
+ __ add(eax, Immediate(argc * kPointerSize)); |
__ mov(ApiParameterOperand(2), eax); // v8::Arguments::values_. |
__ Set(ApiParameterOperand(3), Immediate(argc)); // v8::Arguments::length_. |
// v8::Arguments::is_construct_call_. |
@@ -651,7 +651,7 @@ |
scratch1, scratch2, scratch3, name, |
miss_label); |
- __ EnterInternalFrame(); |
+ FrameScope scope(masm, StackFrame::INTERNAL); |
// Save the name_ register across the call. |
__ push(name_); |
@@ -668,7 +668,8 @@ |
// Restore the name_ register. |
__ pop(name_); |
- __ LeaveInternalFrame(); |
+ |
+ // Leave the internal frame. |
} |
void LoadWithInterceptor(MacroAssembler* masm, |
@@ -676,19 +677,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. |
+ } |
__ cmp(eax, masm->isolate()->factory()->no_interceptor_result_sentinel()); |
__ j(not_equal, interceptor_succeeded); |
@@ -786,8 +789,12 @@ |
// Update the write barrier for the array address. |
// Pass the value being stored in the now unused name_reg. |
- __ mov(name_reg, Operand(eax)); |
- __ RecordWrite(receiver_reg, offset, name_reg, scratch); |
+ __ mov(name_reg, eax); |
+ __ RecordWriteField(receiver_reg, |
+ offset, |
+ name_reg, |
+ scratch, |
+ kDontSaveFPRegs); |
} else { |
// Write to the properties array. |
int offset = index * kPointerSize + FixedArray::kHeaderSize; |
@@ -797,8 +804,12 @@ |
// Update the write barrier for the array address. |
// Pass the value being stored in the now unused name_reg. |
- __ mov(name_reg, Operand(eax)); |
- __ RecordWrite(scratch, offset, name_reg, receiver_reg); |
+ __ mov(name_reg, eax); |
+ __ RecordWriteField(scratch, |
+ offset, |
+ name_reg, |
+ receiver_reg, |
+ kDontSaveFPRegs); |
} |
// Return the value (register eax). |
@@ -932,7 +943,7 @@ |
} else if (heap()->InNewSpace(prototype)) { |
// Get the map of the current object. |
__ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
- __ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map()))); |
+ __ cmp(scratch1, Immediate(Handle<Map>(current->map()))); |
// Branch on the result of the map check. |
__ j(not_equal, miss); |
// Check access rights to the global object. This has to happen |
@@ -1053,7 +1064,7 @@ |
__ pop(scratch3); // Get return address to place it below. |
__ push(receiver); // receiver |
- __ mov(scratch2, Operand(esp)); |
+ __ mov(scratch2, esp); |
ASSERT(!scratch2.is(reg)); |
__ push(reg); // holder |
// Push data from AccessorInfo. |
@@ -1084,7 +1095,7 @@ |
__ PrepareCallApiFunction(kApiArgc); |
__ mov(ApiParameterOperand(0), ebx); // name. |
- __ add(Operand(ebx), Immediate(kPointerSize)); |
+ __ add(ebx, Immediate(kPointerSize)); |
__ mov(ApiParameterOperand(1), ebx); // arguments pointer. |
// Emitting a stub call may try to allocate (if the code is not |
@@ -1158,41 +1169,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; |
- __ cmp(eax, factory()->no_interceptor_result_sentinel()); |
- __ 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; |
+ __ cmp(eax, factory()->no_interceptor_result_sentinel()); |
+ __ 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_reg. |
if (interceptor_holder != lookup->holder()) { |
@@ -1259,7 +1272,7 @@ |
void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { |
if (kind_ == Code::KEYED_CALL_IC) { |
- __ cmp(Operand(ecx), Immediate(Handle<String>(name))); |
+ __ cmp(ecx, Immediate(Handle<String>(name))); |
__ j(not_equal, miss); |
} |
} |
@@ -1316,7 +1329,7 @@ |
Immediate(Handle<SharedFunctionInfo>(function->shared()))); |
__ j(not_equal, miss); |
} else { |
- __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); |
+ __ cmp(edi, Immediate(Handle<JSFunction>(function))); |
__ j(not_equal, miss); |
} |
} |
@@ -1441,21 +1454,25 @@ |
__ 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 eax and calculate new length. |
__ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
STATIC_ASSERT(kSmiTagSize == 1); |
STATIC_ASSERT(kSmiTag == 0); |
- __ add(Operand(eax), Immediate(Smi::FromInt(argc))); |
+ __ add(eax, Immediate(Smi::FromInt(argc))); |
// Get the element's length into ecx. |
__ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); |
// Check if we could survive without allocation. |
- __ cmp(eax, Operand(ecx)); |
+ __ cmp(eax, ecx); |
__ j(greater, &attempt_to_grow_elements); |
+ // Check if value is a smi. |
+ __ mov(ecx, Operand(esp, argc * kPointerSize)); |
+ __ JumpIfNotSmi(ecx, &with_write_barrier); |
+ |
// Save new length. |
__ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
@@ -1463,20 +1480,29 @@ |
__ lea(edx, FieldOperand(ebx, |
eax, times_half_pointer_size, |
FixedArray::kHeaderSize - argc * kPointerSize)); |
- __ mov(ecx, Operand(esp, argc * kPointerSize)); |
__ mov(Operand(edx, 0), ecx); |
- // Check if value is a smi. |
- __ JumpIfNotSmi(ecx, &with_write_barrier); |
- |
- __ bind(&exit); |
__ ret((argc + 1) * kPointerSize); |
__ bind(&with_write_barrier); |
- __ InNewSpace(ebx, ecx, equal, &exit); |
+ if (FLAG_smi_only_arrays) { |
+ __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
+ __ CheckFastObjectElements(edi, &call_builtin); |
+ } |
- __ RecordWriteHelper(ebx, edx, ecx); |
+ // Save new length. |
+ __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
+ |
+ // Push the element. |
+ __ lea(edx, FieldOperand(ebx, |
+ eax, times_half_pointer_size, |
+ FixedArray::kHeaderSize - argc * kPointerSize)); |
+ __ mov(Operand(edx, 0), ecx); |
+ |
+ __ RecordWrite( |
+ ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
+ |
__ ret((argc + 1) * kPointerSize); |
__ bind(&attempt_to_grow_elements); |
@@ -1484,6 +1510,21 @@ |
__ jmp(&call_builtin); |
} |
+ __ mov(edi, Operand(esp, 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(edi, &no_fast_elements_check); |
+ __ mov(esi, FieldOperand(edx, HeapObject::kMapOffset)); |
+ __ CheckFastObjectElements(esi, &call_builtin, Label::kFar); |
+ __ bind(&no_fast_elements_check); |
+ } |
+ |
+ // We could be lucky and the elements array could be at the top of |
+ // new-space. In this case we can just grow it in place by moving the |
+ // allocation pointer up. |
+ |
ExternalReference new_space_allocation_top = |
ExternalReference::new_space_allocation_top_address(isolate()); |
ExternalReference new_space_allocation_limit = |
@@ -1497,33 +1538,43 @@ |
__ lea(edx, FieldOperand(ebx, |
eax, times_half_pointer_size, |
FixedArray::kHeaderSize - argc * kPointerSize)); |
- __ cmp(edx, Operand(ecx)); |
+ __ cmp(edx, ecx); |
__ j(not_equal, &call_builtin); |
- __ add(Operand(ecx), Immediate(kAllocationDelta * kPointerSize)); |
+ __ add(ecx, Immediate(kAllocationDelta * kPointerSize)); |
__ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit)); |
__ j(above, &call_builtin); |
// We fit and could grow elements. |
__ mov(Operand::StaticVariable(new_space_allocation_top), ecx); |
- __ mov(ecx, Operand(esp, argc * kPointerSize)); |
// Push the argument... |
- __ mov(Operand(edx, 0), ecx); |
+ __ mov(Operand(edx, 0), edi); |
// ... and fill the rest with holes. |
for (int i = 1; i < kAllocationDelta; i++) { |
__ mov(Operand(edx, i * kPointerSize), |
Immediate(factory()->the_hole_value())); |
} |
+ // 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(ebx, edx, edi, kDontSaveFPRegs, OMIT_REMEMBERED_SET); |
+ |
// Restore receiver to edx as finish sequence assumes it's here. |
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
// Increment element's and array's sizes. |
__ add(FieldOperand(ebx, FixedArray::kLengthOffset), |
Immediate(Smi::FromInt(kAllocationDelta))); |
+ |
+ // NOTE: This only happen in new-space, where we don't |
+ // care about the black-byte-count on pages. Otherwise we should |
+ // update that too if the object is black. |
+ |
__ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
- // Elements are in new space, so write barrier is not required. |
__ ret((argc + 1) * kPointerSize); |
} |
@@ -1585,7 +1636,7 @@ |
// Get the array's length into ecx and calculate new length. |
__ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset)); |
- __ sub(Operand(ecx), Immediate(Smi::FromInt(1))); |
+ __ sub(ecx, Immediate(Smi::FromInt(1))); |
__ j(negative, &return_undefined); |
// Get the last element. |
@@ -1594,7 +1645,7 @@ |
__ mov(eax, FieldOperand(ebx, |
ecx, times_half_pointer_size, |
FixedArray::kHeaderSize)); |
- __ cmp(Operand(eax), Immediate(factory()->the_hole_value())); |
+ __ cmp(eax, Immediate(factory()->the_hole_value())); |
__ j(equal, &call_builtin); |
// Set the array's length. |
@@ -2058,10 +2109,10 @@ |
__ sar(ebx, kBitsPerInt - 1); |
// Do bitwise not or do nothing depending on ebx. |
- __ xor_(eax, Operand(ebx)); |
+ __ xor_(eax, ebx); |
// Add 1 or do nothing depending on ebx. |
- __ sub(eax, Operand(ebx)); |
+ __ sub(eax, ebx); |
// If the result is still negative, go to the slow case. |
// This only happens for the most negative smi. |
@@ -2144,7 +2195,7 @@ |
// Allocate space for v8::Arguments implicit values. Must be initialized |
// before calling any runtime function. |
- __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); |
+ __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize)); |
// Check that the maps haven't changed and find a Holder as a side effect. |
CheckPrototypes(JSObject::cast(object), edx, holder, |
@@ -2160,7 +2211,7 @@ |
if (result->IsFailure()) return result; |
__ bind(&miss); |
- __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); |
+ __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); |
__ bind(&miss_before_stack_reserved); |
MaybeObject* maybe_result = GenerateMissBranch(); |
@@ -2599,13 +2650,9 @@ |
Immediate(Handle<Map>(object->map()))); |
__ j(not_equal, &miss); |
- |
// Compute the cell operand to use. |
- Operand cell_operand = Operand::Cell(Handle<JSGlobalPropertyCell>(cell)); |
- if (Serializer::enabled()) { |
- __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
- cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset); |
- } |
+ __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
+ Operand cell_operand = FieldOperand(ebx, 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 |
@@ -2616,8 +2663,23 @@ |
// Store the value in the cell. |
__ mov(cell_operand, eax); |
+ Label done; |
+ __ test(eax, Immediate(kSmiTagMask)); |
+ __ j(zero, &done); |
+ __ mov(ecx, eax); |
+ __ lea(edx, cell_operand); |
+ // Cells are always in the remembered set. |
+ __ RecordWrite(ebx, // Object. |
+ edx, // Address. |
+ ecx, // Value. |
+ kDontSaveFPRegs, |
+ OMIT_REMEMBERED_SET, |
+ OMIT_SMI_CHECK); |
+ |
// Return the value (register eax). |
+ __ bind(&done); |
+ |
Counters* counters = isolate()->counters(); |
__ IncrementCounter(counters->named_store_global_inline(), 1); |
__ ret(0); |
@@ -2649,7 +2711,7 @@ |
__ IncrementCounter(counters->keyed_store_field(), 1); |
// Check that the name has not changed. |
- __ cmp(Operand(ecx), Immediate(Handle<String>(name))); |
+ __ cmp(ecx, Immediate(Handle<String>(name))); |
__ j(not_equal, &miss); |
// Generate store field code. Trashes the name register. |
@@ -2941,7 +3003,7 @@ |
__ IncrementCounter(counters->keyed_load_field(), 1); |
// Check that the name has not changed. |
- __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
+ __ cmp(eax, Immediate(Handle<String>(name))); |
__ j(not_equal, &miss); |
GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss); |
@@ -2971,7 +3033,7 @@ |
__ IncrementCounter(counters->keyed_load_callback(), 1); |
// Check that the name has not changed. |
- __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
+ __ cmp(eax, Immediate(Handle<String>(name))); |
__ j(not_equal, &miss); |
MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, |
@@ -3006,7 +3068,7 @@ |
__ IncrementCounter(counters->keyed_load_constant_function(), 1); |
// Check that the name has not changed. |
- __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
+ __ cmp(eax, Immediate(Handle<String>(name))); |
__ j(not_equal, &miss); |
GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi, |
@@ -3034,7 +3096,7 @@ |
__ IncrementCounter(counters->keyed_load_interceptor(), 1); |
// Check that the name has not changed. |
- __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
+ __ cmp(eax, Immediate(Handle<String>(name))); |
__ j(not_equal, &miss); |
LookupResult lookup; |
@@ -3070,7 +3132,7 @@ |
__ IncrementCounter(counters->keyed_load_array_length(), 1); |
// Check that the name has not changed. |
- __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
+ __ cmp(eax, Immediate(Handle<String>(name))); |
__ j(not_equal, &miss); |
GenerateLoadArrayLength(masm(), edx, ecx, &miss); |
@@ -3095,7 +3157,7 @@ |
__ IncrementCounter(counters->keyed_load_string_length(), 1); |
// Check that the name has not changed. |
- __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
+ __ cmp(eax, Immediate(Handle<String>(name))); |
__ j(not_equal, &miss); |
GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); |
@@ -3120,7 +3182,7 @@ |
__ IncrementCounter(counters->keyed_load_function_prototype(), 1); |
// Check that the name has not changed. |
- __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
+ __ cmp(eax, Immediate(Handle<String>(name))); |
__ j(not_equal, &miss); |
GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); |
@@ -3298,7 +3360,7 @@ |
// Move argc to ebx and retrieve and tag the JSObject to return. |
__ mov(ebx, eax); |
__ pop(eax); |
- __ or_(Operand(eax), Immediate(kHeapObjectTag)); |
+ __ or_(eax, Immediate(kHeapObjectTag)); |
// Remove caller arguments and receiver from the stack and return. |
__ pop(ecx); |
@@ -3679,10 +3741,10 @@ |
// If the value is NaN or +/-infinity, the result is 0x80000000, |
// which is automatically zero when taken mod 2^n, n < 32. |
__ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
- __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
+ __ sub(esp, Immediate(2 * kPointerSize)); |
__ fisttp_d(Operand(esp, 0)); |
__ pop(ebx); |
- __ add(Operand(esp), Immediate(kPointerSize)); |
+ __ add(esp, Immediate(kPointerSize)); |
} else { |
ASSERT(CpuFeatures::IsSupported(SSE2)); |
CpuFeatures::Scope scope(SSE2); |
@@ -3838,8 +3900,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 ------------- |
// -- eax : value |
// -- ecx : key |
@@ -3870,11 +3934,28 @@ |
__ j(above_equal, &miss_force_generic); |
} |
- // Do the store and update the write barrier. Make sure to preserve |
- // the value in register eax. |
- __ mov(edx, Operand(eax)); |
- __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax); |
- __ RecordWrite(edi, 0, edx, ecx); |
+ if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
+ __ JumpIfNotSmi(eax, &miss_force_generic); |
+ // ecx is a smi, use times_half_pointer_size instead of |
+ // times_pointer_size |
+ __ mov(FieldOperand(edi, |
+ ecx, |
+ times_half_pointer_size, |
+ FixedArray::kHeaderSize), eax); |
+ } else { |
+ ASSERT(elements_kind == FAST_ELEMENTS); |
+ // Do the store and update the write barrier. |
+ // ecx is a smi, use times_half_pointer_size instead of |
+ // times_pointer_size |
+ __ lea(ecx, FieldOperand(edi, |
+ ecx, |
+ times_half_pointer_size, |
+ FixedArray::kHeaderSize)); |
+ __ mov(Operand(ecx, 0), eax); |
+ // Make sure to preserve the value in register eax. |
+ __ mov(edx, eax); |
+ __ RecordWrite(edi, ecx, edx, kDontSaveFPRegs); |
+ } |
// Done. |
__ ret(0); |
@@ -3896,8 +3977,7 @@ |
// -- edx : receiver |
// -- esp[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. |
@@ -3918,59 +3998,13 @@ |
} |
__ j(above_equal, &miss_force_generic); |
- __ JumpIfSmi(eax, &smi_value, Label::kNear); |
- |
- __ CheckMap(eax, |
- masm->isolate()->factory()->heap_number_map(), |
- &miss_force_generic, |
- DONT_DO_SMI_CHECK); |
- |
- // Double value, canonicalize NaN. |
- uint32_t offset = HeapNumber::kValueOffset + sizeof(kHoleNanLower32); |
- __ cmp(FieldOperand(eax, offset), Immediate(kNaNOrInfinityLowerBoundUpper32)); |
- __ j(greater_equal, &maybe_nan, Label::kNear); |
- |
- __ bind(¬_nan); |
- ExternalReference canonical_nan_reference = |
- ExternalReference::address_of_canonical_non_hole_nan(); |
- if (CpuFeatures::IsSupported(SSE2)) { |
- CpuFeatures::Scope use_sse2(SSE2); |
- __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); |
- __ bind(&have_double_value); |
- __ movdbl(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize), |
- xmm0); |
- __ ret(0); |
- } else { |
- __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
- __ bind(&have_double_value); |
- __ fstp_d(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize)); |
- __ 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); |
- __ cmp(FieldOperand(eax, HeapNumber::kValueOffset), Immediate(0)); |
- __ j(zero, ¬_nan); |
- __ bind(&is_nan); |
- if (CpuFeatures::IsSupported(SSE2)) { |
- CpuFeatures::Scope use_sse2(SSE2); |
- __ movdbl(xmm0, Operand::StaticVariable(canonical_nan_reference)); |
- } else { |
- __ fld_d(Operand::StaticVariable(canonical_nan_reference)); |
- } |
- __ jmp(&have_double_value, Label::kNear); |
- |
- __ bind(&smi_value); |
- // Value is a smi. convert to a double and store. |
- // Preserve original value. |
- __ mov(edx, eax); |
- __ SmiUntag(edx); |
- __ push(edx); |
- __ fild_s(Operand(esp, 0)); |
- __ pop(edx); |
- __ fstp_d(FieldOperand(edi, ecx, times_4, FixedDoubleArray::kHeaderSize)); |
+ __ StoreNumberToDoubleElements(eax, |
+ edi, |
+ ecx, |
+ edx, |
+ xmm0, |
+ &miss_force_generic, |
+ true); |
__ ret(0); |
// Handle store cache miss, replacing the ic with the generic stub. |