Index: runtime/vm/stub_code_arm64.cc |
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc |
index 4148925ece6ff501b25393e4ba0fb2c9cb793098..9c41377eb6ce3c674de643370a550bab25c9cd46 100644 |
--- a/runtime/vm/stub_code_arm64.cc |
+++ b/runtime/vm/stub_code_arm64.cc |
@@ -41,7 +41,6 @@ void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
const intptr_t argv_offset = NativeArguments::argv_offset(); |
const intptr_t retval_offset = NativeArguments::retval_offset(); |
- const intptr_t exitframe_last_param_slot_from_fp = 1; |
__ SetPrologueOffset(); |
__ Comment("CallToRuntimeStub"); |
@@ -91,7 +90,7 @@ void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
__ add(R2, ZR, Operand(R4, LSL, 3)); |
__ add(R2, FP, Operand(R2)); // Compute argv. |
// Set argv in NativeArguments. |
- __ AddImmediate(R2, R2, exitframe_last_param_slot_from_fp * kWordSize); |
+ __ AddImmediate(R2, R2, kParamEndSlotFromFp * kWordSize); |
ASSERT(retval_offset == 3 * kWordSize); |
__ AddImmediate(R3, R2, kWordSize); |
@@ -346,12 +345,12 @@ void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { |
__ PushObject(Object::null_object()); |
__ CallRuntime(kPatchStaticCallRuntimeEntry, 0); |
// Get Code object result and restore arguments descriptor array. |
- __ Pop(R0); |
+ __ Pop(CODE_REG); |
__ Pop(R4); |
// Remove the stub frame. |
__ LeaveStubFrame(); |
// Jump to the dart function. |
- __ LoadFieldFromOffset(R0, R0, Code::entry_point_offset()); |
+ __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); |
__ br(R0); |
} |
@@ -360,6 +359,10 @@ void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { |
// (invalid because its function was optimized or deoptimized). |
// R4: arguments descriptor array. |
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
+ // Load code pointer to this stub from the thread: |
+ // The one that is passed in, is not correct - it points to the code object |
+ // that needs to be replaced. |
+ __ ldr(CODE_REG, Address(THR, Thread::fix_callers_target_code_offset())); |
// Create a stub frame as we are pushing some objects on the stack before |
// calling into the runtime. |
__ EnterStubFrame(); |
@@ -368,12 +371,12 @@ void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
__ PushObject(Object::null_object()); |
__ CallRuntime(kFixCallersTargetRuntimeEntry, 0); |
// Get Code object result and restore arguments descriptor array. |
- __ Pop(R0); |
+ __ Pop(CODE_REG); |
__ Pop(R4); |
// Remove the stub frame. |
__ LeaveStubFrame(); |
// Jump to the dart function. |
- __ LoadFieldFromOffset(R0, R0, Code::entry_point_offset()); |
+ __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); |
__ br(R0); |
} |
@@ -381,16 +384,20 @@ void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
// Called from object allocate instruction when the allocation stub has been |
// disabled. |
void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) { |
+ // Load code pointer to this stub from the thread: |
+ // The one that is passed in, is not correct - it points to the code object |
+ // that needs to be replaced. |
+ __ ldr(CODE_REG, Address(THR, Thread::fix_allocation_stub_code_offset())); |
__ EnterStubFrame(); |
// Setup space on stack for return value. |
__ PushObject(Object::null_object()); |
__ CallRuntime(kFixAllocationStubTargetRuntimeEntry, 0); |
// Get Code object result. |
- __ Pop(R0); |
+ __ Pop(CODE_REG); |
// Remove the stub frame. |
__ LeaveStubFrame(); |
// Jump to the dart function. |
- __ LoadFieldFromOffset(R0, R0, Code::entry_point_offset()); |
+ __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); |
__ br(R0); |
} |
@@ -448,11 +455,13 @@ static void PushArgumentsArray(Assembler* assembler) { |
// +------------------+ |
// | return-address | (deoptimization point) |
// +------------------+ |
+// | Saved CODE_REG | |
+// +------------------+ |
// | ... | <- SP of optimized frame |
// |
// Parts of the code cannot GC, part of the code can GC. |
static void GenerateDeoptimizationSequence(Assembler* assembler, |
- bool preserve_result) { |
+ DeoptStubKind kind) { |
// DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
// is no need to set the correct PC marker or load PP, since they get patched. |
__ EnterStubFrame(); |
@@ -467,7 +476,15 @@ static void GenerateDeoptimizationSequence(Assembler* assembler, |
// lowest address. |
for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; i--) { |
const Register r = static_cast<Register>(i); |
- __ str(r, Address(SP, -1 * kWordSize, Address::PreIndex)); |
+ if (r == CODE_REG) { |
+ // Save the original value of CODE_REG pushed before invoking this stub |
+ // instead of the value used to call this stub. |
+ COMPILE_ASSERT(R25 > CODE_REG); |
+ __ ldr(R25, Address(FP, 2 * kWordSize)); |
+ __ str(R25, Address(SP, -1 * kWordSize, Address::PreIndex)); |
+ } else { |
+ __ str(r, Address(SP, -1 * kWordSize, Address::PreIndex)); |
+ } |
} |
for (intptr_t reg_idx = kNumberOfVRegisters - 1; reg_idx >= 0; reg_idx--) { |
@@ -476,16 +493,19 @@ static void GenerateDeoptimizationSequence(Assembler* assembler, |
} |
__ mov(R0, SP); // Pass address of saved registers block. |
+ __ LoadImmediate(R1, kind == kLazyDeopt ? 1 : 0); |
__ ReserveAlignedFrameSpace(0); |
- __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 1); |
+ __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); |
// Result (R0) is stack-size (FP - SP) in bytes. |
+ const bool preserve_result = (kind == kLazyDeopt); |
if (preserve_result) { |
// Restore result into R1 temporarily. |
__ LoadFromOffset(R1, FP, saved_result_slot_from_fp * kWordSize); |
} |
// There is a Dart Frame on the stack. We must restore PP and leave frame. |
+ __ RestoreCodePointer(); |
__ LeaveStubFrame(); |
__ sub(SP, FP, Operand(R0)); |
@@ -505,6 +525,7 @@ static void GenerateDeoptimizationSequence(Assembler* assembler, |
} |
// Code above cannot cause GC. |
// There is a Dart Frame on the stack. We must restore PP and leave frame. |
+ __ RestoreCodePointer(); |
__ LeaveStubFrame(); |
// Frame is fully rewritten at this point and it is safe to perform a GC. |
@@ -534,13 +555,16 @@ static void GenerateDeoptimizationSequence(Assembler* assembler, |
void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { |
// Correct return address to point just after the call that is being |
// deoptimized. |
- __ AddImmediate(LR, LR, -CallPattern::kLengthInBytes); |
- GenerateDeoptimizationSequence(assembler, true); // Preserve R0. |
+ __ AddImmediate(LR, LR, -CallPattern::kDeoptCallLengthInBytes); |
+ // Push zap value instead of CODE_REG for lazy deopt. |
+ __ LoadImmediate(TMP, 0xf1f1f1f1); |
+ __ Push(TMP); |
+ GenerateDeoptimizationSequence(assembler, kLazyDeopt); |
} |
void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
- GenerateDeoptimizationSequence(assembler, false); // Don't preserve R0. |
+ GenerateDeoptimizationSequence(assembler, kEagerDeopt); |
} |
@@ -601,6 +625,7 @@ void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { |
__ Pop(R4); |
__ Pop(R5); |
+ __ RestoreCodePointer(); |
__ LeaveStubFrame(); |
if (!FLAG_lazy_dispatchers) { |
@@ -610,6 +635,7 @@ void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { |
} |
// Tail-call to target function. |
+ __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); |
__ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
__ br(R2); |
} |
@@ -766,7 +792,7 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { |
// Called when invoking Dart code from C++ (VM code). |
// Input parameters: |
// LR : points to return address. |
-// R0 : entrypoint of the Dart function to call. |
+// R0 : code object of the Dart function to call. |
// R1 : arguments descriptor array. |
// R2 : arguments array. |
// R3 : current thread. |
@@ -778,6 +804,10 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
__ SetupDartSP(Isolate::GetSpecifiedStackSize()); |
__ EnterFrame(0); |
+ // Push code object to PC marker slot. |
+ __ ldr(TMP, Address(R3, Thread::invoke_dart_code_stub_offset())); |
+ __ Push(TMP); |
+ |
// Save the callee-saved registers. |
for (int i = kAbiFirstPreservedCpuReg; i <= kAbiLastPreservedCpuReg; i++) { |
const Register r = static_cast<Register>(i); |
@@ -793,11 +823,6 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
__ PushDouble(r); |
} |
- // We now load the pool pointer(PP) as we are about to invoke dart code and we |
- // could potentially invoke some intrinsic functions which need the PP to be |
- // set up. |
- __ LoadPoolPointer(); |
- |
// Set up THR, which caches the current thread in Dart code. |
if (THR != R3) { |
__ mov(THR, R3); |
@@ -821,7 +846,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
__ LoadFromOffset(R6, THR, Thread::top_exit_frame_info_offset()); |
__ StoreToOffset(ZR, THR, Thread::top_exit_frame_info_offset()); |
// kExitLinkSlotFromEntryFp must be kept in sync with the code below. |
- ASSERT(kExitLinkSlotFromEntryFp == -21); |
+ ASSERT(kExitLinkSlotFromEntryFp == -22); |
__ Push(R6); |
// Load arguments descriptor array into R4, which is passed to Dart code. |
@@ -850,13 +875,17 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
__ b(&push_arguments, LT); |
__ Bind(&done_push_arguments); |
+ // We now load the pool pointer(PP) with a GC safe value as we are about to |
+ // invoke dart code. We don't need a real object pool here. |
+ // Smi zero does not work because ARM64 assumes PP to be untagged. |
+ __ LoadObject(PP, Object::null_object()); |
+ |
// Call the Dart code entrypoint. |
+ __ ldr(CODE_REG, Address(R0, VMHandles::kOffsetOfRawPtrInHandle)); |
+ __ ldr(R0, FieldAddress(CODE_REG, Code::entry_point_offset())); |
__ blr(R0); // R4 is the arguments descriptor array. |
__ Comment("InvokeDartCodeStub return"); |
- // Restore constant pool pointer after return. |
- __ LoadPoolPointer(); |
- |
// Get rid of arguments pushed on the stack. |
__ AddImmediate(SP, FP, kExitLinkSlotFromEntryFp * kWordSize); |
@@ -888,7 +917,6 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
// using it as the stack pointer. |
__ ldr(r, Address(SP, 1 * kWordSize, Address::PostIndex)); |
} |
- __ set_constant_pool_allowed(false); |
// Restore the frame pointer and C stack pointer and return. |
__ LeaveFrame(); |
@@ -1074,10 +1102,8 @@ void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) { |
// Input parameters: |
// LR : return address. |
// SP + 0 : type arguments object (only if class is parameterized). |
-void StubCode::GenerateAllocationStubForClass( |
- Assembler* assembler, const Class& cls, |
- uword* entry_patch_offset, uword* patch_code_pc_offset) { |
- *entry_patch_offset = assembler->CodeSize(); |
+void StubCode::GenerateAllocationStubForClass(Assembler* assembler, |
+ const Class& cls) { |
// The generated code is different if the class is parameterized. |
const bool is_cls_parameterized = cls.NumTypeArguments() > 0; |
ASSERT(!is_cls_parameterized || |
@@ -1197,8 +1223,6 @@ void StubCode::GenerateAllocationStubForClass( |
// Restore the frame pointer. |
__ LeaveStubFrame(); |
__ ret(); |
- *patch_code_pc_offset = assembler->CodeSize(); |
- __ BranchPatchable(*StubCode::FixAllocationStubTarget_entry()); |
} |
@@ -1515,6 +1539,9 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( |
__ Pop(R0); // Pop returned function object into R0. |
__ Pop(R5); // Restore IC Data. |
__ Pop(R4); // Restore arguments descriptor array. |
+ if (range_collection_mode == kCollectRanges) { |
+ __ RestoreCodePointer(); |
+ } |
__ LeaveStubFrame(); |
Label call_target_function; |
if (!FLAG_lazy_dispatchers) { |
@@ -1542,8 +1569,8 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( |
__ Comment("Call target"); |
__ Bind(&call_target_function); |
// R0: target function. |
- __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
if (range_collection_mode == kCollectRanges) { |
+ __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
__ ldr(R1, Address(SP, 0 * kWordSize)); |
if (num_args == 2) { |
__ ldr(R3, Address(SP, 1 * kWordSize)); |
@@ -1554,6 +1581,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( |
__ Push(R3); |
} |
__ Push(R1); |
+ __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); |
__ blr(R2); |
Label done; |
@@ -1563,6 +1591,8 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( |
__ LeaveStubFrame(); |
__ ret(); |
} else { |
+ __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); |
+ __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
__ br(R2); |
} |
@@ -1572,6 +1602,7 @@ void StubCode::GenerateNArgsCheckInlineCacheStub( |
__ Push(R5); // Preserve IC data. |
__ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
__ Pop(R5); |
+ __ RestoreCodePointer(); |
__ LeaveStubFrame(); |
__ b(&done_stepping); |
} |
@@ -1716,6 +1747,7 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
// Get function and call it, if possible. |
__ LoadFromOffset(R0, R6, target_offset); |
+ __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); |
__ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
__ br(R2); |
@@ -1725,6 +1757,7 @@ void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
__ Push(R5); // Preserve IC data. |
__ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
__ Pop(R5); |
+ __ RestoreCodePointer(); |
__ LeaveStubFrame(); |
__ b(&done_stepping); |
} |
@@ -1763,6 +1796,7 @@ void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
__ Pop(R5); // Restore IC Data. |
__ LeaveStubFrame(); |
+ __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); |
__ LoadFieldFromOffset(R2, R0, Function::entry_point_offset()); |
__ br(R2); |
} |
@@ -1774,9 +1808,10 @@ void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) { |
__ Push(R5); |
__ PushObject(Object::null_object()); // Space for result. |
__ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
- __ Pop(R0); |
+ __ Pop(CODE_REG); |
__ Pop(R5); |
__ LeaveStubFrame(); |
+ __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); |
__ br(R0); |
} |
@@ -1785,8 +1820,9 @@ void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) { |
__ EnterStubFrame(); |
__ PushObject(Object::null_object()); // Space for result. |
__ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
- __ Pop(R0); |
+ __ Pop(CODE_REG); |
__ LeaveStubFrame(); |
+ __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); |
__ br(R0); |
} |
@@ -1964,9 +2000,9 @@ void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { |
__ Push(R6); |
__ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); |
__ Pop(R0); // Discard argument. |
- __ Pop(R0); // Get Code object |
+ __ Pop(CODE_REG); // Get Code object |
__ Pop(R4); // Restore argument descriptor. |
- __ LoadFieldFromOffset(R0, R0, Code::entry_point_offset()); |
+ __ LoadFieldFromOffset(R0, CODE_REG, Code::entry_point_offset()); |
__ LeaveStubFrame(); |
__ br(R0); |
__ brk(0); |
@@ -2059,6 +2095,7 @@ void StubCode::GenerateUnoptimizedIdenticalWithNumberCheckStub( |
__ Bind(&stepping); |
__ EnterStubFrame(); |
__ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
+ __ RestoreCodePointer(); |
__ LeaveStubFrame(); |
__ b(&done_stepping); |
} |
@@ -2117,6 +2154,7 @@ void StubCode::EmitMegamorphicLookup( |
// be invoked as a normal Dart function. |
__ add(TMP, R2, Operand(R3, LSL, 3)); |
__ LoadFieldFromOffset(R0, TMP, base + kWordSize); |
+ __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset()); |
__ LoadFieldFromOffset(R1, R0, Function::entry_point_offset()); |
} |