blob: 9c33b95e3b9ebc4fbe7f62d7ecd26c577cbdb32c [file] [log] [blame]
Ben Murdochda12d292016-06-02 14:46:10 +01001// Copyright 2015 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#include "src/v8.h"
6
7#if V8_TARGET_ARCH_S390
8
9#include "src/codegen.h"
10#include "src/debug/debug.h"
11
12namespace v8 {
13namespace internal {
14
15#define __ ACCESS_MASM(masm)
16
17void EmitDebugBreakSlot(MacroAssembler* masm) {
18 Label check_size;
19 __ bind(&check_size);
20 // oill r3, 0
21 // oill r3, 0
22 __ nop(Assembler::DEBUG_BREAK_NOP);
23 __ nop(Assembler::DEBUG_BREAK_NOP);
24
25 // lr r0, r0 64-bit only
26 // lr r0, r0 64-bit only
27 // lr r0, r0 64-bit only
28 for (int i = 8; i < Assembler::kDebugBreakSlotLength; i += 2) {
29 __ nop();
30 }
31 DCHECK_EQ(Assembler::kDebugBreakSlotLength,
32 masm->SizeOfCodeGeneratedSince(&check_size));
33}
34
35void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) {
36 // Generate enough nop's to make space for a call instruction.
37 masm->RecordDebugBreakSlot(mode);
38 EmitDebugBreakSlot(masm);
39}
40
41void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) {
42 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength);
43 EmitDebugBreakSlot(patcher.masm());
44}
45
46void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc,
47 Handle<Code> code) {
Ben Murdoch61f157c2016-09-16 13:49:30 +010048 DCHECK(code->is_debug_stub());
Ben Murdochda12d292016-06-02 14:46:10 +010049 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength);
50 // Patch the code changing the debug break slot code from
51 //
52 // oill r3, 0
53 // oill r3, 0
54 // oill r3, 0 64-bit only
55 // lr r0, r0 64-bit only
56 //
57 // to a call to the debug break code, using a FIXED_SEQUENCE.
58 //
59 // iilf r14, <address> 6-bytes
60 // basr r14, r14A 2-bytes
61 //
62 // The 64bit sequence has an extra iihf.
63 //
64 // iihf r14, <high 32-bits address> 6-bytes
65 // iilf r14, <lower 32-bits address> 6-bytes
66 // basr r14, r14 2-bytes
67 patcher.masm()->mov(v8::internal::r14,
68 Operand(reinterpret_cast<intptr_t>(code->entry())));
69 patcher.masm()->basr(v8::internal::r14, v8::internal::r14);
70}
71
72bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) {
73 Instr current_instr = Assembler::instr_at(pc);
74 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP);
75}
76
77void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
78 DebugBreakCallHelperMode mode) {
79 __ RecordComment("Debug break");
80 {
81 FrameScope scope(masm, StackFrame::INTERNAL);
82
83 // Load padding words on stack.
84 __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingValue));
85 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
86 __ push(ip);
87 }
88 __ LoadSmiLiteral(ip, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
89 __ push(ip);
90
91 // Push arguments for DebugBreak call.
92 if (mode == SAVE_RESULT_REGISTER) {
93 // Break on return.
94 __ push(r2);
95 } else {
96 // Non-return breaks.
97 __ Push(masm->isolate()->factory()->the_hole_value());
98 }
99 __ mov(r2, Operand(1));
100 __ mov(r3,
101 Operand(ExternalReference(
102 Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate())));
103
104 CEntryStub ceb(masm->isolate(), 1);
105 __ CallStub(&ceb);
106
107 if (FLAG_debug_code) {
108 for (int i = 0; i < kNumJSCallerSaved; i++) {
109 Register reg = {JSCallerSavedCode(i)};
110 // Do not clobber r2 if mode is SAVE_RESULT_REGISTER. It will
111 // contain return value of the function.
112 if (!(reg.is(r2) && (mode == SAVE_RESULT_REGISTER))) {
113 __ mov(reg, Operand(kDebugZapValue));
114 }
115 }
116 }
117
118 // Don't bother removing padding bytes pushed on the stack
119 // as the frame is going to be restored right away.
120
121 // Leave the internal frame.
122 }
123
124 // Now that the break point has been handled, resume normal execution by
125 // jumping to the target address intended by the caller and that was
126 // overwritten by the address of DebugBreakXXX.
127 ExternalReference after_break_target =
128 ExternalReference::debug_after_break_target_address(masm->isolate());
129 __ mov(ip, Operand(after_break_target));
130 __ LoadP(ip, MemOperand(ip));
131 __ JumpToJSEntry(ip);
132}
133
134void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
135 // Load the function pointer off of our current stack frame.
136 __ LoadP(r3, MemOperand(fp, FrameDropperFrameConstants::kFunctionOffset));
137
138 // Pop return address and frame
139 __ LeaveFrame(StackFrame::INTERNAL);
140
141 ParameterCount dummy(0);
142 __ FloodFunctionIfStepping(r3, no_reg, dummy, dummy);
143
144 // Load context from the function.
145 __ LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
146
147 // Clear new.target as a safety measure.
148 __ LoadRoot(r5, Heap::kUndefinedValueRootIndex);
149
150 // Get function code.
151 __ LoadP(ip, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset));
152 __ LoadP(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset));
153 __ AddP(ip, Operand(Code::kHeaderSize - kHeapObjectTag));
154
155 // Re-run JSFunction, r3 is function, cp is context.
156 __ Jump(ip);
157}
158
159const bool LiveEdit::kFrameDropperSupported = true;
160
161#undef __
162} // namespace internal
163} // namespace v8
164
165#endif // V8_TARGET_ARCH_S390