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 11namespace v8 { 12namespace internal { 13 14#define __ ACCESS_MASM(masm) 15 16 17void 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 26void 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 33void DebugCodegen::ClearDebugBreakSlot(Isolate* isolate, Address pc) { 34 CodePatcher patcher(isolate, pc, Assembler::kDebugBreakSlotLength); 35 EmitDebugBreakSlot(patcher.masm()); 36} 37 38 39void DebugCodegen::PatchDebugBreakSlot(Isolate* isolate, Address pc, 40 Handle<Code> code) { 41 DCHECK_EQ(Code::BUILTIN, code->kind()); 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 54void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm, 55 DebugBreakCallHelperMode mode) { 56 __ RecordComment("Debug break"); 57 58 // Enter an internal frame. 59 { 60 FrameScope scope(masm, StackFrame::INTERNAL); 61 62 // Load padding words on stack. 63 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { 64 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue))); 65 } 66 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); 67 68 if (mode == SAVE_RESULT_REGISTER) __ push(eax); 69 70 __ Move(eax, Immediate(0)); // No arguments. 71 __ mov(ebx, 72 Immediate(ExternalReference( 73 Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); 74 75 CEntryStub ceb(masm->isolate(), 1); 76 __ CallStub(&ceb); 77 78 if (FLAG_debug_code) { 79 for (int i = 0; i < kNumJSCallerSaved; ++i) { 80 Register reg = {JSCallerSavedCode(i)}; 81 __ Move(reg, Immediate(kDebugZapValue)); 82 } 83 } 84 85 if (mode == SAVE_RESULT_REGISTER) __ pop(eax); 86 87 __ pop(ebx); 88 // We divide stored value by 2 (untagging) and multiply it by word's size. 89 STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); 90 __ lea(esp, Operand(esp, ebx, times_half_pointer_size, 0)); 91 92 // Get rid of the internal frame. 93 } 94 95 // This call did not replace a call , so there will be an unwanted 96 // return address left on the stack. Here we get rid of that. 97 __ add(esp, Immediate(kPointerSize)); 98 99 // Now that the break point has been handled, resume normal execution by 100 // jumping to the target address intended by the caller and that was 101 // overwritten by the address of DebugBreakXXX. 102 ExternalReference after_break_target = 103 ExternalReference::debug_after_break_target_address(masm->isolate()); 104 __ jmp(Operand::StaticVariable(after_break_target)); 105} 106 107 108void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { 109 // We do not know our frame height, but set esp based on ebp. 110 __ lea(esp, Operand(ebp, -1 * kPointerSize)); 111 112 __ pop(edi); // Function. 113 __ pop(ebp); 114 115 ParameterCount dummy(0); 116 __ FloodFunctionIfStepping(edi, no_reg, dummy, dummy); 117 118 // Load context from the function. 119 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 120 121 // Clear new.target register as a safety measure. 122 __ mov(edx, masm->isolate()->factory()->undefined_value()); 123 124 // Get function code. 125 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 126 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kCodeOffset)); 127 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); 128 129 // Re-run JSFunction, edi is function, esi is context. 130 __ jmp(ebx); 131} 132 133 134const bool LiveEdit::kFrameDropperSupported = true; 135 136#undef __ 137 138} // namespace internal 139} // namespace v8 140 141#endif // V8_TARGET_ARCH_X87 142