Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: src/debug/debug.cc

Issue 1703453002: [interpreter, debugger] support debug breaks via bytecode array copy (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698