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_IA32 6 7 #include "src/debug/debug.h" 8 9 #include "src/codegen.h" 10 #include "src/debug/liveedit.h" 11 #include "src/ia32/frames-ia32.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 // Push arguments for DebugBreak call. 68 if (mode == SAVE_RESULT_REGISTER) { 69 // Break on return. 70 __ push(eax); 71 } else { 72 // Non-return breaks. 73 __ Push(masm->isolate()->factory()->the_hole_value()); 74 } 75 __ Move(eax, Immediate(1)); 76 __ mov(ebx, 77 Immediate(ExternalReference( 78 Runtime::FunctionForId(Runtime::kDebugBreak), masm->isolate()))); 79 80 CEntryStub ceb(masm->isolate(), 1); 81 __ CallStub(&ceb); 82 83 if (FLAG_debug_code) { 84 for (int i = 0; i < kNumJSCallerSaved; ++i) { 85 Register reg = {JSCallerSavedCode(i)}; 86 // Do not clobber eax if mode is SAVE_RESULT_REGISTER. It will 87 // contain return value of the function. 88 if (!(reg.is(eax) && (mode == SAVE_RESULT_REGISTER))) { 89 __ Move(reg, Immediate(kDebugZapValue)); 90 } 91 } 92 } 93 // Get rid of the internal frame. 94 } 95 96 __ MaybeDropFrames(); 97 98 // Return to caller. 99 __ ret(0); 100 } 101 102 void DebugCodegen::GenerateHandleDebuggerStatement(MacroAssembler* masm) { 103 { 104 FrameScope scope(masm, StackFrame::INTERNAL); 105 __ CallRuntime(Runtime::kHandleDebuggerStatement, 0); 106 } 107 __ MaybeDropFrames(); 108 109 // Return to caller. 110 __ ret(0); 111 } 112 113 void DebugCodegen::GenerateFrameDropperTrampoline(MacroAssembler* masm) { 114 // Frame is being dropped: 115 // - Drop to the target frame specified by ebx. 116 // - Look up current function on the frame. 117 // - Leave the frame. 118 // - Restart the frame by calling the function. 119 __ mov(ebp, ebx); 120 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 121 __ leave(); 122 123 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 124 __ mov(ebx, 125 FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset)); 126 127 ParameterCount dummy(ebx); 128 __ InvokeFunction(edi, dummy, dummy, JUMP_FUNCTION, 129 CheckDebugStepCallWrapper()); 130 } 131 132 133 const bool LiveEdit::kFrameDropperSupported = true; 134 135 #undef __ 136 137 } // namespace internal 138 } // namespace v8 139 140 #endif // V8_TARGET_ARCH_IA32 141