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
EmitDebugBreakSlot(MacroAssembler * masm)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
GenerateSlot(MacroAssembler * masm,RelocInfo::Mode mode)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
ClearDebugBreakSlot(Isolate * isolate,Address pc)36 void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
37 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength);
38 EmitDebugBreakSlot(patcher.masm());
39 }
40
41
PatchDebugBreakSlot(Isolate * isolate,Address pc,Handle<Code> code)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
DebugBreakSlotIsPatched(Address pc)56 bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) {
57 return !Assembler::IsNop(pc);
58 }
59
GenerateDebugBreakStub(MacroAssembler * masm,DebugBreakCallHelperMode mode)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
GenerateHandleDebuggerStatement(MacroAssembler * masm)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
GenerateFrameDropperTrampoline(MacroAssembler * masm)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