OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
11 // with the distribution. | 11 // with the distribution. |
(...skipping 21 matching lines...) Expand all Loading... |
33 | 33 |
34 #include "codegen.h" | 34 #include "codegen.h" |
35 #include "debug.h" | 35 #include "debug.h" |
36 | 36 |
37 namespace v8 { | 37 namespace v8 { |
38 namespace internal { | 38 namespace internal { |
39 | 39 |
40 #ifdef ENABLE_DEBUGGER_SUPPORT | 40 #ifdef ENABLE_DEBUGGER_SUPPORT |
41 | 41 |
42 bool BreakLocationIterator::IsDebugBreakAtReturn() { | 42 bool BreakLocationIterator::IsDebugBreakAtReturn() { |
43 UNIMPLEMENTED_MIPS(); | 43 return Debug::IsDebugBreakAtReturn(rinfo()); |
44 return false; | |
45 } | 44 } |
46 | 45 |
47 | 46 |
48 void BreakLocationIterator::SetDebugBreakAtReturn() { | 47 void BreakLocationIterator::SetDebugBreakAtReturn() { |
49 UNIMPLEMENTED_MIPS(); | 48 // 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); |
50 } | 71 } |
51 | 72 |
52 | 73 |
53 // Restore the JS frame exit code. | 74 // Restore the JS frame exit code. |
54 void BreakLocationIterator::ClearDebugBreakAtReturn() { | 75 void BreakLocationIterator::ClearDebugBreakAtReturn() { |
55 UNIMPLEMENTED_MIPS(); | 76 rinfo()->PatchCode(original_rinfo()->pc(), |
| 77 Assembler::kJSReturnSequenceInstructions); |
56 } | 78 } |
57 | 79 |
58 | 80 |
59 // A debug break in the exit code is identified by the JS frame exit code | 81 // A debug break in the exit code is identified by the JS frame exit code |
60 // having been patched with li/call psuedo-instrunction (liu/ori/jalr) | 82 // having been patched with li/call psuedo-instrunction (liu/ori/jalr). |
61 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) { | 83 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) { |
62 UNIMPLEMENTED_MIPS(); | 84 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode())); |
63 return false; | 85 return rinfo->IsPatchedReturnSequence(); |
64 } | 86 } |
65 | 87 |
66 | 88 |
67 bool BreakLocationIterator::IsDebugBreakAtSlot() { | 89 bool BreakLocationIterator::IsDebugBreakAtSlot() { |
68 UNIMPLEMENTED_MIPS(); | 90 ASSERT(IsDebugBreakSlot()); |
69 return false; | 91 // Check whether the debug break slot instructions have been patched. |
| 92 return rinfo()->IsPatchedDebugBreakSlotSequence(); |
70 } | 93 } |
71 | 94 |
72 | 95 |
73 void BreakLocationIterator::SetDebugBreakAtSlot() { | 96 void BreakLocationIterator::SetDebugBreakAtSlot() { |
74 UNIMPLEMENTED_MIPS(); | 97 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>( |
| 108 Isolate::Current()->debug()->debug_break_return()->entry()))); |
| 109 patcher.masm()->Call(v8::internal::t9); |
75 } | 110 } |
76 | 111 |
77 | 112 |
78 void BreakLocationIterator::ClearDebugBreakAtSlot() { | 113 void BreakLocationIterator::ClearDebugBreakAtSlot() { |
79 UNIMPLEMENTED_MIPS(); | 114 ASSERT(IsDebugBreakSlot()); |
| 115 rinfo()->PatchCode(original_rinfo()->pc(), |
| 116 Assembler::kDebugBreakSlotInstructions); |
80 } | 117 } |
81 | 118 |
82 | 119 |
83 #define __ ACCESS_MASM(masm) | 120 #define __ ACCESS_MASM(masm) |
84 | 121 |
85 | 122 |
| 123 |
| 124 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, |
| 125 RegList object_regs, |
| 126 RegList non_object_regs) { |
| 127 __ EnterInternalFrame(); |
| 128 |
| 129 // Store the registers containing live values on the expression stack to |
| 130 // make sure that these are correctly updated during GC. Non object values |
| 131 // are stored as a smi causing it to be untouched by GC. |
| 132 ASSERT((object_regs & ~kJSCallerSaved) == 0); |
| 133 ASSERT((non_object_regs & ~kJSCallerSaved) == 0); |
| 134 ASSERT((object_regs & non_object_regs) == 0); |
| 135 if ((object_regs | non_object_regs) != 0) { |
| 136 for (int i = 0; i < kNumJSCallerSaved; i++) { |
| 137 int r = JSCallerSavedCode(i); |
| 138 Register reg = { r }; |
| 139 if ((non_object_regs & (1 << r)) != 0) { |
| 140 if (FLAG_debug_code) { |
| 141 __ And(at, reg, 0xc0000000); |
| 142 __ Assert(eq, "Unable to encode value as smi", at, Operand(zero_reg)); |
| 143 } |
| 144 __ sll(reg, reg, kSmiTagSize); |
| 145 } |
| 146 } |
| 147 __ MultiPush(object_regs | non_object_regs); |
| 148 } |
| 149 |
| 150 #ifdef DEBUG |
| 151 __ RecordComment("// Calling from debug break to runtime - come in - over"); |
| 152 #endif |
| 153 __ mov(a0, zero_reg); // No arguments. |
| 154 __ li(a1, Operand(ExternalReference::debug_break(masm->isolate()))); |
| 155 |
| 156 CEntryStub ceb(1); |
| 157 __ CallStub(&ceb); |
| 158 |
| 159 // Restore the register values from the expression stack. |
| 160 if ((object_regs | non_object_regs) != 0) { |
| 161 __ MultiPop(object_regs | non_object_regs); |
| 162 for (int i = 0; i < kNumJSCallerSaved; i++) { |
| 163 int r = JSCallerSavedCode(i); |
| 164 Register reg = { r }; |
| 165 if ((non_object_regs & (1 << r)) != 0) { |
| 166 __ srl(reg, reg, kSmiTagSize); |
| 167 } |
| 168 if (FLAG_debug_code && |
| 169 (((object_regs |non_object_regs) & (1 << r)) == 0)) { |
| 170 __ li(reg, kDebugZapValue); |
| 171 } |
| 172 } |
| 173 } |
| 174 |
| 175 __ LeaveInternalFrame(); |
| 176 |
| 177 // Now that the break point has been handled, resume normal execution by |
| 178 // jumping to the target address intended by the caller and that was |
| 179 // overwritten by the address of DebugBreakXXX. |
| 180 __ li(t9, Operand( |
| 181 ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate()))); |
| 182 __ lw(t9, MemOperand(t9)); |
| 183 __ Jump(t9); |
| 184 } |
| 185 |
| 186 |
86 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) { | 187 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) { |
87 UNIMPLEMENTED_MIPS(); | 188 // Calling convention for IC load (from ic-mips.cc). |
| 189 // ----------- S t a t e ------------- |
| 190 // -- a2 : name |
| 191 // -- ra : return address |
| 192 // -- a0 : receiver |
| 193 // -- [sp] : receiver |
| 194 // ----------------------------------- |
| 195 // Registers a0 and a2 contain objects that need to be pushed on the |
| 196 // expression stack of the fake JS frame. |
| 197 Generate_DebugBreakCallHelper(masm, a0.bit() | a2.bit(), 0); |
88 } | 198 } |
89 | 199 |
90 | 200 |
91 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) { | 201 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) { |
92 UNIMPLEMENTED_MIPS(); | 202 // Calling convention for IC store (from ic-mips.cc). |
| 203 // ----------- S t a t e ------------- |
| 204 // -- a0 : value |
| 205 // -- a1 : receiver |
| 206 // -- a2 : name |
| 207 // -- ra : return address |
| 208 // ----------------------------------- |
| 209 // Registers a0, a1, and a2 contain objects that need to be pushed on the |
| 210 // expression stack of the fake JS frame. |
| 211 Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0); |
93 } | 212 } |
94 | 213 |
95 | 214 |
96 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) { | 215 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) { |
97 UNIMPLEMENTED_MIPS(); | 216 // ---------- S t a t e -------------- |
| 217 // -- ra : return address |
| 218 // -- a0 : key |
| 219 // -- a1 : receiver |
| 220 Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit(), 0); |
98 } | 221 } |
99 | 222 |
100 | 223 |
101 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) { | 224 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) { |
102 UNIMPLEMENTED_MIPS(); | 225 // ---------- S t a t e -------------- |
| 226 // -- a0 : value |
| 227 // -- a1 : key |
| 228 // -- a2 : receiver |
| 229 // -- ra : return address |
| 230 Generate_DebugBreakCallHelper(masm, a0.bit() | a1.bit() | a2.bit(), 0); |
103 } | 231 } |
104 | 232 |
105 | 233 |
106 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) { | 234 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) { |
107 UNIMPLEMENTED_MIPS(); | 235 // Calling convention for IC call (from ic-mips.cc). |
| 236 // ----------- S t a t e ------------- |
| 237 // -- a2: name |
| 238 // ----------------------------------- |
| 239 Generate_DebugBreakCallHelper(masm, a2.bit(), 0); |
108 } | 240 } |
109 | 241 |
110 | 242 |
111 void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) { | 243 void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) { |
112 UNIMPLEMENTED_MIPS(); | 244 // Calling convention for construct call (from builtins-mips.cc). |
| 245 // -- a0 : number of arguments (not smi) |
| 246 // -- a1 : constructor function |
| 247 Generate_DebugBreakCallHelper(masm, a1.bit(), a0.bit()); |
113 } | 248 } |
114 | 249 |
115 | 250 |
116 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) { | 251 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) { |
117 UNIMPLEMENTED_MIPS(); | 252 // In places other than IC call sites it is expected that v0 is TOS which |
| 253 // is an object - this is not generally the case so this should be used with |
| 254 // care. |
| 255 Generate_DebugBreakCallHelper(masm, v0.bit(), 0); |
118 } | 256 } |
119 | 257 |
120 | 258 |
121 void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) { | 259 void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) { |
122 UNIMPLEMENTED_MIPS(); | 260 // ----------- S t a t e ------------- |
| 261 // No registers used on entry. |
| 262 // ----------------------------------- |
| 263 Generate_DebugBreakCallHelper(masm, 0, 0); |
123 } | 264 } |
124 | 265 |
125 | 266 |
126 void Debug::GenerateSlot(MacroAssembler* masm) { | 267 void Debug::GenerateSlot(MacroAssembler* masm) { |
127 UNIMPLEMENTED_MIPS(); | 268 // Generate enough nop's to make space for a call instruction. Avoid emitting |
| 269 // the trampoline pool in the debug break slot code. |
| 270 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm); |
| 271 Label check_codesize; |
| 272 __ bind(&check_codesize); |
| 273 __ RecordDebugBreakSlot(); |
| 274 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) { |
| 275 __ nop(MacroAssembler::DEBUG_BREAK_NOP); |
| 276 } |
| 277 ASSERT_EQ(Assembler::kDebugBreakSlotInstructions, |
| 278 masm->InstructionsGeneratedSince(&check_codesize)); |
128 } | 279 } |
129 | 280 |
130 | 281 |
131 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) { | 282 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) { |
132 UNIMPLEMENTED_MIPS(); | 283 // In the places where a debug break slot is inserted no registers can contain |
| 284 // object pointers. |
| 285 Generate_DebugBreakCallHelper(masm, 0, 0); |
133 } | 286 } |
134 | 287 |
135 | 288 |
136 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { | 289 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { |
137 UNIMPLEMENTED_MIPS(); | 290 masm->Abort("LiveEdit frame dropping is not supported on mips"); |
138 } | 291 } |
139 | 292 |
140 | 293 |
141 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { | 294 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { |
142 UNIMPLEMENTED_MIPS(); | 295 masm->Abort("LiveEdit frame dropping is not supported on mips"); |
143 } | 296 } |
144 | 297 |
145 | 298 |
146 const bool Debug::kFrameDropperSupported = false; | 299 const bool Debug::kFrameDropperSupported = false; |
147 | 300 |
148 #undef __ | 301 #undef __ |
149 | 302 |
150 | 303 |
151 #endif // ENABLE_DEBUGGER_SUPPORT | 304 #endif // ENABLE_DEBUGGER_SUPPORT |
152 | 305 |
153 } } // namespace v8::internal | 306 } } // namespace v8::internal |
154 | 307 |
155 #endif // V8_TARGET_ARCH_MIPS | 308 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |