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