Index: src/arm/stub-cache-arm.cc |
=================================================================== |
--- src/arm/stub-cache-arm.cc (revision 9531) |
+++ src/arm/stub-cache-arm.cc (working copy) |
@@ -431,7 +431,13 @@ |
// Update the write barrier for the array address. |
// Pass the now unused name_reg as a scratch register. |
- __ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch); |
+ __ mov(name_reg, r0); |
+ __ RecordWriteField(receiver_reg, |
+ offset, |
+ name_reg, |
+ scratch, |
+ kLRHasNotBeenSaved, |
+ kDontSaveFPRegs); |
} else { |
// Write to the properties array. |
int offset = index * kPointerSize + FixedArray::kHeaderSize; |
@@ -444,7 +450,13 @@ |
// Update the write barrier for the array address. |
// Ok to clobber receiver_reg and name_reg, since we return. |
- __ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg); |
+ __ mov(name_reg, r0); |
+ __ RecordWriteField(scratch, |
+ offset, |
+ name_reg, |
+ receiver_reg, |
+ kLRHasNotBeenSaved, |
+ kDontSaveFPRegs); |
} |
// Return the value (register r0). |
@@ -553,9 +565,10 @@ |
} |
-static MaybeObject* GenerateFastApiDirectCall(MacroAssembler* masm, |
- const CallOptimization& optimization, |
- int argc) { |
+static MaybeObject* GenerateFastApiDirectCall( |
+ MacroAssembler* masm, |
+ const CallOptimization& optimization, |
+ int argc) { |
// ----------- S t a t e ------------- |
// -- sp[0] : holder (set by CheckPrototypes) |
// -- sp[4] : callee js function |
@@ -591,6 +604,8 @@ |
ApiFunction fun(api_function_address); |
const int kApiStackSpace = 4; |
+ |
+ FrameScope frame_scope(masm, StackFrame::MANUAL); |
__ EnterExitFrame(false, kApiStackSpace); |
// r0 = v8::Arguments& |
@@ -616,9 +631,11 @@ |
ExternalReference ref = ExternalReference(&fun, |
ExternalReference::DIRECT_API_CALL, |
masm->isolate()); |
+ AllowExternalCallThatCantCauseGC scope(masm); |
return masm->TryCallApiFunctionAndReturn(ref, kStackUnwindSpace); |
} |
+ |
class CallInterceptorCompiler BASE_EMBEDDED { |
public: |
CallInterceptorCompiler(StubCompiler* stub_compiler, |
@@ -794,7 +811,7 @@ |
miss_label); |
// Call a runtime function to load the interceptor property. |
- __ EnterInternalFrame(); |
+ FrameScope scope(masm, StackFrame::INTERNAL); |
// Save the name_ register across the call. |
__ push(name_); |
@@ -811,7 +828,8 @@ |
// Restore the name_ register. |
__ pop(name_); |
- __ LeaveInternalFrame(); |
+ |
+ // Leave the internal frame. |
} |
void LoadWithInterceptor(MacroAssembler* masm, |
@@ -820,18 +838,19 @@ |
JSObject* holder_obj, |
Register scratch, |
Label* interceptor_succeeded) { |
- __ EnterInternalFrame(); |
- __ Push(holder, name_); |
+ { |
+ FrameScope scope(masm, StackFrame::INTERNAL); |
+ __ Push(holder, 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. |
+ } |
// If interceptor returns no-result sentinel, call the constant function. |
__ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex); |
@@ -1228,7 +1247,10 @@ |
ApiFunction fun(getter_address); |
const int kApiStackSpace = 1; |
+ |
+ FrameScope frame_scope(masm(), StackFrame::MANUAL); |
__ EnterExitFrame(false, kApiStackSpace); |
+ |
// Create AccessorInfo instance on the stack above the exit frame with |
// scratch2 (internal::Object **args_) as the data. |
__ str(scratch2, MemOperand(sp, 1 * kPointerSize)); |
@@ -1288,42 +1310,44 @@ |
// 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, holder_reg, name_reg); |
- } else { |
- __ Push(holder_reg, name_reg); |
- } |
+ if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
+ // CALLBACKS case needs a receiver to be passed into C++ callback. |
+ __ Push(receiver, holder_reg, name_reg); |
+ } else { |
+ __ Push(holder_reg, 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; |
- __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); |
- __ cmp(r0, scratch1); |
- __ b(eq, &interceptor_failed); |
- __ LeaveInternalFrame(); |
- __ Ret(); |
+ // Check if interceptor provided a value for property. If it's |
+ // the case, return immediately. |
+ Label interceptor_failed; |
+ __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); |
+ __ cmp(r0, scratch1); |
+ __ b(eq, &interceptor_failed); |
+ frame_scope.GenerateLeaveFrame(); |
+ __ Ret(); |
- __ 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()) { |
@@ -1556,7 +1580,7 @@ |
DONT_DO_SMI_CHECK); |
if (argc == 1) { // Otherwise fall through to call the builtin. |
- Label exit, with_write_barrier, attempt_to_grow_elements; |
+ Label attempt_to_grow_elements; |
// Get the array's length into r0 and calculate new length. |
__ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
@@ -1571,11 +1595,15 @@ |
__ cmp(r0, r4); |
__ b(gt, &attempt_to_grow_elements); |
+ // Check if value is a smi. |
+ Label with_write_barrier; |
+ __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); |
+ __ JumpIfNotSmi(r4, &with_write_barrier); |
+ |
// Save new length. |
__ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
// Push the element. |
- __ ldr(r4, MemOperand(sp, (argc - 1) * kPointerSize)); |
// We may need a register containing the address end_elements below, |
// so write back the value in end_elements. |
__ add(end_elements, elements, |
@@ -1585,14 +1613,33 @@ |
__ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex)); |
// Check for a smi. |
- __ JumpIfNotSmi(r4, &with_write_barrier); |
- __ bind(&exit); |
__ Drop(argc + 1); |
__ Ret(); |
__ bind(&with_write_barrier); |
- __ InNewSpace(elements, r4, eq, &exit); |
- __ RecordWriteHelper(elements, end_elements, r4); |
+ |
+ if (FLAG_smi_only_arrays) { |
+ __ ldr(r6, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
+ __ CheckFastSmiOnlyElements(r6, r6, &call_builtin); |
+ } |
+ |
+ // Save new length. |
+ __ str(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
+ |
+ // Push the element. |
+ // We may need a register containing the address end_elements below, |
+ // so write back the value in end_elements. |
+ __ add(end_elements, elements, |
+ Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize)); |
+ __ str(r4, MemOperand(end_elements, kEndElementsOffset, PreIndex)); |
+ |
+ __ RecordWrite(elements, |
+ end_elements, |
+ r4, |
+ kLRHasNotBeenSaved, |
+ kDontSaveFPRegs, |
+ EMIT_REMEMBERED_SET, |
+ OMIT_SMI_CHECK); |
__ Drop(argc + 1); |
__ Ret(); |
@@ -1604,6 +1651,17 @@ |
__ b(&call_builtin); |
} |
+ __ ldr(r2, MemOperand(sp, (argc - 1) * 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(r2, &no_fast_elements_check); |
+ __ ldr(r7, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
+ __ CheckFastObjectElements(r7, r7, &call_builtin); |
+ __ bind(&no_fast_elements_check); |
+ } |
+ |
Isolate* isolate = masm()->isolate(); |
ExternalReference new_space_allocation_top = |
ExternalReference::new_space_allocation_top_address(isolate); |
@@ -1630,8 +1688,7 @@ |
// Update new_space_allocation_top. |
__ str(r6, MemOperand(r7)); |
// Push the argument. |
- __ ldr(r6, MemOperand(sp, (argc - 1) * kPointerSize)); |
- __ str(r6, MemOperand(end_elements)); |
+ __ str(r2, MemOperand(end_elements)); |
// Fill the rest with holes. |
__ LoadRoot(r6, Heap::kTheHoleValueRootIndex); |
for (int i = 1; i < kAllocationDelta; i++) { |
@@ -2713,6 +2770,15 @@ |
// Store the value in the cell. |
__ str(r0, FieldMemOperand(r4, JSGlobalPropertyCell::kValueOffset)); |
+ __ mov(r1, r0); |
+ __ RecordWriteField(r4, |
+ JSGlobalPropertyCell::kValueOffset, |
+ r1, |
+ r2, |
+ kLRHasNotBeenSaved, |
+ kDontSaveFPRegs, |
+ OMIT_REMEMBERED_SET); |
+ |
Counters* counters = masm()->isolate()->counters(); |
__ IncrementCounter(counters->named_store_global_inline(), 1, r4, r3); |
__ Ret(); |
@@ -3454,6 +3520,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: |
@@ -3540,6 +3607,7 @@ |
} |
break; |
case FAST_ELEMENTS: |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: |
case DICTIONARY_ELEMENTS: |
case NON_STRICT_ARGUMENTS_ELEMENTS: |
@@ -3880,6 +3948,7 @@ |
} |
break; |
case FAST_ELEMENTS: |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: |
case DICTIONARY_ELEMENTS: |
case NON_STRICT_ARGUMENTS_ELEMENTS: |
@@ -3943,6 +4012,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: |
@@ -4082,6 +4152,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: |
@@ -4234,8 +4305,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 ------------- |
// -- r0 : value |
// -- r1 : key |
@@ -4277,15 +4350,33 @@ |
__ cmp(key_reg, scratch); |
__ b(hs, &miss_force_generic); |
- __ add(scratch, |
- elements_reg, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
- STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
- __ str(value_reg, |
- MemOperand(scratch, key_reg, LSL, kPointerSizeLog2 - kSmiTagSize)); |
- __ RecordWrite(scratch, |
- Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize), |
- receiver_reg , elements_reg); |
- |
+ if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
+ __ JumpIfNotSmi(value_reg, &miss_force_generic); |
+ __ add(scratch, |
+ elements_reg, |
+ Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
+ __ add(scratch, |
+ scratch, |
+ Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize)); |
+ __ str(value_reg, MemOperand(scratch)); |
+ } else { |
+ ASSERT(elements_kind == FAST_ELEMENTS); |
+ __ add(scratch, |
+ elements_reg, |
+ Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
+ STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
+ __ add(scratch, |
+ scratch, |
+ Operand(key_reg, LSL, kPointerSizeLog2 - kSmiTagSize)); |
+ __ str(value_reg, MemOperand(scratch)); |
+ __ mov(receiver_reg, value_reg); |
+ __ RecordWrite(elements_reg, // Object. |
+ scratch, // Address. |
+ receiver_reg, // Value. |
+ kLRHasNotBeenSaved, |
+ kDontSaveFPRegs); |
+ } |
// value_reg (r0) is preserved. |
// Done. |
__ Ret(); |