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