| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
| 8 | 8 |
| 9 #include "src/assembler.h" | 9 #include "src/assembler.h" |
| 10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
| 11 #include "src/debug.h" | 11 #include "src/debug.h" |
| 12 | 12 |
| 13 | 13 |
| 14 namespace v8 { | 14 namespace v8 { |
| 15 namespace internal { | 15 namespace internal { |
| 16 | 16 |
| 17 bool BreakLocationIterator::IsDebugBreakAtReturn() { | 17 bool BreakLocationIterator::IsDebugBreakAtReturn() { |
| 18 return Debug::IsDebugBreakAtReturn(rinfo()); | 18 return Debug::IsDebugBreakAtReturn(rinfo()); |
| 19 } | 19 } |
| 20 | 20 |
| 21 | 21 |
| 22 // Patch the JS frame exit code with a debug break call. See | 22 // Patch the JS frame exit code with a debug break call. See |
| 23 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc | 23 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x64.cc |
| 24 // for the precise return instructions sequence. | 24 // for the precise return instructions sequence. |
| 25 void BreakLocationIterator::SetDebugBreakAtReturn() { | 25 void BreakLocationIterator::SetDebugBreakAtReturn() { |
| 26 ASSERT(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength); | 26 DCHECK(Assembler::kJSReturnSequenceLength >= Assembler::kCallSequenceLength); |
| 27 rinfo()->PatchCodeWithCall( | 27 rinfo()->PatchCodeWithCall( |
| 28 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(), | 28 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(), |
| 29 Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength); | 29 Assembler::kJSReturnSequenceLength - Assembler::kCallSequenceLength); |
| 30 } | 30 } |
| 31 | 31 |
| 32 | 32 |
| 33 // Restore the JS frame exit code. | 33 // Restore the JS frame exit code. |
| 34 void BreakLocationIterator::ClearDebugBreakAtReturn() { | 34 void BreakLocationIterator::ClearDebugBreakAtReturn() { |
| 35 rinfo()->PatchCode(original_rinfo()->pc(), | 35 rinfo()->PatchCode(original_rinfo()->pc(), |
| 36 Assembler::kJSReturnSequenceLength); | 36 Assembler::kJSReturnSequenceLength); |
| 37 } | 37 } |
| 38 | 38 |
| 39 | 39 |
| 40 // A debug break in the frame exit code is identified by the JS frame exit code | 40 // A debug break in the frame exit code is identified by the JS frame exit code |
| 41 // having been patched with a call instruction. | 41 // having been patched with a call instruction. |
| 42 bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) { | 42 bool Debug::IsDebugBreakAtReturn(v8::internal::RelocInfo* rinfo) { |
| 43 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode())); | 43 DCHECK(RelocInfo::IsJSReturn(rinfo->rmode())); |
| 44 return rinfo->IsPatchedReturnSequence(); | 44 return rinfo->IsPatchedReturnSequence(); |
| 45 } | 45 } |
| 46 | 46 |
| 47 | 47 |
| 48 bool BreakLocationIterator::IsDebugBreakAtSlot() { | 48 bool BreakLocationIterator::IsDebugBreakAtSlot() { |
| 49 ASSERT(IsDebugBreakSlot()); | 49 DCHECK(IsDebugBreakSlot()); |
| 50 // Check whether the debug break slot instructions have been patched. | 50 // Check whether the debug break slot instructions have been patched. |
| 51 return rinfo()->IsPatchedDebugBreakSlotSequence(); | 51 return rinfo()->IsPatchedDebugBreakSlotSequence(); |
| 52 } | 52 } |
| 53 | 53 |
| 54 | 54 |
| 55 void BreakLocationIterator::SetDebugBreakAtSlot() { | 55 void BreakLocationIterator::SetDebugBreakAtSlot() { |
| 56 ASSERT(IsDebugBreakSlot()); | 56 DCHECK(IsDebugBreakSlot()); |
| 57 rinfo()->PatchCodeWithCall( | 57 rinfo()->PatchCodeWithCall( |
| 58 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(), | 58 debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry(), |
| 59 Assembler::kDebugBreakSlotLength - Assembler::kCallSequenceLength); | 59 Assembler::kDebugBreakSlotLength - Assembler::kCallSequenceLength); |
| 60 } | 60 } |
| 61 | 61 |
| 62 | 62 |
| 63 void BreakLocationIterator::ClearDebugBreakAtSlot() { | 63 void BreakLocationIterator::ClearDebugBreakAtSlot() { |
| 64 ASSERT(IsDebugBreakSlot()); | 64 DCHECK(IsDebugBreakSlot()); |
| 65 rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength); | 65 rinfo()->PatchCode(original_rinfo()->pc(), Assembler::kDebugBreakSlotLength); |
| 66 } | 66 } |
| 67 | 67 |
| 68 | 68 |
| 69 #define __ ACCESS_MASM(masm) | 69 #define __ ACCESS_MASM(masm) |
| 70 | 70 |
| 71 | 71 |
| 72 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, | 72 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, |
| 73 RegList object_regs, | 73 RegList object_regs, |
| 74 RegList non_object_regs, | 74 RegList non_object_regs, |
| 75 bool convert_call_to_jmp) { | 75 bool convert_call_to_jmp) { |
| 76 // Enter an internal frame. | 76 // Enter an internal frame. |
| 77 { | 77 { |
| 78 FrameScope scope(masm, StackFrame::INTERNAL); | 78 FrameScope scope(masm, StackFrame::INTERNAL); |
| 79 | 79 |
| 80 // Load padding words on stack. | 80 // Load padding words on stack. |
| 81 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { | 81 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { |
| 82 __ Push(Smi::FromInt(LiveEdit::kFramePaddingValue)); | 82 __ Push(Smi::FromInt(LiveEdit::kFramePaddingValue)); |
| 83 } | 83 } |
| 84 __ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); | 84 __ Push(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)); |
| 85 | 85 |
| 86 // Store the registers containing live values on the expression stack to | 86 // Store the registers containing live values on the expression stack to |
| 87 // make sure that these are correctly updated during GC. Non object values | 87 // make sure that these are correctly updated during GC. Non object values |
| 88 // are stored as as two smis causing it to be untouched by GC. | 88 // are stored as as two smis causing it to be untouched by GC. |
| 89 ASSERT((object_regs & ~kJSCallerSaved) == 0); | 89 DCHECK((object_regs & ~kJSCallerSaved) == 0); |
| 90 ASSERT((non_object_regs & ~kJSCallerSaved) == 0); | 90 DCHECK((non_object_regs & ~kJSCallerSaved) == 0); |
| 91 ASSERT((object_regs & non_object_regs) == 0); | 91 DCHECK((object_regs & non_object_regs) == 0); |
| 92 for (int i = 0; i < kNumJSCallerSaved; i++) { | 92 for (int i = 0; i < kNumJSCallerSaved; i++) { |
| 93 int r = JSCallerSavedCode(i); | 93 int r = JSCallerSavedCode(i); |
| 94 Register reg = { r }; | 94 Register reg = { r }; |
| 95 ASSERT(!reg.is(kScratchRegister)); | 95 DCHECK(!reg.is(kScratchRegister)); |
| 96 if ((object_regs & (1 << r)) != 0) { | 96 if ((object_regs & (1 << r)) != 0) { |
| 97 __ Push(reg); | 97 __ Push(reg); |
| 98 } | 98 } |
| 99 if ((non_object_regs & (1 << r)) != 0) { | 99 if ((non_object_regs & (1 << r)) != 0) { |
| 100 __ PushRegisterAsTwoSmis(reg); | 100 __ PushRegisterAsTwoSmis(reg); |
| 101 } | 101 } |
| 102 } | 102 } |
| 103 | 103 |
| 104 #ifdef DEBUG | 104 #ifdef DEBUG |
| 105 __ RecordComment("// Calling from debug break to runtime - come in - over"); | 105 __ RecordComment("// Calling from debug break to runtime - come in - over"); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 248 rax.bit(), false); | 248 rax.bit(), false); |
| 249 } | 249 } |
| 250 | 250 |
| 251 | 251 |
| 252 void DebugCodegen::GenerateSlot(MacroAssembler* masm) { | 252 void DebugCodegen::GenerateSlot(MacroAssembler* masm) { |
| 253 // Generate enough nop's to make space for a call instruction. | 253 // Generate enough nop's to make space for a call instruction. |
| 254 Label check_codesize; | 254 Label check_codesize; |
| 255 __ bind(&check_codesize); | 255 __ bind(&check_codesize); |
| 256 __ RecordDebugBreakSlot(); | 256 __ RecordDebugBreakSlot(); |
| 257 __ Nop(Assembler::kDebugBreakSlotLength); | 257 __ Nop(Assembler::kDebugBreakSlotLength); |
| 258 ASSERT_EQ(Assembler::kDebugBreakSlotLength, | 258 DCHECK_EQ(Assembler::kDebugBreakSlotLength, |
| 259 masm->SizeOfCodeGeneratedSince(&check_codesize)); | 259 masm->SizeOfCodeGeneratedSince(&check_codesize)); |
| 260 } | 260 } |
| 261 | 261 |
| 262 | 262 |
| 263 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) { | 263 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) { |
| 264 // In the places where a debug break slot is inserted no registers can contain | 264 // In the places where a debug break slot is inserted no registers can contain |
| 265 // object pointers. | 265 // object pointers. |
| 266 Generate_DebugBreakCallHelper(masm, 0, 0, true); | 266 Generate_DebugBreakCallHelper(masm, 0, 0, true); |
| 267 } | 267 } |
| 268 | 268 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 297 __ jmp(rdx); | 297 __ jmp(rdx); |
| 298 } | 298 } |
| 299 | 299 |
| 300 const bool LiveEdit::kFrameDropperSupported = true; | 300 const bool LiveEdit::kFrameDropperSupported = true; |
| 301 | 301 |
| 302 #undef __ | 302 #undef __ |
| 303 | 303 |
| 304 } } // namespace v8::internal | 304 } } // namespace v8::internal |
| 305 | 305 |
| 306 #endif // V8_TARGET_ARCH_X64 | 306 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |