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