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/debug/debug.h" 8 9 #include "src/assembler.h" 10 #include "src/codegen.h" 11 #include "src/debug/liveedit.h" 12 #include "src/objects-inl.h" 13 14 namespace v8 { 15 namespace internal { 16 17 #define __ ACCESS_MASM(masm) 18 19 20 void EmitDebugBreakSlot(MacroAssembler* masm) { 21 Label check_codesize; 22 __ bind(&check_codesize); 23 __ Nop(Assembler::kDebugBreakSlotLength); 24 DCHECK_EQ(Assembler::kDebugBreakSlotLength, 25 masm->SizeOfCodeGeneratedSince(&check_codesize)); 26 } 27 28 29 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) { 30 // Generate enough nop's to make space for a call instruction. 31 masm->RecordDebugBreakSlot(mode); 32 EmitDebugBreakSlot(masm); 33 } 34 35 36 void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) { 37 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength); 38 EmitDebugBreakSlot(patcher.masm()); 39 } 40 41 42 void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, 43 Handle<Code> code) { 44 DCHECK(code->is_debug_stub()); 45 static const int kSize = Assembler::kDebugBreakSlotLength; 46 CodePatcher patcher(isolate, pc, kSize); 47 Label check_codesize; 48 patcher.masm()->bind(&check_codesize); 49 patcher.masm()->movp(kScratchRegister, reinterpret_cast<void*>(code->entry()), 50 Assembler::RelocInfoNone()); 51 patcher.masm()->call(kScratchRegister); 52 // Check that the size of the code generated is as expected. 53 DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize)); 54 } 55 56 bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { 57 return !Assembler::IsNop(pc); 58 } 59 60 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, 61 DebugBreakCallHelperMode mode) { 62 __ RecordComment("Debug break"); 63 64 // Enter an internal frame. 65 { 66 FrameScope scope(masm, StackFrame::INTERNAL); 67 68 // Push arguments for DebugBreak call. 69 if (mode == SAVE_RESULT_REGISTER) { 70 // Break on return. 71 __ Push(rax); 72 } else { 73 // Non-return breaks. 74 __ Push(masm->isolate()->factory()->the_hole_value()); 75 } 76 77 __ CallRuntime(Runtime::kDebugBreak, 1, kDontSaveFPRegs); 78 79 if (FLAG_debug_code) { 80 for (int i = 0; i < kNumJSCallerSaved; ++i) { 81 Register reg = {JSCallerSavedCode(i)}; 82 // Do not clobber rax if mode is SAVE_RESULT_REGISTER. It will 83 // contain return value of the function. 84 if (!(reg.is(rax) && (mode == SAVE_RESULT_REGISTER))) { 85 __ Set(reg, kDebugZapValue); 86 } 87 } 88 } 89 // Get rid of the internal frame. 90 } 91 92 __ MaybeDropFrames(); 93 94 // Return to caller. 95 __ ret(0); 96 } 97 98 void DebugCodegen::GenerateHandleDebuggerStatement(MacroAssembler* masm) { 99 { 100 FrameScope scope(masm, StackFrame::INTERNAL); 101 __ CallRuntime(Runtime::kHandleDebuggerStatement, 0); 102 } 103 __ MaybeDropFrames(); 104 105 // Return to caller. 106 __ ret(0); 107 } 108 109 void DebugCodegen::GenerateFrameDropperTrampoline(MacroAssembler* masm) { 110 // Frame is being dropped: 111 // - Drop to the target frame specified by rbx. 112 // - Look up current function on the frame. 113 // - Leave the frame. 114 // - Restart the frame by calling the function. 115 __ movp(rbp, rbx); 116 __ movp(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); 117 __ leave(); 118 119 __ movp(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); 120 __ LoadSharedFunctionInfoSpecialField( 121 rbx, rbx, SharedFunctionInfo::kFormalParameterCountOffset); 122 123 ParameterCount dummy(rbx); 124 __ InvokeFunction(rdi, no_reg, dummy, dummy, JUMP_FUNCTION, 125 CheckDebugStepCallWrapper()); 126 } 127 128 const bool LiveEdit::kFrameDropperSupported = true; 129 130 #undef __ 131 132 } // namespace internal 133 } // namespace v8 134 135 #endif // V8_TARGET_ARCH_X64 136