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

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: rebase 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
« no previous file with comments | « src/debug/debug.h ('k') | src/debug/debug-frames.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/debug/debug.h ('k') | src/debug/debug-frames.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698