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