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 12namespace v8 { 13namespace internal { 14 15#define __ ACCESS_MASM(masm) 16 17 18void 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 29void 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 38void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) { 39 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions); 40 EmitDebugBreakSlot(patcher.masm()); 41} 42 43 44void 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 67bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { 68 Instr current_instr = Assembler::instr_at(pc); 69 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); 70} 71 72void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, 73 DebugBreakCallHelperMode mode) { 74 __ RecordComment("Debug break"); 75 { 76 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); 77 78 // Push arguments for DebugBreak call. 79 if (mode == SAVE_RESULT_REGISTER) { 80 // Break on return. 81 __ push(r0); 82 } else { 83 // Non-return breaks. 84 __ Push(masm->isolate()->factory()->the_hole_value()); 85 } 86 __ mov(r0, Operand(1)); 87 __ mov(r1, 88 Operand(ExternalReference( 89 Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); 90 91 CEntryStub ceb(masm->isolate(), 1); 92 __ CallStub(&ceb); 93 94 if (FLAG_debug_code) { 95 for (int i = 0; i < kNumJSCallerSaved; i++) { 96 Register reg = {JSCallerSavedCode(i)}; 97 // Do not clobber r0 if mode is SAVE_RESULT_REGISTER. It will 98 // contain return value of the function. 99 if (!(reg.is(r0) && (mode == SAVE_RESULT_REGISTER))) { 100 __ mov(reg, Operand(kDebugZapValue)); 101 } 102 } 103 } 104 // Leave the internal frame. 105 } 106 107 __ MaybeDropFrames(); 108 109 // Return to caller. 110 __ Ret(); 111} 112 113void DebugCodegen::GenerateHandleDebuggerStatement(MacroAssembler* masm) { 114 { 115 FrameScope scope(masm, StackFrame::INTERNAL); 116 __ CallRuntime(Runtime::kHandleDebuggerStatement, 0); 117 } 118 __ MaybeDropFrames(); 119 120 // Return to caller. 121 __ Ret(); 122} 123 124void DebugCodegen::GenerateFrameDropperTrampoline(MacroAssembler* masm) { 125 // Frame is being dropped: 126 // - Drop to the target frame specified by r1. 127 // - Look up current function on the frame. 128 // - Leave the frame. 129 // - Restart the frame by calling the function. 130 __ mov(fp, r1); 131 __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 132 __ LeaveFrame(StackFrame::INTERNAL); 133 134 __ ldr(r0, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); 135 __ ldr(r0, 136 FieldMemOperand(r0, SharedFunctionInfo::kFormalParameterCountOffset)); 137 __ mov(r2, r0); 138 139 ParameterCount dummy1(r2); 140 ParameterCount dummy2(r0); 141 __ InvokeFunction(r1, dummy1, dummy2, JUMP_FUNCTION, 142 CheckDebugStepCallWrapper()); 143} 144 145 146const bool LiveEdit::kFrameDropperSupported = true; 147 148#undef __ 149 150} // namespace internal 151} // namespace v8 152 153#endif // V8_TARGET_ARCH_ARM 154