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