debug-arm.cc 6.06 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/v8.h"
6

7
#if V8_TARGET_ARCH_ARM
8

9 10
#include "src/codegen.h"
#include "src/debug.h"
11

12 13
namespace v8 {
namespace internal {
14

15
void BreakLocation::SetDebugBreakAtReturn() {
16 17 18 19 20 21
  // Patch the code changing the return from JS function sequence from
  //   mov sp, fp
  //   ldmia sp!, {fp, lr}
  //   add sp, sp, #4
  //   bx lr
  // to a call to the debug break return code.
22 23
  //   ldr ip, [pc, #0]
  //   blx ip
24
  //   <debug break return code entry point address>
25
  //   bkpt 0
26
  CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
27 28
  patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
  patcher.masm()->blx(v8::internal::ip);
29
  patcher.Emit(
30
      debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry());
31
  patcher.masm()->bkpt(0);
32 33 34
}


35
void BreakLocation::SetDebugBreakAtSlot() {
36
  DCHECK(IsDebugBreakSlot());
37 38 39 40 41 42 43 44
  // Patch the code changing the debug break slot code from
  //   mov r2, r2
  //   mov r2, r2
  //   mov r2, r2
  // to a call to the debug break slot code.
  //   ldr ip, [pc, #0]
  //   blx ip
  //   <debug break slot code entry point address>
45
  CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
46 47
  patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
  patcher.masm()->blx(v8::internal::ip);
48
  patcher.Emit(
49
      debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry());
50 51 52
}


53
#define __ ACCESS_MASM(masm)
54 55 56


static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
57
                                          RegList object_regs) {
58
  {
59
    FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
60

61 62 63 64 65 66 67 68
    // Load padding words on stack.
    __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue)));
    for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
      __ push(ip);
    }
    __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
    __ push(ip);

69 70 71
    // Store the registers containing live values on the expression stack to
    // make sure that these are correctly updated during GC. Non object values
    // are stored as a smi causing it to be untouched by GC.
72
    DCHECK((object_regs & ~kJSCallerSaved) == 0);
73 74
    if (object_regs != 0) {
      __ stm(db_w, sp, object_regs);
75
    }
76 77

#ifdef DEBUG
78
    __ RecordComment("// Calling from debug break to runtime - come in - over");
79
#endif
80
    __ mov(r0, Operand::Zero());  // no arguments
81 82
    __ mov(r1, Operand(ExternalReference::debug_break(masm->isolate())));

83
    CEntryStub ceb(masm->isolate(), 1);
84 85 86
    __ CallStub(&ceb);

    // Restore the register values from the expression stack.
87 88 89 90 91 92 93 94 95
    if (object_regs != 0) {
      __ ldm(ia_w, sp, object_regs);
    }

    for (int i = 0; i < kNumJSCallerSaved; i++) {
      int r = JSCallerSavedCode(i);
      Register reg = {r};
      if (FLAG_debug_code && ((object_regs & (1 << r)) == 0)) {
        __ mov(reg, Operand(kDebugZapValue));
96 97
      }
    }
98

99 100 101
    // Don't bother removing padding bytes pushed on the stack
    // as the frame is going to be restored right away.

102 103
    // Leave the internal frame.
  }
104

105 106 107
  // Now that the break point has been handled, resume normal execution by
  // jumping to the target address intended by the caller and that was
  // overwritten by the address of DebugBreakXXX.
108
  ExternalReference after_break_target =
109
      ExternalReference::debug_after_break_target_address(masm->isolate());
110
  __ mov(ip, Operand(after_break_target));
111 112 113 114 115
  __ ldr(ip, MemOperand(ip));
  __ Jump(ip);
}


116
void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
117 118 119
  // In places other than IC call sites it is expected that r0 is TOS which
  // is an object - this is not generally the case so this should be used with
  // care.
120
  Generate_DebugBreakCallHelper(masm, r0.bit());
121 122 123
}


124 125 126
void DebugCodegen::GenerateSlot(MacroAssembler* masm,
                                DebugCodegen::SlotLocation location,
                                int call_argc) {
127 128 129
  // Generate enough nop's to make space for a call instruction. Avoid emitting
  // the constant pool in the debug break slot code.
  Assembler::BlockConstPoolScope block_const_pool(masm);
130 131
  Label check_codesize;
  __ bind(&check_codesize);
132
  RecordRelocInfo(masm, location, call_argc);
133
  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
134
    __ nop(MacroAssembler::DEBUG_BREAK_NOP);
135
  }
136
  DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
137 138 139 140
            masm->InstructionsGeneratedSince(&check_codesize));
}


141
void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
142 143
  // In the places where a debug break slot is inserted no registers can contain
  // object pointers.
144
  Generate_DebugBreakCallHelper(masm, 0);
145 146 147
}


148
void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
149
  __ Ret();
150 151
}

152

153
void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
154 155 156 157 158 159 160
  ExternalReference restarter_frame_function_slot =
      ExternalReference::debug_restarter_frame_function_pointer_address(
          masm->isolate());
  __ mov(ip, Operand(restarter_frame_function_slot));
  __ mov(r1, Operand::Zero());
  __ str(r1, MemOperand(ip, 0));

161 162 163
  // Load the function pointer off of our current stack frame.
  __ ldr(r1, MemOperand(fp,
         StandardFrameConstants::kConstantPoolOffset - kPointerSize));
164

165
  // Pop return address, frame and constant pool pointer (if
166
  // FLAG_enable_embedded_constant_pool).
167
  __ LeaveFrame(StackFrame::INTERNAL);
168

169 170 171
  { ConstantPoolUnavailableScope constant_pool_unavailable(masm);
    // Load context from the function.
    __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
172

173 174 175 176
    // Get function code.
    __ ldr(ip, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
    __ ldr(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset));
    __ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
177

178 179 180
    // Re-run JSFunction, r1 is function, cp is context.
    __ Jump(ip);
  }
181 182
}

183

184
const bool LiveEdit::kFrameDropperSupported = true;
185

186 187
#undef __

188 189
}  // namespace internal
}  // namespace v8
190 191

#endif  // V8_TARGET_ARCH_ARM