Home | History | Annotate | Download | only in x64
      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_X64
      6 
      7 #include "src/assembler.h"
      8 #include "src/codegen.h"
      9 #include "src/debug/debug.h"
     10 
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 #define __ ACCESS_MASM(masm)
     16 
     17 
     18 void EmitDebugBreakSlot(MacroAssembler* masm) {
     19   Label check_codesize;
     20   __ bind(&check_codesize);
     21   __ Nop(Assembler::kDebugBreakSlotLength);
     22   DCHECK_EQ(Assembler::kDebugBreakSlotLength,
     23             masm->SizeOfCodeGeneratedSince(&check_codesize));
     24 }
     25 
     26 
     27 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
     28   // Generate enough nop's to make space for a call instruction.
     29   masm->RecordDebugBreakSlot(mode);
     30   EmitDebugBreakSlot(masm);
     31 }
     32 
     33 
     34 void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
     35   CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength);
     36   EmitDebugBreakSlot(patcher.masm());
     37 }
     38 
     39 
     40 void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
     41                                        Handle<Code> code) {
     42   DCHECK(code->is_debug_stub());
     43   static const int kSize = Assembler::kDebugBreakSlotLength;
     44   CodePatcher patcher(isolate, pc, kSize);
     45   Label check_codesize;
     46   patcher.masm()->bind(&check_codesize);
     47   patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(code->entry()),
     48                        Assembler::RelocInfoNone());
     49   patcher.masm()->call(kScratchRegister);
     50   // Check that the size of the code generated is as expected.
     51   DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
     52 }
     53 
     54 bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) {
     55   return !Assembler::IsNop(pc);
     56 }
     57 
     58 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
     59                                           DebugBreakCallHelperMode mode) {
     60   __ RecordComment("Debug break");
     61 
     62   // Enter an internal frame.
     63   {
     64     FrameScope scope(masm, StackFrame::INTERNAL);
     65 
     66     // Load padding words on stack.
     67     for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
     68       __ Push(Smi::FromInt(LiveEdit::kFramePaddingValue));
     69     }
     70     __ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
     71 
     72     // Push arguments for DebugBreak call.
     73     if (mode == SAVE_RESULT_REGISTER) {
     74       // Break on return.
     75       __ Push(rax);
     76     } else {
     77       // Non-return breaks.
     78       __ Push(masm->isolate()->factory()->the_hole_value());
     79     }
     80     __ Set(rax, 1);
     81     __ Move(rbx, ExternalReference(Runtime::FunctionForId(Runtime::kDebugBreak),
     82                                    masm->isolate()));
     83 
     84     CEntryStub ceb(masm->isolate(), 1);
     85     __ CallStub(&ceb);
     86 
     87     if (FLAG_debug_code) {
     88       for (int i = 0; i < kNumJSCallerSaved; ++i) {
     89         Register reg = {JSCallerSavedCode(i)};
     90         // Do not clobber rax if mode is SAVE_RESULT_REGISTER. It will
     91         // contain return value of the function.
     92         if (!(reg.is(rax) && (mode == SAVE_RESULT_REGISTER))) {
     93           __ Set(reg, kDebugZapValue);
     94         }
     95       }
     96     }
     97 
     98     // Read current padding counter and skip corresponding number of words.
     99     __ Pop(kScratchRegister);
    100     __ SmiToInteger32(kScratchRegister, kScratchRegister);
    101     __ leap(rsp, Operand(rsp, kScratchRegister, times_pointer_size, 0));
    102 
    103     // Get rid of the internal frame.
    104   }
    105 
    106   // This call did not replace a call , so there will be an unwanted
    107   // return address left on the stack. Here we get rid of that.
    108   __ addp(rsp, Immediate(kPCOnStackSize));
    109 
    110   // Now that the break point has been handled, resume normal execution by
    111   // jumping to the target address intended by the caller and that was
    112   // overwritten by the address of DebugBreakXXX.
    113   ExternalReference after_break_target =
    114       ExternalReference::debug_after_break_target_address(masm->isolate());
    115   __ Move(kScratchRegister, after_break_target);
    116   __ Jump(Operand(kScratchRegister, 0));
    117 }
    118 
    119 
    120 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
    121   // We do not know our frame height, but set rsp based on rbp.
    122   __ leap(rsp, Operand(rbp, FrameDropperFrameConstants::kFunctionOffset));
    123   __ Pop(rdi);  // Function.
    124   __ addp(rsp,
    125           Immediate(-FrameDropperFrameConstants::kCodeOffset));  // INTERNAL
    126                                                                  // frame marker
    127                                                                  // and code
    128   __ popq(rbp);
    129 
    130   ParameterCount dummy(0);
    131   __ FloodFunctionIfStepping(rdi, no_reg, dummy, dummy);
    132 
    133   // Load context from the function.
    134   __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
    135 
    136   // Clear new.target as a safety measure.
    137   __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
    138 
    139   // Get function code.
    140   __ movp(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
    141   __ movp(rbx, FieldOperand(rbx, SharedFunctionInfo::kCodeOffset));
    142   __ leap(rbx, FieldOperand(rbx, Code::kHeaderSize));
    143 
    144   // Re-run JSFunction, rdi is function, rsi is context.
    145   __ jmp(rbx);
    146 }
    147 
    148 const bool LiveEdit::kFrameDropperSupported = true;
    149 
    150 #undef __
    151 
    152 }  // namespace internal
    153 }  // namespace v8
    154 
    155 #endif  // V8_TARGET_ARCH_X64
    156