[arm] Port native routines to use UseScratchRegisterScope

Make use of UseScratchRegisterScope instead of using the ip register directly in
code stubs, builtin and the deoptimizer. In a lot of cases, we can
simply use a different register rather than using the new scope.

Bug: v8:6553
Change-Id: Ibc8a9a78bb88f3850c6e8b45871cc3a5b3971b3b
Reviewed-on: https://chromium-review.googlesource.com/544837
Commit-Queue: Pierre Langlois <pierre.langlois@arm.com>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46429}
This commit is contained in:
Pierre Langlois 2017-06-09 11:15:48 +01:00 committed by Commit Bot
parent 6cb999b97b
commit f6aed61992
4 changed files with 203 additions and 148 deletions

View File

@ -1006,9 +1006,16 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
__ mov(r5, Operand(ExternalReference(IsolateAddressId::kCEntryFPAddress, __ mov(r5, Operand(ExternalReference(IsolateAddressId::kCEntryFPAddress,
isolate()))); isolate())));
__ ldr(r5, MemOperand(r5)); __ ldr(r5, MemOperand(r5));
__ mov(ip, Operand(-1)); // Push a bad frame pointer to fail if it is used. {
__ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | UseScratchRegisterScope temps(masm);
ip.bit()); Register scratch = temps.Acquire();
// Push a bad frame pointer to fail if it is used.
__ mov(scratch, Operand(-1));
__ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | scratch.bit());
}
Register scratch = r6;
// Set up frame pointer for the frame to be pushed. // Set up frame pointer for the frame to be pushed.
__ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
@ -1017,17 +1024,17 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
Label non_outermost_js; Label non_outermost_js;
ExternalReference js_entry_sp(IsolateAddressId::kJSEntrySPAddress, isolate()); ExternalReference js_entry_sp(IsolateAddressId::kJSEntrySPAddress, isolate());
__ mov(r5, Operand(ExternalReference(js_entry_sp))); __ mov(r5, Operand(ExternalReference(js_entry_sp)));
__ ldr(r6, MemOperand(r5)); __ ldr(scratch, MemOperand(r5));
__ cmp(r6, Operand::Zero()); __ cmp(scratch, Operand::Zero());
__ b(ne, &non_outermost_js); __ b(ne, &non_outermost_js);
__ str(fp, MemOperand(r5)); __ str(fp, MemOperand(r5));
__ mov(ip, Operand(StackFrame::OUTERMOST_JSENTRY_FRAME)); __ mov(scratch, Operand(StackFrame::OUTERMOST_JSENTRY_FRAME));
Label cont; Label cont;
__ b(&cont); __ b(&cont);
__ bind(&non_outermost_js); __ bind(&non_outermost_js);
__ mov(ip, Operand(StackFrame::INNER_JSENTRY_FRAME)); __ mov(scratch, Operand(StackFrame::INNER_JSENTRY_FRAME));
__ bind(&cont); __ bind(&cont);
__ push(ip); __ push(scratch);
// Jump to a faked try block that does the invoke, with a faked catch // Jump to a faked try block that does the invoke, with a faked catch
// block that sets the pending exception. // block that sets the pending exception.
@ -1044,10 +1051,11 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// field in the JSEnv and return a failure sentinel. Coming in here the // field in the JSEnv and return a failure sentinel. Coming in here the
// fp will be invalid because the PushStackHandler below sets it to 0 to // fp will be invalid because the PushStackHandler below sets it to 0 to
// signal the existence of the JSEntry frame. // signal the existence of the JSEntry frame.
__ mov(ip, Operand(ExternalReference( __ mov(scratch,
IsolateAddressId::kPendingExceptionAddress, isolate()))); Operand(ExternalReference(IsolateAddressId::kPendingExceptionAddress,
isolate())));
} }
__ str(r0, MemOperand(ip)); __ str(r0, MemOperand(scratch));
__ LoadRoot(r0, Heap::kExceptionRootIndex); __ LoadRoot(r0, Heap::kExceptionRootIndex);
__ b(&exit); __ b(&exit);
@ -1073,16 +1081,16 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
if (type() == StackFrame::ENTRY_CONSTRUCT) { if (type() == StackFrame::ENTRY_CONSTRUCT) {
ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline, ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline,
isolate()); isolate());
__ mov(ip, Operand(construct_entry)); __ mov(scratch, Operand(construct_entry));
} else { } else {
ExternalReference entry(Builtins::kJSEntryTrampoline, isolate()); ExternalReference entry(Builtins::kJSEntryTrampoline, isolate());
__ mov(ip, Operand(entry)); __ mov(scratch, Operand(entry));
} }
__ ldr(ip, MemOperand(ip)); // deref address __ ldr(scratch, MemOperand(scratch)); // deref address
__ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); __ add(scratch, scratch, Operand(Code::kHeaderSize - kHeapObjectTag));
// Branch and link to JSEntryTrampoline. // Branch and link to JSEntryTrampoline.
__ Call(ip); __ Call(scratch);
// Unlink this frame from the handler chain. // Unlink this frame from the handler chain.
__ PopStackHandler(); __ PopStackHandler();
@ -1100,9 +1108,9 @@ void JSEntryStub::Generate(MacroAssembler* masm) {
// Restore the top frame descriptors from the stack. // Restore the top frame descriptors from the stack.
__ pop(r3); __ pop(r3);
__ mov(ip, Operand(ExternalReference(IsolateAddressId::kCEntryFPAddress, __ mov(scratch, Operand(ExternalReference(IsolateAddressId::kCEntryFPAddress,
isolate()))); isolate())));
__ str(r3, MemOperand(ip)); __ str(r3, MemOperand(scratch));
// Reset the stack to the callee saved registers. // Reset the stack to the callee saved registers.
__ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset)); __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
@ -1203,8 +1211,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// write-barrier is needed. // write-barrier is needed.
__ bind(&megamorphic); __ bind(&megamorphic);
__ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3)); __ add(r5, r2, Operand::PointerOffsetFromSmiKey(r3));
__ LoadRoot(ip, Heap::kmegamorphic_symbolRootIndex); __ LoadRoot(r4, Heap::kmegamorphic_symbolRootIndex);
__ str(ip, FieldMemOperand(r5, FixedArray::kHeaderSize)); __ str(r4, FieldMemOperand(r5, FixedArray::kHeaderSize));
__ jmp(&done); __ jmp(&done);
// An uninitialized cache is patched with the function // An uninitialized cache is patched with the function
@ -1296,8 +1304,8 @@ void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
__ bind(&got_smi_index_); __ bind(&got_smi_index_);
// Check for index out of range. // Check for index out of range.
__ ldr(ip, FieldMemOperand(object_, String::kLengthOffset)); __ ldr(result_, FieldMemOperand(object_, String::kLengthOffset));
__ cmp(ip, Operand(index_)); __ cmp(result_, Operand(index_));
__ b(ls, index_out_of_range_); __ b(ls, index_out_of_range_);
__ SmiUntag(index_); __ SmiUntag(index_);
@ -1796,22 +1804,22 @@ void CompareICStub::GenerateKnownReceivers(MacroAssembler* masm) {
void CompareICStub::GenerateMiss(MacroAssembler* masm) { void CompareICStub::GenerateMiss(MacroAssembler* masm) {
Register scratch = r2;
{ {
// Call the runtime system in a fresh internal frame. // Call the runtime system in a fresh internal frame.
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r1, r0); __ Push(r1, r0);
__ Push(lr, r1, r0); __ Push(lr, r1, r0);
__ mov(ip, Operand(Smi::FromInt(op()))); __ mov(scratch, Operand(Smi::FromInt(op())));
__ push(ip); __ push(scratch);
__ CallRuntime(Runtime::kCompareIC_Miss); __ CallRuntime(Runtime::kCompareIC_Miss);
// Compute the entry point of the rewritten stub. // Compute the entry point of the rewritten stub.
__ add(r2, r0, Operand(Code::kHeaderSize - kHeapObjectTag)); __ add(scratch, r0, Operand(Code::kHeaderSize - kHeapObjectTag));
// Restore registers. // Restore registers.
__ pop(lr); __ pop(lr);
__ Pop(r1, r0); __ Pop(r1, r0);
} }
__ Jump(scratch);
__ Jump(r2);
} }
@ -2245,22 +2253,27 @@ void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
__ and_(sp, sp, Operand(-frame_alignment)); __ and_(sp, sp, Operand(-frame_alignment));
} }
#if V8_HOST_ARCH_ARM {
int32_t entry_hook = UseScratchRegisterScope temps(masm);
reinterpret_cast<int32_t>(isolate()->function_entry_hook()); Register scratch = temps.Acquire();
__ mov(ip, Operand(entry_hook));
#else
// Under the simulator we need to indirect the entry hook through a
// trampoline function at a known address.
// It additionally takes an isolate as a third parameter
__ mov(r2, Operand(ExternalReference::isolate_address(isolate())));
ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline)); #if V8_HOST_ARCH_ARM
__ mov(ip, Operand(ExternalReference(&dispatcher, int32_t entry_hook =
ExternalReference::BUILTIN_CALL, reinterpret_cast<int32_t>(isolate()->function_entry_hook());
isolate()))); __ mov(scratch, Operand(entry_hook));
#else
// Under the simulator we need to indirect the entry hook through a
// trampoline function at a known address.
// It additionally takes an isolate as a third parameter
__ mov(r2, Operand(ExternalReference::isolate_address(isolate())));
ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
__ mov(scratch,
Operand(ExternalReference(
&dispatcher, ExternalReference::BUILTIN_CALL, isolate())));
#endif #endif
__ Call(ip); __ Call(scratch);
}
// Restore the stack pointer if needed. // Restore the stack pointer if needed.
if (frame_alignment > kPointerSize) { if (frame_alignment > kPointerSize) {
@ -2648,8 +2661,8 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
} }
__ sub(r6, r6, Operand(1)); __ sub(r6, r6, Operand(1));
__ str(r6, MemOperand(r9, kLevelOffset)); __ str(r6, MemOperand(r9, kLevelOffset));
__ ldr(ip, MemOperand(r9, kLimitOffset)); __ ldr(r6, MemOperand(r9, kLimitOffset));
__ cmp(r5, ip); __ cmp(r5, r6);
__ b(ne, &delete_allocated_handles); __ b(ne, &delete_allocated_handles);
// Leave the API exit frame. // Leave the API exit frame.
@ -2668,8 +2681,8 @@ static void CallApiFunctionAndReturn(MacroAssembler* masm,
// Check if the function scheduled an exception. // Check if the function scheduled an exception.
__ LoadRoot(r4, Heap::kTheHoleValueRootIndex); __ LoadRoot(r4, Heap::kTheHoleValueRootIndex);
__ mov(ip, Operand(ExternalReference::scheduled_exception_address(isolate))); __ mov(r6, Operand(ExternalReference::scheduled_exception_address(isolate)));
__ ldr(r5, MemOperand(ip)); __ ldr(r5, MemOperand(r6));
__ cmp(r4, r5); __ cmp(r4, r5);
__ b(ne, &promote_scheduled_exception); __ b(ne, &promote_scheduled_exception);
@ -2739,20 +2752,22 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
// call data // call data
__ push(call_data); __ push(call_data);
Register scratch = call_data; Register scratch0 = call_data;
__ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); Register scratch1 = r5;
__ LoadRoot(scratch0, Heap::kUndefinedValueRootIndex);
// return value // return value
__ push(scratch); __ push(scratch0);
// return value default // return value default
__ push(scratch); __ push(scratch0);
// isolate // isolate
__ mov(scratch, Operand(ExternalReference::isolate_address(masm->isolate()))); __ mov(scratch1,
__ push(scratch); Operand(ExternalReference::isolate_address(masm->isolate())));
__ push(scratch1);
// holder // holder
__ push(holder); __ push(holder);
// Prepare arguments. // Prepare arguments.
__ mov(scratch, sp); __ mov(scratch0, sp);
// Allocate the v8::Arguments structure in the arguments' space since // Allocate the v8::Arguments structure in the arguments' space since
// it's not controlled by GC. // it's not controlled by GC.
@ -2761,18 +2776,19 @@ void CallApiCallbackStub::Generate(MacroAssembler* masm) {
FrameScope frame_scope(masm, StackFrame::MANUAL); FrameScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace); __ EnterExitFrame(false, kApiStackSpace);
DCHECK(!api_function_address.is(r0) && !scratch.is(r0)); DCHECK(!api_function_address.is(r0) && !scratch0.is(r0));
// r0 = FunctionCallbackInfo& // r0 = FunctionCallbackInfo&
// Arguments is after the return address. // Arguments is after the return address.
__ add(r0, sp, Operand(1 * kPointerSize)); __ add(r0, sp, Operand(1 * kPointerSize));
// FunctionCallbackInfo::implicit_args_ // FunctionCallbackInfo::implicit_args_
__ str(scratch, MemOperand(r0, 0 * kPointerSize)); __ str(scratch0, MemOperand(r0, 0 * kPointerSize));
// FunctionCallbackInfo::values_ // FunctionCallbackInfo::values_
__ add(ip, scratch, Operand((FCA::kArgsLength - 1 + argc()) * kPointerSize)); __ add(scratch1, scratch0,
__ str(ip, MemOperand(r0, 1 * kPointerSize)); Operand((FCA::kArgsLength - 1 + argc()) * kPointerSize));
__ str(scratch1, MemOperand(r0, 1 * kPointerSize));
// FunctionCallbackInfo::length_ = argc // FunctionCallbackInfo::length_ = argc
__ mov(ip, Operand(argc())); __ mov(scratch0, Operand(argc()));
__ str(ip, MemOperand(r0, 2 * kPointerSize)); __ str(scratch0, MemOperand(r0, 2 * kPointerSize));
ExternalReference thunk_ref = ExternalReference thunk_ref =
ExternalReference::invoke_function_callback(masm->isolate()); ExternalReference::invoke_function_callback(masm->isolate());

