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_X87 6 7 #include "src/codegen.h" 8 #include "src/debug/debug.h" 9 #include "src/x87/frames-x87.h" 10 11 namespace v8 { 12 namespace internal { 13 14 #define __ ACCESS_MASM(masm) 15 16 17 void EmitDebugBreakSlot(MacroAssembler* masm) { 18 Label check_codesize; 19 __ bind(&check_codesize); 20 __ Nop(Assembler::kDebugBreakSlotLength); 21 DCHECK_EQ(Assembler::kDebugBreakSlotLength, 22 masm->SizeOfCodeGeneratedSince(&check_codesize)); 23 } 24 25 26 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode) { 27 // Generate enough nop's to make space for a call instruction. 28 masm->RecordDebugBreakSlot(mode); 29 EmitDebugBreakSlot(masm); 30 } 31 32 33 void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) { 34 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength); 35 EmitDebugBreakSlot(patcher.masm()); 36 } 37 38 39 void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, 40 Handle<Code> code) { 41 DCHECK(code->is_debug_stub()); 42 static const int kSize = Assembler::kDebugBreakSlotLength; 43 CodePatcher patcher(isolate, pc, kSize); 44 45 // Add a label for checking the size of the code used for returning. 46 Label check_codesize; 47 patcher.masm()->bind(&check_codesize); 48 patcher.masm()->call(code->entry(), RelocInfo::NONE32); 49 // Check that the size of the code generated is as expected. 50 DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize)); 51 } 52 53 bool DebugCodegen::DebugBreakSlotIsPatched(Address pc) { 54 return !Assembler::IsNop(pc); 55 } 56 57 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, 58 DebugBreakCallHelperMode mode) { 59 __ RecordComment("Debug break"); 60 61 // Enter an internal frame. 62 { 63 FrameScope scope(masm, StackFrame::INTERNAL); 64 65 // Load padding words on stack. 66 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { 67 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue))); 68 } 69 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); 70 71 // Push arguments for DebugBreak call. 72 if (mode == SAVE_RESULT_REGISTER) { 73 // Break on return. 74 __ push(eax); 75 } else { 76 // Non-return breaks. 77 __ Push(masm->isolate()->factory()->the_hole_value()); 78 } 79 __ Move(eax, Immediate(1)); 80 __ mov(ebx, 81 Immediate(ExternalReference( 82 Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); 83 84 CEntryStub ceb(masm->isolate(), 1); 85 __ CallStub(&ceb); 86 87 if (FLAG_debug_code) { 88 for (int i = 0; i < kNumJSCallerSaved; ++i) { 89 Register reg = {JSCallerSavedCode(i)}; 90 // Do not clobber eax if mode is SAVE_RESULT_REGISTER. It will 91 // contain return value of the function. 92 if (!(reg.is(eax) && (mode == SAVE_RESULT_REGISTER))) { 93 __ Move(reg, Immediate(kDebugZapValue)); 94 } 95 } 96 } 97 98 __ pop(ebx); 99 // We divide stored value by 2 (untagging) and multiply it by word's size. 100 STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); 101 __ lea(esp, Operand(esp, ebx, times_half_pointer_size, 0)); 102 103 // Get rid of the internal frame. 104 } 105 106 // This call did not replace a call , so there will be an unwanted 107 // return address left on the stack. Here we get rid of that. 108 __ add(esp, Immediate(kPointerSize)); 109 110 // Now that the break point has been handled, resume normal execution by 111 // jumping to the target address intended by the caller and that was 112 // overwritten by the address of DebugBreakXXX. 113 ExternalReference after_break_target = 114 ExternalReference::debug_after_break_target_address(masm->isolate()); 115 __ jmp(Operand::StaticVariable(after_break_target)); 116 } 117 118 119 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { 120 // We do not know our frame height, but set esp based on ebp. 121 __ lea(esp, Operand(ebp, FrameDropperFrameConstants::kFunctionOffset)); 122 __ pop(edi); // Function. 123 __ add(esp, Immediate(-FrameDropperFrameConstants::kCodeOffset)); // INTERNAL 124 // frame 125 // marker 126 // and code 127 __ pop(ebp); 128 129 ParameterCount dummy(0); 130 __ FloodFunctionIfStepping(edi, no_reg, dummy, dummy); 131 132 // Load context from the function. 133 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 134 135 // Clear new.target register as a safety measure. 136 __ mov(edx, masm->isolate()->factory()->undefined_value()); 137 138 // Get function code. 139 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 140 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset)); 141 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); 142 143 // Re-run JSFunction, edi is function, esi is context. 144 __ jmp(ebx); 145 } 146 147 148 const bool LiveEdit::kFrameDropperSupported = true; 149 150 #undef __ 151 152 } // namespace internal 153 } // namespace v8 154 155 #endif // V8_TARGET_ARCH_X87 156