| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 #include "src/v8.h" | 7 #include "src/v8.h" |
| 8 | 8 |
| 9 #if V8_TARGET_ARCH_MIPS | 9 #if V8_TARGET_ARCH_MIPS64 |
| 10 | 10 |
| 11 #include "src/codegen.h" | 11 #include "src/codegen.h" |
| 12 #include "src/debug.h" | 12 #include "src/debug.h" |
| 13 | 13 |
| 14 namespace v8 { | 14 namespace v8 { |
| 15 namespace internal { | 15 namespace internal { |
| 16 | 16 |
| 17 bool BreakLocationIterator::IsDebugBreakAtReturn() { | 17 bool BreakLocationIterator::IsDebugBreakAtReturn() { |
| 18 return Debug::IsDebugBreakAtReturn(rinfo()); | 18 return Debug::IsDebugBreakAtReturn(rinfo()); |
| 19 } | 19 } |
| 20 | 20 |
| 21 | 21 |
| 22 void BreakLocationIterator::SetDebugBreakAtReturn() { | 22 void BreakLocationIterator::SetDebugBreakAtReturn() { |
| 23 // Mips return sequence: | 23 // Mips return sequence: |
| 24 // mov sp, fp | 24 // mov sp, fp |
| 25 // lw fp, sp(0) | 25 // lw fp, sp(0) |
| 26 // lw ra, sp(4) | 26 // lw ra, sp(4) |
| 27 // addiu sp, sp, 8 | 27 // addiu sp, sp, 8 |
| 28 // addiu sp, sp, N | 28 // addiu sp, sp, N |
| 29 // jr ra | 29 // jr ra |
| 30 // nop (in branch delay slot) | 30 // nop (in branch delay slot) |
| 31 | 31 |
| 32 // Make sure this constant matches the number if instrucntions we emit. | 32 // Make sure this constant matches the number if instructions we emit. |
| 33 ASSERT(Assembler::kJSReturnSequenceInstructions == 7); | 33 ASSERT(Assembler::kJSReturnSequenceInstructions == 7); |
| 34 CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions); | 34 CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions); |
| 35 // li and Call pseudo-instructions emit two instructions each. | 35 // li and Call pseudo-instructions emit 6 + 2 instructions. |
| 36 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>( | 36 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int64_t>( |
| 37 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry()))); | 37 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry())), |
| 38 ADDRESS_LOAD); |
| 38 patcher.masm()->Call(v8::internal::t9); | 39 patcher.masm()->Call(v8::internal::t9); |
| 40 // Place nop to match return sequence size. |
| 39 patcher.masm()->nop(); | 41 patcher.masm()->nop(); |
| 40 patcher.masm()->nop(); | |
| 41 patcher.masm()->nop(); | |
| 42 | |
| 43 // TODO(mips): Open issue about using breakpoint instruction instead of nops. | 42 // TODO(mips): Open issue about using breakpoint instruction instead of nops. |
| 44 // patcher.masm()->bkpt(0); | 43 // patcher.masm()->bkpt(0); |
| 45 } | 44 } |
| 46 | 45 |
| 47 | 46 |
| 48 // Restore the JS frame exit code. | 47 // Restore the JS frame exit code. |
| 49 void BreakLocationIterator::ClearDebugBreakAtReturn() { | 48 void BreakLocationIterator::ClearDebugBreakAtReturn() { |
| 50 rinfo()->PatchCode(original_rinfo()->pc(), | 49 rinfo()->PatchCode(original_rinfo()->pc(), |
| 51 Assembler::kJSReturnSequenceInstructions); | 50 Assembler::kJSReturnSequenceInstructions); |
| 52 } | 51 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 67 } | 66 } |
| 68 | 67 |
| 69 | 68 |
| 70 void BreakLocationIterator::SetDebugBreakAtSlot() { | 69 void BreakLocationIterator::SetDebugBreakAtSlot() { |
| 71 ASSERT(IsDebugBreakSlot()); | 70 ASSERT(IsDebugBreakSlot()); |
| 72 // Patch the code changing the debug break slot code from: | 71 // Patch the code changing the debug break slot code from: |
| 73 // nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1) | 72 // nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1) |
| 74 // nop(DEBUG_BREAK_NOP) | 73 // nop(DEBUG_BREAK_NOP) |
| 75 // nop(DEBUG_BREAK_NOP) | 74 // nop(DEBUG_BREAK_NOP) |
| 76 // nop(DEBUG_BREAK_NOP) | 75 // nop(DEBUG_BREAK_NOP) |
| 76 // nop(DEBUG_BREAK_NOP) |
| 77 // nop(DEBUG_BREAK_NOP) |
| 77 // to a call to the debug break slot code. | 78 // to a call to the debug break slot code. |
| 78 // li t9, address (lui t9 / ori t9 instruction pair) | 79 // li t9, address (4-instruction sequence on mips64) |
| 79 // call t9 (jalr t9 / nop instruction pair) | 80 // call t9 (jalr t9 / nop instruction pair) |
| 80 CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions); | 81 CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions); |
| 81 patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>( | 82 patcher.masm()->li(v8::internal::t9, |
| 82 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry()))); | 83 Operand(reinterpret_cast<int64_t>( |
| 84 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry())), |
| 85 ADDRESS_LOAD); |
| 83 patcher.masm()->Call(v8::internal::t9); | 86 patcher.masm()->Call(v8::internal::t9); |
| 84 } | 87 } |
| 85 | 88 |
| 86 | 89 |
| 87 void BreakLocationIterator::ClearDebugBreakAtSlot() { | 90 void BreakLocationIterator::ClearDebugBreakAtSlot() { |
| 88 ASSERT(IsDebugBreakSlot()); | 91 ASSERT(IsDebugBreakSlot()); |
| 89 rinfo()->PatchCode(original_rinfo()->pc(), | 92 rinfo()->PatchCode(original_rinfo()->pc(), |
| 90 Assembler::kDebugBreakSlotInstructions); | 93 Assembler::kDebugBreakSlotInstructions); |
| 91 } | 94 } |
| 92 | 95 |
| 93 | 96 |
| 94 #define __ ACCESS_MASM(masm) | 97 #define __ ACCESS_MASM(masm) |
| 95 | 98 |
| 96 | 99 |
| 97 | 100 |
| 98 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, | 101 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, |
| 99 RegList object_regs, | 102 RegList object_regs, |
| 100 RegList non_object_regs) { | 103 RegList non_object_regs) { |
| 101 { | 104 { |
| 102 FrameScope scope(masm, StackFrame::INTERNAL); | 105 FrameScope scope(masm, StackFrame::INTERNAL); |
| 103 | 106 |
| 104 // Load padding words on stack. | 107 // Load padding words on stack. |
| 105 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue))); | 108 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue))); |
| 106 __ Subu(sp, sp, | 109 __ Dsubu(sp, sp, |
| 107 Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize)); | 110 Operand(kPointerSize * LiveEdit::kFramePaddingInitialSize)); |
| 108 for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) { | 111 for (int i = LiveEdit::kFramePaddingInitialSize - 1; i >= 0; i--) { |
| 109 __ sw(at, MemOperand(sp, kPointerSize * i)); | 112 __ sd(at, MemOperand(sp, kPointerSize * i)); |
| 110 } | 113 } |
| 111 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); | 114 __ li(at, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); |
| 112 __ push(at); | 115 __ push(at); |
| 113 | 116 |
| 117 |
| 118 // TODO(plind): This needs to be revised to store pairs of smi's per |
| 119 // the other 64-bit arch's. |
| 120 |
| 114 // Store the registers containing live values on the expression stack to | 121 // Store the registers containing live values on the expression stack to |
| 115 // make sure that these are correctly updated during GC. Non object values | 122 // make sure that these are correctly updated during GC. Non object values |
| 116 // are stored as a smi causing it to be untouched by GC. | 123 // are stored as a smi causing it to be untouched by GC. |
| 117 ASSERT((object_regs & ~kJSCallerSaved) == 0); | 124 ASSERT((object_regs & ~kJSCallerSaved) == 0); |
| 118 ASSERT((non_object_regs & ~kJSCallerSaved) == 0); | 125 ASSERT((non_object_regs & ~kJSCallerSaved) == 0); |
| 119 ASSERT((object_regs & non_object_regs) == 0); | 126 ASSERT((object_regs & non_object_regs) == 0); |
| 120 if ((object_regs | non_object_regs) != 0) { | 127 for (int i = 0; i < kNumJSCallerSaved; i++) { |
| 121 for (int i = 0; i < kNumJSCallerSaved; i++) { | 128 int r = JSCallerSavedCode(i); |
| 122 int r = JSCallerSavedCode(i); | 129 Register reg = { r }; |
| 123 Register reg = { r }; | 130 if ((object_regs & (1 << r)) != 0) { |
| 124 if ((non_object_regs & (1 << r)) != 0) { | 131 __ push(reg); |
| 125 if (FLAG_debug_code) { | |
| 126 __ And(at, reg, 0xc0000000); | |
| 127 __ Assert(eq, kUnableToEncodeValueAsSmi, at, Operand(zero_reg)); | |
| 128 } | |
| 129 __ sll(reg, reg, kSmiTagSize); | |
| 130 } | |
| 131 } | 132 } |
| 132 __ MultiPush(object_regs | non_object_regs); | 133 if ((non_object_regs & (1 << r)) != 0) { |
| 134 __ PushRegisterAsTwoSmis(reg); |
| 135 } |
| 133 } | 136 } |
| 134 | 137 |
| 135 #ifdef DEBUG | 138 #ifdef DEBUG |
| 136 __ RecordComment("// Calling from debug break to runtime - come in - over"); | 139 __ RecordComment("// Calling from debug break to runtime - come in - over"); |
| 137 #endif | 140 #endif |
| 138 __ PrepareCEntryArgs(0); // No arguments. | 141 __ PrepareCEntryArgs(0); // No arguments. |
| 139 __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate())); | 142 __ PrepareCEntryFunction(ExternalReference::debug_break(masm->isolate())); |
| 140 | 143 |
| 141 CEntryStub ceb(masm->isolate(), 1); | 144 CEntryStub ceb(masm->isolate(), 1); |
| 142 __ CallStub(&ceb); | 145 __ CallStub(&ceb); |
| 143 | 146 |
| 144 // Restore the register values from the expression stack. | 147 // Restore the register values from the expression stack. |
| 145 if ((object_regs | non_object_regs) != 0) { | 148 for (int i = kNumJSCallerSaved - 1; i >= 0; i--) { |
| 146 __ MultiPop(object_regs | non_object_regs); | 149 int r = JSCallerSavedCode(i); |
| 147 for (int i = 0; i < kNumJSCallerSaved; i++) { | 150 Register reg = { r }; |
| 148 int r = JSCallerSavedCode(i); | 151 if ((non_object_regs & (1 << r)) != 0) { |
| 149 Register reg = { r }; | 152 __ PopRegisterAsTwoSmis(reg, at); |
| 150 if ((non_object_regs & (1 << r)) != 0) { | 153 } |
| 151 __ srl(reg, reg, kSmiTagSize); | 154 if ((object_regs & (1 << r)) != 0) { |
| 152 } | 155 __ pop(reg); |
| 153 if (FLAG_debug_code && | 156 } |
| 154 (((object_regs |non_object_regs) & (1 << r)) == 0)) { | 157 if (FLAG_debug_code && |
| 155 __ li(reg, kDebugZapValue); | 158 (((object_regs |non_object_regs) & (1 << r)) == 0)) { |
| 156 } | 159 __ li(reg, kDebugZapValue); |
| 157 } | 160 } |
| 158 } | 161 } |
| 159 | 162 |
| 160 // Don't bother removing padding bytes pushed on the stack | 163 // Don't bother removing padding bytes pushed on the stack |
| 161 // as the frame is going to be restored right away. | 164 // as the frame is going to be restored right away. |
| 162 | 165 |
| 163 // Leave the internal frame. | 166 // Leave the internal frame. |
| 164 } | 167 } |
| 165 | 168 |
| 166 // Now that the break point has been handled, resume normal execution by | 169 // Now that the break point has been handled, resume normal execution by |
| 167 // jumping to the target address intended by the caller and that was | 170 // jumping to the target address intended by the caller and that was |
| 168 // overwritten by the address of DebugBreakXXX. | 171 // overwritten by the address of DebugBreakXXX. |
| 169 ExternalReference after_break_target = | 172 ExternalReference after_break_target = |
| 170 ExternalReference::debug_after_break_target_address(masm->isolate()); | 173 ExternalReference::debug_after_break_target_address(masm->isolate()); |
| 171 __ li(t9, Operand(after_break_target)); | 174 __ li(t9, Operand(after_break_target)); |
| 172 __ lw(t9, MemOperand(t9)); | 175 __ ld(t9, MemOperand(t9)); |
| 173 __ Jump(t9); | 176 __ Jump(t9); |
| 174 } | 177 } |
| 175 | 178 |
| 176 | 179 |
| 177 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) { | 180 void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) { |
| 178 // Register state for CallICStub | 181 // Register state for CallICStub |
| 179 // ----------- S t a t e ------------- | 182 // ----------- S t a t e ------------- |
| 180 // -- a1 : function | 183 // -- a1 : function |
| 181 // -- a3 : slot in feedback array (smi) | 184 // -- a3 : slot in feedback array (smi) |
| 182 // ----------------------------------- | 185 // ----------------------------------- |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) { | 253 void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) { |
| 251 // Calling convention for CallConstructStub (from code-stubs-mips.cc). | 254 // Calling convention for CallConstructStub (from code-stubs-mips.cc). |
| 252 // ----------- S t a t e ------------- | 255 // ----------- S t a t e ------------- |
| 253 // -- a0 : number of arguments (not smi) | 256 // -- a0 : number of arguments (not smi) |
| 254 // -- a1 : constructor function | 257 // -- a1 : constructor function |
| 255 // ----------------------------------- | 258 // ----------------------------------- |
| 256 Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit()); | 259 Generate_DebugBreakCallHelper(masm, a1.bit() , a0.bit()); |
| 257 } | 260 } |
| 258 | 261 |
| 259 | 262 |
| 263 |
| 260 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak( | 264 void DebugCodegen::GenerateCallConstructStubRecordDebugBreak( |
| 261 MacroAssembler* masm) { | 265 MacroAssembler* masm) { |
| 262 // Calling convention for CallConstructStub (from code-stubs-mips.cc). | 266 // Calling convention for CallConstructStub (from code-stubs-mips.cc). |
| 263 // ----------- S t a t e ------------- | 267 // ----------- S t a t e ------------- |
| 264 // -- a0 : number of arguments (not smi) | 268 // -- a0 : number of arguments (not smi) |
| 265 // -- a1 : constructor function | 269 // -- a1 : constructor function |
| 266 // -- a2 : feedback array | 270 // -- a2 : feedback array |
| 267 // -- a3 : feedback slot (smi) | 271 // -- a3 : feedback slot (smi) |
| 268 // ----------------------------------- | 272 // ----------------------------------- |
| 269 Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit()); | 273 Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit() | a3.bit(), a0.bit()); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 298 | 302 |
| 299 | 303 |
| 300 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { | 304 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { |
| 301 ExternalReference restarter_frame_function_slot = | 305 ExternalReference restarter_frame_function_slot = |
| 302 ExternalReference::debug_restarter_frame_function_pointer_address( | 306 ExternalReference::debug_restarter_frame_function_pointer_address( |
| 303 masm->isolate()); | 307 masm->isolate()); |
| 304 __ li(at, Operand(restarter_frame_function_slot)); | 308 __ li(at, Operand(restarter_frame_function_slot)); |
| 305 __ sw(zero_reg, MemOperand(at, 0)); | 309 __ sw(zero_reg, MemOperand(at, 0)); |
| 306 | 310 |
| 307 // We do not know our frame height, but set sp based on fp. | 311 // We do not know our frame height, but set sp based on fp. |
| 308 __ Subu(sp, fp, Operand(kPointerSize)); | 312 __ Dsubu(sp, fp, Operand(kPointerSize)); |
| 309 | 313 |
| 310 __ Pop(ra, fp, a1); // Return address, Frame, Function. | 314 __ Pop(ra, fp, a1); // Return address, Frame, Function. |
| 311 | 315 |
| 312 // Load context from the function. | 316 // Load context from the function. |
| 313 __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); | 317 __ ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset)); |
| 314 | 318 |
| 315 // Get function code. | 319 // Get function code. |
| 316 __ lw(at, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); | 320 __ ld(at, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset)); |
| 317 __ lw(at, FieldMemOperand(at, SharedFunctionInfo::kCodeOffset)); | 321 __ ld(at, FieldMemOperand(at, SharedFunctionInfo::kCodeOffset)); |
| 318 __ Addu(t9, at, Operand(Code::kHeaderSize - kHeapObjectTag)); | 322 __ Daddu(t9, at, Operand(Code::kHeaderSize - kHeapObjectTag)); |
| 319 | 323 |
| 320 // Re-run JSFunction, a1 is function, cp is context. | 324 // Re-run JSFunction, a1 is function, cp is context. |
| 321 __ Jump(t9); | 325 __ Jump(t9); |
| 322 } | 326 } |
| 323 | 327 |
| 324 | 328 |
| 325 const bool LiveEdit::kFrameDropperSupported = true; | 329 const bool LiveEdit::kFrameDropperSupported = true; |
| 326 | 330 |
| 327 #undef __ | 331 #undef __ |
| 328 | 332 |
| 329 } } // namespace v8::internal | 333 } } // namespace v8::internal |
| 330 | 334 |
| 331 #endif // V8_TARGET_ARCH_MIPS | 335 #endif // V8_TARGET_ARCH_MIPS64 |
| OLD | NEW |