Home | History | Annotate | Download | only in mips64
      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 #if V8_TARGET_ARCH_MIPS64
      6 
      7 #include "src/debug/debug.h"
      8 
      9 #include "src/codegen.h"
     10 #include "src/debug/liveedit.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 #define __ ACCESS_MASM(masm)
     16 
     17 void EmitDebugBreakSlot(MacroAssembler* masm) {
     18   Label check_size;
     19   __ bind(&check_size);
     20   for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
     21     __ nop(MacroAssembler::DEBUG_BREAK_NOP);
     22   }
     23   DCHECK_EQ(Assembler::kDebugBreakSlotInstructions,
     24             masm->InstructionsGeneratedSince(&check_size));
     25 }
     26 
     27 
     28 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
     29   // Generate enough nop's to make space for a call instruction. Avoid emitting
     30   // the trampoline pool in the debug break slot code.
     31   Assembler::BlockTrampolinePoolScope block_pool(masm);
     32   masm->RecordDebugBreakSlot(mode);
     33   EmitDebugBreakSlot(masm);
     34 }
     35 
     36 
     37 void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
     38   CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
     39   EmitDebugBreakSlot(patcher.masm());
     40 }
     41 
     42 
     43 void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
     44                                        Handle<Code> code) {
     45   DCHECK(code->is_debug_stub());
     46   CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotInstructions);
     47   // Patch the code changing the debug break slot code from:
     48   //   nop(DEBUG_BREAK_NOP) - nop(1) is sll(zero_reg, zero_reg, 1)
     49   //   nop(DEBUG_BREAK_NOP)
     50   //   nop(DEBUG_BREAK_NOP)
     51   //   nop(DEBUG_BREAK_NOP)
     52   //   nop(DEBUG_BREAK_NOP)
     53   //   nop(DEBUG_BREAK_NOP)
     54   // to a call to the debug break slot code.
     55   //   li t9, address   (4-instruction sequence on mips64)
     56   //   call t9          (jalr t9 / nop instruction pair)
     57   patcher.masm()->li(v8::internal::t9,
     58                      Operand(reinterpret_cast<int64_t>(code->entry())),
     59                      ADDRESS_LOAD);
     60   patcher.masm()->Call(v8::internal::t9);
     61 }
     62 
     63 bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) {
     64   Instr current_instr = Assembler::instr_at(pc);
     65   return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
     66 }
     67 
     68 void DebugCodegen::GenerateHandleDebuggerStatement(MacroAssembler* masm) {
     69   {
     70     FrameScope scope(masm, StackFrame::INTERNAL);
     71     __ CallRuntime(Runtime::kHandleDebuggerStatement, 0);
     72   }
     73   __ MaybeDropFrames();
     74 
     75   // Return to caller.
     76   __ Ret();
     77 }
     78 
     79 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
     80                                           DebugBreakCallHelperMode mode) {
     81   __ RecordComment("Debug break");
     82   {
     83     FrameScope scope(masm, StackFrame::INTERNAL);
     84 
     85     // Push arguments for DebugBreak call.
     86     if (mode == SAVE_RESULT_REGISTER) {
     87       // Break on return.
     88       __ push(v0);
     89     } else {
     90       // Non-return breaks.
     91       __ Push(masm->isolate()->factory()->the_hole_value());
     92     }
     93     __ PrepareCEntryArgs(1);
     94     __ PrepareCEntryFunction(ExternalReference(
     95         Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()));
     96 
     97     CEntryStub ceb(masm->isolate(), 1);
     98     __ CallStub(&ceb);
     99 
    100     if (FLAG_debug_code) {
    101       for (int i = 0; i < kNumJSCallerSaved; i++) {
    102         Register reg = {JSCallerSavedCode(i)};
    103         // Do not clobber v0 if mode is SAVE_RESULT_REGISTER. It will
    104         // contain return value of the function returned by DebugBreak.
    105         if (!(reg.is(v0) && (mode == SAVE_RESULT_REGISTER))) {
    106           __ li(reg, kDebugZapValue);
    107         }
    108       }
    109     }
    110 
    111     // Leave the internal frame.
    112   }
    113 
    114   __ MaybeDropFrames();
    115 
    116   // Return to caller.
    117   __ Ret();
    118 }
    119 
    120 void DebugCodegen::GenerateFrameDropperTrampoline(MacroAssembler* masm) {
    121   // Frame is being dropped:
    122   // - Drop to the target frame specified by a1.
    123   // - Look up current function on the frame.
    124   // - Leave the frame.
    125   // - Restart the frame by calling the function.
    126   __ mov(fp, a1);
    127   __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
    128 
    129   // Pop return address and frame.
    130   __ LeaveFrame(StackFrame::INTERNAL);
    131 
    132   __ ld(a0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
    133   __ ld(a0,
    134         FieldMemOperand(a0, SharedFunctionInfo::kFormalParameterCountOffset));
    135   __ mov(a2, a0);
    136 
    137   ParameterCount dummy1(a2);
    138   ParameterCount dummy2(a0);
    139   __ InvokeFunction(a1, dummy1, dummy2, JUMP_FUNCTION,
    140                     CheckDebugStepCallWrapper());
    141 }
    142 
    143 
    144 const bool LiveEdit::kFrameDropperSupported = true;
    145 
    146 #undef __
    147 
    148 }  // namespace internal
    149 }  // namespace v8
    150 
    151 #endif  // V8_TARGET_ARCH_MIPS64
    152