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