View File

@ -143,7 +143,8 @@ MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
__ ldr(temp1, MemOperand(src, 4, PostIndex)); __ ldr(temp1, MemOperand(src, 4, PostIndex));
__ str(temp1, MemOperand(dest, 4, PostIndex)); __ str(temp1, MemOperand(dest, 4, PostIndex));
} else { } else {
Register temp2 = ip; UseScratchRegisterScope temps(&masm);
Register temp2 = temps.Acquire();
Label loop; Label loop;
__ bic(temp2, chars, Operand(0x3), SetCC); __ bic(temp2, chars, Operand(0x3), SetCC);
@ -219,8 +220,10 @@ MemCopyUint16Uint8Function CreateMemCopyUint16Uint8Function(
__ vst1(Neon16, NeonListOperand(d0, 2), NeonMemOperand(dest)); __ vst1(Neon16, NeonListOperand(d0, 2), NeonMemOperand(dest));
__ Ret(); __ Ret();
} else { } else {
UseScratchRegisterScope temps(&masm);
Register temp1 = r3; Register temp1 = r3;
Register temp2 = ip; Register temp2 = temps.Acquire();
Register temp3 = lr; Register temp3 = lr;
Register temp4 = r4; Register temp4 = r4;
Label loop; Label loop;

View File

@ -111,9 +111,11 @@ void Deoptimizer::TableEntryGenerator::Generate() {
// We use a run-time check for VFP32DREGS. // We use a run-time check for VFP32DREGS.
CpuFeatureScope scope(masm(), VFP32DREGS, CpuFeatureScope scope(masm(), VFP32DREGS,
CpuFeatureScope::kDontCheckSupported); CpuFeatureScope::kDontCheckSupported);
UseScratchRegisterScope temps(masm());
Register scratch = temps.Acquire();
// Check CPU flags for number of registers, setting the Z condition flag. // Check CPU flags for number of registers, setting the Z condition flag.
__ CheckFor32DRegs(ip); __ CheckFor32DRegs(scratch);
// Push registers d0-d15, and possibly d16-d31, on the stack. // Push registers d0-d15, and possibly d16-d31, on the stack.
// If d16-d31 are not pushed, decrease the stack pointer instead. // If d16-d31 are not pushed, decrease the stack pointer instead.
@ -130,9 +132,13 @@ void Deoptimizer::TableEntryGenerator::Generate() {
// handle this a bit differently. // handle this a bit differently.
__ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit()); __ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit());
__ mov(ip, Operand(ExternalReference(IsolateAddressId::kCEntryFPAddress, {
isolate()))); UseScratchRegisterScope temps(masm());
__ str(fp, MemOperand(ip)); Register scratch = temps.Acquire();
__ mov(scratch, Operand(ExternalReference(
IsolateAddressId::kCEntryFPAddress, isolate())));
__ str(fp, MemOperand(scratch));
}
const int kSavedRegistersAreaSize = const int kSavedRegistersAreaSize =
(kNumberOfRegisters * kPointerSize) + kDoubleRegsSize + kFloatRegsSize; (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize + kFloatRegsSize;
@ -294,15 +300,18 @@ void Deoptimizer::TableEntryGenerator::Generate() {
// Restore the registers from the stack. // Restore the registers from the stack.
__ ldm(ia_w, sp, restored_regs); // all but pc registers. __ ldm(ia_w, sp, restored_regs); // all but pc registers.
__ pop(ip); // remove sp
__ pop(ip); // remove lr
__ InitializeRootRegister(); __ InitializeRootRegister();
__ pop(ip); // remove pc // Remove sp, lr and pc.
__ pop(ip); // get continuation, leave pc on stack __ Drop(3);
__ pop(lr); {
__ Jump(ip); UseScratchRegisterScope temps(masm());
Register scratch = temps.Acquire();
__ pop(scratch); // get continuation, leave pc on stack
__ pop(lr);
__ Jump(scratch);
}
__ stop("Unreachable."); __ stop("Unreachable.");
} }
@ -315,13 +324,15 @@ void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
// ARMv7, we can use movw (with a maximum immediate of 0xffff). On ARMv6, we // ARMv7, we can use movw (with a maximum immediate of 0xffff). On ARMv6, we
// need two instructions. // need two instructions.
STATIC_ASSERT((kMaxNumberOfEntries - 1) <= 0xffff); STATIC_ASSERT((kMaxNumberOfEntries - 1) <= 0xffff);
UseScratchRegisterScope temps(masm());
Register scratch = temps.Acquire();
if (CpuFeatures::IsSupported(ARMv7)) { if (CpuFeatures::IsSupported(ARMv7)) {
CpuFeatureScope scope(masm(), ARMv7); CpuFeatureScope scope(masm(), ARMv7);
Label done; Label done;
for (int i = 0; i < count(); i++) { for (int i = 0; i < count(); i++) {
int start = masm()->pc_offset(); int start = masm()->pc_offset();
USE(start); USE(start);
__ movw(ip, i); __ movw(scratch, i);
__ b(&done); __ b(&done);
DCHECK_EQ(table_entry_size_, masm()->pc_offset() - start); DCHECK_EQ(table_entry_size_, masm()->pc_offset() - start);
} }
@ -337,14 +348,14 @@ void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
for (int i = 0; i < count(); i++) { for (int i = 0; i < count(); i++) {
int start = masm()->pc_offset(); int start = masm()->pc_offset();
USE(start); USE(start);
__ mov(ip, Operand(i & 0xff)); // Set the low byte. __ mov(scratch, Operand(i & 0xff)); // Set the low byte.
__ b(&high_fixes[i >> 8]); // Jump to the secondary table. __ b(&high_fixes[i >> 8]); // Jump to the secondary table.
DCHECK_EQ(table_entry_size_, masm()->pc_offset() - start); DCHECK_EQ(table_entry_size_, masm()->pc_offset() - start);
} }
// Generate the secondary table, to set the high byte. // Generate the secondary table, to set the high byte.
for (int high = 1; high <= high_fix_max; high++) { for (int high = 1; high <= high_fix_max; high++) {
__ bind(&high_fixes[high]); __ bind(&high_fixes[high]);
__ orr(ip, ip, Operand(high << 8)); __ orr(scratch, scratch, Operand(high << 8));
// If this isn't the last entry, emit a branch to the end of the table. // If this isn't the last entry, emit a branch to the end of the table.
// The last entry can just fall through. // The last entry can just fall through.
if (high < high_fix_max) __ b(&high_fixes[0]); if (high < high_fix_max) __ b(&high_fixes[0]);
@ -354,7 +365,7 @@ void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
// through with no additional branch. // through with no additional branch.
__ bind(&high_fixes[0]); __ bind(&high_fixes[0]);
} }
__ push(ip); __ push(scratch);
} }

View File

@ -439,6 +439,8 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
// -- sp[...]: constructor arguments // -- sp[...]: constructor arguments
// ----------------------------------- // -----------------------------------
Register scratch = r2;
// Enter a construct frame. // Enter a construct frame.
{ {
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT); FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
@ -469,8 +471,8 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
// ----------------------------------- // -----------------------------------
__ b(&entry); __ b(&entry);
__ bind(&loop); __ bind(&loop);
__ ldr(ip, MemOperand(r4, r5, LSL, kPointerSizeLog2)); __ ldr(scratch, MemOperand(r4, r5, LSL, kPointerSizeLog2));
__ push(ip); __ push(scratch);
__ bind(&entry); __ bind(&entry);
__ sub(r5, r5, Operand(1), SetCC); __ sub(r5, r5, Operand(1), SetCC);
__ b(ge, &loop); __ b(ge, &loop);
@ -486,13 +488,13 @@ void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) {
// Restore context from the frame. // Restore context from the frame.
__ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset)); __ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
// Restore smi-tagged arguments count from the frame. // Restore smi-tagged arguments count from the frame.
__ ldr(r1, MemOperand(fp, ConstructFrameConstants::kLengthOffset)); __ ldr(scratch, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
// Leave construct frame. // Leave construct frame.
} }
// Remove caller arguments from the stack and return. // Remove caller arguments from the stack and return.
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); __ add(sp, sp, Operand(scratch, LSL, kPointerSizeLog2 - kSmiTagSize));
__ add(sp, sp, Operand(kPointerSize)); __ add(sp, sp, Operand(kPointerSize));
__ Jump(lr); __ Jump(lr);
} }
@ -592,9 +594,10 @@ void Generate_JSConstructStubGeneric(MacroAssembler* masm,
// -- sp[4*kPointerSize]: context // -- sp[4*kPointerSize]: context
// ----------------------------------- // -----------------------------------
__ b(&entry); __ b(&entry);
__ bind(&loop); __ bind(&loop);
__ ldr(ip, MemOperand(r4, r5, LSL, kPointerSizeLog2)); __ ldr(r6, MemOperand(r4, r5, LSL, kPointerSizeLog2));
__ push(ip); __ push(r6);
__ bind(&entry); __ bind(&entry);
__ sub(r5, r5, Operand(1), SetCC); __ sub(r5, r5, Operand(1), SetCC);
__ b(ge, &loop); __ b(ge, &loop);
@ -731,28 +734,31 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
__ ldr(r4, FieldMemOperand(r1, JSGeneratorObject::kFunctionOffset)); __ ldr(r4, FieldMemOperand(r1, JSGeneratorObject::kFunctionOffset));
__ ldr(cp, FieldMemOperand(r4, JSFunction::kContextOffset)); __ ldr(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
// Flood function if we are stepping.
Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator; Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator;
Label stepping_prepared; Label stepping_prepared;
Register scratch = r5;
// Flood function if we are stepping.
ExternalReference debug_hook = ExternalReference debug_hook =
ExternalReference::debug_hook_on_function_call_address(masm->isolate()); ExternalReference::debug_hook_on_function_call_address(masm->isolate());
__ mov(ip, Operand(debug_hook)); __ mov(scratch, Operand(debug_hook));
__ ldrsb(ip, MemOperand(ip)); __ ldrsb(scratch, MemOperand(scratch));
__ cmp(ip, Operand(0)); __ cmp(scratch, Operand(0));
__ b(ne, &prepare_step_in_if_stepping); __ b(ne, &prepare_step_in_if_stepping);
// Flood function if we need to continue stepping in the suspended generator. // Flood function if we need to continue stepping in the suspended
// generator.
ExternalReference debug_suspended_generator = ExternalReference debug_suspended_generator =
ExternalReference::debug_suspended_generator_address(masm->isolate()); ExternalReference::debug_suspended_generator_address(masm->isolate());
__ mov(ip, Operand(debug_suspended_generator)); __ mov(scratch, Operand(debug_suspended_generator));
__ ldr(ip, MemOperand(ip)); __ ldr(scratch, MemOperand(scratch));
__ cmp(ip, Operand(r1)); __ cmp(scratch, Operand(r1));
__ b(eq, &prepare_step_in_suspended_generator); __ b(eq, &prepare_step_in_suspended_generator);
__ bind(&stepping_prepared); __ bind(&stepping_prepared);
// Push receiver. // Push receiver.
__ ldr(ip, FieldMemOperand(r1, JSGeneratorObject::kReceiverOffset)); __ ldr(scratch, FieldMemOperand(r1, JSGeneratorObject::kReceiverOffset));
__ Push(ip); __ Push(scratch);
// ----------- S t a t e ------------- // ----------- S t a t e -------------
// -- r1 : the JSGeneratorObject to resume // -- r1 : the JSGeneratorObject to resume
@ -798,8 +804,8 @@ void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) {
// undefined because generator functions are non-constructable. // undefined because generator functions are non-constructable.
__ Move(r3, r1); __ Move(r3, r1);
__ Move(r1, r4); __ Move(r1, r4);
__ ldr(r5, FieldMemOperand(r1, JSFunction::kCodeEntryOffset)); __ ldr(scratch, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
__ Jump(r5); __ Jump(scratch);
} }
__ bind(&prepare_step_in_if_stepping); __ bind(&prepare_step_in_if_stepping);
@ -1056,14 +1062,13 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm,
Operand(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); Operand(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue)));
__ Assert(eq, kExpectedOptimizationSentinel); __ Assert(eq, kExpectedOptimizationSentinel);
} }
// Checking whether the queued function is ready for install is
// Checking whether the queued function is ready for install is optional, // optional, since we come across interrupts and stack checks elsewhere.
// since we come across interrupts and stack checks elsewhere. However, // However, not checking may delay installing ready functions, and
// not checking may delay installing ready functions, and always checking // always checking would be quite expensive. A good compromise is to
// would be quite expensive. A good compromise is to first check against // first check against stack limit as a cue for an interrupt signal.
// stack limit as a cue for an interrupt signal. __ LoadRoot(scratch2, Heap::kStackLimitRootIndex);
__ LoadRoot(ip, Heap::kStackLimitRootIndex); __ cmp(sp, Operand(scratch2));
__ cmp(sp, Operand(ip));
__ b(hs, &fallthrough); __ b(hs, &fallthrough);
GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode); GenerateTailCallToReturnedCode(masm, Runtime::kTryInstallOptimizedCode);
} }
@ -1229,9 +1234,9 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Dispatch to the first bytecode handler for the function. // Dispatch to the first bytecode handler for the function.
__ ldrb(r1, MemOperand(kInterpreterBytecodeArrayRegister, __ ldrb(r1, MemOperand(kInterpreterBytecodeArrayRegister,
kInterpreterBytecodeOffsetRegister)); kInterpreterBytecodeOffsetRegister));
__ ldr(ip, MemOperand(kInterpreterDispatchTableRegister, r1, LSL, __ ldr(r4, MemOperand(kInterpreterDispatchTableRegister, r1, LSL,
kPointerSizeLog2)); kPointerSizeLog2));
__ Call(ip); __ Call(r4);
masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset()); masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset());
// The return value is in r0. // The return value is in r0.
@ -1361,8 +1366,8 @@ void Builtins::Generate_InterpreterPushArgsThenConstructImpl(
Label stack_overflow; Label stack_overflow;
// Push a slot for the receiver to be constructed. // Push a slot for the receiver to be constructed.
__ mov(ip, Operand::Zero()); __ mov(r5, Operand::Zero());
__ push(ip); __ push(r5);
Generate_StackOverflowCheck(masm, r0, r5, &stack_overflow); Generate_StackOverflowCheck(masm, r0, r5, &stack_overflow);
@ -1415,8 +1420,8 @@ void Builtins::Generate_InterpreterPushArgsThenConstructArray(
Label stack_overflow; Label stack_overflow;
// Push a slot for the receiver to be constructed. // Push a slot for the receiver to be constructed.
__ mov(ip, Operand::Zero()); __ mov(r5, Operand::Zero());
__ push(ip); __ push(r5);
Generate_StackOverflowCheck(masm, r0, r5, &stack_overflow); Generate_StackOverflowCheck(masm, r0, r5, &stack_overflow);
@ -1473,9 +1478,11 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
// Dispatch to the target bytecode. // Dispatch to the target bytecode.
__ ldrb(r1, MemOperand(kInterpreterBytecodeArrayRegister, __ ldrb(r1, MemOperand(kInterpreterBytecodeArrayRegister,
kInterpreterBytecodeOffsetRegister)); kInterpreterBytecodeOffsetRegister));
__ ldr(ip, MemOperand(kInterpreterDispatchTableRegister, r1, LSL, UseScratchRegisterScope temps(masm);
kPointerSizeLog2)); Register scratch = temps.Acquire();
__ mov(pc, ip); __ ldr(scratch, MemOperand(kInterpreterDispatchTableRegister, r1, LSL,
kPointerSizeLog2));
__ Jump(scratch);
} }
void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) {
@ -1741,11 +1748,14 @@ void Generate_ContinueToBuiltinHelper(MacroAssembler* masm,
} }
__ ldr(fp, MemOperand( __ ldr(fp, MemOperand(
sp, BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp)); sp, BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp));
__ Pop(ip);
UseScratchRegisterScope temps(masm);
Register scratch = temps.Acquire();
__ Pop(scratch);
__ add(sp, sp, __ add(sp, sp,
Operand(BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp)); Operand(BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp));
__ Pop(lr); __ Pop(lr);
__ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); __ add(pc, scratch, Operand(Code::kHeaderSize - kHeapObjectTag));
} }
} // namespace } // namespace
@ -1949,13 +1959,14 @@ void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) {
// r0: actual number of arguments // r0: actual number of arguments
// r1: callable // r1: callable
{ {
Register scratch = r3;
Label loop; Label loop;
// Calculate the copy start address (destination). Copy end address is sp. // Calculate the copy start address (destination). Copy end address is sp.
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
__ bind(&loop); __ bind(&loop);
__ ldr(ip, MemOperand(r2, -kPointerSize)); __ ldr(scratch, MemOperand(r2, -kPointerSize));
__ str(ip, MemOperand(r2)); __ str(scratch, MemOperand(r2));
__ sub(r2, r2, Operand(kPointerSize)); __ sub(r2, r2, Operand(kPointerSize));
__ cmp(r2, sp); __ cmp(r2, sp);
__ b(ne, &loop); __ b(ne, &loop);
@ -2092,17 +2103,19 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
// ----------------------------------- // -----------------------------------
__ AssertFixedArray(r2); __ AssertFixedArray(r2);
Register scratch = r8;
// Check for stack overflow. // Check for stack overflow.
{ {
// Check the stack for overflow. We are not trying to catch interruptions // Check the stack for overflow. We are not trying to catch interruptions
// (i.e. debug break and preemption) here, so check the "real stack limit". // (i.e. debug break and preemption) here, so check the "real stack limit".
Label done; Label done;
__ LoadRoot(ip, Heap::kRealStackLimitRootIndex); __ LoadRoot(scratch, Heap::kRealStackLimitRootIndex);
// Make ip the space we have left. The stack might already be overflowed // The stack might already be overflowed here which will cause 'scratch' to
// here which will cause ip to become negative. // become negative.
__ sub(ip, sp, ip); __ sub(scratch, sp, scratch);
// Check if the arguments will overflow the stack. // Check if the arguments will overflow the stack.
__ cmp(ip, Operand(r4, LSL, kPointerSizeLog2)); __ cmp(scratch, Operand(r4, LSL, kPointerSizeLog2));
__ b(gt, &done); // Signed comparison. __ b(gt, &done); // Signed comparison.
__ TailCallRuntime(Runtime::kThrowStackOverflow); __ TailCallRuntime(Runtime::kThrowStackOverflow);
__ bind(&done); __ bind(&done);
@ -2116,11 +2129,11 @@ void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm,
__ bind(&loop); __ bind(&loop);
__ cmp(r6, r4); __ cmp(r6, r4);
__ b(eq, &done); __ b(eq, &done);
__ add(ip, r2, Operand(r6, LSL, kPointerSizeLog2)); __ add(scratch, r2, Operand(r6, LSL, kPointerSizeLog2));
__ ldr(ip, FieldMemOperand(ip, FixedArray::kHeaderSize)); __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kHeaderSize));
__ cmp(ip, r5); __ cmp(scratch, r5);
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex, eq); __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex, eq);
__ Push(ip); __ Push(scratch);
__ add(r6, r6, Operand(1)); __ add(r6, r6, Operand(1));
__ b(&loop); __ b(&loop);
__ bind(&done); __ bind(&done);
@ -2141,11 +2154,15 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
// -- r2 : start index (to support rest parameters) // -- r2 : start index (to support rest parameters)
// ----------------------------------- // -----------------------------------
Register scratch = r6;
// Check if we have an arguments adaptor frame below the function frame. // Check if we have an arguments adaptor frame below the function frame.
Label arguments_adaptor, arguments_done; Label arguments_adaptor, arguments_done;
__ ldr(r4, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); __ ldr(r4, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
__ ldr(ip, MemOperand(r4, CommonFrameConstants::kContextOrFrameTypeOffset)); __ ldr(scratch,
__ cmp(ip, Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); MemOperand(r4, CommonFrameConstants::kContextOrFrameTypeOffset));
__ cmp(scratch,
Operand(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR)));
__ b(eq, &arguments_adaptor); __ b(eq, &arguments_adaptor);
{ {
__ ldr(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); __ ldr(r5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
@ -2177,8 +2194,8 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
__ add(r0, r0, r5); __ add(r0, r0, r5);
__ bind(&loop); __ bind(&loop);
{ {
__ ldr(ip, MemOperand(r4, r5, LSL, kPointerSizeLog2)); __ ldr(scratch, MemOperand(r4, r5, LSL, kPointerSizeLog2));
__ push(ip); __ push(scratch);
__ sub(r5, r5, Operand(1), SetCC); __ sub(r5, r5, Operand(1), SetCC);
__ b(ne, &loop); __ b(ne, &loop);
} }
@ -2438,6 +2455,8 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
__ bind(&done); __ bind(&done);
} }
Register scratch = r6;
// Relocate arguments down the stack. // Relocate arguments down the stack.
{ {
Label loop, done_loop; Label loop, done_loop;
@ -2445,8 +2464,8 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
__ bind(&loop); __ bind(&loop);
__ cmp(r5, r0); __ cmp(r5, r0);
__ b(gt, &done_loop); __ b(gt, &done_loop);
__ ldr(ip, MemOperand(sp, r4, LSL, kPointerSizeLog2)); __ ldr(scratch, MemOperand(sp, r4, LSL, kPointerSizeLog2));
__ str(ip, MemOperand(sp, r5, LSL, kPointerSizeLog2)); __ str(scratch, MemOperand(sp, r5, LSL, kPointerSizeLog2));
__ add(r4, r4, Operand(1)); __ add(r4, r4, Operand(1));
__ add(r5, r5, Operand(1)); __ add(r5, r5, Operand(1));
__ b(&loop); __ b(&loop);
@ -2461,8 +2480,8 @@ void Generate_PushBoundArguments(MacroAssembler* masm) {
__ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
__ bind(&loop); __ bind(&loop);
__ sub(r4, r4, Operand(1), SetCC); __ sub(r4, r4, Operand(1), SetCC);
__ ldr(ip, MemOperand(r2, r4, LSL, kPointerSizeLog2)); __ ldr(scratch, MemOperand(r2, r4, LSL, kPointerSizeLog2));
__ str(ip, MemOperand(sp, r0, LSL, kPointerSizeLog2)); __ str(scratch, MemOperand(sp, r0, LSL, kPointerSizeLog2));
__ add(r0, r0, Operand(1)); __ add(r0, r0, Operand(1));
__ b(gt, &loop); __ b(gt, &loop);
} }
@ -2486,18 +2505,19 @@ void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm,
} }
// Patch the receiver to [[BoundThis]]. // Patch the receiver to [[BoundThis]].
__ ldr(ip, FieldMemOperand(r1, JSBoundFunction::kBoundThisOffset)); __ ldr(r3, FieldMemOperand(r1, JSBoundFunction::kBoundThisOffset));
__ str(ip, MemOperand(sp, r0, LSL, kPointerSizeLog2)); __ str(r3, MemOperand(sp, r0, LSL, kPointerSizeLog2));
// Push the [[BoundArguments]] onto the stack. // Push the [[BoundArguments]] onto the stack.
Generate_PushBoundArguments(masm); Generate_PushBoundArguments(masm);
// Call the [[BoundTargetFunction]] via the Call builtin. // Call the [[BoundTargetFunction]] via the Call builtin.
__ ldr(r1, FieldMemOperand(r1, JSBoundFunction::kBoundTargetFunctionOffset)); __ ldr(r1, FieldMemOperand(r1, JSBoundFunction::kBoundTargetFunctionOffset));
__ mov(ip, Operand(ExternalReference(Builtins::kCall_ReceiverIsAny,
__ mov(r3, Operand(ExternalReference(Builtins::kCall_ReceiverIsAny,
masm->isolate()))); masm->isolate())));
__ ldr(ip, MemOperand(ip)); __ ldr(r3, MemOperand(r3));
__ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); __ add(pc, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
} }
// static // static
@ -2599,9 +2619,10 @@ void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) {
// Construct the [[BoundTargetFunction]] via the Construct builtin. // Construct the [[BoundTargetFunction]] via the Construct builtin.
__ ldr(r1, FieldMemOperand(r1, JSBoundFunction::kBoundTargetFunctionOffset)); __ ldr(r1, FieldMemOperand(r1, JSBoundFunction::kBoundTargetFunctionOffset));
__ mov(ip, Operand(ExternalReference(Builtins::kConstruct, masm->isolate())));
__ ldr(ip, MemOperand(ip)); __ mov(r2, Operand(ExternalReference(Builtins::kConstruct, masm->isolate())));
__ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); __ ldr(r2, MemOperand(r2));
__ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
} }
// static // static
@ -2726,10 +2747,12 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
__ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel)); __ cmp(r2, Operand(SharedFunctionInfo::kDontAdaptArgumentsSentinel));
__ b(eq, &dont_adapt_arguments); __ b(eq, &dont_adapt_arguments);
Register scratch = r5;
{ // Enough parameters: actual >= expected { // Enough parameters: actual >= expected
__ bind(&enough); __ bind(&enough);
EnterArgumentsAdaptorFrame(masm); EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r2, r5, &stack_overflow); Generate_StackOverflowCheck(masm, r2, scratch, &stack_overflow);
// Calculate copy start address into r0 and copy end address into r4. // Calculate copy start address into r0 and copy end address into r4.
// r0: actual number of arguments as a smi // r0: actual number of arguments as a smi
@ -2750,8 +2773,8 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
Label copy; Label copy;
__ bind(&copy); __ bind(&copy);
__ ldr(ip, MemOperand(r0, 0)); __ ldr(scratch, MemOperand(r0, 0));
__ push(ip); __ push(scratch);
__ cmp(r0, r4); // Compare before moving to next argument. __ cmp(r0, r4); // Compare before moving to next argument.
__ sub(r0, r0, Operand(kPointerSize)); __ sub(r0, r0, Operand(kPointerSize));
__ b(ne, &copy); __ b(ne, &copy);
@ -2762,7 +2785,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
{ // Too few parameters: Actual < expected { // Too few parameters: Actual < expected
__ bind(&too_few); __ bind(&too_few);
EnterArgumentsAdaptorFrame(masm); EnterArgumentsAdaptorFrame(masm);
Generate_StackOverflowCheck(masm, r2, r5, &stack_overflow); Generate_StackOverflowCheck(masm, r2, scratch, &stack_overflow);
// Calculate copy start address into r0 and copy end address is fp. // Calculate copy start address into r0 and copy end address is fp.
// r0: actual number of arguments as a smi // r0: actual number of arguments as a smi
@ -2778,9 +2801,11 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// r3: new target (passed through to callee) // r3: new target (passed through to callee)
Label copy; Label copy;
__ bind(&copy); __ bind(&copy);
// Adjust load for return address and receiver. // Adjust load for return address and receiver.
__ ldr(ip, MemOperand(r0, 2 * kPointerSize)); __ ldr(scratch, MemOperand(r0, 2 * kPointerSize));
__ push(ip); __ push(scratch);
__ cmp(r0, fp); // Compare before moving to next argument. __ cmp(r0, fp); // Compare before moving to next argument.
__ sub(r0, r0, Operand(kPointerSize)); __ sub(r0, r0, Operand(kPointerSize));
__ b(ne, &copy); __ b(ne, &copy);
@ -2789,7 +2814,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
// r1: function // r1: function
// r2: expected number of arguments // r2: expected number of arguments
// r3: new target (passed through to callee) // r3: new target (passed through to callee)
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex); __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
__ sub(r4, fp, Operand(r2, LSL, kPointerSizeLog2)); __ sub(r4, fp, Operand(r2, LSL, kPointerSizeLog2));
// Adjust for frame. // Adjust for frame.
__ sub(r4, r4, Operand(StandardFrameConstants::kFixedFrameSizeFromFp + __ sub(r4, r4, Operand(StandardFrameConstants::kFixedFrameSizeFromFp +
@ -2797,7 +2822,7 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
Label fill; Label fill;
__ bind(&fill); __ bind(&fill);
__ push(ip); __ push(scratch);
__ cmp(sp, r4); __ cmp(sp, r4);
__ b(ne, &fill); __ b(ne, &fill);
} }