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.
15 bool BreakLocationIterator::IsDebugBreakAtReturn() {
16 return Debug::IsDebugBreakAtReturn(rinfo());
20 void BreakLocationIterator::SetDebugBreakAtReturn() {
21 // Patch the code changing the return from JS function sequence from
23 // ldmia sp!, {fp, lr}
26 // to a call to the debug break return code.
29 // <debug break return code entry point address>
31 CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
32 patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
33 patcher.masm()->blx(v8::internal::ip);
35 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry());
36 patcher.masm()->bkpt(0);
40 // Restore the JS frame exit code.
41 void BreakLocationIterator::ClearDebugBreakAtReturn() {
42 rinfo()->PatchCode(original_rinfo()->pc(),
43 Assembler::kJSReturnSequenceInstructions);
47 // A debug break in the frame exit code is identified by the JS frame exit code
48 // having been patched with a call instruction.
49 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
50 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
51 return rinfo->IsPatchedReturnSequence();
55 bool BreakLocationIterator::IsDebugBreakAtSlot() {
56 ASSERT(IsDebugBreakSlot());
57 // Check whether the debug break slot instructions have been patched.
58 return rinfo()->IsPatchedDebugBreakSlotSequence();
62 void BreakLocationIterator::SetDebugBreakAtSlot() {
63 ASSERT(IsDebugBreakSlot());
64 // Patch the code changing the debug break slot code from
68 // to a call to the debug break slot code.
71 // <debug break slot code entry point address>
72 CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
73 patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
74 patcher.masm()->blx(v8::internal::ip);
76 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry());
80 void BreakLocationIterator::ClearDebugBreakAtSlot() {
81 ASSERT(IsDebugBreakSlot());
82 rinfo()->PatchCode(original_rinfo()->pc(),
83 Assembler::kDebugBreakSlotInstructions);
86 const bool Debug::FramePaddingLayout::kIsSupported = false;
89 #define __ ACCESS_MASM(masm)
92 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
94 RegList non_object_regs) {
96 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
98 // Store the registers containing live values on the expression stack to
99 // make sure that these are correctly updated during GC. Non object values
100 // are stored as a smi causing it to be untouched by GC.
101 ASSERT((object_regs & ~kJSCallerSaved) == 0);
102 ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
103 ASSERT((object_regs & non_object_regs) == 0);
104 if ((object_regs | non_object_regs) != 0) {
105 for (int i = 0; i < kNumJSCallerSaved; i++) {
106 int r = JSCallerSavedCode(i);
107 Register reg = { r };
108 if ((non_object_regs & (1 << r)) != 0) {
109 if (FLAG_debug_code) {
110 __ tst(reg, Operand(0xc0000000));
111 __ Assert(eq, kUnableToEncodeValueAsSmi);
116 __ stm(db_w, sp, object_regs | non_object_regs);
120 __ RecordComment("// Calling from debug break to runtime - come in - over");
122 __ mov(r0, Operand::Zero()); // no arguments
123 __ mov(r1, Operand(ExternalReference::debug_break(masm->isolate())));
125 CEntryStub ceb(masm->isolate(), 1);
128 // Restore the register values from the expression stack.
129 if ((object_regs | non_object_regs) != 0) {
130 __ ldm(ia_w, sp, object_regs | non_object_regs);
131 for (int i = 0; i < kNumJSCallerSaved; i++) {
132 int r = JSCallerSavedCode(i);
133 Register reg = { r };
134 if ((non_object_regs & (1 << r)) != 0) {
137 if (FLAG_debug_code &&
138 (((object_regs |non_object_regs) & (1 << r)) == 0)) {
139 __ mov(reg, Operand(kDebugZapValue));
144 // Leave the internal frame.
147 // Now that the break point has been handled, resume normal execution by
148 // jumping to the target address intended by the caller and that was
149 // overwritten by the address of DebugBreakXXX.
150 ExternalReference after_break_target =
151 ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate());
152 __ mov(ip, Operand(after_break_target));
153 __ ldr(ip, MemOperand(ip));
158 void Debug::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
159 // Register state for CallICStub
160 // ----------- S t a t e -------------
162 // -- r3 : slot in feedback array (smi)
163 // -----------------------------------
164 Generate_DebugBreakCallHelper(masm, r1.bit() | r3.bit(), 0);
168 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
169 // Calling convention for IC load (from ic-arm.cc).
170 // ----------- S t a t e -------------
172 // -- lr : return address
174 // -- [sp] : receiver
175 // -----------------------------------
176 // Registers r0 and r2 contain objects that need to be pushed on the
177 // expression stack of the fake JS frame.
178 Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit(), 0);
182 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
183 // Calling convention for IC store (from ic-arm.cc).
184 // ----------- S t a t e -------------
188 // -- lr : return address
189 // -----------------------------------
190 // Registers r0, r1, and r2 contain objects that need to be pushed on the
191 // expression stack of the fake JS frame.
192 Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
196 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
197 // ---------- S t a t e --------------
198 // -- lr : return address
201 Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit(), 0);
205 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
206 // ---------- S t a t e --------------
210 // -- lr : return address
211 Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
215 void Debug::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
216 // Register state for CompareNil IC
217 // ----------- S t a t e -------------
219 // -----------------------------------
220 Generate_DebugBreakCallHelper(masm, r0.bit(), 0);
224 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
225 // In places other than IC call sites it is expected that r0 is TOS which
226 // is an object - this is not generally the case so this should be used with
228 Generate_DebugBreakCallHelper(masm, r0.bit(), 0);
232 void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
233 // Register state for CallFunctionStub (from code-stubs-arm.cc).
234 // ----------- S t a t e -------------
236 // -----------------------------------
237 Generate_DebugBreakCallHelper(masm, r1.bit(), 0);
241 void Debug::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
242 // Calling convention for CallConstructStub (from code-stubs-arm.cc)
243 // ----------- S t a t e -------------
244 // -- r0 : number of arguments (not smi)
245 // -- r1 : constructor function
246 // -----------------------------------
247 Generate_DebugBreakCallHelper(masm, r1.bit(), r0.bit());
251 void Debug::GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm) {
252 // Calling convention for CallConstructStub (from code-stubs-arm.cc)
253 // ----------- S t a t e -------------
254 // -- r0 : number of arguments (not smi)
255 // -- r1 : constructor function
256 // -- r2 : feedback array
257 // -- r3 : feedback slot (smi)
258 // -----------------------------------
259 Generate_DebugBreakCallHelper(masm, r1.bit() | r2.bit() | r3.bit(), r0.bit());
263 void Debug::GenerateSlot(MacroAssembler* masm) {
264 // Generate enough nop's to make space for a call instruction. Avoid emitting
265 // the constant pool in the debug break slot code.
266 Assembler::BlockConstPoolScope block_const_pool(masm);
267 Label check_codesize;
268 __ bind(&check_codesize);
269 __ RecordDebugBreakSlot();
270 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
271 __ nop(MacroAssembler::DEBUG_BREAK_NOP);
273 ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
274 masm->InstructionsGeneratedSince(&check_codesize));
278 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
279 // In the places where a debug break slot is inserted no registers can contain
281 Generate_DebugBreakCallHelper(masm, 0, 0);
285 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
286 masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm);
290 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
291 masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm);
294 const bool Debug::kFrameDropperSupported = false;
298 } } // namespace v8::internal
300 #endif // V8_TARGET_ARCH_ARM