blob: 3be1e4d8b271d29a500b866f2617a7a004de919c [file] [log] [blame]
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29
30#include "v8.h"
31
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000032#if defined(V8_TARGET_ARCH_MIPS)
33
karlklose@chromium.org83a47282011-05-11 11:54:09 +000034#include "codegen.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000035#include "debug.h"
36
37namespace v8 {
38namespace internal {
39
40#ifdef ENABLE_DEBUGGER_SUPPORT
lrn@chromium.org7516f052011-03-30 08:52:27 +000041
ager@chromium.org5c838252010-02-19 08:53:10 +000042bool BreakLocationIterator::IsDebugBreakAtReturn() {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000043 return Debug::IsDebugBreakAtReturn(rinfo());
ager@chromium.org5c838252010-02-19 08:53:10 +000044}
45
46
47void BreakLocationIterator::SetDebugBreakAtReturn() {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000048 // Mips return sequence:
49 // mov sp, fp
50 // lw fp, sp(0)
51 // lw ra, sp(4)
52 // addiu sp, sp, 8
53 // addiu sp, sp, N
54 // jr ra
55 // nop (in branch delay slot)
56
57 // Make sure this constant matches the number if instrucntions we emit.
58 ASSERT(Assembler::kJSReturnSequenceInstructions == 7);
59 CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
60 // li and Call pseudo-instructions emit two instructions each.
61 patcher.masm()->li(v8::internal::t9,
62 Operand(reinterpret_cast<int32_t>(
63 Isolate::Current()->debug()->debug_break_return()->entry())));
64 patcher.masm()->Call(v8::internal::t9);
65 patcher.masm()->nop();
66 patcher.masm()->nop();
67 patcher.masm()->nop();
68
69 // TODO(mips): Open issue about using breakpoint instruction instead of nops.
70 // patcher.masm()->bkpt(0);
ager@chromium.org5c838252010-02-19 08:53:10 +000071}
72
73
74// Restore the JS frame exit code.
75void BreakLocationIterator::ClearDebugBreakAtReturn() {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000076 rinfo()->PatchCode(original_rinfo()->pc(),
77 Assembler::kJSReturnSequenceInstructions);
ager@chromium.org5c838252010-02-19 08:53:10 +000078}
79
80
lrn@chromium.org7516f052011-03-30 08:52:27 +000081// A debug break in the exit code is identified by the JS frame exit code
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000082// having been patched with li/call psuedo-instrunction (liu/ori/jalr).
ager@chromium.org5c838252010-02-19 08:53:10 +000083bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000084 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
85 return rinfo->IsPatchedReturnSequence();
lrn@chromium.org7516f052011-03-30 08:52:27 +000086}
87
88
89bool BreakLocationIterator::IsDebugBreakAtSlot() {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000090 ASSERT(IsDebugBreakSlot());
91 // Check whether the debug break slot instructions have been patched.
92 return rinfo()->IsPatchedDebugBreakSlotSequence();
lrn@chromium.org7516f052011-03-30 08:52:27 +000093}
94
95
96void BreakLocationIterator::SetDebugBreakAtSlot() {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000097 ASSERT(IsDebugBreakSlot());
98 // Patch the code changing the debug break slot code from:
99 // nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
100 // nop(DEBUG_BREAK_NOP)
101 // nop(DEBUG_BREAK_NOP)
102 // nop(DEBUG_BREAK_NOP)
103 // to a call to the debug break slot code.
104 // li t9, address (lui t9 / ori t9 instruction pair)
105 // call t9 (jalr t9 / nop instruction pair)
106 CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
107 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
danno@chromium.org40cb8782011-05-25 07:58:50 +0000108 Isolate::Current()->debug()->debug_break_slot()->entry())));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000109 patcher.masm()->Call(v8::internal::t9);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000110}
111
112
113void BreakLocationIterator::ClearDebugBreakAtSlot() {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000114 ASSERT(IsDebugBreakSlot());
115 rinfo()->PatchCode(original_rinfo()->pc(),
116 Assembler::kDebugBreakSlotInstructions);
ager@chromium.org5c838252010-02-19 08:53:10 +0000117}
118
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000119const bool Debug::FramePaddingLayout::kIsSupported = false;
120
ager@chromium.org5c838252010-02-19 08:53:10 +0000121
122#define __ ACCESS_MASM(masm)
123
124
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000125
126static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
127 RegList object_regs,
128 RegList non_object_regs) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000129 {
130 FrameScope scope(masm, StackFrame::INTERNAL);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000131
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000132 // Store the registers containing live values on the expression stack to
133 // make sure that these are correctly updated during GC. Non object values
134 // are stored as a smi causing it to be untouched by GC.
135 ASSERT((object_regs & ~kJSCallerSaved) == 0);
136 ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
137 ASSERT((object_regs & non_object_regs) == 0);
138 if ((object_regs | non_object_regs) != 0) {
139 for (int i = 0; i < kNumJSCallerSaved; i++) {
140 int r = JSCallerSavedCode(i);
141 Register reg = { r };
142 if ((non_object_regs & (1 << r)) != 0) {
143 if (FLAG_debug_code) {
144 __ And(at, reg, 0xc0000000);
145 __ Assert(
146 eq, "Unable to encode value as smi", at, Operand(zero_reg));
147 }
148 __ sll(reg, reg, kSmiTagSize);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000149 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000150 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000151 __ MultiPush(object_regs | non_object_regs);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000152 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000153
154#ifdef DEBUG
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000155 __ RecordComment("// Calling from debug break to runtime - come in - over");
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000156#endif
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000157 __ PrepareCEntryArgs(0); // No arguments.
158 __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate()));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000159
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000160 CEntryStub ceb(1);
161 __ CallStub(&ceb);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000162
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000163 // Restore the register values from the expression stack.
164 if ((object_regs | non_object_regs) != 0) {
165 __ MultiPop(object_regs | non_object_regs);
166 for (int i = 0; i < kNumJSCallerSaved; i++) {
167 int r = JSCallerSavedCode(i);
168 Register reg = { r };
169 if ((non_object_regs & (1 << r)) != 0) {
170 __ srl(reg, reg, kSmiTagSize);
171 }
172 if (FLAG_debug_code &&
173 (((object_regs |non_object_regs) & (1 << r)) == 0)) {
174 __ li(reg, kDebugZapValue);
175 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000176 }
177 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000178
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000179 // Leave the internal frame.
180 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000181
182 // Now that the break point has been handled, resume normal execution by
183 // jumping to the target address intended by the caller and that was
184 // overwritten by the address of DebugBreakXXX.
185 __ li(t9, Operand(
186 ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate())));
187 __ lw(t9, MemOperand(t9));
188 __ Jump(t9);
189}
190
191
ager@chromium.org5c838252010-02-19 08:53:10 +0000192void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000193 // Calling convention for IC load (from ic-mips.cc).
194 // ----------- S t a t e -------------
195 // -- a2 : name
196 // -- ra : return address
197 // -- a0 : receiver
198 // -- [sp] : receiver
199 // -----------------------------------
200 // Registers a0 and a2 contain objects that need to be pushed on the
201 // expression stack of the fake JS frame.
202 Generate_DebugBreakCallHelper(masm, a0.bit() | a2.bit(), 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000203}
204
205
206void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000207 // Calling convention for IC store (from ic-mips.cc).
208 // ----------- S t a t e -------------
209 // -- a0 : value
210 // -- a1 : receiver
211 // -- a2 : name
212 // -- ra : return address
213 // -----------------------------------
214 // Registers a0, a1, and a2 contain objects that need to be pushed on the
215 // expression stack of the fake JS frame.
216 Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000217}
218
219
220void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000221 // ---------- S t a t e --------------
222 // -- ra : return address
223 // -- a0 : key
224 // -- a1 : receiver
225 Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit(), 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000226}
227
228
229void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000230 // ---------- S t a t e --------------
231 // -- a0 : value
232 // -- a1 : key
233 // -- a2 : receiver
234 // -- ra : return address
235 Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000236}
237
238
239void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000240 // Calling convention for IC call (from ic-mips.cc).
241 // ----------- S t a t e -------------
242 // -- a2: name
243 // -----------------------------------
244 Generate_DebugBreakCallHelper(masm, a2.bit(), 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000245}
246
247
ager@chromium.org5c838252010-02-19 08:53:10 +0000248void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000249 // In places other than IC call sites it is expected that v0 is TOS which
250 // is an object - this is not generally the case so this should be used with
251 // care.
252 Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000253}
254
255
danno@chromium.orgc612e022011-11-10 11:38:15 +0000256void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000257 // Register state for CallFunctionStub (from code-stubs-mips.cc).
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000258 // ----------- S t a t e -------------
danno@chromium.orgc612e022011-11-10 11:38:15 +0000259 // -- a1 : function
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000260 // -----------------------------------
danno@chromium.orgc612e022011-11-10 11:38:15 +0000261 Generate_DebugBreakCallHelper(masm, a1.bit(), 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000262}
263
264
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000265void Debug::GenerateCallFunctionStubRecordDebugBreak(MacroAssembler* masm) {
266 // Register state for CallFunctionStub (from code-stubs-mips.cc).
267 // ----------- S t a t e -------------
268 // -- a1 : function
269 // -- a2 : cache cell for call target
270 // -----------------------------------
271 Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit(), 0);
272}
273
274
275void Debug::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
276 // Calling convention for CallConstructStub (from code-stubs-mips.cc).
277 // ----------- S t a t e -------------
278 // -- a0 : number of arguments (not smi)
279 // -- a1 : constructor function
280 // -----------------------------------
281 Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit());
282}
283
284
285void Debug::GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm) {
286 // Calling convention for CallConstructStub (from code-stubs-mips.cc).
287 // ----------- S t a t e -------------
288 // -- a0 : number of arguments (not smi)
289 // -- a1 : constructor function
290 // -- a2 : cache cell for call target
291 // -----------------------------------
292 Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit(), a0.bit());
293}
294
295
lrn@chromium.org7516f052011-03-30 08:52:27 +0000296void Debug::GenerateSlot(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000297 // Generate enough nop's to make space for a call instruction. Avoid emitting
298 // the trampoline pool in the debug break slot code.
299 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
300 Label check_codesize;
301 __ bind(&check_codesize);
302 __ RecordDebugBreakSlot();
303 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
304 __ nop(MacroAssembler::DEBUG_BREAK_NOP);
305 }
306 ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
307 masm->InstructionsGeneratedSince(&check_codesize));
ager@chromium.org357bf652010-04-12 11:30:10 +0000308}
309
lrn@chromium.org7516f052011-03-30 08:52:27 +0000310
311void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000312 // In the places where a debug break slot is inserted no registers can contain
313 // object pointers.
314 Generate_DebugBreakCallHelper(masm, 0, 0);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000315}
316
317
318void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000319 masm->Abort("LiveEdit frame dropping is not supported on mips");
lrn@chromium.org7516f052011-03-30 08:52:27 +0000320}
321
322
ager@chromium.org357bf652010-04-12 11:30:10 +0000323void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000324 masm->Abort("LiveEdit frame dropping is not supported on mips");
ager@chromium.org357bf652010-04-12 11:30:10 +0000325}
326
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000327
328const bool Debug::kFrameDropperSupported = false;
329
ager@chromium.org5c838252010-02-19 08:53:10 +0000330#undef __
331
ager@chromium.org357bf652010-04-12 11:30:10 +0000332
ager@chromium.org5c838252010-02-19 08:53:10 +0000333#endif // ENABLE_DEBUGGER_SUPPORT
334
335} } // namespace v8::internal
336
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000337#endif // V8_TARGET_ARCH_MIPS