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.
9 #if V8_TARGET_ARCH_MIPS
11 #include "src/codegen.h"
12 #include "src/debug.h"
17 void BreakLocation::SetDebugBreakAtReturn() {
18 // Mips return sequence:
25 // nop (in branch delay slot)
27 // Make sure this constant matches the number if instrucntions we emit.
28 DCHECK(Assembler::kJSReturnSequenceInstructions == 7);
29 CodePatcher patcher(pc(), Assembler::kJSReturnSequenceInstructions);
30 // li and Call pseudo-instructions emit two instructions each.
31 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
32 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())));
33 patcher.masm()->Call(v8::internal::t9);
34 patcher.masm()->nop();
35 patcher.masm()->nop();
36 patcher.masm()->nop();
38 // TODO(mips): Open issue about using breakpoint instruction instead of nops.
39 // patcher.masm()->bkpt(0);
43 void BreakLocation::SetDebugBreakAtSlot() {
44 DCHECK(IsDebugBreakSlot());
45 // Patch the code changing the debug break slot code from:
46 // nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
47 // nop(DEBUG_BREAK_NOP)
48 // nop(DEBUG_BREAK_NOP)
49 // nop(DEBUG_BREAK_NOP)
50 // to a call to the debug break slot code.
51 // li t9, address (lui t9 / ori t9 instruction pair)
52 // call t9 (jalr t9 / nop instruction pair)
53 CodePatcher patcher(pc(), Assembler::kDebugBreakSlotInstructions);
54 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
55 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())));
56 patcher.masm()->Call(v8::internal::t9);
60 #define __ ACCESS_MASM(masm)
64 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
66 RegList non_object_regs) {
68 FrameScope scope(masm, StackFrame::INTERNAL);
70 // Load padding words on stack.
71 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue)));
73 Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize));
74 for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) {
75 __ sw(at, MemOperand(sp, kPointerSize * i));
77 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
80 // Store the registers containing live values on the expression stack to
81 // make sure that these are correctly updated during GC. Non object values
82 // are stored as a smi causing it to be untouched by GC.
83 DCHECK((object_regs & ~kJSCallerSaved) == 0);
84 DCHECK((non_object_regs & ~kJSCallerSaved) == 0);
85 DCHECK((object_regs & non_object_regs) == 0);
86 if ((object_regs | non_object_regs) != 0) {
87 for (int i = 0; i < kNumJSCallerSaved; i++) {
88 int r = JSCallerSavedCode(i);
90 if ((non_object_regs & (1 << r)) != 0) {
91 if (FLAG_debug_code) {
92 __ And(at, reg, 0xc0000000);
93 __ Assert(eq, kUnableToEncodeValueAsSmi, at, Operand(zero_reg));
95 __ sll(reg, reg, kSmiTagSize);
98 __ MultiPush(object_regs | non_object_regs);
102 __ RecordComment("// Calling from debug break to runtime - come in - over");
104 __ PrepareCEntryArgs(0); // No arguments.
105 __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate()));
107 CEntryStub ceb(masm->isolate(), 1);
110 // Restore the register values from the expression stack.
111 if ((object_regs | non_object_regs) != 0) {
112 __ MultiPop(object_regs | non_object_regs);
113 for (int i = 0; i < kNumJSCallerSaved; i++) {
114 int r = JSCallerSavedCode(i);
115 Register reg = { r };
116 if ((non_object_regs & (1 << r)) != 0) {
117 __ srl(reg, reg, kSmiTagSize);
119 if (FLAG_debug_code &&
120 (((object_regs |non_object_regs) & (1 << r)) == 0)) {
121 __ li(reg, kDebugZapValue);
126 // Don't bother removing padding bytes pushed on the stack
127 // as the frame is going to be restored right away.
129 // Leave the internal frame.
132 // Now that the break point has been handled, resume normal execution by
133 // jumping to the target address intended by the caller and that was
134 // overwritten by the address of DebugBreakXXX.
135 ExternalReference after_break_target =
136 ExternalReference::debug_after_break_target_address(masm->isolate());
137 __ li(t9, Operand(after_break_target));
138 __ lw(t9, MemOperand(t9));
143 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
144 // Register state for CallICStub
145 // ----------- S t a t e -------------
147 // -- a3 : slot in feedback array (smi)
148 // -----------------------------------
149 Generate_DebugBreakCallHelper(masm, a1.bit() | a3.bit(), 0);
153 void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
154 Register receiver = LoadDescriptor::ReceiverRegister();
155 Register name = LoadDescriptor::NameRegister();
156 RegList regs = receiver.bit() | name.bit();
157 if (FLAG_vector_ics) {
158 regs |= VectorLoadICTrampolineDescriptor::SlotRegister().bit();
160 Generate_DebugBreakCallHelper(masm, regs, 0);
164 void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
165 // Calling convention for IC store (from ic-mips.cc).
166 Register receiver = StoreDescriptor::ReceiverRegister();
167 Register name = StoreDescriptor::NameRegister();
168 Register value = StoreDescriptor::ValueRegister();
169 Generate_DebugBreakCallHelper(
170 masm, receiver.bit() | name.bit() | value.bit(), 0);
174 void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
175 // Calling convention for keyed IC load (from ic-mips.cc).
176 GenerateLoadICDebugBreak(masm);
180 void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
181 // Calling convention for IC keyed store call (from ic-mips.cc).
182 Register receiver = StoreDescriptor::ReceiverRegister();
183 Register name = StoreDescriptor::NameRegister();
184 Register value = StoreDescriptor::ValueRegister();
185 Generate_DebugBreakCallHelper(
186 masm, receiver.bit() | name.bit() | value.bit(), 0);
190 void DebugCodegen::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
191 // Register state for CompareNil IC
192 // ----------- S t a t e -------------
194 // -----------------------------------
195 Generate_DebugBreakCallHelper(masm, a0.bit(), 0);
199 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
200 // In places other than IC call sites it is expected that v0 is TOS which
201 // is an object - this is not generally the case so this should be used with
203 Generate_DebugBreakCallHelper(masm, v0.bit(), 0);
207 void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
208 // Register state for CallFunctionStub (from code-stubs-mips.cc).
209 // ----------- S t a t e -------------
211 // -----------------------------------
212 Generate_DebugBreakCallHelper(masm, a1.bit(), 0);
216 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
217 // Calling convention for CallConstructStub (from code-stubs-mips.cc).
218 // ----------- S t a t e -------------
219 // -- a0 : number of arguments (not smi)
220 // -- a1 : constructor function
221 // -----------------------------------
222 Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit());
226 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
227 MacroAssembler* masm) {
228 // Calling convention for CallConstructStub (from code-stubs-mips.cc).
229 // ----------- S t a t e -------------
230 // -- a0 : number of arguments (not smi)
231 // -- a1 : constructor function
232 // -- a2 : feedback array
233 // -- a3 : feedback slot (smi)
234 // -----------------------------------
235 Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit());
239 void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
240 // Generate enough nop's to make space for a call instruction. Avoid emitting
241 // the trampoline pool in the debug break slot code.
242 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm);
243 Label check_codesize;
244 __ bind(&check_codesize);
245 __ RecordDebugBreakSlot();
246 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
247 __ nop(MacroAssembler::DEBUG_BREAK_NOP);
249 DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
250 masm->InstructionsGeneratedSince(&check_codesize));
254 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
255 // In the places where a debug break slot is inserted no registers can contain
257 Generate_DebugBreakCallHelper(masm, 0, 0);
261 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
266 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
267 ExternalReference restarter_frame_function_slot =
268 ExternalReference::debug_restarter_frame_function_pointer_address(
270 __ li(at, Operand(restarter_frame_function_slot));
271 __ sw(zero_reg, MemOperand(at, 0));
273 // We do not know our frame height, but set sp based on fp.
274 __ Subu(sp, fp, Operand(kPointerSize));
276 __ Pop(ra, fp, a1); // Return address, Frame, Function.
278 // Load context from the function.
279 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
281 // Get function code.
282 __ lw(at, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
283 __ lw(at, FieldMemOperand(at, SharedFunctionInfo::kCodeOffset));
284 __ Addu(t9, at, Operand(Code::kHeaderSize - kHeapObjectTag));
286 // Re-run JSFunction, a1 is function, cp is context.
291 const bool LiveEdit::kFrameDropperSupported = true;
295 } } // namespace v8::internal
297 #endif // V8_TARGET_ARCH_MIPS