OLD | NEW |
| (Empty) |
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 #include "src/v8.h" | |
6 | |
7 #if V8_TARGET_ARCH_ARM | |
8 | |
9 #include "src/codegen.h" | |
10 #include "src/debug.h" | |
11 | |
12 namespace v8 { | |
13 namespace internal { | |
14 | |
15 #define __ ACCESS_MASM(masm) | |
16 | |
17 | |
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 | |
29 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode, | |
30 int call_argc) { | |
31 // Generate enough nop's to make space for a call instruction. Avoid emitting | |
32 // the constant pool in the debug break slot code. | |
33 Assembler::BlockConstPoolScope block_const_pool(masm); | |
34 masm->RecordDebugBreakSlot(mode, call_argc); | |
35 EmitDebugBreakSlot(masm); | |
36 } | |
37 | |
38 | |
39 void DebugCodegen::ClearDebugBreakSlot(Address pc) { | |
40 CodePatcher patcher(pc, Assembler::kDebugBreakSlotInstructions); | |
41 EmitDebugBreakSlot(patcher.masm()); | |
42 } | |
43 | |
44 | |
45 void DebugCodegen::PatchDebugBreakSlot(Address pc, Handle<Code> code) { | |
46 DCHECK_EQ(Code::BUILTIN, code->kind()); | |
47 CodePatcher patcher(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 | |
67 | |
68 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, | |
69 DebugBreakCallHelperMode mode) { | |
70 __ RecordComment("Debug break"); | |
71 { | |
72 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | |
73 | |
74 // Load padding words on stack. | |
75 __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue))); | |
76 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { | |
77 __ push(ip); | |
78 } | |
79 __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); | |
80 __ push(ip); | |
81 | |
82 if (mode == SAVE_RESULT_REGISTER) __ push(r0); | |
83 | |
84 __ mov(r0, Operand::Zero()); // no arguments | |
85 __ mov(r1, | |
86 Operand(ExternalReference( | |
87 Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); | |
88 | |
89 CEntryStub ceb(masm->isolate(), 1); | |
90 __ CallStub(&ceb); | |
91 | |
92 if (FLAG_debug_code) { | |
93 for (int i = 0; i < kNumJSCallerSaved; i++) { | |
94 Register reg = {JSCallerSavedCode(i)}; | |
95 __ mov(reg, Operand(kDebugZapValue)); | |
96 } | |
97 } | |
98 | |
99 if (mode == SAVE_RESULT_REGISTER) __ pop(r0); | |
100 | |
101 // Don't bother removing padding bytes pushed on the stack | |
102 // as the frame is going to be restored right away. | |
103 | |
104 // Leave the internal frame. | |
105 } | |
106 | |
107 // Now that the break point has been handled, resume normal execution by | |
108 // jumping to the target address intended by the caller and that was | |
109 // overwritten by the address of DebugBreakXXX. | |
110 ExternalReference after_break_target = | |
111 ExternalReference::debug_after_break_target_address(masm->isolate()); | |
112 __ mov(ip, Operand(after_break_target)); | |
113 __ ldr(ip, MemOperand(ip)); | |
114 __ Jump(ip); | |
115 } | |
116 | |
117 | |
118 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { | |
119 __ Ret(); | |
120 } | |
121 | |
122 | |
123 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { | |
124 ExternalReference restarter_frame_function_slot = | |
125 ExternalReference::debug_restarter_frame_function_pointer_address( | |
126 masm->isolate()); | |
127 __ mov(ip, Operand(restarter_frame_function_slot)); | |
128 __ mov(r1, Operand::Zero()); | |
129 __ str(r1, MemOperand(ip, 0)); | |
130 | |
131 // Load the function pointer off of our current stack frame. | |
132 __ ldr(r1, MemOperand(fp, | |
133 StandardFrameConstants::kConstantPoolOffset - kPointerSize)); | |
134 | |
135 // Pop return address, frame and constant pool pointer (if | |
136 // FLAG_enable_embedded_constant_pool). | |
137 __ LeaveFrame(StackFrame::INTERNAL); | |
138 | |
139 { ConstantPoolUnavailableScope constant_pool_unavailable(masm); | |
140 // Load context from the function. | |
141 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | |
142 | |
143 // Get function code. | |
144 __ ldr(ip, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | |
145 __ ldr(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset)); | |
146 __ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); | |
147 | |
148 // Re-run JSFunction, r1 is function, cp is context. | |
149 __ Jump(ip); | |
150 } | |
151 } | |
152 | |
153 | |
154 const bool LiveEdit::kFrameDropperSupported = true; | |
155 | |
156 #undef __ | |
157 | |
158 } // namespace internal | |
159 } // namespace v8 | |
160 | |
161 #endif // V8_TARGET_ARCH_ARM | |
OLD | NEW |