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/debug/debug.h" | 5 #include "src/debug/debug.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
11 #include "src/codegen.h" | 11 #include "src/codegen.h" |
12 #include "src/compilation-cache.h" | 12 #include "src/compilation-cache.h" |
13 #include "src/compiler.h" | 13 #include "src/compiler.h" |
14 #include "src/deoptimizer.h" | 14 #include "src/deoptimizer.h" |
15 #include "src/execution.h" | 15 #include "src/execution.h" |
16 #include "src/frames-inl.h" | 16 #include "src/frames-inl.h" |
17 #include "src/full-codegen/full-codegen.h" | 17 #include "src/full-codegen/full-codegen.h" |
18 #include "src/global-handles.h" | 18 #include "src/global-handles.h" |
19 #include "src/interpreter/bytecodes.h" | 19 #include "src/interpreter/bytecodes.h" |
20 #include "src/interpreter/interpreter.h" | |
20 #include "src/isolate-inl.h" | 21 #include "src/isolate-inl.h" |
21 #include "src/list.h" | 22 #include "src/list.h" |
22 #include "src/log.h" | 23 #include "src/log.h" |
23 #include "src/messages.h" | 24 #include "src/messages.h" |
24 #include "src/snapshot/natives.h" | 25 #include "src/snapshot/natives.h" |
25 | 26 |
26 #include "include/v8-debug.h" | 27 #include "include/v8-debug.h" |
27 | 28 |
28 namespace v8 { | 29 namespace v8 { |
29 namespace internal { | 30 namespace internal { |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
202 break; | 203 break; |
203 } | 204 } |
204 } | 205 } |
205 } | 206 } |
206 | 207 |
207 BreakLocation::DebugBreakType | 208 BreakLocation::DebugBreakType |
208 BreakLocation::BytecodeArrayIterator::GetDebugBreakType() { | 209 BreakLocation::BytecodeArrayIterator::GetDebugBreakType() { |
209 BytecodeArray* bytecode_array = | 210 BytecodeArray* bytecode_array = |
210 debug_info_->abstract_code()->GetBytecodeArray(); | 211 debug_info_->abstract_code()->GetBytecodeArray(); |
211 interpreter::Bytecode bytecode = | 212 interpreter::Bytecode bytecode = |
212 static_cast<interpreter::Bytecode>(bytecode_array->get(code_offset())); | 213 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); |
213 | 214 |
214 if (bytecode == interpreter::Bytecode::kDebugger) { | 215 if (bytecode == interpreter::Bytecode::kDebugger) { |
215 return DEBUGGER_STATEMENT; | 216 return DEBUGGER_STATEMENT; |
216 } else if (bytecode == interpreter::Bytecode::kReturn) { | 217 } else if (bytecode == interpreter::Bytecode::kReturn) { |
217 return DEBUG_BREAK_SLOT_AT_RETURN; | 218 return DEBUG_BREAK_SLOT_AT_RETURN; |
218 } else if (interpreter::Bytecodes::IsCallOrNew(bytecode)) { | 219 } else if (interpreter::Bytecodes::IsCallOrNew(bytecode)) { |
219 return DEBUG_BREAK_SLOT_AT_CALL; | 220 return DEBUG_BREAK_SLOT_AT_CALL; |
220 } else if (source_position_iterator_.is_statement()) { | 221 } else if (source_position_iterator_.is_statement()) { |
221 return DEBUG_BREAK_SLOT; | 222 return DEBUG_BREAK_SLOT; |
222 } else { | 223 } else { |
223 return NOT_DEBUG_BREAK; | 224 return NOT_DEBUG_BREAK; |
224 } | 225 } |
225 } | 226 } |
226 | 227 |
227 BreakLocation BreakLocation::BytecodeArrayIterator::GetBreakLocation() { | 228 BreakLocation BreakLocation::BytecodeArrayIterator::GetBreakLocation() { |
228 return BreakLocation(debug_info_, GetDebugBreakType(), code_offset(), | 229 return BreakLocation(debug_info_, GetDebugBreakType(), code_offset(), |
229 position(), statement_position()); | 230 position(), statement_position()); |
230 } | 231 } |
231 | 232 |
232 // Find the break point at the supplied address, or the closest one before | 233 // Find the break point at the supplied address, or the closest one before |
233 // the address. | 234 // the address. |
234 BreakLocation BreakLocation::FromCodeOffset(Handle<DebugInfo> debug_info, | 235 BreakLocation BreakLocation::FromCodeOffset(Handle<DebugInfo> debug_info, |
235 int offset) { | 236 int offset) { |
236 base::SmartPointer<Iterator> it(GetIterator(debug_info)); | 237 base::SmartPointer<Iterator> it(GetIterator(debug_info)); |
237 it->SkipTo(BreakIndexFromCodeOffset(debug_info, offset)); | 238 it->SkipTo(BreakIndexFromCodeOffset(debug_info, offset)); |
238 return it->GetBreakLocation(); | 239 return it->GetBreakLocation(); |
239 } | 240 } |
240 | 241 |
241 // Move GetFirstFrameSummary Definition to here as FromFrame use it. | |
242 FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) { | 242 FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) { |
243 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); | 243 List<FrameSummary> frames(FLAG_max_inlining_levels + 1); |
244 frame->Summarize(&frames); | 244 frame->Summarize(&frames); |
245 return frames.first(); | 245 return frames.first(); |
246 } | 246 } |
247 | 247 |
248 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, | 248 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, |
249 JavaScriptFrame* frame) { | 249 JavaScriptFrame* frame) { |
250 // Code offset to the instruction after the current one, possibly a break | 250 // Code offset points to the instruction after the call. Subtract 1 to |
251 // location as well. So the "- 1" to exclude it from the search. | 251 // exclude that instruction from the search. For bytecode, the code offset |
252 // Get code offset from the unoptimized code. | 252 // still points to the call. |
253 FrameSummary summary = GetFirstFrameSummary(frame); | 253 FrameSummary summary = GetFirstFrameSummary(frame); |
254 return FromCodeOffset(debug_info, summary.code_offset() - 1); | 254 int call_offset = summary.code_offset(); |
255 if (!frame->is_interpreted()) call_offset--; | |
256 return FromCodeOffset(debug_info, call_offset); | |
255 } | 257 } |
256 | 258 |
257 // Find the break point at the supplied address, or the closest one before | 259 // Find the break point at the supplied address, or the closest one before |
258 // the address. | 260 // the address. |
259 void BreakLocation::FromCodeOffsetSameStatement( | 261 void BreakLocation::FromCodeOffsetSameStatement( |
260 Handle<DebugInfo> debug_info, int offset, List<BreakLocation>* result_out) { | 262 Handle<DebugInfo> debug_info, int offset, List<BreakLocation>* result_out) { |
261 int break_index = BreakIndexFromCodeOffset(debug_info, offset); | 263 int break_index = BreakIndexFromCodeOffset(debug_info, offset); |
262 base::SmartPointer<Iterator> it(GetIterator(debug_info)); | 264 base::SmartPointer<Iterator> it(GetIterator(debug_info)); |
263 it->SkipTo(break_index); | 265 it->SkipTo(break_index); |
264 int statement_position = it->statement_position(); | 266 int statement_position = it->statement_position(); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
393 | 395 |
394 DCHECK(IsDebugBreakSlot()); | 396 DCHECK(IsDebugBreakSlot()); |
395 if (abstract_code()->IsCode()) { | 397 if (abstract_code()->IsCode()) { |
396 Code* code = abstract_code()->GetCode(); | 398 Code* code = abstract_code()->GetCode(); |
397 DCHECK(code->kind() == Code::FUNCTION); | 399 DCHECK(code->kind() == Code::FUNCTION); |
398 Builtins* builtins = isolate()->builtins(); | 400 Builtins* builtins = isolate()->builtins(); |
399 Handle<Code> target = IsReturn() ? builtins->Return_DebugBreak() | 401 Handle<Code> target = IsReturn() ? builtins->Return_DebugBreak() |
400 : builtins->Slot_DebugBreak(); | 402 : builtins->Slot_DebugBreak(); |
401 Address pc = code->instruction_start() + code_offset(); | 403 Address pc = code->instruction_start() + code_offset(); |
402 DebugCodegen::PatchDebugBreakSlot(isolate(), pc, target); | 404 DebugCodegen::PatchDebugBreakSlot(isolate(), pc, target); |
403 DCHECK(IsDebugBreak()); | |
404 } else { | 405 } else { |
405 // TODO(yangguo): implement this once we have a way to record break points. | 406 BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray(); |
Yang
2016/02/16 09:22:20
We may eventually want to move to a representation
| |
407 interpreter::Bytecode bytecode = | |
408 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); | |
409 interpreter::Bytecode debugbreak = | |
410 interpreter::Bytecodes::GetDebugBreak(bytecode); | |
411 bytecode_array->set(code_offset(), | |
412 interpreter::Bytecodes::ToByte(debugbreak)); | |
406 } | 413 } |
414 DCHECK(IsDebugBreak()); | |
407 } | 415 } |
408 | 416 |
409 | 417 |
410 void BreakLocation::ClearDebugBreak() { | 418 void BreakLocation::ClearDebugBreak() { |
411 // Debugger statement always calls debugger. No need to modify it. | 419 // Debugger statement always calls debugger. No need to modify it. |
412 if (IsDebuggerStatement()) return; | 420 if (IsDebuggerStatement()) return; |
413 | 421 |
414 DCHECK(IsDebugBreakSlot()); | 422 DCHECK(IsDebugBreakSlot()); |
415 if (abstract_code()->IsCode()) { | 423 if (abstract_code()->IsCode()) { |
416 Code* code = abstract_code()->GetCode(); | 424 Code* code = abstract_code()->GetCode(); |
417 DCHECK(code->kind() == Code::FUNCTION); | 425 DCHECK(code->kind() == Code::FUNCTION); |
418 Address pc = code->instruction_start() + code_offset(); | 426 Address pc = code->instruction_start() + code_offset(); |
419 DebugCodegen::ClearDebugBreakSlot(isolate(), pc); | 427 DebugCodegen::ClearDebugBreakSlot(isolate(), pc); |
420 DCHECK(!IsDebugBreak()); | |
421 } else { | 428 } else { |
422 // TODO(yangguo): implement this once we have a way to record break points. | 429 BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray(); |
430 BytecodeArray* original = debug_info_->shared()->bytecode_array(); | |
431 bytecode_array->set(code_offset(), original->get(code_offset())); | |
423 } | 432 } |
433 DCHECK(!IsDebugBreak()); | |
424 } | 434 } |
425 | 435 |
426 | 436 |
427 bool BreakLocation::IsDebugBreak() const { | 437 bool BreakLocation::IsDebugBreak() const { |
428 if (IsDebuggerStatement()) return false; | 438 if (IsDebuggerStatement()) return false; |
429 DCHECK(IsDebugBreakSlot()); | 439 DCHECK(IsDebugBreakSlot()); |
430 if (abstract_code()->IsCode()) { | 440 if (abstract_code()->IsCode()) { |
431 Code* code = abstract_code()->GetCode(); | 441 Code* code = abstract_code()->GetCode(); |
432 DCHECK(code->kind() == Code::FUNCTION); | 442 DCHECK(code->kind() == Code::FUNCTION); |
433 Address pc = code->instruction_start() + code_offset(); | 443 Address pc = code->instruction_start() + code_offset(); |
434 return DebugCodegen::DebugBreakSlotIsPatched(pc); | 444 return DebugCodegen::DebugBreakSlotIsPatched(pc); |
435 } else { | 445 } else { |
436 // TODO(yangguo): implement this once we have a way to record break points. | 446 BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray(); |
437 return false; | 447 interpreter::Bytecode bytecode = |
448 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); | |
449 return interpreter::Bytecodes::IsDebugBreak(bytecode); | |
438 } | 450 } |
439 } | 451 } |
440 | 452 |
441 | 453 |
442 Handle<Object> BreakLocation::BreakPointObjects() const { | 454 Handle<Object> BreakLocation::BreakPointObjects() const { |
443 return debug_info_->GetBreakPointObjects(code_offset_); | 455 return debug_info_->GetBreakPointObjects(code_offset_); |
444 } | 456 } |
445 | 457 |
446 void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) { | 458 void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) { |
447 uint32_t mask = 1 << feature; | 459 uint32_t mask = 1 << feature; |
(...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
992 // Return if ensuring debug info failed. | 1004 // Return if ensuring debug info failed. |
993 return; | 1005 return; |
994 } | 1006 } |
995 | 1007 |
996 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 1008 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
997 // Refresh frame summary if the code has been recompiled for debugging. | 1009 // Refresh frame summary if the code has been recompiled for debugging. |
998 if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) { | 1010 if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) { |
999 summary = GetFirstFrameSummary(frame); | 1011 summary = GetFirstFrameSummary(frame); |
1000 } | 1012 } |
1001 | 1013 |
1002 // PC points to the instruction after the current one, possibly a break | 1014 // Code offset points to the instruction after the call. Subtract 1 to |
1003 // location as well. So the "- 1" to exclude it from the search. | 1015 // exclude that instruction from the search. For bytecode, the code offset |
1016 // still points to the call. | |
1017 int call_offset = summary.code_offset(); | |
1018 if (!frame->is_interpreted()) call_offset--; | |
rmcilroy
2016/02/16 10:46:38
Could you extract this code into a helper - it's r
Yang
2016/02/19 13:09:17
Done.
| |
1004 BreakLocation location = | 1019 BreakLocation location = |
1005 BreakLocation::FromCodeOffset(debug_info, summary.code_offset() - 1); | 1020 BreakLocation::FromCodeOffset(debug_info, call_offset); |
1006 | 1021 |
1007 // At a return statement we will step out either way. | 1022 // At a return statement we will step out either way. |
1008 if (location.IsReturn()) step_action = StepOut; | 1023 if (location.IsReturn()) step_action = StepOut; |
1009 | 1024 |
1010 thread_local_.last_statement_position_ = | 1025 thread_local_.last_statement_position_ = |
1011 debug_info->abstract_code()->SourceStatementPosition( | 1026 debug_info->abstract_code()->SourceStatementPosition( |
1012 summary.code_offset()); | 1027 summary.code_offset()); |
1013 thread_local_.last_fp_ = frame->UnpaddedFP(); | 1028 thread_local_.last_fp_ = frame->UnpaddedFP(); |
1014 | 1029 |
1015 switch (step_action) { | 1030 switch (step_action) { |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1516 DebugInfoListNode* current = debug_info_list_; | 1531 DebugInfoListNode* current = debug_info_list_; |
1517 while (current != NULL) { | 1532 while (current != NULL) { |
1518 if (current->debug_info().is_identical_to(debug_info)) { | 1533 if (current->debug_info().is_identical_to(debug_info)) { |
1519 // Unlink from list. If prev is NULL we are looking at the first element. | 1534 // Unlink from list. If prev is NULL we are looking at the first element. |
1520 if (prev == NULL) { | 1535 if (prev == NULL) { |
1521 debug_info_list_ = current->next(); | 1536 debug_info_list_ = current->next(); |
1522 } else { | 1537 } else { |
1523 prev->set_next(current->next()); | 1538 prev->set_next(current->next()); |
1524 } | 1539 } |
1525 delete current; | 1540 delete current; |
1526 shared->set_debug_info(isolate_->heap()->undefined_value()); | 1541 shared->set_debug_info(DebugInfo::uninitialized()); |
1527 return; | 1542 return; |
1528 } | 1543 } |
1529 // Move to next in list. | 1544 // Move to next in list. |
1530 prev = current; | 1545 prev = current; |
1531 current = current->next(); | 1546 current = current->next(); |
1532 } | 1547 } |
1533 | 1548 |
1534 UNREACHABLE(); | 1549 UNREACHABLE(); |
1535 } | 1550 } |
1536 | 1551 |
1537 | 1552 Object* Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { |
1538 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { | 1553 if (frame->is_interpreted()) { |
1539 after_break_target_ = NULL; | 1554 // Find the handler from the original bytecode array. |
1540 | 1555 InterpretedFrame* interpreted_frame = |
1541 if (LiveEdit::SetAfterBreakTarget(this)) return; // LiveEdit did the job. | 1556 reinterpret_cast<InterpretedFrame*>(frame); |
1542 | 1557 SharedFunctionInfo* shared = interpreted_frame->function()->shared(); |
1543 // Continue just after the slot. | 1558 BytecodeArray* bytecode_array = shared->bytecode_array(); |
1544 after_break_target_ = frame->pc(); | 1559 int bytecode_offset = interpreted_frame->GetBytecodeOffset(); |
1560 interpreter::Bytecode bytecode = | |
1561 interpreter::Bytecodes::FromByte(bytecode_array->get(bytecode_offset)); | |
1562 return isolate_->interpreter()->GetHandler(bytecode); | |
1563 } else { | |
1564 after_break_target_ = NULL; | |
1565 if (!LiveEdit::SetAfterBreakTarget(this)) { | |
1566 // Continue just after the slot. | |
1567 after_break_target_ = frame->pc(); | |
1568 } | |
1569 return isolate_->heap()->undefined_value(); | |
1570 } | |
1545 } | 1571 } |
1546 | 1572 |
1547 | 1573 |
1548 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { | 1574 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { |
1549 HandleScope scope(isolate_); | 1575 HandleScope scope(isolate_); |
1550 | 1576 |
1551 // Get the executing function in which the debug break occurred. | 1577 // Get the executing function in which the debug break occurred. |
1552 Handle<JSFunction> function(JSFunction::cast(frame->function())); | 1578 Handle<JSFunction> function(JSFunction::cast(frame->function())); |
1553 Handle<SharedFunctionInfo> shared(function->shared()); | 1579 Handle<SharedFunctionInfo> shared(function->shared()); |
1554 | 1580 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1616 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared()); | 1642 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared()); |
1617 | 1643 |
1618 if (!EnsureDebugInfo(shared, fun)) return; | 1644 if (!EnsureDebugInfo(shared, fun)) return; |
1619 | 1645 |
1620 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 1646 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
1621 // Refresh frame summary if the code has been recompiled for debugging. | 1647 // Refresh frame summary if the code has been recompiled for debugging. |
1622 if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) { | 1648 if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) { |
1623 summary = GetFirstFrameSummary(frame); | 1649 summary = GetFirstFrameSummary(frame); |
1624 } | 1650 } |
1625 | 1651 |
1626 // Find range of break points starting from the break point where execution | 1652 // Code offset points to the instruction after the call. Subtract 1 to |
1627 // has stopped. The code offset points to the instruction after the current | 1653 // exclude that instruction from the search. For bytecode, the code offset |
1628 // possibly a break location, too. Subtract one to exclude it from the search. | 1654 // still points to the call. |
1629 int call_offset = summary.code_offset() - 1; | 1655 int call_offset = summary.code_offset(); |
1656 if (!frame->is_interpreted()) call_offset--; | |
1630 List<BreakLocation> locations; | 1657 List<BreakLocation> locations; |
1631 BreakLocation::FromCodeOffsetSameStatement(debug_info, call_offset, | 1658 BreakLocation::FromCodeOffsetSameStatement(debug_info, call_offset, |
1632 &locations); | 1659 &locations); |
1633 | 1660 |
1634 for (BreakLocation location : locations) { | 1661 for (BreakLocation location : locations) { |
1635 if (location.code_offset() <= summary.code_offset()) { | 1662 if (location.code_offset() <= summary.code_offset()) { |
1636 // The break point is near our pc. Could be a step-in possibility, | 1663 // The break point is near our pc. Could be a step-in possibility, |
1637 // that is currently taken by active debugger call. | 1664 // that is currently taken by active debugger call. |
1638 if (break_frame_id() == StackFrame::NO_ID) { | 1665 if (break_frame_id() == StackFrame::NO_ID) { |
1639 continue; // We are not stepping. | 1666 continue; // We are not stepping. |
(...skipping 929 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2569 } | 2596 } |
2570 | 2597 |
2571 | 2598 |
2572 void LockingCommandMessageQueue::Clear() { | 2599 void LockingCommandMessageQueue::Clear() { |
2573 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 2600 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
2574 queue_.Clear(); | 2601 queue_.Clear(); |
2575 } | 2602 } |
2576 | 2603 |
2577 } // namespace internal | 2604 } // namespace internal |
2578 } // namespace v8 | 2605 } // namespace v8 |
OLD | NEW |