1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #if V8_TARGET_ARCH_ARM 6 7 #include "src/debug/debug.h" 8 9 #include "src/codegen.h" 10 #include "src/debug/liveedit.h" 11 12 namespace v8 { 13 namespace internal { 14 15 #define __ ACCESS_MASM(masm) 16 17 EmitDebugBreakSlot(MacroAssembler * masm)18 void EmitDebugBreakSlot(MacroAssembler* masm) { 19 Label check_size; 20 __ bind(&check_size); 21 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) { 22 __ nop(MacroAssembler::DEBUG_BREAK_NOP); 23 } 24 DCHECK_EQ(Assembler::kDebugBreakSlotInstructions, 25 masm->InstructionsGeneratedSince(&check_size)); 26 } 27 28 GenerateSlot(MacroAssembler * masm,RelocInfo::Mode mode)29 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) { 30 // Generate enough nop's to make space for a call instruction. Avoid emitting 31 // the constant pool in the debug break slot code. 32 Assembler::BlockConstPoolScope block_const_pool(masm); 33 masm->RecordDebugBreakSlot(mode); 34 EmitDebugBreakSlot(masm); 35 } 36 37 ClearDebugBreakSlot(Isolate * isolate,Address pc)38 void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) { 39 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions); 40 EmitDebugBreakSlot(patcher.masm()); 41 } 42 43 PatchDebugBreakSlot(Isolate * isolate,Address pc,Handle<Code> code)44 void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, 45 Handle<Code> code) { 46 DCHECK(code->is_debug_stub()); 47 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions); 48 // Patch the code changing the debug break slot code from 49 // mov r2, r2 50 // mov r2, r2 51 // mov r2, r2 52 // mov r2, r2 53 // to a call to the debug break slot code. 54 // ldr ip, [pc, #0] 55 // b skip 56 // <debug break slot code entry point address> 57 // skip: 58 // blx ip 59 Label skip_constant; 60 patcher.masm()->ldr(ip, MemOperand(v8::internal::pc, 0)); 61 patcher.masm()->b(&skip_constant); 62 patcher.Emit(code->entry()); 63 patcher.masm()->bind(&skip_constant); 64 patcher.masm()->blx(ip); 65 } 66 DebugBreakSlotIsPatched(Address pc)67 bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { 68 Instr current_instr = Assembler::instr_at(pc); 69 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); 70 } 71 GenerateDebugBreakStub(MacroAssembler * masm,DebugBreakCallHelperMode mode)72 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, 73 DebugBreakCallHelperMode mode) { 74 __ RecordComment("Debug break"); 75 { 76 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); 77 78 // Load padding words on stack. 79 __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue))); 80 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { 81 __ push(ip); 82 } 83 __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); 84 __ push(ip); 85 86 // Push arguments for DebugBreak call. 87 if (mode == SAVE_RESULT_REGISTER) { 88 // Break on return. 89 __ push(r0); 90 } else { 91 // Non-return breaks. 92 __ Push(masm->isolate()->factory()->the_hole_value()); 93 } 94 __ mov(r0, Operand(1)); 95 __ mov(r1, 96 Operand(ExternalReference( 97 Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); 98 99 CEntryStub ceb(masm->isolate(), 1); 100 __ CallStub(&ceb); 101 102 if (FLAG_debug_code) { 103 for (int i = 0; i < kNumJSCallerSaved; i++) { 104 Register reg = {JSCallerSavedCode(i)}; 105 // Do not clobber r0 if mode is SAVE_RESULT_REGISTER. It will 106 // contain return value of the function. 107 if (!(reg.is(r0) && (mode == SAVE_RESULT_REGISTER))) { 108 __ mov(reg, Operand(kDebugZapValue)); 109 } 110 } 111 } 112 113 // Don't bother removing padding bytes pushed on the stack 114 // as the frame is going to be restored right away. 115 116 // Leave the internal frame. 117 } 118 119 // Now that the break point has been handled, resume normal execution by 120 // jumping to the target address intended by the caller and that was 121 // overwritten by the address of DebugBreakXXX. 122 ExternalReference after_break_target = 123 ExternalReference::debug_after_break_target_address(masm->isolate()); 124 __ mov(ip, Operand(after_break_target)); 125 __ ldr(ip, MemOperand(ip)); 126 __ Jump(ip); 127 } 128 129 GenerateFrameDropperLiveEdit(MacroAssembler * masm)130 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { 131 // Load the function pointer off of our current stack frame. 132 __ ldr(r1, MemOperand(fp, FrameDropperFrameConstants::kFunctionOffset)); 133 134 // Pop return address, frame and constant pool pointer (if 135 // FLAG_enable_embedded_constant_pool). 136 __ LeaveFrame(StackFrame::INTERNAL); 137 138 ParameterCount dummy(0); 139 __ FloodFunctionIfStepping(r1, no_reg, dummy, dummy); 140 141 { ConstantPoolUnavailableScope constant_pool_unavailable(masm); 142 // Load context from the function. 143 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); 144 145 // Clear new.target as a safety measure. 146 __ LoadRoot(r3, Heap::kUndefinedValueRootIndex); 147 148 // Get function code. 149 __ ldr(ip, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 150 __ ldr(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset)); 151 __ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); 152 153 // Re-run JSFunction, r1 is function, cp is context. 154 __ Jump(ip); 155 } 156 } 157 158 159 const bool LiveEdit::kFrameDropperSupported = true; 160 161 #undef __ 162 163 } // namespace internal 164 } // namespace v8 165 166 #endif // V8_TARGET_ARCH_ARM 167