1 // 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 12 namespace v8 { 13 namespace internal { 14 15 #define __ ACCESS_MASM(masm) 16 17 void 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 35 void 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 41 void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) { 42 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength); 43 EmitDebugBreakSlot(patcher.masm()); 44 } 45 46 void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, 47 Handle<Code> code) { 48 DCHECK(code->is_debug_stub()); 49 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 72 bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { 73 Instr current_instr = Assembler::instr_at(pc); 74 return !Assembler::IsNop(current_instr, Assembler::DEBUG_BREAK_NOP); 75 } 76 77 void 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 134 void 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 159 const bool LiveEdit::kFrameDropperSupported = true; 160 161 #undef __ 162 } // namespace internal 163 } // namespace v8 164 165 #endif // V8_TARGET_ARCH_S390 166