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 3// found in the LICENSE file. 4 5#include "src/debug/debug.h" 6 7#include <memory> 8 9#include "src/api.h" 10#include "src/arguments.h" 11#include "src/bootstrapper.h" 12#include "src/code-stubs.h" 13#include "src/codegen.h" 14#include "src/compilation-cache.h" 15#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" 16#include "src/compiler.h" 17#include "src/debug/liveedit.h" 18#include "src/deoptimizer.h" 19#include "src/execution.h" 20#include "src/frames-inl.h" 21#include "src/full-codegen/full-codegen.h" 22#include "src/global-handles.h" 23#include "src/globals.h" 24#include "src/interpreter/interpreter.h" 25#include "src/isolate-inl.h" 26#include "src/list.h" 27#include "src/log.h" 28#include "src/messages.h" 29#include "src/snapshot/natives.h" 30#include "src/wasm/wasm-module.h" 31 32#include "include/v8-debug.h" 33 34namespace v8 { 35namespace internal { 36 37Debug::Debug(Isolate* isolate) 38 : debug_context_(Handle<Context>()), 39 event_listener_(Handle<Object>()), 40 event_listener_data_(Handle<Object>()), 41 message_handler_(NULL), 42 command_received_(0), 43 command_queue_(isolate->logger(), kQueueInitialSize), 44 is_active_(false), 45 is_suppressed_(false), 46 live_edit_enabled_(true), // TODO(yangguo): set to false by default. 47 break_disabled_(false), 48 break_points_active_(true), 49 in_debug_event_listener_(false), 50 break_on_exception_(false), 51 break_on_uncaught_exception_(false), 52 debug_info_list_(NULL), 53 feature_tracker_(isolate), 54 isolate_(isolate) { 55 ThreadInit(); 56} 57 58BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, 59 JavaScriptFrame* frame) { 60 FrameSummary summary = FrameSummary::GetFirst(frame); 61 int offset = summary.code_offset(); 62 Handle<AbstractCode> abstract_code = summary.abstract_code(); 63 if (abstract_code->IsCode()) offset = offset - 1; 64 auto it = BreakIterator::GetIterator(debug_info, abstract_code); 65 it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset)); 66 return it->GetBreakLocation(); 67} 68 69void BreakLocation::AllAtCurrentStatement(Handle<DebugInfo> debug_info, 70 JavaScriptFrame* frame, 71 List<BreakLocation>* result_out) { 72 FrameSummary summary = FrameSummary::GetFirst(frame); 73 int offset = summary.code_offset(); 74 Handle<AbstractCode> abstract_code = summary.abstract_code(); 75 if (abstract_code->IsCode()) offset = offset - 1; 76 int statement_position; 77 { 78 auto it = BreakIterator::GetIterator(debug_info, abstract_code); 79 it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset)); 80 statement_position = it->statement_position(); 81 } 82 for (auto it = BreakIterator::GetIterator(debug_info, abstract_code); 83 !it->Done(); it->Next()) { 84 if (it->statement_position() == statement_position) { 85 result_out->Add(it->GetBreakLocation()); 86 } 87 } 88} 89 90int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, 91 Handle<AbstractCode> abstract_code, 92 int offset) { 93 // Run through all break points to locate the one closest to the address. 94 int closest_break = 0; 95 int distance = kMaxInt; 96 DCHECK(0 <= offset && offset < abstract_code->Size()); 97 for (auto it = BreakIterator::GetIterator(debug_info, abstract_code); 98 !it->Done(); it->Next()) { 99 // Check if this break point is closer that what was previously found. 100 if (it->code_offset() <= offset && offset - it->code_offset() < distance) { 101 closest_break = it->break_index(); 102 distance = offset - it->code_offset(); 103 // Check whether we can't get any closer. 104 if (distance == 0) break; 105 } 106 } 107 return closest_break; 108} 109 110bool BreakLocation::HasBreakPoint(Handle<DebugInfo> debug_info) const { 111 // First check whether there is a break point with the same source position. 112 if (!debug_info->HasBreakPoint(position_)) return false; 113 // Then check whether a break point at that source position would have 114 // the same code offset. Otherwise it's just a break location that we can 115 // step to, but not actually a location where we can put a break point. 116 if (abstract_code_->IsCode()) { 117 DCHECK_EQ(debug_info->DebugCode(), abstract_code_->GetCode()); 118 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 119 it.SkipToPosition(position_, BREAK_POSITION_ALIGNED); 120 return it.code_offset() == code_offset_; 121 } else { 122 DCHECK(abstract_code_->IsBytecodeArray()); 123 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 124 it.SkipToPosition(position_, BREAK_POSITION_ALIGNED); 125 return it.code_offset() == code_offset_; 126 } 127} 128 129std::unique_ptr<BreakIterator> BreakIterator::GetIterator( 130 Handle<DebugInfo> debug_info, Handle<AbstractCode> abstract_code, 131 BreakLocatorType type) { 132 if (abstract_code->IsBytecodeArray()) { 133 DCHECK(debug_info->HasDebugBytecodeArray()); 134 return std::unique_ptr<BreakIterator>( 135 new BytecodeArrayBreakIterator(debug_info, type)); 136 } else { 137 DCHECK(abstract_code->IsCode()); 138 DCHECK(debug_info->HasDebugCode()); 139 return std::unique_ptr<BreakIterator>( 140 new CodeBreakIterator(debug_info, type)); 141 } 142} 143 144BreakIterator::BreakIterator(Handle<DebugInfo> debug_info, 145 BreakLocatorType type) 146 : debug_info_(debug_info), break_index_(-1), break_locator_type_(type) { 147 position_ = debug_info->shared()->start_position(); 148 statement_position_ = position_; 149} 150 151int BreakIterator::BreakIndexFromPosition(int source_position, 152 BreakPositionAlignment alignment) { 153 int distance = kMaxInt; 154 int closest_break = break_index(); 155 while (!Done()) { 156 int next_position; 157 if (alignment == STATEMENT_ALIGNED) { 158 next_position = statement_position(); 159 } else { 160 DCHECK(alignment == BREAK_POSITION_ALIGNED); 161 next_position = position(); 162 } 163 if (source_position <= next_position && 164 next_position - source_position < distance) { 165 closest_break = break_index(); 166 distance = next_position - source_position; 167 // Check whether we can't get any closer. 168 if (distance == 0) break; 169 } 170 Next(); 171 } 172 return closest_break; 173} 174 175CodeBreakIterator::CodeBreakIterator(Handle<DebugInfo> debug_info, 176 BreakLocatorType type) 177 : BreakIterator(debug_info, type), 178 reloc_iterator_(debug_info->DebugCode(), GetModeMask(type)), 179 source_position_iterator_( 180 debug_info->DebugCode()->source_position_table()) { 181 // There is at least one break location. 182 DCHECK(!Done()); 183 Next(); 184} 185 186int CodeBreakIterator::GetModeMask(BreakLocatorType type) { 187 int mask = 0; 188 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); 189 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL); 190 if (isolate()->is_tail_call_elimination_enabled()) { 191 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL); 192 } 193 if (type == ALL_BREAK_LOCATIONS) { 194 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION); 195 mask |= RelocInfo::ModeMask(RelocInfo::DEBUGGER_STATEMENT); 196 } 197 return mask; 198} 199 200void CodeBreakIterator::Next() { 201 DisallowHeapAllocation no_gc; 202 DCHECK(!Done()); 203 204 // Iterate through reloc info stopping at each breakable code target. 205 bool first = break_index_ == -1; 206 207 if (!first) reloc_iterator_.next(); 208 first = false; 209 if (Done()) return; 210 211 int offset = code_offset(); 212 while (!source_position_iterator_.done() && 213 source_position_iterator_.code_offset() <= offset) { 214 position_ = source_position_iterator_.source_position().ScriptOffset(); 215 if (source_position_iterator_.is_statement()) { 216 statement_position_ = position_; 217 } 218 source_position_iterator_.Advance(); 219 } 220 221 DCHECK(RelocInfo::IsDebugBreakSlot(rmode()) || 222 RelocInfo::IsDebuggerStatement(rmode())); 223 break_index_++; 224} 225 226DebugBreakType CodeBreakIterator::GetDebugBreakType() { 227 if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) { 228 return DEBUG_BREAK_SLOT_AT_RETURN; 229 } else if (RelocInfo::IsDebugBreakSlotAtCall(rmode())) { 230 return DEBUG_BREAK_SLOT_AT_CALL; 231 } else if (RelocInfo::IsDebugBreakSlotAtTailCall(rmode())) { 232 return isolate()->is_tail_call_elimination_enabled() 233 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL 234 : DEBUG_BREAK_SLOT_AT_CALL; 235 } else if (RelocInfo::IsDebuggerStatement(rmode())) { 236 return DEBUGGER_STATEMENT; 237 } else if (RelocInfo::IsDebugBreakSlot(rmode())) { 238 return DEBUG_BREAK_SLOT; 239 } else { 240 return NOT_DEBUG_BREAK; 241 } 242} 243 244void CodeBreakIterator::SkipToPosition(int position, 245 BreakPositionAlignment alignment) { 246 CodeBreakIterator it(debug_info_, break_locator_type_); 247 SkipTo(it.BreakIndexFromPosition(position, alignment)); 248} 249 250void CodeBreakIterator::SetDebugBreak() { 251 DebugBreakType debug_break_type = GetDebugBreakType(); 252 if (debug_break_type == DEBUGGER_STATEMENT) return; 253 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); 254 Builtins* builtins = isolate()->builtins(); 255 Handle<Code> target = debug_break_type == DEBUG_BREAK_SLOT_AT_RETURN 256 ? builtins->Return_DebugBreak() 257 : builtins->Slot_DebugBreak(); 258 DebugCodegen::PatchDebugBreakSlot(isolate(), rinfo()->pc(), target); 259} 260 261void CodeBreakIterator::ClearDebugBreak() { 262 DebugBreakType debug_break_type = GetDebugBreakType(); 263 if (debug_break_type == DEBUGGER_STATEMENT) return; 264 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); 265 DebugCodegen::ClearDebugBreakSlot(isolate(), rinfo()->pc()); 266} 267 268bool CodeBreakIterator::IsDebugBreak() { 269 DebugBreakType debug_break_type = GetDebugBreakType(); 270 if (debug_break_type == DEBUGGER_STATEMENT) return false; 271 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); 272 return DebugCodegen::DebugBreakSlotIsPatched(rinfo()->pc()); 273} 274 275BreakLocation CodeBreakIterator::GetBreakLocation() { 276 Handle<AbstractCode> code(AbstractCode::cast(debug_info_->DebugCode())); 277 return BreakLocation(code, GetDebugBreakType(), code_offset(), position_); 278} 279 280BytecodeArrayBreakIterator::BytecodeArrayBreakIterator( 281 Handle<DebugInfo> debug_info, BreakLocatorType type) 282 : BreakIterator(debug_info, type), 283 source_position_iterator_( 284 debug_info->DebugBytecodeArray()->source_position_table()) { 285 // There is at least one break location. 286 DCHECK(!Done()); 287 Next(); 288} 289 290void BytecodeArrayBreakIterator::Next() { 291 DisallowHeapAllocation no_gc; 292 DCHECK(!Done()); 293 bool first = break_index_ == -1; 294 while (!Done()) { 295 if (!first) source_position_iterator_.Advance(); 296 first = false; 297 if (Done()) return; 298 position_ = source_position_iterator_.source_position().ScriptOffset(); 299 if (source_position_iterator_.is_statement()) { 300 statement_position_ = position_; 301 } 302 DCHECK(position_ >= 0); 303 DCHECK(statement_position_ >= 0); 304 305 DebugBreakType type = GetDebugBreakType(); 306 if (type == NOT_DEBUG_BREAK) continue; 307 308 if (break_locator_type_ == ALL_BREAK_LOCATIONS) break; 309 310 DCHECK_EQ(CALLS_AND_RETURNS, break_locator_type_); 311 if (type == DEBUG_BREAK_SLOT_AT_CALL) break; 312 if (type == DEBUG_BREAK_SLOT_AT_RETURN) break; 313 } 314 break_index_++; 315} 316 317DebugBreakType BytecodeArrayBreakIterator::GetDebugBreakType() { 318 BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray(); 319 interpreter::Bytecode bytecode = 320 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); 321 322 if (bytecode == interpreter::Bytecode::kDebugger) { 323 return DEBUGGER_STATEMENT; 324 } else if (bytecode == interpreter::Bytecode::kReturn) { 325 return DEBUG_BREAK_SLOT_AT_RETURN; 326 } else if (bytecode == interpreter::Bytecode::kTailCall) { 327 return isolate()->is_tail_call_elimination_enabled() 328 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL 329 : DEBUG_BREAK_SLOT_AT_CALL; 330 } else if (interpreter::Bytecodes::IsCallOrNew(bytecode)) { 331 return DEBUG_BREAK_SLOT_AT_CALL; 332 } else if (source_position_iterator_.is_statement()) { 333 return DEBUG_BREAK_SLOT; 334 } else { 335 return NOT_DEBUG_BREAK; 336 } 337} 338 339void BytecodeArrayBreakIterator::SkipToPosition( 340 int position, BreakPositionAlignment alignment) { 341 BytecodeArrayBreakIterator it(debug_info_, break_locator_type_); 342 SkipTo(it.BreakIndexFromPosition(position, alignment)); 343} 344 345void BytecodeArrayBreakIterator::SetDebugBreak() { 346 DebugBreakType debug_break_type = GetDebugBreakType(); 347 if (debug_break_type == DEBUGGER_STATEMENT) return; 348 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); 349 BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); 350 interpreter::Bytecode bytecode = 351 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); 352 if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return; 353 interpreter::Bytecode debugbreak = 354 interpreter::Bytecodes::GetDebugBreak(bytecode); 355 bytecode_array->set(code_offset(), 356 interpreter::Bytecodes::ToByte(debugbreak)); 357} 358 359void BytecodeArrayBreakIterator::ClearDebugBreak() { 360 DebugBreakType debug_break_type = GetDebugBreakType(); 361 if (debug_break_type == DEBUGGER_STATEMENT) return; 362 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); 363 BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); 364 BytecodeArray* original = debug_info_->OriginalBytecodeArray(); 365 bytecode_array->set(code_offset(), original->get(code_offset())); 366} 367 368bool BytecodeArrayBreakIterator::IsDebugBreak() { 369 DebugBreakType debug_break_type = GetDebugBreakType(); 370 if (debug_break_type == DEBUGGER_STATEMENT) return false; 371 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); 372 BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); 373 interpreter::Bytecode bytecode = 374 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); 375 return interpreter::Bytecodes::IsDebugBreak(bytecode); 376} 377 378BreakLocation BytecodeArrayBreakIterator::GetBreakLocation() { 379 Handle<AbstractCode> code( 380 AbstractCode::cast(debug_info_->DebugBytecodeArray())); 381 return BreakLocation(code, GetDebugBreakType(), code_offset(), position_); 382} 383 384 385void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) { 386 uint32_t mask = 1 << feature; 387 // Only count one sample per feature and isolate. 388 if (bitfield_ & mask) return; 389 isolate_->counters()->debug_feature_usage()->AddSample(feature); 390 bitfield_ |= mask; 391} 392 393 394// Threading support. 395void Debug::ThreadInit() { 396 thread_local_.break_count_ = 0; 397 thread_local_.break_id_ = 0; 398 thread_local_.break_frame_id_ = StackFrame::NO_ID; 399 thread_local_.last_step_action_ = StepNone; 400 thread_local_.last_statement_position_ = kNoSourcePosition; 401 thread_local_.last_fp_ = 0; 402 thread_local_.target_fp_ = 0; 403 thread_local_.return_value_ = Handle<Object>(); 404 clear_suspended_generator(); 405 // TODO(isolates): frames_are_dropped_? 406 base::NoBarrier_Store(&thread_local_.current_debug_scope_, 407 static_cast<base::AtomicWord>(0)); 408} 409 410 411char* Debug::ArchiveDebug(char* storage) { 412 // Simply reset state. Don't archive anything. 413 ThreadInit(); 414 return storage + ArchiveSpacePerThread(); 415} 416 417 418char* Debug::RestoreDebug(char* storage) { 419 // Simply reset state. Don't restore anything. 420 ThreadInit(); 421 return storage + ArchiveSpacePerThread(); 422} 423 424int Debug::ArchiveSpacePerThread() { return 0; } 425 426void Debug::Iterate(ObjectVisitor* v) { 427 v->VisitPointer(&thread_local_.suspended_generator_); 428} 429 430DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) { 431 // Globalize the request debug info object and make it weak. 432 GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles(); 433 debug_info_ = 434 Handle<DebugInfo>::cast(global_handles->Create(debug_info)).location(); 435} 436 437 438DebugInfoListNode::~DebugInfoListNode() { 439 if (debug_info_ == nullptr) return; 440 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_)); 441 debug_info_ = nullptr; 442} 443 444 445bool Debug::Load() { 446 // Return if debugger is already loaded. 447 if (is_loaded()) return true; 448 449 // Bail out if we're already in the process of compiling the native 450 // JavaScript source code for the debugger. 451 if (is_suppressed_) return false; 452 SuppressDebug while_loading(this); 453 454 // Disable breakpoints and interrupts while compiling and running the 455 // debugger scripts including the context creation code. 456 DisableBreak disable(this, true); 457 PostponeInterruptsScope postpone(isolate_); 458 459 // Create the debugger context. 460 HandleScope scope(isolate_); 461 ExtensionConfiguration no_extensions; 462 // TODO(yangguo): we rely on the fact that first context snapshot is usable 463 // as debug context. This dependency is gone once we remove 464 // debug context completely. 465 static const int kFirstContextSnapshotIndex = 0; 466 Handle<Context> context = isolate_->bootstrapper()->CreateEnvironment( 467 MaybeHandle<JSGlobalProxy>(), v8::Local<ObjectTemplate>(), &no_extensions, 468 kFirstContextSnapshotIndex, DEBUG_CONTEXT); 469 470 // Fail if no context could be created. 471 if (context.is_null()) return false; 472 473 debug_context_ = Handle<Context>::cast( 474 isolate_->global_handles()->Create(*context)); 475 476 feature_tracker()->Track(DebugFeatureTracker::kActive); 477 478 return true; 479} 480 481 482void Debug::Unload() { 483 ClearAllBreakPoints(); 484 ClearStepping(); 485 486 // Return debugger is not loaded. 487 if (!is_loaded()) return; 488 489 // Clear debugger context global handle. 490 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location()); 491 debug_context_ = Handle<Context>(); 492} 493 494void Debug::Break(JavaScriptFrame* frame) { 495 HandleScope scope(isolate_); 496 497 // Initialize LiveEdit. 498 LiveEdit::InitializeThreadLocal(this); 499 500 // Just continue if breaks are disabled or debugger cannot be loaded. 501 if (break_disabled()) return; 502 503 // Enter the debugger. 504 DebugScope debug_scope(this); 505 if (debug_scope.failed()) return; 506 507 // Postpone interrupt during breakpoint processing. 508 PostponeInterruptsScope postpone(isolate_); 509 510 // Get the debug info (create it if it does not exist). 511 Handle<JSFunction> function(frame->function()); 512 Handle<SharedFunctionInfo> shared(function->shared()); 513 if (!EnsureDebugInfo(shared, function)) { 514 // Return if we failed to retrieve the debug info. 515 return; 516 } 517 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); 518 519 // Find the break location where execution has stopped. 520 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); 521 522 // Find actual break points, if any, and trigger debug break event. 523 Handle<Object> break_points_hit = CheckBreakPoints(debug_info, &location); 524 if (!break_points_hit->IsUndefined(isolate_)) { 525 // Clear all current stepping setup. 526 ClearStepping(); 527 // Notify the debug event listeners. 528 OnDebugBreak(break_points_hit, false); 529 return; 530 } 531 532 // No break point. Check for stepping. 533 StepAction step_action = last_step_action(); 534 Address current_fp = frame->UnpaddedFP(); 535 Address target_fp = thread_local_.target_fp_; 536 Address last_fp = thread_local_.last_fp_; 537 538 bool step_break = false; 539 switch (step_action) { 540 case StepNone: 541 return; 542 case StepOut: 543 // Step out has not reached the target frame yet. 544 if (current_fp < target_fp) return; 545 step_break = true; 546 break; 547 case StepNext: 548 // Step next should not break in a deeper frame. 549 if (current_fp < target_fp) return; 550 // For step-next, a tail call is like a return and should break. 551 step_break = location.IsTailCall(); 552 // Fall through. 553 case StepIn: { 554 FrameSummary summary = FrameSummary::GetFirst(frame); 555 int offset = summary.code_offset(); 556 step_break = step_break || location.IsReturn() || 557 (current_fp != last_fp) || 558 (thread_local_.last_statement_position_ != 559 summary.abstract_code()->SourceStatementPosition(offset)); 560 break; 561 } 562 case StepFrame: 563 step_break = current_fp != last_fp; 564 break; 565 } 566 567 // Clear all current stepping setup. 568 ClearStepping(); 569 570 if (step_break) { 571 // Notify the debug event listeners. 572 OnDebugBreak(isolate_->factory()->undefined_value(), false); 573 } else { 574 // Re-prepare to continue. 575 PrepareStep(step_action); 576 } 577} 578 579 580// Find break point objects for this location, if any, and evaluate them. 581// Return an array of break point objects that evaluated true. 582Handle<Object> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info, 583 BreakLocation* location, 584 bool* has_break_points) { 585 Factory* factory = isolate_->factory(); 586 bool has_break_points_to_check = 587 break_points_active_ && location->HasBreakPoint(debug_info); 588 if (has_break_points) *has_break_points = has_break_points_to_check; 589 if (!has_break_points_to_check) return factory->undefined_value(); 590 591 Handle<Object> break_point_objects = 592 debug_info->GetBreakPointObjects(location->position()); 593 // Count the number of break points hit. If there are multiple break points 594 // they are in a FixedArray. 595 Handle<FixedArray> break_points_hit; 596 int break_points_hit_count = 0; 597 DCHECK(!break_point_objects->IsUndefined(isolate_)); 598 if (break_point_objects->IsFixedArray()) { 599 Handle<FixedArray> array(FixedArray::cast(*break_point_objects)); 600 break_points_hit = factory->NewFixedArray(array->length()); 601 for (int i = 0; i < array->length(); i++) { 602 Handle<Object> break_point_object(array->get(i), isolate_); 603 if (CheckBreakPoint(break_point_object)) { 604 break_points_hit->set(break_points_hit_count++, *break_point_object); 605 } 606 } 607 } else { 608 break_points_hit = factory->NewFixedArray(1); 609 if (CheckBreakPoint(break_point_objects)) { 610 break_points_hit->set(break_points_hit_count++, *break_point_objects); 611 } 612 } 613 if (break_points_hit_count == 0) return factory->undefined_value(); 614 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit); 615 result->set_length(Smi::FromInt(break_points_hit_count)); 616 return result; 617} 618 619 620bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { 621 // A break location is considered muted if break locations on the current 622 // statement have at least one break point, and all of these break points 623 // evaluate to false. Aside from not triggering a debug break event at the 624 // break location, we also do not trigger one for debugger statements, nor 625 // an exception event on exception at this location. 626 Object* fun = frame->function(); 627 if (!fun->IsJSFunction()) return false; 628 JSFunction* function = JSFunction::cast(fun); 629 if (!function->shared()->HasDebugInfo()) return false; 630 HandleScope scope(isolate_); 631 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); 632 // Enter the debugger. 633 DebugScope debug_scope(this); 634 if (debug_scope.failed()) return false; 635 List<BreakLocation> break_locations; 636 BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); 637 bool has_break_points_at_all = false; 638 for (int i = 0; i < break_locations.length(); i++) { 639 bool has_break_points; 640 Handle<Object> check_result = 641 CheckBreakPoints(debug_info, &break_locations[i], &has_break_points); 642 has_break_points_at_all |= has_break_points; 643 if (has_break_points && !check_result->IsUndefined(isolate_)) return false; 644 } 645 return has_break_points_at_all; 646} 647 648 649MaybeHandle<Object> Debug::CallFunction(const char* name, int argc, 650 Handle<Object> args[]) { 651 PostponeInterruptsScope no_interrupts(isolate_); 652 AssertDebugContext(); 653 Handle<JSReceiver> holder = 654 Handle<JSReceiver>::cast(isolate_->natives_utils_object()); 655 Handle<JSFunction> fun = Handle<JSFunction>::cast( 656 JSReceiver::GetProperty(isolate_, holder, name).ToHandleChecked()); 657 Handle<Object> undefined = isolate_->factory()->undefined_value(); 658 return Execution::TryCall(isolate_, fun, undefined, argc, args); 659} 660 661 662// Check whether a single break point object is triggered. 663bool Debug::CheckBreakPoint(Handle<Object> break_point_object) { 664 Factory* factory = isolate_->factory(); 665 HandleScope scope(isolate_); 666 667 // Ignore check if break point object is not a JSObject. 668 if (!break_point_object->IsJSObject()) return true; 669 670 // Get the break id as an object. 671 Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id()); 672 673 // Call IsBreakPointTriggered. 674 Handle<Object> argv[] = { break_id, break_point_object }; 675 Handle<Object> result; 676 if (!CallFunction("IsBreakPointTriggered", arraysize(argv), argv) 677 .ToHandle(&result)) { 678 return false; 679 } 680 681 // Return whether the break point is triggered. 682 return result->IsTrue(isolate_); 683} 684 685 686bool Debug::SetBreakPoint(Handle<JSFunction> function, 687 Handle<Object> break_point_object, 688 int* source_position) { 689 HandleScope scope(isolate_); 690 691 // Make sure the function is compiled and has set up the debug info. 692 Handle<SharedFunctionInfo> shared(function->shared()); 693 if (!EnsureDebugInfo(shared, function)) { 694 // Return if retrieving debug info failed. 695 return true; 696 } 697 698 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 699 // Source positions starts with zero. 700 DCHECK(*source_position >= 0); 701 702 // Find the break point and change it. 703 *source_position = 704 FindBreakablePosition(debug_info, *source_position, STATEMENT_ALIGNED); 705 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); 706 // At least one active break point now. 707 DCHECK(debug_info->GetBreakPointCount() > 0); 708 709 ClearBreakPoints(debug_info); 710 ApplyBreakPoints(debug_info); 711 712 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); 713 return true; 714} 715 716 717bool Debug::SetBreakPointForScript(Handle<Script> script, 718 Handle<Object> break_point_object, 719 int* source_position, 720 BreakPositionAlignment alignment) { 721 if (script->type() == Script::TYPE_WASM) { 722 // TODO(clemensh): set breakpoint for wasm. 723 return false; 724 } 725 HandleScope scope(isolate_); 726 727 // Obtain shared function info for the function. 728 Handle<Object> result = 729 FindSharedFunctionInfoInScript(script, *source_position); 730 if (result->IsUndefined(isolate_)) return false; 731 732 // Make sure the function has set up the debug info. 733 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); 734 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) { 735 // Return if retrieving debug info failed. 736 return false; 737 } 738 739 // Find position within function. The script position might be before the 740 // source position of the first function. 741 if (shared->start_position() > *source_position) { 742 *source_position = shared->start_position(); 743 } 744 745 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 746 747 // Find the break point and change it. 748 *source_position = 749 FindBreakablePosition(debug_info, *source_position, alignment); 750 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); 751 // At least one active break point now. 752 DCHECK(debug_info->GetBreakPointCount() > 0); 753 754 ClearBreakPoints(debug_info); 755 ApplyBreakPoints(debug_info); 756 757 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); 758 return true; 759} 760 761int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info, 762 int source_position, 763 BreakPositionAlignment alignment) { 764 int statement_position; 765 int position; 766 if (debug_info->HasDebugCode()) { 767 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 768 it.SkipToPosition(source_position, alignment); 769 statement_position = it.statement_position(); 770 position = it.position(); 771 } else { 772 DCHECK(debug_info->HasDebugBytecodeArray()); 773 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 774 it.SkipToPosition(source_position, alignment); 775 statement_position = it.statement_position(); 776 position = it.position(); 777 } 778 return alignment == STATEMENT_ALIGNED ? statement_position : position; 779} 780 781void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) { 782 DisallowHeapAllocation no_gc; 783 if (debug_info->break_points()->IsUndefined(isolate_)) return; 784 FixedArray* break_points = debug_info->break_points(); 785 for (int i = 0; i < break_points->length(); i++) { 786 if (break_points->get(i)->IsUndefined(isolate_)) continue; 787 BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i)); 788 if (info->GetBreakPointCount() == 0) continue; 789 if (debug_info->HasDebugCode()) { 790 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 791 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); 792 it.SetDebugBreak(); 793 } 794 if (debug_info->HasDebugBytecodeArray()) { 795 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 796 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); 797 it.SetDebugBreak(); 798 } 799 } 800} 801 802void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) { 803 DisallowHeapAllocation no_gc; 804 if (debug_info->HasDebugCode()) { 805 for (CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); 806 it.Next()) { 807 it.ClearDebugBreak(); 808 } 809 } 810 if (debug_info->HasDebugBytecodeArray()) { 811 for (BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 812 !it.Done(); it.Next()) { 813 it.ClearDebugBreak(); 814 } 815 } 816} 817 818void Debug::ClearBreakPoint(Handle<Object> break_point_object) { 819 HandleScope scope(isolate_); 820 821 for (DebugInfoListNode* node = debug_info_list_; node != NULL; 822 node = node->next()) { 823 Handle<Object> result = 824 DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object); 825 if (result->IsUndefined(isolate_)) continue; 826 Handle<DebugInfo> debug_info = node->debug_info(); 827 if (DebugInfo::ClearBreakPoint(debug_info, break_point_object)) { 828 ClearBreakPoints(debug_info); 829 if (debug_info->GetBreakPointCount() == 0) { 830 RemoveDebugInfoAndClearFromShared(debug_info); 831 } else { 832 ApplyBreakPoints(debug_info); 833 } 834 return; 835 } 836 } 837} 838 839// Clear out all the debug break code. This is ONLY supposed to be used when 840// shutting down the debugger as it will leave the break point information in 841// DebugInfo even though the code is patched back to the non break point state. 842void Debug::ClearAllBreakPoints() { 843 for (DebugInfoListNode* node = debug_info_list_; node != NULL; 844 node = node->next()) { 845 ClearBreakPoints(node->debug_info()); 846 } 847 // Remove all debug info. 848 while (debug_info_list_ != NULL) { 849 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); 850 } 851} 852 853void Debug::FloodWithOneShot(Handle<JSFunction> function, 854 BreakLocatorType type) { 855 // Debug utility functions are not subject to debugging. 856 if (function->native_context() == *debug_context()) return; 857 858 if (!function->shared()->IsSubjectToDebugging()) { 859 // Builtin functions are not subject to stepping, but need to be 860 // deoptimized, because optimized code does not check for debug 861 // step in at call sites. 862 Deoptimizer::DeoptimizeFunction(*function); 863 return; 864 } 865 // Make sure the function is compiled and has set up the debug info. 866 Handle<SharedFunctionInfo> shared(function->shared()); 867 if (!EnsureDebugInfo(shared, function)) { 868 // Return if we failed to retrieve the debug info. 869 return; 870 } 871 872 // Flood the function with break points. 873 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 874 if (debug_info->HasDebugCode()) { 875 for (CodeBreakIterator it(debug_info, type); !it.Done(); it.Next()) { 876 it.SetDebugBreak(); 877 } 878 } 879 if (debug_info->HasDebugBytecodeArray()) { 880 for (BytecodeArrayBreakIterator it(debug_info, type); !it.Done(); 881 it.Next()) { 882 it.SetDebugBreak(); 883 } 884 } 885} 886 887void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { 888 if (type == BreakUncaughtException) { 889 break_on_uncaught_exception_ = enable; 890 } else { 891 break_on_exception_ = enable; 892 } 893} 894 895 896bool Debug::IsBreakOnException(ExceptionBreakType type) { 897 if (type == BreakUncaughtException) { 898 return break_on_uncaught_exception_; 899 } else { 900 return break_on_exception_; 901 } 902} 903 904 905void Debug::PrepareStepIn(Handle<JSFunction> function) { 906 CHECK(last_step_action() >= StepIn); 907 if (!is_active()) return; 908 if (in_debug_scope()) return; 909 FloodWithOneShot(function); 910} 911 912void Debug::PrepareStepInSuspendedGenerator() { 913 CHECK(has_suspended_generator()); 914 if (!is_active()) return; 915 if (in_debug_scope()) return; 916 thread_local_.last_step_action_ = StepIn; 917 Handle<JSFunction> function( 918 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function()); 919 FloodWithOneShot(function); 920 clear_suspended_generator(); 921} 922 923void Debug::PrepareStepOnThrow() { 924 if (!is_active()) return; 925 if (last_step_action() == StepNone) return; 926 if (in_debug_scope()) return; 927 928 ClearOneShot(); 929 930 // Iterate through the JavaScript stack looking for handlers. 931 JavaScriptFrameIterator it(isolate_); 932 while (!it.done()) { 933 JavaScriptFrame* frame = it.frame(); 934 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; 935 it.Advance(); 936 } 937 938 if (last_step_action() == StepNext || last_step_action() == StepOut) { 939 while (!it.done()) { 940 Address current_fp = it.frame()->UnpaddedFP(); 941 if (current_fp >= thread_local_.target_fp_) break; 942 it.Advance(); 943 } 944 } 945 946 // Find the closest Javascript frame we can flood with one-shots. 947 while (!it.done() && 948 !it.frame()->function()->shared()->IsSubjectToDebugging()) { 949 it.Advance(); 950 } 951 952 if (it.done()) return; // No suitable Javascript catch handler. 953 954 FloodWithOneShot(Handle<JSFunction>(it.frame()->function())); 955} 956 957 958void Debug::PrepareStep(StepAction step_action) { 959 HandleScope scope(isolate_); 960 961 DCHECK(in_debug_scope()); 962 963 // Get the frame where the execution has stopped and skip the debug frame if 964 // any. The debug frame will only be present if execution was stopped due to 965 // hitting a break point. In other situations (e.g. unhandled exception) the 966 // debug frame is not present. 967 StackFrame::Id frame_id = break_frame_id(); 968 // If there is no JavaScript stack don't do anything. 969 if (frame_id == StackFrame::NO_ID) return; 970 971 JavaScriptFrameIterator frames_it(isolate_, frame_id); 972 JavaScriptFrame* frame = frames_it.frame(); 973 974 feature_tracker()->Track(DebugFeatureTracker::kStepping); 975 976 thread_local_.last_step_action_ = step_action; 977 978 // If the function on the top frame is unresolved perform step out. This will 979 // be the case when calling unknown function and having the debugger stopped 980 // in an unhandled exception. 981 if (!frame->function()->IsJSFunction()) { 982 // Step out: Find the calling JavaScript frame and flood it with 983 // breakpoints. 984 frames_it.Advance(); 985 // Fill the function to return to with one-shot break points. 986 JSFunction* function = frames_it.frame()->function(); 987 FloodWithOneShot(Handle<JSFunction>(function)); 988 return; 989 } 990 991 // Get the debug info (create it if it does not exist). 992 FrameSummary summary = FrameSummary::GetFirst(frame); 993 Handle<JSFunction> function(summary.function()); 994 Handle<SharedFunctionInfo> shared(function->shared()); 995 if (!EnsureDebugInfo(shared, function)) { 996 // Return if ensuring debug info failed. 997 return; 998 } 999 1000 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 1001 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); 1002 1003 // Any step at a return is a step-out. 1004 if (location.IsReturn()) step_action = StepOut; 1005 // A step-next at a tail call is a step-out. 1006 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; 1007 1008 thread_local_.last_statement_position_ = 1009 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); 1010 thread_local_.last_fp_ = frame->UnpaddedFP(); 1011 // No longer perform the current async step. 1012 clear_suspended_generator(); 1013 1014 switch (step_action) { 1015 case StepNone: 1016 UNREACHABLE(); 1017 break; 1018 case StepOut: 1019 // Advance to caller frame. 1020 frames_it.Advance(); 1021 // Skip native and extension functions on the stack. 1022 while (!frames_it.done() && 1023 !frames_it.frame()->function()->shared()->IsSubjectToDebugging()) { 1024 // Builtin functions are not subject to stepping, but need to be 1025 // deoptimized to include checks for step-in at call sites. 1026 Deoptimizer::DeoptimizeFunction(frames_it.frame()->function()); 1027 frames_it.Advance(); 1028 } 1029 if (!frames_it.done()) { 1030 // Fill the caller function to return to with one-shot break points. 1031 Handle<JSFunction> caller_function(frames_it.frame()->function()); 1032 FloodWithOneShot(caller_function); 1033 thread_local_.target_fp_ = frames_it.frame()->UnpaddedFP(); 1034 } 1035 // Clear last position info. For stepping out it does not matter. 1036 thread_local_.last_statement_position_ = kNoSourcePosition; 1037 thread_local_.last_fp_ = 0; 1038 break; 1039 case StepNext: 1040 thread_local_.target_fp_ = frame->UnpaddedFP(); 1041 FloodWithOneShot(function); 1042 break; 1043 case StepIn: 1044 FloodWithOneShot(function); 1045 break; 1046 case StepFrame: 1047 // No point in setting one-shot breaks at places where we are not about 1048 // to leave the current frame. 1049 FloodWithOneShot(function, CALLS_AND_RETURNS); 1050 break; 1051 } 1052} 1053 1054// Simple function for returning the source positions for active break points. 1055Handle<Object> Debug::GetSourceBreakLocations( 1056 Handle<SharedFunctionInfo> shared, 1057 BreakPositionAlignment position_alignment) { 1058 Isolate* isolate = shared->GetIsolate(); 1059 if (!shared->HasDebugInfo()) { 1060 return isolate->factory()->undefined_value(); 1061 } 1062 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 1063 if (debug_info->GetBreakPointCount() == 0) { 1064 return isolate->factory()->undefined_value(); 1065 } 1066 Handle<FixedArray> locations = 1067 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount()); 1068 int count = 0; 1069 for (int i = 0; i < debug_info->break_points()->length(); ++i) { 1070 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { 1071 BreakPointInfo* break_point_info = 1072 BreakPointInfo::cast(debug_info->break_points()->get(i)); 1073 int break_points = break_point_info->GetBreakPointCount(); 1074 if (break_points == 0) continue; 1075 Smi* position = NULL; 1076 if (position_alignment == STATEMENT_ALIGNED) { 1077 if (debug_info->HasDebugCode()) { 1078 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 1079 it.SkipToPosition(break_point_info->source_position(), 1080 BREAK_POSITION_ALIGNED); 1081 position = Smi::FromInt(it.statement_position()); 1082 } else { 1083 DCHECK(debug_info->HasDebugBytecodeArray()); 1084 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 1085 it.SkipToPosition(break_point_info->source_position(), 1086 BREAK_POSITION_ALIGNED); 1087 position = Smi::FromInt(it.statement_position()); 1088 } 1089 } else { 1090 DCHECK_EQ(BREAK_POSITION_ALIGNED, position_alignment); 1091 position = Smi::FromInt(break_point_info->source_position()); 1092 } 1093 for (int j = 0; j < break_points; ++j) locations->set(count++, position); 1094 } 1095 } 1096 return locations; 1097} 1098 1099void Debug::ClearStepping() { 1100 // Clear the various stepping setup. 1101 ClearOneShot(); 1102 1103 thread_local_.last_step_action_ = StepNone; 1104 thread_local_.last_statement_position_ = kNoSourcePosition; 1105 thread_local_.last_fp_ = 0; 1106 thread_local_.target_fp_ = 0; 1107} 1108 1109 1110// Clears all the one-shot break points that are currently set. Normally this 1111// function is called each time a break point is hit as one shot break points 1112// are used to support stepping. 1113void Debug::ClearOneShot() { 1114 // The current implementation just runs through all the breakpoints. When the 1115 // last break point for a function is removed that function is automatically 1116 // removed from the list. 1117 for (DebugInfoListNode* node = debug_info_list_; node != NULL; 1118 node = node->next()) { 1119 Handle<DebugInfo> debug_info = node->debug_info(); 1120 ClearBreakPoints(debug_info); 1121 ApplyBreakPoints(debug_info); 1122 } 1123} 1124 1125 1126bool MatchingCodeTargets(Code* target1, Code* target2) { 1127 if (target1 == target2) return true; 1128 if (target1->kind() != target2->kind()) return false; 1129 return target1->is_handler() || target1->is_inline_cache_stub(); 1130} 1131 1132 1133// Count the number of calls before the current frame PC to find the 1134// corresponding PC in the newly recompiled code. 1135static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code, 1136 Address old_pc) { 1137 DCHECK_EQ(old_code->kind(), Code::FUNCTION); 1138 DCHECK_EQ(new_code->kind(), Code::FUNCTION); 1139 DCHECK(new_code->has_debug_break_slots()); 1140 static const int mask = RelocInfo::kCodeTargetMask; 1141 1142 // Find the target of the current call. 1143 Code* target = NULL; 1144 intptr_t delta = 0; 1145 for (RelocIterator it(old_code, mask); !it.done(); it.next()) { 1146 RelocInfo* rinfo = it.rinfo(); 1147 Address current_pc = rinfo->pc(); 1148 // The frame PC is behind the call instruction by the call instruction size. 1149 if (current_pc > old_pc) break; 1150 delta = old_pc - current_pc; 1151 target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 1152 } 1153 1154 // Count the number of calls to the same target before the current call. 1155 int index = 0; 1156 for (RelocIterator it(old_code, mask); !it.done(); it.next()) { 1157 RelocInfo* rinfo = it.rinfo(); 1158 Address current_pc = rinfo->pc(); 1159 if (current_pc > old_pc) break; 1160 Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address()); 1161 if (MatchingCodeTargets(target, current)) index++; 1162 } 1163 1164 DCHECK(index > 0); 1165 1166 // Repeat the count on the new code to find corresponding call. 1167 for (RelocIterator it(new_code, mask); !it.done(); it.next()) { 1168 RelocInfo* rinfo = it.rinfo(); 1169 Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address()); 1170 if (MatchingCodeTargets(target, current)) index--; 1171 if (index == 0) return rinfo->pc() + delta; 1172 } 1173 1174 UNREACHABLE(); 1175 return NULL; 1176} 1177 1178 1179// Count the number of continuations at which the current pc offset is at. 1180static int ComputeContinuationIndexFromPcOffset(Code* code, int pc_offset) { 1181 DCHECK_EQ(code->kind(), Code::FUNCTION); 1182 Address pc = code->instruction_start() + pc_offset; 1183 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION); 1184 int index = 0; 1185 for (RelocIterator it(code, mask); !it.done(); it.next()) { 1186 index++; 1187 RelocInfo* rinfo = it.rinfo(); 1188 Address current_pc = rinfo->pc(); 1189 if (current_pc == pc) break; 1190 DCHECK(current_pc < pc); 1191 } 1192 return index; 1193} 1194 1195 1196// Find the pc offset for the given continuation index. 1197static int ComputePcOffsetFromContinuationIndex(Code* code, int index) { 1198 DCHECK_EQ(code->kind(), Code::FUNCTION); 1199 DCHECK(code->has_debug_break_slots()); 1200 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION); 1201 RelocIterator it(code, mask); 1202 for (int i = 1; i < index; i++) it.next(); 1203 return static_cast<int>(it.rinfo()->pc() - code->instruction_start()); 1204} 1205 1206 1207class RedirectActiveFunctions : public ThreadVisitor { 1208 public: 1209 explicit RedirectActiveFunctions(SharedFunctionInfo* shared) 1210 : shared_(shared) { 1211 DCHECK(shared->HasDebugCode()); 1212 } 1213 1214 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { 1215 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) { 1216 JavaScriptFrame* frame = it.frame(); 1217 JSFunction* function = frame->function(); 1218 if (frame->is_optimized()) continue; 1219 if (!function->Inlines(shared_)) continue; 1220 1221 if (frame->is_interpreted()) { 1222 InterpretedFrame* interpreted_frame = 1223 reinterpret_cast<InterpretedFrame*>(frame); 1224 BytecodeArray* debug_copy = 1225 shared_->GetDebugInfo()->DebugBytecodeArray(); 1226 interpreted_frame->PatchBytecodeArray(debug_copy); 1227 continue; 1228 } 1229 1230 Code* frame_code = frame->LookupCode(); 1231 DCHECK(frame_code->kind() == Code::FUNCTION); 1232 if (frame_code->has_debug_break_slots()) continue; 1233 1234 Code* new_code = function->shared()->code(); 1235 Address old_pc = frame->pc(); 1236 Address new_pc = ComputeNewPcForRedirect(new_code, frame_code, old_pc); 1237 1238 if (FLAG_trace_deopt) { 1239 PrintF("Replacing pc for debugging: %08" V8PRIxPTR " => %08" V8PRIxPTR 1240 "\n", 1241 reinterpret_cast<intptr_t>(old_pc), 1242 reinterpret_cast<intptr_t>(new_pc)); 1243 } 1244 1245 if (FLAG_enable_embedded_constant_pool) { 1246 // Update constant pool pointer for new code. 1247 frame->set_constant_pool(new_code->constant_pool()); 1248 } 1249 1250 // Patch the return address to return into the code with 1251 // debug break slots. 1252 frame->set_pc(new_pc); 1253 } 1254 } 1255 1256 private: 1257 SharedFunctionInfo* shared_; 1258 DisallowHeapAllocation no_gc_; 1259}; 1260 1261 1262bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) { 1263 DCHECK(shared->is_compiled()); 1264 1265 if (isolate_->concurrent_recompilation_enabled()) { 1266 isolate_->optimizing_compile_dispatcher()->Flush( 1267 OptimizingCompileDispatcher::BlockingBehavior::kBlock); 1268 } 1269 1270 List<Handle<JSFunction> > functions; 1271 List<Handle<JSGeneratorObject> > suspended_generators; 1272 1273 // Flush all optimized code maps. Note that the below heap iteration does not 1274 // cover this, because the given function might have been inlined into code 1275 // for which no JSFunction exists. 1276 { 1277 SharedFunctionInfo::Iterator iterator(isolate_); 1278 while (SharedFunctionInfo* shared = iterator.Next()) { 1279 shared->ClearCodeFromOptimizedCodeMap(); 1280 } 1281 } 1282 1283 // Make sure we abort incremental marking. 1284 isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, 1285 GarbageCollectionReason::kDebugger); 1286 1287 DCHECK(shared->is_compiled()); 1288 bool baseline_exists = shared->HasBaselineCode(); 1289 1290 { 1291 // TODO(yangguo): with bytecode, we still walk the heap to find all 1292 // optimized code for the function to deoptimize. We can probably be 1293 // smarter here and avoid the heap walk. 1294 HeapIterator iterator(isolate_->heap()); 1295 HeapObject* obj; 1296 // Continuation from old-style generators need to be recomputed. 1297 bool find_resumables = 1298 baseline_exists && IsResumableFunction(shared->kind()); 1299 1300 while ((obj = iterator.next())) { 1301 if (obj->IsJSFunction()) { 1302 JSFunction* function = JSFunction::cast(obj); 1303 if (!function->Inlines(*shared)) continue; 1304 if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) { 1305 Deoptimizer::DeoptimizeFunction(function); 1306 } 1307 if (baseline_exists && function->shared() == *shared) { 1308 functions.Add(handle(function)); 1309 } 1310 } else if (find_resumables && obj->IsJSGeneratorObject()) { 1311 // This case handles async functions as well, as they use generator 1312 // objects for in-progress async function execution. 1313 JSGeneratorObject* generator_obj = JSGeneratorObject::cast(obj); 1314 if (!generator_obj->is_suspended()) continue; 1315 JSFunction* function = generator_obj->function(); 1316 if (!function->Inlines(*shared)) continue; 1317 int pc_offset = generator_obj->continuation(); 1318 int index = 1319 ComputeContinuationIndexFromPcOffset(function->code(), pc_offset); 1320 generator_obj->set_continuation(index); 1321 suspended_generators.Add(handle(generator_obj)); 1322 } 1323 } 1324 } 1325 1326 // We do not need to replace code to debug bytecode. 1327 DCHECK(baseline_exists || functions.is_empty()); 1328 DCHECK(baseline_exists || suspended_generators.is_empty()); 1329 1330 // We do not need to recompile to debug bytecode. 1331 if (baseline_exists && !shared->code()->has_debug_break_slots()) { 1332 if (!Compiler::CompileDebugCode(shared)) return false; 1333 } 1334 1335 for (Handle<JSFunction> const function : functions) { 1336 function->ReplaceCode(shared->code()); 1337 JSFunction::EnsureLiterals(function); 1338 } 1339 1340 for (Handle<JSGeneratorObject> const generator_obj : suspended_generators) { 1341 int index = generator_obj->continuation(); 1342 int pc_offset = ComputePcOffsetFromContinuationIndex(shared->code(), index); 1343 generator_obj->set_continuation(pc_offset); 1344 } 1345 1346 // Update PCs on the stack to point to recompiled code. 1347 RedirectActiveFunctions redirect_visitor(*shared); 1348 redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top()); 1349 isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor); 1350 1351 return true; 1352} 1353 1354namespace { 1355template <typename Iterator> 1356void GetBreakablePositions(Iterator* it, int start_position, int end_position, 1357 BreakPositionAlignment alignment, 1358 std::set<int>* positions) { 1359 it->SkipToPosition(start_position, alignment); 1360 while (!it->Done() && it->position() < end_position && 1361 it->position() >= start_position) { 1362 positions->insert(alignment == STATEMENT_ALIGNED ? it->statement_position() 1363 : it->position()); 1364 it->Next(); 1365 } 1366} 1367 1368void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position, 1369 int end_position, BreakPositionAlignment alignment, 1370 std::set<int>* positions) { 1371 if (debug_info->HasDebugCode()) { 1372 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 1373 GetBreakablePositions(&it, start_position, end_position, alignment, 1374 positions); 1375 } else { 1376 DCHECK(debug_info->HasDebugBytecodeArray()); 1377 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); 1378 GetBreakablePositions(&it, start_position, end_position, alignment, 1379 positions); 1380 } 1381} 1382} // namespace 1383 1384bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position, 1385 int end_position, std::set<int>* positions) { 1386 while (true) { 1387 if (!script->shared_function_infos()->IsWeakFixedArray()) return false; 1388 1389 WeakFixedArray* infos = 1390 WeakFixedArray::cast(script->shared_function_infos()); 1391 HandleScope scope(isolate_); 1392 List<Handle<SharedFunctionInfo>> candidates; 1393 { 1394 WeakFixedArray::Iterator iterator(infos); 1395 SharedFunctionInfo* info; 1396 while ((info = iterator.Next<SharedFunctionInfo>())) { 1397 if (info->end_position() < start_position || 1398 info->start_position() >= end_position) { 1399 continue; 1400 } 1401 if (!info->IsSubjectToDebugging()) continue; 1402 if (!info->HasDebugCode() && !info->allows_lazy_compilation()) continue; 1403 candidates.Add(i::handle(info)); 1404 } 1405 } 1406 1407 bool was_compiled = false; 1408 for (int i = 0; i < candidates.length(); ++i) { 1409 // Code that cannot be compiled lazily are internal and not debuggable. 1410 DCHECK(candidates[i]->allows_lazy_compilation()); 1411 if (!candidates[i]->HasDebugCode()) { 1412 if (!Compiler::CompileDebugCode(candidates[i])) { 1413 return false; 1414 } else { 1415 was_compiled = true; 1416 } 1417 } 1418 if (!EnsureDebugInfo(candidates[i], Handle<JSFunction>::null())) 1419 return false; 1420 } 1421 if (was_compiled) continue; 1422 1423 for (int i = 0; i < candidates.length(); ++i) { 1424 CHECK(candidates[i]->HasDebugInfo()); 1425 Handle<DebugInfo> debug_info(candidates[i]->GetDebugInfo()); 1426 FindBreakablePositions(debug_info, start_position, end_position, 1427 STATEMENT_ALIGNED, positions); 1428 } 1429 return true; 1430 } 1431 UNREACHABLE(); 1432 return false; 1433} 1434 1435void Debug::RecordAsyncFunction(Handle<JSGeneratorObject> generator_object) { 1436 if (last_step_action() <= StepOut) return; 1437 if (!IsAsyncFunction(generator_object->function()->shared()->kind())) return; 1438 DCHECK(!has_suspended_generator()); 1439 thread_local_.suspended_generator_ = *generator_object; 1440 ClearStepping(); 1441} 1442 1443class SharedFunctionInfoFinder { 1444 public: 1445 explicit SharedFunctionInfoFinder(int target_position) 1446 : current_candidate_(NULL), 1447 current_candidate_closure_(NULL), 1448 current_start_position_(kNoSourcePosition), 1449 target_position_(target_position) {} 1450 1451 void NewCandidate(SharedFunctionInfo* shared, JSFunction* closure = NULL) { 1452 if (!shared->IsSubjectToDebugging()) return; 1453 int start_position = shared->function_token_position(); 1454 if (start_position == kNoSourcePosition) { 1455 start_position = shared->start_position(); 1456 } 1457 1458 if (start_position > target_position_) return; 1459 if (target_position_ > shared->end_position()) return; 1460 1461 if (current_candidate_ != NULL) { 1462 if (current_start_position_ == start_position && 1463 shared->end_position() == current_candidate_->end_position()) { 1464 // If we already have a matching closure, do not throw it away. 1465 if (current_candidate_closure_ != NULL && closure == NULL) return; 1466 // If a top-level function contains only one function 1467 // declaration the source for the top-level and the function 1468 // is the same. In that case prefer the non top-level function. 1469 if (!current_candidate_->is_toplevel() && shared->is_toplevel()) return; 1470 } else if (start_position < current_start_position_ || 1471 current_candidate_->end_position() < shared->end_position()) { 1472 return; 1473 } 1474 } 1475 1476 current_start_position_ = start_position; 1477 current_candidate_ = shared; 1478 current_candidate_closure_ = closure; 1479 } 1480 1481 SharedFunctionInfo* Result() { return current_candidate_; } 1482 1483 JSFunction* ResultClosure() { return current_candidate_closure_; } 1484 1485 private: 1486 SharedFunctionInfo* current_candidate_; 1487 JSFunction* current_candidate_closure_; 1488 int current_start_position_; 1489 int target_position_; 1490 DisallowHeapAllocation no_gc_; 1491}; 1492 1493 1494// We need to find a SFI for a literal that may not yet have been compiled yet, 1495// and there may not be a JSFunction referencing it. Find the SFI closest to 1496// the given position, compile it to reveal possible inner SFIs and repeat. 1497// While we are at this, also ensure code with debug break slots so that we do 1498// not have to compile a SFI without JSFunction, which is paifu for those that 1499// cannot be compiled without context (need to find outer compilable SFI etc.) 1500Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, 1501 int position) { 1502 for (int iteration = 0;; iteration++) { 1503 // Go through all shared function infos associated with this script to 1504 // find the inner most function containing this position. 1505 // If there is no shared function info for this script at all, there is 1506 // no point in looking for it by walking the heap. 1507 if (!script->shared_function_infos()->IsWeakFixedArray()) break; 1508 1509 SharedFunctionInfo* shared; 1510 { 1511 SharedFunctionInfoFinder finder(position); 1512 WeakFixedArray::Iterator iterator(script->shared_function_infos()); 1513 SharedFunctionInfo* candidate; 1514 while ((candidate = iterator.Next<SharedFunctionInfo>())) { 1515 finder.NewCandidate(candidate); 1516 } 1517 shared = finder.Result(); 1518 if (shared == NULL) break; 1519 // We found it if it's already compiled and has debug code. 1520 if (shared->HasDebugCode()) { 1521 Handle<SharedFunctionInfo> shared_handle(shared); 1522 // If the iteration count is larger than 1, we had to compile the outer 1523 // function in order to create this shared function info. So there can 1524 // be no JSFunction referencing it. We can anticipate creating a debug 1525 // info while bypassing PrepareFunctionForBreakpoints. 1526 if (iteration > 1) { 1527 AllowHeapAllocation allow_before_return; 1528 CreateDebugInfo(shared_handle); 1529 } 1530 return shared_handle; 1531 } 1532 } 1533 // If not, compile to reveal inner functions. 1534 HandleScope scope(isolate_); 1535 // Code that cannot be compiled lazily are internal and not debuggable. 1536 DCHECK(shared->allows_lazy_compilation()); 1537 if (!Compiler::CompileDebugCode(handle(shared))) break; 1538 } 1539 return isolate_->factory()->undefined_value(); 1540} 1541 1542 1543// Ensures the debug information is present for shared. 1544bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, 1545 Handle<JSFunction> function) { 1546 if (!shared->IsSubjectToDebugging()) return false; 1547 1548 // Return if we already have the debug info for shared. 1549 if (shared->HasDebugInfo()) return true; 1550 1551 if (function.is_null()) { 1552 DCHECK(shared->HasDebugCode()); 1553 } else if (!Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) { 1554 return false; 1555 } 1556 1557 // To prepare bytecode for debugging, we already need to have the debug 1558 // info (containing the debug copy) upfront, but since we do not recompile, 1559 // preparing for break points cannot fail. 1560 CreateDebugInfo(shared); 1561 CHECK(PrepareFunctionForBreakPoints(shared)); 1562 return true; 1563} 1564 1565 1566void Debug::CreateDebugInfo(Handle<SharedFunctionInfo> shared) { 1567 // Create the debug info object. 1568 Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared); 1569 1570 // Add debug info to the list. 1571 DebugInfoListNode* node = new DebugInfoListNode(*debug_info); 1572 node->set_next(debug_info_list_); 1573 debug_info_list_ = node; 1574} 1575 1576 1577void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) { 1578 HandleScope scope(isolate_); 1579 Handle<SharedFunctionInfo> shared(debug_info->shared()); 1580 1581 DCHECK_NOT_NULL(debug_info_list_); 1582 // Run through the debug info objects to find this one and remove it. 1583 DebugInfoListNode* prev = NULL; 1584 DebugInfoListNode* current = debug_info_list_; 1585 while (current != NULL) { 1586 if (current->debug_info().is_identical_to(debug_info)) { 1587 // Unlink from list. If prev is NULL we are looking at the first element. 1588 if (prev == NULL) { 1589 debug_info_list_ = current->next(); 1590 } else { 1591 prev->set_next(current->next()); 1592 } 1593 delete current; 1594 shared->set_debug_info(DebugInfo::uninitialized()); 1595 return; 1596 } 1597 // Move to next in list. 1598 prev = current; 1599 current = current->next(); 1600 } 1601 1602 UNREACHABLE(); 1603} 1604 1605void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { 1606 after_break_target_ = NULL; 1607 if (!LiveEdit::SetAfterBreakTarget(this)) { 1608 // Continue just after the slot. 1609 after_break_target_ = frame->pc(); 1610 } 1611} 1612 1613bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { 1614 HandleScope scope(isolate_); 1615 1616 // Get the executing function in which the debug break occurred. 1617 Handle<SharedFunctionInfo> shared(frame->function()->shared()); 1618 1619 // With no debug info there are no break points, so we can't be at a return. 1620 if (!shared->HasDebugInfo()) return false; 1621 1622 DCHECK(!frame->is_optimized()); 1623 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 1624 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); 1625 return location.IsReturn() || location.IsTailCall(); 1626} 1627 1628void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, 1629 LiveEditFrameDropMode mode) { 1630 if (mode != LIVE_EDIT_CURRENTLY_SET_MODE) { 1631 thread_local_.frame_drop_mode_ = mode; 1632 } 1633 thread_local_.break_frame_id_ = new_break_frame_id; 1634} 1635 1636 1637bool Debug::IsDebugGlobal(JSGlobalObject* global) { 1638 return is_loaded() && global == debug_context()->global_object(); 1639} 1640 1641 1642void Debug::ClearMirrorCache() { 1643 PostponeInterruptsScope postpone(isolate_); 1644 HandleScope scope(isolate_); 1645 CallFunction("ClearMirrorCache", 0, NULL); 1646} 1647 1648 1649Handle<FixedArray> Debug::GetLoadedScripts() { 1650 isolate_->heap()->CollectAllGarbage(Heap::kFinalizeIncrementalMarkingMask, 1651 GarbageCollectionReason::kDebugger); 1652 Factory* factory = isolate_->factory(); 1653 if (!factory->script_list()->IsWeakFixedArray()) { 1654 return factory->empty_fixed_array(); 1655 } 1656 Handle<WeakFixedArray> array = 1657 Handle<WeakFixedArray>::cast(factory->script_list()); 1658 Handle<FixedArray> results = factory->NewFixedArray(array->Length()); 1659 int length = 0; 1660 { 1661 Script::Iterator iterator(isolate_); 1662 Script* script; 1663 while ((script = iterator.Next())) { 1664 if (script->HasValidSource()) results->set(length++, script); 1665 } 1666 } 1667 results->Shrink(length); 1668 return results; 1669} 1670 1671 1672MaybeHandle<Object> Debug::MakeExecutionState() { 1673 // Create the execution state object. 1674 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()) }; 1675 return CallFunction("MakeExecutionState", arraysize(argv), argv); 1676} 1677 1678 1679MaybeHandle<Object> Debug::MakeBreakEvent(Handle<Object> break_points_hit) { 1680 // Create the new break event object. 1681 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()), 1682 break_points_hit }; 1683 return CallFunction("MakeBreakEvent", arraysize(argv), argv); 1684} 1685 1686 1687MaybeHandle<Object> Debug::MakeExceptionEvent(Handle<Object> exception, 1688 bool uncaught, 1689 Handle<Object> promise) { 1690 // Create the new exception event object. 1691 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()), 1692 exception, 1693 isolate_->factory()->ToBoolean(uncaught), 1694 promise }; 1695 return CallFunction("MakeExceptionEvent", arraysize(argv), argv); 1696} 1697 1698 1699MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script, 1700 v8::DebugEvent type) { 1701 // Create the compile event object. 1702 Handle<Object> script_wrapper = Script::GetWrapper(script); 1703 Handle<Object> argv[] = { script_wrapper, 1704 isolate_->factory()->NewNumberFromInt(type) }; 1705 return CallFunction("MakeCompileEvent", arraysize(argv), argv); 1706} 1707 1708MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<String> type, 1709 Handle<Object> id, 1710 Handle<String> name) { 1711 DCHECK(id->IsNumber()); 1712 // Create the async task event object. 1713 Handle<Object> argv[] = {type, id, name}; 1714 return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv); 1715} 1716 1717 1718void Debug::OnThrow(Handle<Object> exception) { 1719 if (in_debug_scope() || ignore_events()) return; 1720 PrepareStepOnThrow(); 1721 // Temporarily clear any scheduled_exception to allow evaluating 1722 // JavaScript from the debug event handler. 1723 HandleScope scope(isolate_); 1724 Handle<Object> scheduled_exception; 1725 if (isolate_->has_scheduled_exception()) { 1726 scheduled_exception = handle(isolate_->scheduled_exception(), isolate_); 1727 isolate_->clear_scheduled_exception(); 1728 } 1729 OnException(exception, isolate_->GetPromiseOnStackOnThrow()); 1730 if (!scheduled_exception.is_null()) { 1731 isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception; 1732 } 1733} 1734 1735void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) { 1736 if (in_debug_scope() || ignore_events()) return; 1737 HandleScope scope(isolate_); 1738 // Check whether the promise has been marked as having triggered a message. 1739 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); 1740 if (!promise->IsJSObject() || 1741 JSReceiver::GetDataProperty(Handle<JSObject>::cast(promise), key) 1742 ->IsUndefined(isolate_)) { 1743 OnException(value, promise); 1744 } 1745} 1746 1747 1748void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { 1749 // We cannot generate debug events when JS execution is disallowed. 1750 // TODO(5530): Reenable debug events within DisallowJSScopes once relevant 1751 // code (MakeExceptionEvent and ProcessDebugEvent) have been moved to C++. 1752 if (!AllowJavascriptExecution::IsAllowed(isolate_)) return; 1753 1754 Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher(); 1755 1756 // Don't notify listener of exceptions that are internal to a desugaring. 1757 if (catch_type == Isolate::CAUGHT_BY_DESUGARING) return; 1758 1759 bool uncaught = catch_type == Isolate::NOT_CAUGHT; 1760 if (promise->IsJSObject()) { 1761 Handle<JSObject> jspromise = Handle<JSObject>::cast(promise); 1762 // Mark the promise as already having triggered a message. 1763 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); 1764 JSObject::SetProperty(jspromise, key, key, STRICT).Assert(); 1765 // Check whether the promise reject is considered an uncaught exception. 1766 uncaught = !isolate_->PromiseHasUserDefinedRejectHandler(jspromise); 1767 } 1768 // Bail out if exception breaks are not active 1769 if (uncaught) { 1770 // Uncaught exceptions are reported by either flags. 1771 if (!(break_on_uncaught_exception_ || break_on_exception_)) return; 1772 } else { 1773 // Caught exceptions are reported is activated. 1774 if (!break_on_exception_) return; 1775 } 1776 1777 { 1778 // Check whether the break location is muted. 1779 JavaScriptFrameIterator it(isolate_); 1780 if (!it.done() && IsMutedAtCurrentLocation(it.frame())) return; 1781 } 1782 1783 DebugScope debug_scope(this); 1784 if (debug_scope.failed()) return; 1785 1786 // Create the event data object. 1787 Handle<Object> event_data; 1788 // Bail out and don't call debugger if exception. 1789 if (!MakeExceptionEvent( 1790 exception, uncaught, promise).ToHandle(&event_data)) { 1791 return; 1792 } 1793 1794 // Process debug event. 1795 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false); 1796 // Return to continue execution from where the exception was thrown. 1797} 1798 1799 1800void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) { 1801 // The caller provided for DebugScope. 1802 AssertDebugContext(); 1803 // Bail out if there is no listener for this event 1804 if (ignore_events()) return; 1805 1806#ifdef DEBUG 1807 PrintBreakLocation(); 1808#endif // DEBUG 1809 1810 HandleScope scope(isolate_); 1811 // Create the event data object. 1812 Handle<Object> event_data; 1813 // Bail out and don't call debugger if exception. 1814 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; 1815 1816 // Process debug event. 1817 ProcessDebugEvent(v8::Break, 1818 Handle<JSObject>::cast(event_data), 1819 auto_continue); 1820} 1821 1822 1823void Debug::OnCompileError(Handle<Script> script) { 1824 ProcessCompileEvent(v8::CompileError, script); 1825} 1826 1827 1828void Debug::OnBeforeCompile(Handle<Script> script) { 1829 ProcessCompileEvent(v8::BeforeCompile, script); 1830} 1831 1832 1833// Handle debugger actions when a new script is compiled. 1834void Debug::OnAfterCompile(Handle<Script> script) { 1835 ProcessCompileEvent(v8::AfterCompile, script); 1836} 1837 1838void Debug::OnAsyncTaskEvent(Handle<String> type, Handle<Object> id, 1839 Handle<String> name) { 1840 DCHECK(id->IsNumber()); 1841 if (in_debug_scope() || ignore_events()) return; 1842 1843 HandleScope scope(isolate_); 1844 DebugScope debug_scope(this); 1845 if (debug_scope.failed()) return; 1846 1847 // Create the script collected state object. 1848 Handle<Object> event_data; 1849 // Bail out and don't call debugger if exception. 1850 if (!MakeAsyncTaskEvent(type, id, name).ToHandle(&event_data)) return; 1851 1852 // Process debug event. 1853 ProcessDebugEvent(v8::AsyncTaskEvent, 1854 Handle<JSObject>::cast(event_data), 1855 true); 1856} 1857 1858 1859void Debug::ProcessDebugEvent(v8::DebugEvent event, 1860 Handle<JSObject> event_data, 1861 bool auto_continue) { 1862 HandleScope scope(isolate_); 1863 1864 // Create the execution state. 1865 Handle<Object> exec_state; 1866 // Bail out and don't call debugger if exception. 1867 if (!MakeExecutionState().ToHandle(&exec_state)) return; 1868 1869 // First notify the message handler if any. 1870 if (message_handler_ != NULL) { 1871 NotifyMessageHandler(event, 1872 Handle<JSObject>::cast(exec_state), 1873 event_data, 1874 auto_continue); 1875 } 1876 // Notify registered debug event listener. This can be either a C or 1877 // a JavaScript function. Don't call event listener for v8::Break 1878 // here, if it's only a debug command -- they will be processed later. 1879 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) { 1880 CallEventCallback(event, exec_state, event_data, NULL); 1881 } 1882} 1883 1884 1885void Debug::CallEventCallback(v8::DebugEvent event, 1886 Handle<Object> exec_state, 1887 Handle<Object> event_data, 1888 v8::Debug::ClientData* client_data) { 1889 // Prevent other interrupts from triggering, for example API callbacks, 1890 // while dispatching event listners. 1891 PostponeInterruptsScope postpone(isolate_); 1892 bool previous = in_debug_event_listener_; 1893 in_debug_event_listener_ = true; 1894 if (event_listener_->IsForeign()) { 1895 // Invoke the C debug event listener. 1896 v8::DebugInterface::EventCallback callback = 1897 FUNCTION_CAST<v8::DebugInterface::EventCallback>( 1898 Handle<Foreign>::cast(event_listener_)->foreign_address()); 1899 EventDetailsImpl event_details(event, 1900 Handle<JSObject>::cast(exec_state), 1901 Handle<JSObject>::cast(event_data), 1902 event_listener_data_, 1903 client_data); 1904 callback(event_details); 1905 CHECK(!isolate_->has_scheduled_exception()); 1906 } else { 1907 // Invoke the JavaScript debug event listener. 1908 DCHECK(event_listener_->IsJSFunction()); 1909 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_), 1910 exec_state, 1911 event_data, 1912 event_listener_data_ }; 1913 Handle<JSReceiver> global = isolate_->global_proxy(); 1914 MaybeHandle<Object> result = 1915 Execution::Call(isolate_, Handle<JSFunction>::cast(event_listener_), 1916 global, arraysize(argv), argv); 1917 CHECK(!result.is_null()); // Listeners must not throw. 1918 } 1919 in_debug_event_listener_ = previous; 1920} 1921 1922 1923void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { 1924 if (ignore_events()) return; 1925 SuppressDebug while_processing(this); 1926 1927 bool in_nested_debug_scope = in_debug_scope(); 1928 HandleScope scope(isolate_); 1929 DebugScope debug_scope(this); 1930 if (debug_scope.failed()) return; 1931 1932 if (event == v8::AfterCompile) { 1933 // If debugging there might be script break points registered for this 1934 // script. Make sure that these break points are set. 1935 Handle<Object> argv[] = {Script::GetWrapper(script)}; 1936 if (CallFunction("UpdateScriptBreakPoints", arraysize(argv), argv) 1937 .is_null()) { 1938 return; 1939 } 1940 } 1941 1942 // Create the compile state object. 1943 Handle<Object> event_data; 1944 // Bail out and don't call debugger if exception. 1945 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return; 1946 1947 // Don't call NotifyMessageHandler if already in debug scope to avoid running 1948 // nested command loop. 1949 if (in_nested_debug_scope) { 1950 if (event_listener_.is_null()) return; 1951 // Create the execution state. 1952 Handle<Object> exec_state; 1953 // Bail out and don't call debugger if exception. 1954 if (!MakeExecutionState().ToHandle(&exec_state)) return; 1955 1956 CallEventCallback(event, exec_state, event_data, NULL); 1957 } else { 1958 // Process debug event. 1959 ProcessDebugEvent(event, Handle<JSObject>::cast(event_data), true); 1960 } 1961} 1962 1963 1964Handle<Context> Debug::GetDebugContext() { 1965 if (!is_loaded()) return Handle<Context>(); 1966 DebugScope debug_scope(this); 1967 if (debug_scope.failed()) return Handle<Context>(); 1968 // The global handle may be destroyed soon after. Return it reboxed. 1969 return handle(*debug_context(), isolate_); 1970} 1971 1972 1973void Debug::NotifyMessageHandler(v8::DebugEvent event, 1974 Handle<JSObject> exec_state, 1975 Handle<JSObject> event_data, 1976 bool auto_continue) { 1977 // Prevent other interrupts from triggering, for example API callbacks, 1978 // while dispatching message handler callbacks. 1979 PostponeInterruptsScope no_interrupts(isolate_); 1980 DCHECK(is_active_); 1981 HandleScope scope(isolate_); 1982 // Process the individual events. 1983 bool sendEventMessage = false; 1984 switch (event) { 1985 case v8::Break: 1986 sendEventMessage = !auto_continue; 1987 break; 1988 case v8::NewFunction: 1989 case v8::BeforeCompile: 1990 case v8::CompileError: 1991 case v8::AsyncTaskEvent: 1992 break; 1993 case v8::Exception: 1994 case v8::AfterCompile: 1995 sendEventMessage = true; 1996 break; 1997 } 1998 1999 // The debug command interrupt flag might have been set when the command was 2000 // added. It should be enough to clear the flag only once while we are in the 2001 // debugger. 2002 DCHECK(in_debug_scope()); 2003 isolate_->stack_guard()->ClearDebugCommand(); 2004 2005 // Notify the debugger that a debug event has occurred unless auto continue is 2006 // active in which case no event is send. 2007 if (sendEventMessage) { 2008 MessageImpl message = MessageImpl::NewEvent( 2009 event, 2010 auto_continue, 2011 Handle<JSObject>::cast(exec_state), 2012 Handle<JSObject>::cast(event_data)); 2013 InvokeMessageHandler(message); 2014 } 2015 2016 // If auto continue don't make the event cause a break, but process messages 2017 // in the queue if any. For script collected events don't even process 2018 // messages in the queue as the execution state might not be what is expected 2019 // by the client. 2020 if (auto_continue && !has_commands()) return; 2021 2022 // DebugCommandProcessor goes here. 2023 bool running = auto_continue; 2024 2025 Handle<Object> cmd_processor_ctor = 2026 JSReceiver::GetProperty(isolate_, exec_state, "debugCommandProcessor") 2027 .ToHandleChecked(); 2028 Handle<Object> ctor_args[] = { isolate_->factory()->ToBoolean(running) }; 2029 Handle<JSReceiver> cmd_processor = Handle<JSReceiver>::cast( 2030 Execution::Call(isolate_, cmd_processor_ctor, exec_state, 1, ctor_args) 2031 .ToHandleChecked()); 2032 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast( 2033 JSReceiver::GetProperty(isolate_, cmd_processor, "processDebugRequest") 2034 .ToHandleChecked()); 2035 Handle<Object> is_running = 2036 JSReceiver::GetProperty(isolate_, cmd_processor, "isRunning") 2037 .ToHandleChecked(); 2038 2039 // Process requests from the debugger. 2040 do { 2041 // Wait for new command in the queue. 2042 command_received_.Wait(); 2043 2044 // Get the command from the queue. 2045 CommandMessage command = command_queue_.Get(); 2046 isolate_->logger()->DebugTag( 2047 "Got request from command queue, in interactive loop."); 2048 if (!is_active()) { 2049 // Delete command text and user data. 2050 command.Dispose(); 2051 return; 2052 } 2053 2054 Vector<const uc16> command_text( 2055 const_cast<const uc16*>(command.text().start()), 2056 command.text().length()); 2057 Handle<String> request_text = isolate_->factory()->NewStringFromTwoByte( 2058 command_text).ToHandleChecked(); 2059 Handle<Object> request_args[] = { request_text }; 2060 Handle<Object> answer_value; 2061 Handle<String> answer; 2062 MaybeHandle<Object> maybe_exception; 2063 MaybeHandle<Object> maybe_result = 2064 Execution::TryCall(isolate_, process_debug_request, cmd_processor, 1, 2065 request_args, &maybe_exception); 2066 2067 if (maybe_result.ToHandle(&answer_value)) { 2068 if (answer_value->IsUndefined(isolate_)) { 2069 answer = isolate_->factory()->empty_string(); 2070 } else { 2071 answer = Handle<String>::cast(answer_value); 2072 } 2073 2074 // Log the JSON request/response. 2075 if (FLAG_trace_debug_json) { 2076 PrintF("%s\n", request_text->ToCString().get()); 2077 PrintF("%s\n", answer->ToCString().get()); 2078 } 2079 2080 Handle<Object> is_running_args[] = { answer }; 2081 maybe_result = Execution::Call( 2082 isolate_, is_running, cmd_processor, 1, is_running_args); 2083 Handle<Object> result; 2084 if (!maybe_result.ToHandle(&result)) break; 2085 running = result->IsTrue(isolate_); 2086 } else { 2087 Handle<Object> exception; 2088 if (!maybe_exception.ToHandle(&exception)) break; 2089 Handle<Object> result; 2090 if (!Object::ToString(isolate_, exception).ToHandle(&result)) break; 2091 answer = Handle<String>::cast(result); 2092 } 2093 2094 // Return the result. 2095 MessageImpl message = MessageImpl::NewResponse( 2096 event, running, exec_state, event_data, answer, command.client_data()); 2097 InvokeMessageHandler(message); 2098 command.Dispose(); 2099 2100 // Return from debug event processing if either the VM is put into the 2101 // running state (through a continue command) or auto continue is active 2102 // and there are no more commands queued. 2103 } while (!running || has_commands()); 2104 command_queue_.Clear(); 2105} 2106 2107 2108void Debug::SetEventListener(Handle<Object> callback, 2109 Handle<Object> data) { 2110 GlobalHandles* global_handles = isolate_->global_handles(); 2111 2112 // Remove existing entry. 2113 GlobalHandles::Destroy(event_listener_.location()); 2114 event_listener_ = Handle<Object>(); 2115 GlobalHandles::Destroy(event_listener_data_.location()); 2116 event_listener_data_ = Handle<Object>(); 2117 2118 // Set new entry. 2119 if (!callback->IsUndefined(isolate_) && !callback->IsNull(isolate_)) { 2120 event_listener_ = global_handles->Create(*callback); 2121 if (data.is_null()) data = isolate_->factory()->undefined_value(); 2122 event_listener_data_ = global_handles->Create(*data); 2123 } 2124 2125 UpdateState(); 2126} 2127 2128 2129void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) { 2130 message_handler_ = handler; 2131 UpdateState(); 2132 if (handler == NULL && in_debug_scope()) { 2133 // Send an empty command to the debugger if in a break to make JavaScript 2134 // run again if the debugger is closed. 2135 EnqueueCommandMessage(Vector<const uint16_t>::empty()); 2136 } 2137} 2138 2139 2140 2141void Debug::UpdateState() { 2142 bool is_active = message_handler_ != NULL || !event_listener_.is_null(); 2143 if (is_active || in_debug_scope()) { 2144 // Note that the debug context could have already been loaded to 2145 // bootstrap test cases. 2146 isolate_->compilation_cache()->Disable(); 2147 is_active = Load(); 2148 } else if (is_loaded()) { 2149 isolate_->compilation_cache()->Enable(); 2150 Unload(); 2151 } 2152 is_active_ = is_active; 2153} 2154 2155 2156// Calls the registered debug message handler. This callback is part of the 2157// public API. 2158void Debug::InvokeMessageHandler(MessageImpl message) { 2159 if (message_handler_ != NULL) message_handler_(message); 2160} 2161 2162 2163// Puts a command coming from the public API on the queue. Creates 2164// a copy of the command string managed by the debugger. Up to this 2165// point, the command data was managed by the API client. Called 2166// by the API client thread. 2167void Debug::EnqueueCommandMessage(Vector<const uint16_t> command, 2168 v8::Debug::ClientData* client_data) { 2169 // Need to cast away const. 2170 CommandMessage message = CommandMessage::New( 2171 Vector<uint16_t>(const_cast<uint16_t*>(command.start()), 2172 command.length()), 2173 client_data); 2174 isolate_->logger()->DebugTag("Put command on command_queue."); 2175 command_queue_.Put(message); 2176 command_received_.Signal(); 2177 2178 // Set the debug command break flag to have the command processed. 2179 if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand(); 2180} 2181 2182 2183MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) { 2184 DebugScope debug_scope(this); 2185 if (debug_scope.failed()) return isolate_->factory()->undefined_value(); 2186 2187 // Create the execution state. 2188 Handle<Object> exec_state; 2189 if (!MakeExecutionState().ToHandle(&exec_state)) { 2190 return isolate_->factory()->undefined_value(); 2191 } 2192 2193 Handle<Object> argv[] = { exec_state, data }; 2194 return Execution::Call( 2195 isolate_, 2196 fun, 2197 Handle<Object>(debug_context()->global_proxy(), isolate_), 2198 arraysize(argv), 2199 argv); 2200} 2201 2202 2203void Debug::HandleDebugBreak() { 2204 // Ignore debug break during bootstrapping. 2205 if (isolate_->bootstrapper()->IsActive()) return; 2206 // Just continue if breaks are disabled. 2207 if (break_disabled()) return; 2208 // Ignore debug break if debugger is not active. 2209 if (!is_active()) return; 2210 2211 StackLimitCheck check(isolate_); 2212 if (check.HasOverflowed()) return; 2213 2214 { JavaScriptFrameIterator it(isolate_); 2215 DCHECK(!it.done()); 2216 Object* fun = it.frame()->function(); 2217 if (fun && fun->IsJSFunction()) { 2218 // Don't stop in builtin functions. 2219 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return; 2220 JSGlobalObject* global = 2221 JSFunction::cast(fun)->context()->global_object(); 2222 // Don't stop in debugger functions. 2223 if (IsDebugGlobal(global)) return; 2224 // Don't stop if the break location is muted. 2225 if (IsMutedAtCurrentLocation(it.frame())) return; 2226 } 2227 } 2228 2229 // Collect the break state before clearing the flags. 2230 bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() && 2231 !isolate_->stack_guard()->CheckDebugBreak(); 2232 2233 isolate_->stack_guard()->ClearDebugBreak(); 2234 2235 // Clear stepping to avoid duplicate breaks. 2236 ClearStepping(); 2237 2238 ProcessDebugMessages(debug_command_only); 2239} 2240 2241 2242void Debug::ProcessDebugMessages(bool debug_command_only) { 2243 isolate_->stack_guard()->ClearDebugCommand(); 2244 2245 StackLimitCheck check(isolate_); 2246 if (check.HasOverflowed()) return; 2247 2248 HandleScope scope(isolate_); 2249 DebugScope debug_scope(this); 2250 if (debug_scope.failed()) return; 2251 2252 // Notify the debug event listeners. Indicate auto continue if the break was 2253 // a debug command break. 2254 OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only); 2255} 2256 2257#ifdef DEBUG 2258void Debug::PrintBreakLocation() { 2259 if (!FLAG_print_break_location) return; 2260 HandleScope scope(isolate_); 2261 JavaScriptFrameIterator iterator(isolate_); 2262 if (iterator.done()) return; 2263 JavaScriptFrame* frame = iterator.frame(); 2264 FrameSummary summary = FrameSummary::GetFirst(frame); 2265 int source_position = 2266 summary.abstract_code()->SourcePosition(summary.code_offset()); 2267 Handle<Object> script_obj(summary.function()->shared()->script(), isolate_); 2268 PrintF("[debug] break in function '"); 2269 summary.function()->PrintName(); 2270 PrintF("'.\n"); 2271 if (script_obj->IsScript()) { 2272 Handle<Script> script = Handle<Script>::cast(script_obj); 2273 Handle<String> source(String::cast(script->source())); 2274 Script::InitLineEnds(script); 2275 int line = 2276 Script::GetLineNumber(script, source_position) - script->line_offset(); 2277 int column = Script::GetColumnNumber(script, source_position) - 2278 (line == 0 ? script->column_offset() : 0); 2279 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends())); 2280 int line_start = 2281 line == 0 ? 0 : Smi::cast(line_ends->get(line - 1))->value() + 1; 2282 int line_end = Smi::cast(line_ends->get(line))->value(); 2283 DisallowHeapAllocation no_gc; 2284 String::FlatContent content = source->GetFlatContent(); 2285 if (content.IsOneByte()) { 2286 PrintF("[debug] %.*s\n", line_end - line_start, 2287 content.ToOneByteVector().start() + line_start); 2288 PrintF("[debug] "); 2289 for (int i = 0; i < column; i++) PrintF(" "); 2290 PrintF("^\n"); 2291 } else { 2292 PrintF("[debug] at line %d column %d\n", line, column); 2293 } 2294 } 2295} 2296#endif // DEBUG 2297 2298DebugScope::DebugScope(Debug* debug) 2299 : debug_(debug), 2300 prev_(debug->debugger_entry()), 2301 save_(debug_->isolate_), 2302 no_termination_exceptons_(debug_->isolate_, 2303 StackGuard::TERMINATE_EXECUTION) { 2304 // Link recursive debugger entry. 2305 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_, 2306 reinterpret_cast<base::AtomicWord>(this)); 2307 2308 // Store the previous break id, frame id and return value. 2309 break_id_ = debug_->break_id(); 2310 break_frame_id_ = debug_->break_frame_id(); 2311 return_value_ = debug_->return_value(); 2312 2313 // Create the new break info. If there is no proper frames there is no break 2314 // frame id. 2315 StackTraceFrameIterator it(isolate()); 2316 bool has_frames = !it.done(); 2317 // We don't currently support breaking inside wasm framess. 2318 DCHECK(!has_frames || !it.is_wasm()); 2319 debug_->thread_local_.break_frame_id_ = 2320 has_frames ? it.frame()->id() : StackFrame::NO_ID; 2321 debug_->SetNextBreakId(); 2322 2323 debug_->UpdateState(); 2324 // Make sure that debugger is loaded and enter the debugger context. 2325 // The previous context is kept in save_. 2326 failed_ = !debug_->is_loaded(); 2327 if (!failed_) isolate()->set_context(*debug->debug_context()); 2328} 2329 2330 2331DebugScope::~DebugScope() { 2332 if (!failed_ && prev_ == NULL) { 2333 // Clear mirror cache when leaving the debugger. Skip this if there is a 2334 // pending exception as clearing the mirror cache calls back into 2335 // JavaScript. This can happen if the v8::Debug::Call is used in which 2336 // case the exception should end up in the calling code. 2337 if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache(); 2338 2339 // If there are commands in the queue when leaving the debugger request 2340 // that these commands are processed. 2341 if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand(); 2342 } 2343 2344 // Leaving this debugger entry. 2345 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_, 2346 reinterpret_cast<base::AtomicWord>(prev_)); 2347 2348 // Restore to the previous break state. 2349 debug_->thread_local_.break_frame_id_ = break_frame_id_; 2350 debug_->thread_local_.break_id_ = break_id_; 2351 debug_->thread_local_.return_value_ = return_value_; 2352 2353 debug_->UpdateState(); 2354} 2355 2356 2357MessageImpl MessageImpl::NewEvent(DebugEvent event, 2358 bool running, 2359 Handle<JSObject> exec_state, 2360 Handle<JSObject> event_data) { 2361 MessageImpl message(true, event, running, 2362 exec_state, event_data, Handle<String>(), NULL); 2363 return message; 2364} 2365 2366 2367MessageImpl MessageImpl::NewResponse(DebugEvent event, 2368 bool running, 2369 Handle<JSObject> exec_state, 2370 Handle<JSObject> event_data, 2371 Handle<String> response_json, 2372 v8::Debug::ClientData* client_data) { 2373 MessageImpl message(false, event, running, 2374 exec_state, event_data, response_json, client_data); 2375 return message; 2376} 2377 2378 2379MessageImpl::MessageImpl(bool is_event, 2380 DebugEvent event, 2381 bool running, 2382 Handle<JSObject> exec_state, 2383 Handle<JSObject> event_data, 2384 Handle<String> response_json, 2385 v8::Debug::ClientData* client_data) 2386 : is_event_(is_event), 2387 event_(event), 2388 running_(running), 2389 exec_state_(exec_state), 2390 event_data_(event_data), 2391 response_json_(response_json), 2392 client_data_(client_data) {} 2393 2394 2395bool MessageImpl::IsEvent() const { 2396 return is_event_; 2397} 2398 2399 2400bool MessageImpl::IsResponse() const { 2401 return !is_event_; 2402} 2403 2404 2405DebugEvent MessageImpl::GetEvent() const { 2406 return event_; 2407} 2408 2409 2410bool MessageImpl::WillStartRunning() const { 2411 return running_; 2412} 2413 2414 2415v8::Local<v8::Object> MessageImpl::GetExecutionState() const { 2416 return v8::Utils::ToLocal(exec_state_); 2417} 2418 2419 2420v8::Isolate* MessageImpl::GetIsolate() const { 2421 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); 2422} 2423 2424 2425v8::Local<v8::Object> MessageImpl::GetEventData() const { 2426 return v8::Utils::ToLocal(event_data_); 2427} 2428 2429 2430v8::Local<v8::String> MessageImpl::GetJSON() const { 2431 Isolate* isolate = event_data_->GetIsolate(); 2432 v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate)); 2433 2434 if (IsEvent()) { 2435 // Call toJSONProtocol on the debug event object. 2436 Handle<Object> fun = 2437 JSReceiver::GetProperty(isolate, event_data_, "toJSONProtocol") 2438 .ToHandleChecked(); 2439 if (!fun->IsJSFunction()) { 2440 return v8::Local<v8::String>(); 2441 } 2442 2443 MaybeHandle<Object> maybe_json = 2444 Execution::TryCall(isolate, fun, event_data_, 0, NULL); 2445 Handle<Object> json; 2446 if (!maybe_json.ToHandle(&json) || !json->IsString()) { 2447 return v8::Local<v8::String>(); 2448 } 2449 return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json))); 2450 } else { 2451 return v8::Utils::ToLocal(response_json_); 2452 } 2453} 2454 2455namespace { 2456v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) { 2457 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); 2458 // Isolate::context() may have been NULL when "script collected" event 2459 // occured. 2460 if (context.is_null()) return v8::Local<v8::Context>(); 2461 Handle<Context> native_context(context->native_context()); 2462 return v8::Utils::ToLocal(native_context); 2463} 2464} // anonymous namespace 2465 2466v8::Local<v8::Context> MessageImpl::GetEventContext() const { 2467 Isolate* isolate = event_data_->GetIsolate(); 2468 v8::Local<v8::Context> context = GetDebugEventContext(isolate); 2469 // Isolate::context() may be NULL when "script collected" event occurs. 2470 DCHECK(!context.IsEmpty()); 2471 return context; 2472} 2473 2474 2475v8::Debug::ClientData* MessageImpl::GetClientData() const { 2476 return client_data_; 2477} 2478 2479 2480EventDetailsImpl::EventDetailsImpl(DebugEvent event, 2481 Handle<JSObject> exec_state, 2482 Handle<JSObject> event_data, 2483 Handle<Object> callback_data, 2484 v8::Debug::ClientData* client_data) 2485 : event_(event), 2486 exec_state_(exec_state), 2487 event_data_(event_data), 2488 callback_data_(callback_data), 2489 client_data_(client_data) {} 2490 2491 2492DebugEvent EventDetailsImpl::GetEvent() const { 2493 return event_; 2494} 2495 2496 2497v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const { 2498 return v8::Utils::ToLocal(exec_state_); 2499} 2500 2501 2502v8::Local<v8::Object> EventDetailsImpl::GetEventData() const { 2503 return v8::Utils::ToLocal(event_data_); 2504} 2505 2506 2507v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const { 2508 return GetDebugEventContext(exec_state_->GetIsolate()); 2509} 2510 2511 2512v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const { 2513 return v8::Utils::ToLocal(callback_data_); 2514} 2515 2516 2517v8::Debug::ClientData* EventDetailsImpl::GetClientData() const { 2518 return client_data_; 2519} 2520 2521v8::Isolate* EventDetailsImpl::GetIsolate() const { 2522 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); 2523} 2524 2525CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()), 2526 client_data_(NULL) { 2527} 2528 2529 2530CommandMessage::CommandMessage(const Vector<uint16_t>& text, 2531 v8::Debug::ClientData* data) 2532 : text_(text), 2533 client_data_(data) { 2534} 2535 2536 2537void CommandMessage::Dispose() { 2538 text_.Dispose(); 2539 delete client_data_; 2540 client_data_ = NULL; 2541} 2542 2543 2544CommandMessage CommandMessage::New(const Vector<uint16_t>& command, 2545 v8::Debug::ClientData* data) { 2546 return CommandMessage(command.Clone(), data); 2547} 2548 2549 2550CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0), 2551 size_(size) { 2552 messages_ = NewArray<CommandMessage>(size); 2553} 2554 2555 2556CommandMessageQueue::~CommandMessageQueue() { 2557 while (!IsEmpty()) Get().Dispose(); 2558 DeleteArray(messages_); 2559} 2560 2561 2562CommandMessage CommandMessageQueue::Get() { 2563 DCHECK(!IsEmpty()); 2564 int result = start_; 2565 start_ = (start_ + 1) % size_; 2566 return messages_[result]; 2567} 2568 2569 2570void CommandMessageQueue::Put(const CommandMessage& message) { 2571 if ((end_ + 1) % size_ == start_) { 2572 Expand(); 2573 } 2574 messages_[end_] = message; 2575 end_ = (end_ + 1) % size_; 2576} 2577 2578 2579void CommandMessageQueue::Expand() { 2580 CommandMessageQueue new_queue(size_ * 2); 2581 while (!IsEmpty()) { 2582 new_queue.Put(Get()); 2583 } 2584 CommandMessage* array_to_free = messages_; 2585 *this = new_queue; 2586 new_queue.messages_ = array_to_free; 2587 // Make the new_queue empty so that it doesn't call Dispose on any messages. 2588 new_queue.start_ = new_queue.end_; 2589 // Automatic destructor called on new_queue, freeing array_to_free. 2590} 2591 2592 2593LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size) 2594 : logger_(logger), queue_(size) {} 2595 2596 2597bool LockingCommandMessageQueue::IsEmpty() const { 2598 base::LockGuard<base::Mutex> lock_guard(&mutex_); 2599 return queue_.IsEmpty(); 2600} 2601 2602 2603CommandMessage LockingCommandMessageQueue::Get() { 2604 base::LockGuard<base::Mutex> lock_guard(&mutex_); 2605 CommandMessage result = queue_.Get(); 2606 logger_->DebugEvent("Get", result.text()); 2607 return result; 2608} 2609 2610 2611void LockingCommandMessageQueue::Put(const CommandMessage& message) { 2612 base::LockGuard<base::Mutex> lock_guard(&mutex_); 2613 queue_.Put(message); 2614 logger_->DebugEvent("Put", message.text()); 2615} 2616 2617 2618void LockingCommandMessageQueue::Clear() { 2619 base::LockGuard<base::Mutex> lock_guard(&mutex_); 2620 queue_.Clear(); 2621} 2622 2623} // namespace internal 2624} // namespace v8 2625