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 #include <unordered_set> 9 10 #include "src/api-inl.h" 11 #include "src/arguments.h" 12 #include "src/assembler-inl.h" 13 #include "src/base/platform/mutex.h" 14 #include "src/bootstrapper.h" 15 #include "src/builtins/builtins.h" 16 #include "src/code-stubs.h" 17 #include "src/compilation-cache.h" 18 #include "src/compiler.h" 19 #include "src/debug/debug-evaluate.h" 20 #include "src/debug/liveedit.h" 21 #include "src/deoptimizer.h" 22 #include "src/execution.h" 23 #include "src/frames-inl.h" 24 #include "src/global-handles.h" 25 #include "src/globals.h" 26 #include "src/interpreter/bytecode-array-accessor.h" 27 #include "src/interpreter/bytecode-array-iterator.h" 28 #include "src/interpreter/interpreter.h" 29 #include "src/isolate-inl.h" 30 #include "src/log.h" 31 #include "src/messages.h" 32 #include "src/objects/debug-objects-inl.h" 33 #include "src/objects/js-generator-inl.h" 34 #include "src/objects/js-promise-inl.h" 35 #include "src/snapshot/natives.h" 36 #include "src/snapshot/snapshot.h" 37 #include "src/wasm/wasm-objects-inl.h" 38 39 namespace v8 { 40 namespace internal { 41 42 class Debug::TemporaryObjectsTracker : public HeapObjectAllocationTracker { 43 public: 44 TemporaryObjectsTracker() = default; 45 ~TemporaryObjectsTracker() = default; 46 47 void AllocationEvent(Address addr, int) override { objects_.insert(addr); } 48 49 void MoveEvent(Address from, Address to, int) override { 50 if (from == to) return; 51 base::LockGuard<base::Mutex> guard(&mutex_); 52 auto it = objects_.find(from); 53 if (it == objects_.end()) { 54 // If temporary object was collected we can get MoveEvent which moves 55 // existing non temporary object to the address where we had temporary 56 // object. So we should mark new address as non temporary. 57 objects_.erase(to); 58 return; 59 } 60 objects_.erase(it); 61 objects_.insert(to); 62 } 63 64 bool HasObject(Handle<HeapObject> obj) const { 65 if (obj->IsJSObject() && 66 Handle<JSObject>::cast(obj)->GetEmbedderFieldCount()) { 67 // Embedder may store any pointers using embedder fields and implements 68 // non trivial logic, e.g. create wrappers lazily and store pointer to 69 // native object inside embedder field. We should consider all objects 70 // with embedder fields as non temporary. 71 return false; 72 } 73 return objects_.find(obj->address()) != objects_.end(); 74 } 75 76 private: 77 std::unordered_set<Address> objects_; 78 base::Mutex mutex_; 79 DISALLOW_COPY_AND_ASSIGN(TemporaryObjectsTracker); 80 }; 81 82 Debug::Debug(Isolate* isolate) 83 : is_active_(false), 84 hook_on_function_call_(false), 85 is_suppressed_(false), 86 break_disabled_(false), 87 break_points_active_(true), 88 break_on_exception_(false), 89 break_on_uncaught_exception_(false), 90 side_effect_check_failed_(false), 91 debug_info_list_(nullptr), 92 feature_tracker_(isolate), 93 isolate_(isolate) { 94 ThreadInit(); 95 } 96 97 Debug::~Debug() { DCHECK_NULL(debug_delegate_); } 98 99 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, 100 JavaScriptFrame* frame) { 101 if (debug_info->CanBreakAtEntry()) { 102 return BreakLocation(Debug::kBreakAtEntryPosition, DEBUG_BREAK_AT_ENTRY); 103 } 104 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); 105 int offset = summary.code_offset(); 106 Handle<AbstractCode> abstract_code = summary.abstract_code(); 107 BreakIterator it(debug_info); 108 it.SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset)); 109 return it.GetBreakLocation(); 110 } 111 112 void BreakLocation::AllAtCurrentStatement( 113 Handle<DebugInfo> debug_info, JavaScriptFrame* frame, 114 std::vector<BreakLocation>* result_out) { 115 DCHECK(!debug_info->CanBreakAtEntry()); 116 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); 117 int offset = summary.code_offset(); 118 Handle<AbstractCode> abstract_code = summary.abstract_code(); 119 if (abstract_code->IsCode()) offset = offset - 1; 120 int statement_position; 121 { 122 BreakIterator it(debug_info); 123 it.SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset)); 124 statement_position = it.statement_position(); 125 } 126 for (BreakIterator it(debug_info); !it.Done(); it.Next()) { 127 if (it.statement_position() == statement_position) { 128 result_out->push_back(it.GetBreakLocation()); 129 } 130 } 131 } 132 133 JSGeneratorObject* BreakLocation::GetGeneratorObjectForSuspendedFrame( 134 JavaScriptFrame* frame) const { 135 DCHECK(IsSuspend()); 136 DCHECK_GE(generator_obj_reg_index_, 0); 137 138 Object* generator_obj = 139 InterpretedFrame::cast(frame)->ReadInterpreterRegister( 140 generator_obj_reg_index_); 141 142 return JSGeneratorObject::cast(generator_obj); 143 } 144 145 int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, 146 Handle<AbstractCode> abstract_code, 147 int offset) { 148 // Run through all break points to locate the one closest to the address. 149 int closest_break = 0; 150 int distance = kMaxInt; 151 DCHECK(0 <= offset && offset < abstract_code->Size()); 152 for (BreakIterator it(debug_info); !it.Done(); it.Next()) { 153 // Check if this break point is closer that what was previously found. 154 if (it.code_offset() <= offset && offset - it.code_offset() < distance) { 155 closest_break = it.break_index(); 156 distance = offset - it.code_offset(); 157 // Check whether we can't get any closer. 158 if (distance == 0) break; 159 } 160 } 161 return closest_break; 162 } 163 164 bool BreakLocation::HasBreakPoint(Isolate* isolate, 165 Handle<DebugInfo> debug_info) const { 166 // First check whether there is a break point with the same source position. 167 if (!debug_info->HasBreakPoint(isolate, position_)) return false; 168 if (debug_info->CanBreakAtEntry()) { 169 DCHECK_EQ(Debug::kBreakAtEntryPosition, position_); 170 return debug_info->BreakAtEntry(); 171 } else { 172 // Then check whether a break point at that source position would have 173 // the same code offset. Otherwise it's just a break location that we can 174 // step to, but not actually a location where we can put a break point. 175 DCHECK(abstract_code_->IsBytecodeArray()); 176 BreakIterator it(debug_info); 177 it.SkipToPosition(position_); 178 return it.code_offset() == code_offset_; 179 } 180 } 181 182 debug::BreakLocationType BreakLocation::type() const { 183 switch (type_) { 184 case DEBUGGER_STATEMENT: 185 return debug::kDebuggerStatementBreakLocation; 186 case DEBUG_BREAK_SLOT_AT_CALL: 187 return debug::kCallBreakLocation; 188 case DEBUG_BREAK_SLOT_AT_RETURN: 189 return debug::kReturnBreakLocation; 190 191 // Externally, suspend breaks should look like normal breaks. 192 case DEBUG_BREAK_SLOT_AT_SUSPEND: 193 default: 194 return debug::kCommonBreakLocation; 195 } 196 } 197 198 BreakIterator::BreakIterator(Handle<DebugInfo> debug_info) 199 : debug_info_(debug_info), 200 break_index_(-1), 201 source_position_iterator_( 202 debug_info->DebugBytecodeArray()->SourcePositionTable()) { 203 position_ = debug_info->shared()->StartPosition(); 204 statement_position_ = position_; 205 // There is at least one break location. 206 DCHECK(!Done()); 207 Next(); 208 } 209 210 int BreakIterator::BreakIndexFromPosition(int source_position) { 211 int distance = kMaxInt; 212 int closest_break = break_index(); 213 while (!Done()) { 214 int next_position = position(); 215 if (source_position <= next_position && 216 next_position - source_position < distance) { 217 closest_break = break_index(); 218 distance = next_position - source_position; 219 // Check whether we can't get any closer. 220 if (distance == 0) break; 221 } 222 Next(); 223 } 224 return closest_break; 225 } 226 227 void BreakIterator::Next() { 228 DisallowHeapAllocation no_gc; 229 DCHECK(!Done()); 230 bool first = break_index_ == -1; 231 while (!Done()) { 232 if (!first) source_position_iterator_.Advance(); 233 first = false; 234 if (Done()) return; 235 position_ = source_position_iterator_.source_position().ScriptOffset(); 236 if (source_position_iterator_.is_statement()) { 237 statement_position_ = position_; 238 } 239 DCHECK_LE(0, position_); 240 DCHECK_LE(0, statement_position_); 241 242 DebugBreakType type = GetDebugBreakType(); 243 if (type != NOT_DEBUG_BREAK) break; 244 } 245 break_index_++; 246 } 247 248 DebugBreakType BreakIterator::GetDebugBreakType() { 249 BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray(); 250 interpreter::Bytecode bytecode = 251 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); 252 253 // Make sure we read the actual bytecode, not a prefix scaling bytecode. 254 if (interpreter::Bytecodes::IsPrefixScalingBytecode(bytecode)) { 255 bytecode = interpreter::Bytecodes::FromByte( 256 bytecode_array->get(code_offset() + 1)); 257 } 258 259 if (bytecode == interpreter::Bytecode::kDebugger) { 260 return DEBUGGER_STATEMENT; 261 } else if (bytecode == interpreter::Bytecode::kReturn) { 262 return DEBUG_BREAK_SLOT_AT_RETURN; 263 } else if (bytecode == interpreter::Bytecode::kSuspendGenerator) { 264 return DEBUG_BREAK_SLOT_AT_SUSPEND; 265 } else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) { 266 return DEBUG_BREAK_SLOT_AT_CALL; 267 } else if (source_position_iterator_.is_statement()) { 268 return DEBUG_BREAK_SLOT; 269 } else { 270 return NOT_DEBUG_BREAK; 271 } 272 } 273 274 void BreakIterator::SkipToPosition(int position) { 275 BreakIterator it(debug_info_); 276 SkipTo(it.BreakIndexFromPosition(position)); 277 } 278 279 void BreakIterator::SetDebugBreak() { 280 DebugBreakType debug_break_type = GetDebugBreakType(); 281 if (debug_break_type == DEBUGGER_STATEMENT) return; 282 HandleScope scope(isolate()); 283 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); 284 Handle<BytecodeArray> bytecode_array(debug_info_->DebugBytecodeArray(), 285 isolate()); 286 interpreter::BytecodeArrayAccessor(bytecode_array, code_offset()) 287 .ApplyDebugBreak(); 288 } 289 290 void BreakIterator::ClearDebugBreak() { 291 DebugBreakType debug_break_type = GetDebugBreakType(); 292 if (debug_break_type == DEBUGGER_STATEMENT) return; 293 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); 294 BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); 295 BytecodeArray* original = debug_info_->OriginalBytecodeArray(); 296 bytecode_array->set(code_offset(), original->get(code_offset())); 297 } 298 299 BreakLocation BreakIterator::GetBreakLocation() { 300 Handle<AbstractCode> code( 301 AbstractCode::cast(debug_info_->DebugBytecodeArray()), isolate()); 302 DebugBreakType type = GetDebugBreakType(); 303 int generator_object_reg_index = -1; 304 if (type == DEBUG_BREAK_SLOT_AT_SUSPEND) { 305 // For suspend break, we'll need the generator object to be able to step 306 // over the suspend as if it didn't return. We get the interpreter register 307 // index that holds the generator object by reading it directly off the 308 // bytecode array, and we'll read the actual generator object off the 309 // interpreter stack frame in GetGeneratorObjectForSuspendedFrame. 310 BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray(); 311 interpreter::BytecodeArrayAccessor accessor( 312 handle(bytecode_array, isolate()), code_offset()); 313 314 DCHECK_EQ(accessor.current_bytecode(), 315 interpreter::Bytecode::kSuspendGenerator); 316 interpreter::Register generator_obj_reg = accessor.GetRegisterOperand(0); 317 generator_object_reg_index = generator_obj_reg.index(); 318 } 319 return BreakLocation(code, type, code_offset(), position_, 320 generator_object_reg_index); 321 } 322 323 Isolate* BreakIterator::isolate() { return debug_info_->GetIsolate(); } 324 325 void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) { 326 uint32_t mask = 1 << feature; 327 // Only count one sample per feature and isolate. 328 if (bitfield_ & mask) return; 329 isolate_->counters()->debug_feature_usage()->AddSample(feature); 330 bitfield_ |= mask; 331 } 332 333 334 // Threading support. 335 void Debug::ThreadInit() { 336 thread_local_.break_frame_id_ = StackFrame::NO_ID; 337 thread_local_.last_step_action_ = StepNone; 338 thread_local_.last_statement_position_ = kNoSourcePosition; 339 thread_local_.last_frame_count_ = -1; 340 thread_local_.fast_forward_to_return_ = false; 341 thread_local_.ignore_step_into_function_ = Smi::kZero; 342 thread_local_.target_frame_count_ = -1; 343 thread_local_.return_value_ = Smi::kZero; 344 thread_local_.last_breakpoint_id_ = 0; 345 clear_suspended_generator(); 346 thread_local_.restart_fp_ = kNullAddress; 347 base::Relaxed_Store(&thread_local_.current_debug_scope_, 348 static_cast<base::AtomicWord>(0)); 349 thread_local_.break_on_next_function_call_ = false; 350 UpdateHookOnFunctionCall(); 351 } 352 353 354 char* Debug::ArchiveDebug(char* storage) { 355 MemCopy(storage, reinterpret_cast<char*>(&thread_local_), 356 ArchiveSpacePerThread()); 357 return storage + ArchiveSpacePerThread(); 358 } 359 360 char* Debug::RestoreDebug(char* storage) { 361 MemCopy(reinterpret_cast<char*>(&thread_local_), storage, 362 ArchiveSpacePerThread()); 363 364 // Enter the debugger. 365 DebugScope debug_scope(this); 366 367 // Clear any one-shot breakpoints that may have been set by the other 368 // thread, and reapply breakpoints for this thread. 369 ClearOneShot(); 370 371 if (thread_local_.last_step_action_ != StepNone) { 372 // Reset the previous step action for this thread. 373 PrepareStep(thread_local_.last_step_action_); 374 } 375 376 return storage + ArchiveSpacePerThread(); 377 } 378 379 int Debug::ArchiveSpacePerThread() { return sizeof(ThreadLocal); } 380 381 void Debug::Iterate(RootVisitor* v) { 382 v->VisitRootPointer(Root::kDebug, nullptr, &thread_local_.return_value_); 383 v->VisitRootPointer(Root::kDebug, nullptr, 384 &thread_local_.suspended_generator_); 385 v->VisitRootPointer(Root::kDebug, nullptr, 386 &thread_local_.ignore_step_into_function_); 387 } 388 389 DebugInfoListNode::DebugInfoListNode(Isolate* isolate, DebugInfo* debug_info) 390 : next_(nullptr) { 391 // Globalize the request debug info object and make it weak. 392 GlobalHandles* global_handles = isolate->global_handles(); 393 debug_info_ = global_handles->Create(debug_info).location(); 394 } 395 396 397 DebugInfoListNode::~DebugInfoListNode() { 398 if (debug_info_ == nullptr) return; 399 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_)); 400 debug_info_ = nullptr; 401 } 402 403 void Debug::Unload() { 404 ClearAllBreakPoints(); 405 ClearStepping(); 406 RemoveAllCoverageInfos(); 407 ClearAllDebuggerHints(); 408 debug_delegate_ = nullptr; 409 } 410 411 void Debug::Break(JavaScriptFrame* frame, Handle<JSFunction> break_target) { 412 // Initialize LiveEdit. 413 LiveEdit::InitializeThreadLocal(this); 414 415 // Just continue if breaks are disabled or debugger cannot be loaded. 416 if (break_disabled()) return; 417 418 // Enter the debugger. 419 DebugScope debug_scope(this); 420 421 // Postpone interrupt during breakpoint processing. 422 PostponeInterruptsScope postpone(isolate_); 423 DisableBreak no_recursive_break(this); 424 425 // Return if we fail to retrieve debug info. 426 Handle<SharedFunctionInfo> shared(break_target->shared(), isolate_); 427 if (!EnsureBreakInfo(shared)) return; 428 PrepareFunctionForDebugExecution(shared); 429 430 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); 431 432 // Find the break location where execution has stopped. 433 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); 434 435 // Find actual break points, if any, and trigger debug break event. 436 MaybeHandle<FixedArray> break_points_hit = 437 CheckBreakPoints(debug_info, &location); 438 if (!break_points_hit.is_null() || break_on_next_function_call()) { 439 // Clear all current stepping setup. 440 ClearStepping(); 441 // Notify the debug event listeners. 442 OnDebugBreak(!break_points_hit.is_null() 443 ? break_points_hit.ToHandleChecked() 444 : isolate_->factory()->empty_fixed_array()); 445 return; 446 } 447 448 // Debug break at function entry, do not worry about stepping. 449 if (location.IsDebugBreakAtEntry()) { 450 DCHECK(debug_info->BreakAtEntry()); 451 return; 452 } 453 454 DCHECK_NOT_NULL(frame); 455 456 // No break point. Check for stepping. 457 StepAction step_action = last_step_action(); 458 int current_frame_count = CurrentFrameCount(); 459 int target_frame_count = thread_local_.target_frame_count_; 460 int last_frame_count = thread_local_.last_frame_count_; 461 462 // StepOut at not return position was requested and return break locations 463 // were flooded with one shots. 464 if (thread_local_.fast_forward_to_return_) { 465 DCHECK(location.IsReturnOrSuspend()); 466 // We have to ignore recursive calls to function. 467 if (current_frame_count > target_frame_count) return; 468 ClearStepping(); 469 PrepareStep(StepOut); 470 return; 471 } 472 473 bool step_break = false; 474 switch (step_action) { 475 case StepNone: 476 return; 477 case StepOut: 478 // Step out should not break in a deeper frame than target frame. 479 if (current_frame_count > target_frame_count) return; 480 step_break = true; 481 break; 482 case StepNext: 483 // Step next should not break in a deeper frame than target frame. 484 if (current_frame_count > target_frame_count) return; 485 V8_FALLTHROUGH; 486 case StepIn: { 487 // Special case "next" and "in" for generators that are about to suspend. 488 if (location.IsSuspend()) { 489 DCHECK(!has_suspended_generator()); 490 thread_local_.suspended_generator_ = 491 location.GetGeneratorObjectForSuspendedFrame(frame); 492 ClearStepping(); 493 return; 494 } 495 496 FrameSummary summary = FrameSummary::GetTop(frame); 497 step_break = step_break || location.IsReturn() || 498 current_frame_count != last_frame_count || 499 thread_local_.last_statement_position_ != 500 summary.SourceStatementPosition(); 501 break; 502 } 503 } 504 505 // Clear all current stepping setup. 506 ClearStepping(); 507 508 if (step_break) { 509 // Notify the debug event listeners. 510 OnDebugBreak(isolate_->factory()->empty_fixed_array()); 511 } else { 512 // Re-prepare to continue. 513 PrepareStep(step_action); 514 } 515 } 516 517 518 // Find break point objects for this location, if any, and evaluate them. 519 // Return an array of break point objects that evaluated true, or an empty 520 // handle if none evaluated true. 521 MaybeHandle<FixedArray> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info, 522 BreakLocation* location, 523 bool* has_break_points) { 524 bool has_break_points_to_check = 525 break_points_active_ && location->HasBreakPoint(isolate_, debug_info); 526 if (has_break_points) *has_break_points = has_break_points_to_check; 527 if (!has_break_points_to_check) return {}; 528 529 return Debug::GetHitBreakPoints(debug_info, location->position()); 530 } 531 532 533 bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { 534 HandleScope scope(isolate_); 535 // A break location is considered muted if break locations on the current 536 // statement have at least one break point, and all of these break points 537 // evaluate to false. Aside from not triggering a debug break event at the 538 // break location, we also do not trigger one for debugger statements, nor 539 // an exception event on exception at this location. 540 FrameSummary summary = FrameSummary::GetTop(frame); 541 DCHECK(!summary.IsWasm()); 542 Handle<JSFunction> function = summary.AsJavaScript().function(); 543 if (!function->shared()->HasBreakInfo()) return false; 544 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo(), isolate_); 545 // Enter the debugger. 546 DebugScope debug_scope(this); 547 std::vector<BreakLocation> break_locations; 548 BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); 549 bool has_break_points_at_all = false; 550 for (size_t i = 0; i < break_locations.size(); i++) { 551 bool has_break_points; 552 MaybeHandle<FixedArray> check_result = 553 CheckBreakPoints(debug_info, &break_locations[i], &has_break_points); 554 has_break_points_at_all |= has_break_points; 555 if (has_break_points && !check_result.is_null()) return false; 556 } 557 return has_break_points_at_all; 558 } 559 560 // Check whether a single break point object is triggered. 561 bool Debug::CheckBreakPoint(Handle<BreakPoint> break_point, 562 bool is_break_at_entry) { 563 HandleScope scope(isolate_); 564 565 if (!break_point->condition()->length()) return true; 566 Handle<String> condition(break_point->condition(), isolate_); 567 MaybeHandle<Object> maybe_result; 568 Handle<Object> result; 569 570 if (is_break_at_entry) { 571 maybe_result = DebugEvaluate::WithTopmostArguments(isolate_, condition); 572 } else { 573 // Since we call CheckBreakpoint only for deoptimized frame on top of stack, 574 // we can use 0 as index of inlined frame. 575 const int inlined_jsframe_index = 0; 576 const bool throw_on_side_effect = false; 577 maybe_result = 578 DebugEvaluate::Local(isolate_, break_frame_id(), inlined_jsframe_index, 579 condition, throw_on_side_effect); 580 } 581 582 if (!maybe_result.ToHandle(&result)) { 583 if (isolate_->has_pending_exception()) { 584 isolate_->clear_pending_exception(); 585 } 586 return false; 587 } 588 return result->BooleanValue(isolate_); 589 } 590 591 bool Debug::SetBreakPoint(Handle<JSFunction> function, 592 Handle<BreakPoint> break_point, 593 int* source_position) { 594 HandleScope scope(isolate_); 595 596 // Make sure the function is compiled and has set up the debug info. 597 Handle<SharedFunctionInfo> shared(function->shared(), isolate_); 598 if (!EnsureBreakInfo(shared)) return false; 599 PrepareFunctionForDebugExecution(shared); 600 601 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); 602 // Source positions starts with zero. 603 DCHECK_LE(0, *source_position); 604 605 // Find the break point and change it. 606 *source_position = FindBreakablePosition(debug_info, *source_position); 607 DebugInfo::SetBreakPoint(isolate_, debug_info, *source_position, break_point); 608 // At least one active break point now. 609 DCHECK_LT(0, debug_info->GetBreakPointCount(isolate_)); 610 611 ClearBreakPoints(debug_info); 612 ApplyBreakPoints(debug_info); 613 614 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); 615 return true; 616 } 617 618 bool Debug::SetBreakPointForScript(Handle<Script> script, 619 Handle<String> condition, 620 int* source_position, int* id) { 621 *id = ++thread_local_.last_breakpoint_id_; 622 Handle<BreakPoint> break_point = 623 isolate_->factory()->NewBreakPoint(*id, condition); 624 if (script->type() == Script::TYPE_WASM) { 625 Handle<WasmModuleObject> module_object( 626 WasmModuleObject::cast(script->wasm_module_object()), isolate_); 627 return WasmModuleObject::SetBreakPoint(module_object, source_position, 628 break_point); 629 } 630 631 HandleScope scope(isolate_); 632 633 // Obtain shared function info for the function. 634 Handle<Object> result = 635 FindSharedFunctionInfoInScript(script, *source_position); 636 if (result->IsUndefined(isolate_)) return false; 637 638 // Make sure the function has set up the debug info. 639 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); 640 if (!EnsureBreakInfo(shared)) return false; 641 PrepareFunctionForDebugExecution(shared); 642 643 // Find position within function. The script position might be before the 644 // source position of the first function. 645 if (shared->StartPosition() > *source_position) { 646 *source_position = shared->StartPosition(); 647 } 648 649 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); 650 651 // Find breakable position returns first breakable position after 652 // *source_position, it can return 0 if no break location is found after 653 // *source_position. 654 int breakable_position = FindBreakablePosition(debug_info, *source_position); 655 if (breakable_position < *source_position) return false; 656 *source_position = breakable_position; 657 658 DebugInfo::SetBreakPoint(isolate_, debug_info, *source_position, break_point); 659 // At least one active break point now. 660 DCHECK_LT(0, debug_info->GetBreakPointCount(isolate_)); 661 662 ClearBreakPoints(debug_info); 663 ApplyBreakPoints(debug_info); 664 665 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); 666 return true; 667 } 668 669 int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info, 670 int source_position) { 671 if (debug_info->CanBreakAtEntry()) { 672 return kBreakAtEntryPosition; 673 } else { 674 DCHECK(debug_info->HasInstrumentedBytecodeArray()); 675 BreakIterator it(debug_info); 676 it.SkipToPosition(source_position); 677 return it.position(); 678 } 679 } 680 681 void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) { 682 DisallowHeapAllocation no_gc; 683 if (debug_info->CanBreakAtEntry()) { 684 debug_info->SetBreakAtEntry(); 685 } else { 686 if (!debug_info->HasInstrumentedBytecodeArray()) return; 687 FixedArray* break_points = debug_info->break_points(); 688 for (int i = 0; i < break_points->length(); i++) { 689 if (break_points->get(i)->IsUndefined(isolate_)) continue; 690 BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i)); 691 if (info->GetBreakPointCount(isolate_) == 0) continue; 692 DCHECK(debug_info->HasInstrumentedBytecodeArray()); 693 BreakIterator it(debug_info); 694 it.SkipToPosition(info->source_position()); 695 it.SetDebugBreak(); 696 } 697 } 698 debug_info->SetDebugExecutionMode(DebugInfo::kBreakpoints); 699 } 700 701 void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) { 702 if (debug_info->CanBreakAtEntry()) { 703 debug_info->ClearBreakAtEntry(); 704 } else { 705 // If we attempt to clear breakpoints but none exist, simply return. This 706 // can happen e.g. CoverageInfos exist but no breakpoints are set. 707 if (!debug_info->HasInstrumentedBytecodeArray() || 708 !debug_info->HasBreakInfo()) { 709 return; 710 } 711 712 DisallowHeapAllocation no_gc; 713 for (BreakIterator it(debug_info); !it.Done(); it.Next()) { 714 it.ClearDebugBreak(); 715 } 716 } 717 } 718 719 void Debug::ClearBreakPoint(Handle<BreakPoint> break_point) { 720 HandleScope scope(isolate_); 721 722 for (DebugInfoListNode* node = debug_info_list_; node != nullptr; 723 node = node->next()) { 724 if (!node->debug_info()->HasBreakInfo()) continue; 725 Handle<Object> result = DebugInfo::FindBreakPointInfo( 726 isolate_, node->debug_info(), break_point); 727 if (result->IsUndefined(isolate_)) continue; 728 Handle<DebugInfo> debug_info = node->debug_info(); 729 if (DebugInfo::ClearBreakPoint(isolate_, debug_info, break_point)) { 730 ClearBreakPoints(debug_info); 731 if (debug_info->GetBreakPointCount(isolate_) == 0) { 732 RemoveBreakInfoAndMaybeFree(debug_info); 733 } else { 734 ApplyBreakPoints(debug_info); 735 } 736 return; 737 } 738 } 739 } 740 741 int Debug::GetFunctionDebuggingId(Handle<JSFunction> function) { 742 Handle<SharedFunctionInfo> shared = handle(function->shared(), isolate_); 743 Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared); 744 int id = debug_info->debugging_id(); 745 if (id == DebugInfo::kNoDebuggingId) { 746 id = isolate_->heap()->NextDebuggingId(); 747 debug_info->set_debugging_id(id); 748 } 749 return id; 750 } 751 752 bool Debug::SetBreakpointForFunction(Handle<JSFunction> function, 753 Handle<String> condition, int* id) { 754 *id = ++thread_local_.last_breakpoint_id_; 755 Handle<BreakPoint> breakpoint = 756 isolate_->factory()->NewBreakPoint(*id, condition); 757 int source_position = 0; 758 return SetBreakPoint(function, breakpoint, &source_position); 759 } 760 761 void Debug::RemoveBreakpoint(int id) { 762 Handle<BreakPoint> breakpoint = isolate_->factory()->NewBreakPoint( 763 id, isolate_->factory()->empty_string()); 764 ClearBreakPoint(breakpoint); 765 } 766 767 // Clear out all the debug break code. 768 void Debug::ClearAllBreakPoints() { 769 ClearAllDebugInfos([=](Handle<DebugInfo> info) { 770 ClearBreakPoints(info); 771 info->ClearBreakInfo(isolate_); 772 }); 773 } 774 775 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared, 776 bool returns_only) { 777 if (IsBlackboxed(shared)) return; 778 // Make sure the function is compiled and has set up the debug info. 779 if (!EnsureBreakInfo(shared)) return; 780 PrepareFunctionForDebugExecution(shared); 781 782 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); 783 // Flood the function with break points. 784 DCHECK(debug_info->HasInstrumentedBytecodeArray()); 785 for (BreakIterator it(debug_info); !it.Done(); it.Next()) { 786 if (returns_only && !it.GetBreakLocation().IsReturnOrSuspend()) continue; 787 it.SetDebugBreak(); 788 } 789 } 790 791 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { 792 if (type == BreakUncaughtException) { 793 break_on_uncaught_exception_ = enable; 794 } else { 795 break_on_exception_ = enable; 796 } 797 } 798 799 800 bool Debug::IsBreakOnException(ExceptionBreakType type) { 801 if (type == BreakUncaughtException) { 802 return break_on_uncaught_exception_; 803 } else { 804 return break_on_exception_; 805 } 806 } 807 808 MaybeHandle<FixedArray> Debug::GetHitBreakPoints(Handle<DebugInfo> debug_info, 809 int position) { 810 Handle<Object> break_points = debug_info->GetBreakPoints(isolate_, position); 811 bool is_break_at_entry = debug_info->BreakAtEntry(); 812 DCHECK(!break_points->IsUndefined(isolate_)); 813 if (!break_points->IsFixedArray()) { 814 if (!CheckBreakPoint(Handle<BreakPoint>::cast(break_points), 815 is_break_at_entry)) { 816 return {}; 817 } 818 Handle<FixedArray> break_points_hit = isolate_->factory()->NewFixedArray(1); 819 break_points_hit->set(0, *break_points); 820 return break_points_hit; 821 } 822 823 Handle<FixedArray> array(FixedArray::cast(*break_points), isolate_); 824 int num_objects = array->length(); 825 Handle<FixedArray> break_points_hit = 826 isolate_->factory()->NewFixedArray(num_objects); 827 int break_points_hit_count = 0; 828 for (int i = 0; i < num_objects; ++i) { 829 Handle<Object> break_point(array->get(i), isolate_); 830 if (CheckBreakPoint(Handle<BreakPoint>::cast(break_point), 831 is_break_at_entry)) { 832 break_points_hit->set(break_points_hit_count++, *break_point); 833 } 834 } 835 if (break_points_hit_count == 0) return {}; 836 break_points_hit->Shrink(isolate_, break_points_hit_count); 837 return break_points_hit; 838 } 839 840 void Debug::SetBreakOnNextFunctionCall() { 841 // This method forces V8 to break on next function call regardless current 842 // last_step_action_. If any break happens between SetBreakOnNextFunctionCall 843 // and ClearBreakOnNextFunctionCall, we will clear this flag and stepping. If 844 // break does not happen, e.g. all called functions are blackboxed or no 845 // function is called, then we will clear this flag and let stepping continue 846 // its normal business. 847 thread_local_.break_on_next_function_call_ = true; 848 UpdateHookOnFunctionCall(); 849 } 850 851 void Debug::ClearBreakOnNextFunctionCall() { 852 thread_local_.break_on_next_function_call_ = false; 853 UpdateHookOnFunctionCall(); 854 } 855 856 void Debug::PrepareStepIn(Handle<JSFunction> function) { 857 CHECK(last_step_action() >= StepIn || break_on_next_function_call()); 858 if (ignore_events()) return; 859 if (in_debug_scope()) return; 860 if (break_disabled()) return; 861 Handle<SharedFunctionInfo> shared(function->shared(), isolate_); 862 if (IsBlackboxed(shared)) return; 863 if (*function == thread_local_.ignore_step_into_function_) return; 864 thread_local_.ignore_step_into_function_ = Smi::kZero; 865 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_)); 866 } 867 868 void Debug::PrepareStepInSuspendedGenerator() { 869 CHECK(has_suspended_generator()); 870 if (ignore_events()) return; 871 if (in_debug_scope()) return; 872 if (break_disabled()) return; 873 thread_local_.last_step_action_ = StepIn; 874 UpdateHookOnFunctionCall(); 875 Handle<JSFunction> function( 876 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function(), 877 isolate_); 878 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_)); 879 clear_suspended_generator(); 880 } 881 882 void Debug::PrepareStepOnThrow() { 883 if (last_step_action() == StepNone) return; 884 if (ignore_events()) return; 885 if (in_debug_scope()) return; 886 if (break_disabled()) return; 887 888 ClearOneShot(); 889 890 int current_frame_count = CurrentFrameCount(); 891 892 // Iterate through the JavaScript stack looking for handlers. 893 JavaScriptFrameIterator it(isolate_); 894 while (!it.done()) { 895 JavaScriptFrame* frame = it.frame(); 896 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; 897 std::vector<SharedFunctionInfo*> infos; 898 frame->GetFunctions(&infos); 899 current_frame_count -= infos.size(); 900 it.Advance(); 901 } 902 903 // No handler found. Nothing to instrument. 904 if (it.done()) return; 905 906 bool found_handler = false; 907 // Iterate frames, including inlined frames. First, find the handler frame. 908 // Then skip to the frame we want to break in, then instrument for stepping. 909 for (; !it.done(); it.Advance()) { 910 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); 911 if (last_step_action() == StepIn) { 912 // Deoptimize frame to ensure calls are checked for step-in. 913 Deoptimizer::DeoptimizeFunction(frame->function()); 914 } 915 std::vector<FrameSummary> summaries; 916 frame->Summarize(&summaries); 917 for (size_t i = summaries.size(); i != 0; i--, current_frame_count--) { 918 const FrameSummary& summary = summaries[i - 1]; 919 if (!found_handler) { 920 // We have yet to find the handler. If the frame inlines multiple 921 // functions, we have to check each one for the handler. 922 // If it only contains one function, we already found the handler. 923 if (summaries.size() > 1) { 924 Handle<AbstractCode> code = summary.AsJavaScript().abstract_code(); 925 CHECK_EQ(AbstractCode::INTERPRETED_FUNCTION, code->kind()); 926 HandlerTable table(code->GetBytecodeArray()); 927 int code_offset = summary.code_offset(); 928 HandlerTable::CatchPrediction prediction; 929 int index = table.LookupRange(code_offset, nullptr, &prediction); 930 if (index > 0) found_handler = true; 931 } else { 932 found_handler = true; 933 } 934 } 935 936 if (found_handler) { 937 // We found the handler. If we are stepping next or out, we need to 938 // iterate until we found the suitable target frame to break in. 939 if ((last_step_action() == StepNext || last_step_action() == StepOut) && 940 current_frame_count > thread_local_.target_frame_count_) { 941 continue; 942 } 943 Handle<SharedFunctionInfo> info( 944 summary.AsJavaScript().function()->shared(), isolate_); 945 if (IsBlackboxed(info)) continue; 946 FloodWithOneShot(info); 947 return; 948 } 949 } 950 } 951 } 952 953 954 void Debug::PrepareStep(StepAction step_action) { 955 HandleScope scope(isolate_); 956 957 DCHECK(in_debug_scope()); 958 959 // Get the frame where the execution has stopped and skip the debug frame if 960 // any. The debug frame will only be present if execution was stopped due to 961 // hitting a break point. In other situations (e.g. unhandled exception) the 962 // debug frame is not present. 963 StackFrame::Id frame_id = break_frame_id(); 964 // If there is no JavaScript stack don't do anything. 965 if (frame_id == StackFrame::NO_ID) return; 966 967 feature_tracker()->Track(DebugFeatureTracker::kStepping); 968 969 thread_local_.last_step_action_ = step_action; 970 971 StackTraceFrameIterator frames_it(isolate_, frame_id); 972 StandardFrame* frame = frames_it.frame(); 973 974 // Handle stepping in wasm functions via the wasm interpreter. 975 if (frame->is_wasm()) { 976 // If the top frame is compiled, we cannot step. 977 if (frame->is_wasm_compiled()) return; 978 WasmInterpreterEntryFrame* wasm_frame = 979 WasmInterpreterEntryFrame::cast(frame); 980 wasm_frame->debug_info()->PrepareStep(step_action); 981 return; 982 } 983 984 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); 985 DCHECK(js_frame->function()->IsJSFunction()); 986 987 // Get the debug info (create it if it does not exist). 988 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); 989 Handle<JSFunction> function(summary.function()); 990 Handle<SharedFunctionInfo> shared(function->shared(), isolate_); 991 if (!EnsureBreakInfo(shared)) return; 992 PrepareFunctionForDebugExecution(shared); 993 994 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); 995 996 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame); 997 998 // Any step at a return is a step-out, and a step-out at a suspend behaves 999 // like a return. 1000 if (location.IsReturn() || (location.IsSuspend() && step_action == StepOut)) { 1001 // On StepOut we'll ignore our further calls to current function in 1002 // PrepareStepIn callback. 1003 if (last_step_action() == StepOut) { 1004 thread_local_.ignore_step_into_function_ = *function; 1005 } 1006 step_action = StepOut; 1007 thread_local_.last_step_action_ = StepIn; 1008 } 1009 1010 // We need to schedule DebugOnFunction call callback 1011 UpdateHookOnFunctionCall(); 1012 1013 // A step-next in blackboxed function is a step-out. 1014 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut; 1015 1016 thread_local_.last_statement_position_ = 1017 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); 1018 int current_frame_count = CurrentFrameCount(); 1019 thread_local_.last_frame_count_ = current_frame_count; 1020 // No longer perform the current async step. 1021 clear_suspended_generator(); 1022 1023 switch (step_action) { 1024 case StepNone: 1025 UNREACHABLE(); 1026 break; 1027 case StepOut: { 1028 // Clear last position info. For stepping out it does not matter. 1029 thread_local_.last_statement_position_ = kNoSourcePosition; 1030 thread_local_.last_frame_count_ = -1; 1031 if (!location.IsReturnOrSuspend() && !IsBlackboxed(shared)) { 1032 // At not return position we flood return positions with one shots and 1033 // will repeat StepOut automatically at next break. 1034 thread_local_.target_frame_count_ = current_frame_count; 1035 thread_local_.fast_forward_to_return_ = true; 1036 FloodWithOneShot(shared, true); 1037 return; 1038 } 1039 // Skip the current frame, find the first frame we want to step out to 1040 // and deoptimize every frame along the way. 1041 bool in_current_frame = true; 1042 for (; !frames_it.done(); frames_it.Advance()) { 1043 // TODO(clemensh): Implement stepping out from JS to wasm. 1044 if (frames_it.frame()->is_wasm()) continue; 1045 JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame()); 1046 if (last_step_action() == StepIn) { 1047 // Deoptimize frame to ensure calls are checked for step-in. 1048 Deoptimizer::DeoptimizeFunction(frame->function()); 1049 } 1050 HandleScope scope(isolate_); 1051 std::vector<Handle<SharedFunctionInfo>> infos; 1052 frame->GetFunctions(&infos); 1053 for (; !infos.empty(); current_frame_count--) { 1054 Handle<SharedFunctionInfo> info = infos.back(); 1055 infos.pop_back(); 1056 if (in_current_frame) { 1057 // We want to skip out, so skip the current frame. 1058 in_current_frame = false; 1059 continue; 1060 } 1061 if (IsBlackboxed(info)) continue; 1062 FloodWithOneShot(info); 1063 thread_local_.target_frame_count_ = current_frame_count; 1064 return; 1065 } 1066 } 1067 break; 1068 } 1069 case StepNext: 1070 thread_local_.target_frame_count_ = current_frame_count; 1071 V8_FALLTHROUGH; 1072 case StepIn: 1073 // TODO(clemensh): Implement stepping from JS into wasm. 1074 FloodWithOneShot(shared); 1075 break; 1076 } 1077 } 1078 1079 // Simple function for returning the source positions for active break points. 1080 Handle<Object> Debug::GetSourceBreakLocations( 1081 Isolate* isolate, Handle<SharedFunctionInfo> shared) { 1082 if (!shared->HasBreakInfo()) { 1083 return isolate->factory()->undefined_value(); 1084 } 1085 1086 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate); 1087 if (debug_info->GetBreakPointCount(isolate) == 0) { 1088 return isolate->factory()->undefined_value(); 1089 } 1090 Handle<FixedArray> locations = isolate->factory()->NewFixedArray( 1091 debug_info->GetBreakPointCount(isolate)); 1092 int count = 0; 1093 for (int i = 0; i < debug_info->break_points()->length(); ++i) { 1094 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { 1095 BreakPointInfo* break_point_info = 1096 BreakPointInfo::cast(debug_info->break_points()->get(i)); 1097 int break_points = break_point_info->GetBreakPointCount(isolate); 1098 if (break_points == 0) continue; 1099 for (int j = 0; j < break_points; ++j) { 1100 locations->set(count++, 1101 Smi::FromInt(break_point_info->source_position())); 1102 } 1103 } 1104 } 1105 return locations; 1106 } 1107 1108 void Debug::ClearStepping() { 1109 // Clear the various stepping setup. 1110 ClearOneShot(); 1111 1112 thread_local_.last_step_action_ = StepNone; 1113 thread_local_.last_statement_position_ = kNoSourcePosition; 1114 thread_local_.ignore_step_into_function_ = Smi::kZero; 1115 thread_local_.fast_forward_to_return_ = false; 1116 thread_local_.last_frame_count_ = -1; 1117 thread_local_.target_frame_count_ = -1; 1118 thread_local_.break_on_next_function_call_ = false; 1119 UpdateHookOnFunctionCall(); 1120 } 1121 1122 1123 // Clears all the one-shot break points that are currently set. Normally this 1124 // function is called each time a break point is hit as one shot break points 1125 // are used to support stepping. 1126 void Debug::ClearOneShot() { 1127 // The current implementation just runs through all the breakpoints. When the 1128 // last break point for a function is removed that function is automatically 1129 // removed from the list. 1130 for (DebugInfoListNode* node = debug_info_list_; node != nullptr; 1131 node = node->next()) { 1132 Handle<DebugInfo> debug_info = node->debug_info(); 1133 ClearBreakPoints(debug_info); 1134 ApplyBreakPoints(debug_info); 1135 } 1136 } 1137 1138 class RedirectActiveFunctions : public ThreadVisitor { 1139 public: 1140 explicit RedirectActiveFunctions(SharedFunctionInfo* shared) 1141 : shared_(shared) { 1142 DCHECK(shared->HasBytecodeArray()); 1143 } 1144 1145 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { 1146 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) { 1147 JavaScriptFrame* frame = it.frame(); 1148 JSFunction* function = frame->function(); 1149 if (!frame->is_interpreted()) continue; 1150 if (function->shared() != shared_) continue; 1151 InterpretedFrame* interpreted_frame = 1152 reinterpret_cast<InterpretedFrame*>(frame); 1153 BytecodeArray* debug_copy = shared_->GetDebugInfo()->DebugBytecodeArray(); 1154 interpreted_frame->PatchBytecodeArray(debug_copy); 1155 } 1156 } 1157 1158 private: 1159 SharedFunctionInfo* shared_; 1160 DisallowHeapAllocation no_gc_; 1161 }; 1162 1163 void Debug::DeoptimizeFunction(Handle<SharedFunctionInfo> shared) { 1164 // Deoptimize all code compiled from this shared function info including 1165 // inlining. 1166 isolate_->AbortConcurrentOptimization(BlockingBehavior::kBlock); 1167 1168 // Make sure we abort incremental marking. 1169 isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask, 1170 GarbageCollectionReason::kDebugger); 1171 1172 bool found_something = false; 1173 Code::OptimizedCodeIterator iterator(isolate_); 1174 while (Code* code = iterator.Next()) { 1175 if (code->Inlines(*shared)) { 1176 code->set_marked_for_deoptimization(true); 1177 found_something = true; 1178 } 1179 } 1180 1181 if (found_something) { 1182 // Only go through with the deoptimization if something was found. 1183 Deoptimizer::DeoptimizeMarkedCode(isolate_); 1184 } 1185 } 1186 1187 void Debug::PrepareFunctionForDebugExecution( 1188 Handle<SharedFunctionInfo> shared) { 1189 // To prepare bytecode for debugging, we already need to have the debug 1190 // info (containing the debug copy) upfront, but since we do not recompile, 1191 // preparing for break points cannot fail. 1192 DCHECK(shared->is_compiled()); 1193 DCHECK(shared->HasDebugInfo()); 1194 Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared); 1195 if (debug_info->flags() & DebugInfo::kPreparedForDebugExecution) return; 1196 1197 // Make a copy of the bytecode array if available. 1198 Handle<Object> maybe_original_bytecode_array = 1199 isolate_->factory()->undefined_value(); 1200 if (shared->HasBytecodeArray()) { 1201 Handle<BytecodeArray> original_bytecode_array = 1202 handle(shared->GetBytecodeArray(), isolate_); 1203 Handle<BytecodeArray> debug_bytecode_array = 1204 isolate_->factory()->CopyBytecodeArray(original_bytecode_array); 1205 shared->SetDebugBytecodeArray(*debug_bytecode_array); 1206 maybe_original_bytecode_array = original_bytecode_array; 1207 } 1208 debug_info->set_original_bytecode_array(*maybe_original_bytecode_array); 1209 1210 if (debug_info->CanBreakAtEntry()) { 1211 // Deopt everything in case the function is inlined anywhere. 1212 Deoptimizer::DeoptimizeAll(isolate_); 1213 InstallDebugBreakTrampoline(); 1214 } else { 1215 DeoptimizeFunction(shared); 1216 // Update PCs on the stack to point to recompiled code. 1217 RedirectActiveFunctions redirect_visitor(*shared); 1218 redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top()); 1219 isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor); 1220 } 1221 debug_info->set_flags(debug_info->flags() | 1222 DebugInfo::kPreparedForDebugExecution); 1223 } 1224 1225 void Debug::InstallDebugBreakTrampoline() { 1226 // Check the list of debug infos whether the debug break trampoline needs to 1227 // be installed. If that's the case, iterate the heap for functions to rewire 1228 // to the trampoline. 1229 HandleScope scope(isolate_); 1230 // If there is a breakpoint at function entry, we need to install trampoline. 1231 bool needs_to_use_trampoline = false; 1232 // If there we break at entry to an api callback, we need to clear ICs. 1233 bool needs_to_clear_ic = false; 1234 for (DebugInfoListNode* current = debug_info_list_; current != nullptr; 1235 current = current->next()) { 1236 if (current->debug_info()->CanBreakAtEntry()) { 1237 needs_to_use_trampoline = true; 1238 if (current->debug_info()->shared()->IsApiFunction()) { 1239 needs_to_clear_ic = true; 1240 break; 1241 } 1242 } 1243 } 1244 1245 if (!needs_to_use_trampoline) return; 1246 1247 Handle<Code> trampoline = BUILTIN_CODE(isolate_, DebugBreakTrampoline); 1248 std::vector<Handle<JSFunction>> needs_compile; 1249 { 1250 HeapIterator iterator(isolate_->heap()); 1251 while (HeapObject* obj = iterator.next()) { 1252 if (needs_to_clear_ic && obj->IsFeedbackVector()) { 1253 FeedbackVector::cast(obj)->ClearSlots(isolate_); 1254 continue; 1255 } else if (obj->IsJSFunction()) { 1256 JSFunction* fun = JSFunction::cast(obj); 1257 SharedFunctionInfo* shared = fun->shared(); 1258 if (!shared->HasDebugInfo()) continue; 1259 if (!shared->GetDebugInfo()->CanBreakAtEntry()) continue; 1260 if (!fun->is_compiled()) { 1261 needs_compile.push_back(handle(fun, isolate_)); 1262 } else { 1263 fun->set_code(*trampoline); 1264 } 1265 } 1266 } 1267 } 1268 // By overwriting the function code with DebugBreakTrampoline, which tailcalls 1269 // to shared code, we bypass CompileLazy. Perform CompileLazy here instead. 1270 for (Handle<JSFunction> fun : needs_compile) { 1271 Compiler::Compile(fun, Compiler::CLEAR_EXCEPTION); 1272 fun->set_code(*trampoline); 1273 } 1274 } 1275 1276 namespace { 1277 template <typename Iterator> 1278 void GetBreakablePositions(Iterator* it, int start_position, int end_position, 1279 std::vector<BreakLocation>* locations) { 1280 while (!it->Done()) { 1281 if (it->position() >= start_position && it->position() < end_position) { 1282 locations->push_back(it->GetBreakLocation()); 1283 } 1284 it->Next(); 1285 } 1286 } 1287 1288 void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position, 1289 int end_position, 1290 std::vector<BreakLocation>* locations) { 1291 DCHECK(debug_info->HasInstrumentedBytecodeArray()); 1292 BreakIterator it(debug_info); 1293 GetBreakablePositions(&it, start_position, end_position, locations); 1294 } 1295 } // namespace 1296 1297 bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position, 1298 int end_position, bool restrict_to_function, 1299 std::vector<BreakLocation>* locations) { 1300 if (restrict_to_function) { 1301 Handle<Object> result = 1302 FindSharedFunctionInfoInScript(script, start_position); 1303 if (result->IsUndefined(isolate_)) return false; 1304 1305 // Make sure the function has set up the debug info. 1306 Handle<SharedFunctionInfo> shared = 1307 Handle<SharedFunctionInfo>::cast(result); 1308 if (!EnsureBreakInfo(shared)) return false; 1309 PrepareFunctionForDebugExecution(shared); 1310 1311 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); 1312 FindBreakablePositions(debug_info, start_position, end_position, locations); 1313 return true; 1314 } 1315 1316 while (true) { 1317 HandleScope scope(isolate_); 1318 std::vector<Handle<SharedFunctionInfo>> candidates; 1319 SharedFunctionInfo::ScriptIterator iterator(isolate_, *script); 1320 for (SharedFunctionInfo* info = iterator.Next(); info != nullptr; 1321 info = iterator.Next()) { 1322 if (info->EndPosition() < start_position || 1323 info->StartPosition() >= end_position) { 1324 continue; 1325 } 1326 if (!info->IsSubjectToDebugging()) continue; 1327 if (!info->is_compiled() && !info->allows_lazy_compilation()) continue; 1328 candidates.push_back(i::handle(info, isolate_)); 1329 } 1330 1331 bool was_compiled = false; 1332 for (const auto& candidate : candidates) { 1333 // Code that cannot be compiled lazily are internal and not debuggable. 1334 DCHECK(candidate->allows_lazy_compilation()); 1335 if (!candidate->is_compiled()) { 1336 if (!Compiler::Compile(candidate, Compiler::CLEAR_EXCEPTION)) { 1337 return false; 1338 } else { 1339 was_compiled = true; 1340 } 1341 } 1342 if (!EnsureBreakInfo(candidate)) return false; 1343 PrepareFunctionForDebugExecution(candidate); 1344 } 1345 if (was_compiled) continue; 1346 1347 for (const auto& candidate : candidates) { 1348 CHECK(candidate->HasBreakInfo()); 1349 Handle<DebugInfo> debug_info(candidate->GetDebugInfo(), isolate_); 1350 FindBreakablePositions(debug_info, start_position, end_position, 1351 locations); 1352 } 1353 return true; 1354 } 1355 UNREACHABLE(); 1356 } 1357 1358 class SharedFunctionInfoFinder { 1359 public: 1360 explicit SharedFunctionInfoFinder(int target_position) 1361 : current_candidate_(nullptr), 1362 current_candidate_closure_(nullptr), 1363 current_start_position_(kNoSourcePosition), 1364 target_position_(target_position) {} 1365 1366 void NewCandidate(SharedFunctionInfo* shared, JSFunction* closure = nullptr) { 1367 if (!shared->IsSubjectToDebugging()) return; 1368 int start_position = shared->function_token_position(); 1369 if (start_position == kNoSourcePosition) { 1370 start_position = shared->StartPosition(); 1371 } 1372 1373 if (start_position > target_position_) return; 1374 if (target_position_ > shared->EndPosition()) return; 1375 1376 if (current_candidate_ != nullptr) { 1377 if (current_start_position_ == start_position && 1378 shared->EndPosition() == current_candidate_->EndPosition()) { 1379 // If we already have a matching closure, do not throw it away. 1380 if (current_candidate_closure_ != nullptr && closure == nullptr) return; 1381 // If a top-level function contains only one function 1382 // declaration the source for the top-level and the function 1383 // is the same. In that case prefer the non top-level function. 1384 if (!current_candidate_->is_toplevel() && shared->is_toplevel()) return; 1385 } else if (start_position < current_start_position_ || 1386 current_candidate_->EndPosition() < shared->EndPosition()) { 1387 return; 1388 } 1389 } 1390 1391 current_start_position_ = start_position; 1392 current_candidate_ = shared; 1393 current_candidate_closure_ = closure; 1394 } 1395 1396 SharedFunctionInfo* Result() { return current_candidate_; } 1397 1398 JSFunction* ResultClosure() { return current_candidate_closure_; } 1399 1400 private: 1401 SharedFunctionInfo* current_candidate_; 1402 JSFunction* current_candidate_closure_; 1403 int current_start_position_; 1404 int target_position_; 1405 DisallowHeapAllocation no_gc_; 1406 }; 1407 1408 1409 // We need to find a SFI for a literal that may not yet have been compiled yet, 1410 // and there may not be a JSFunction referencing it. Find the SFI closest to 1411 // the given position, compile it to reveal possible inner SFIs and repeat. 1412 // While we are at this, also ensure code with debug break slots so that we do 1413 // not have to compile a SFI without JSFunction, which is paifu for those that 1414 // cannot be compiled without context (need to find outer compilable SFI etc.) 1415 Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script, 1416 int position) { 1417 for (int iteration = 0;; iteration++) { 1418 // Go through all shared function infos associated with this script to 1419 // find the inner most function containing this position. 1420 // If there is no shared function info for this script at all, there is 1421 // no point in looking for it by walking the heap. 1422 1423 SharedFunctionInfo* shared; 1424 { 1425 SharedFunctionInfoFinder finder(position); 1426 SharedFunctionInfo::ScriptIterator iterator(isolate_, *script); 1427 for (SharedFunctionInfo* info = iterator.Next(); info != nullptr; 1428 info = iterator.Next()) { 1429 finder.NewCandidate(info); 1430 } 1431 shared = finder.Result(); 1432 if (shared == nullptr) break; 1433 // We found it if it's already compiled. 1434 if (shared->is_compiled()) { 1435 Handle<SharedFunctionInfo> shared_handle(shared, isolate_); 1436 // If the iteration count is larger than 1, we had to compile the outer 1437 // function in order to create this shared function info. So there can 1438 // be no JSFunction referencing it. We can anticipate creating a debug 1439 // info while bypassing PrepareFunctionForDebugExecution. 1440 if (iteration > 1) { 1441 AllowHeapAllocation allow_before_return; 1442 CreateBreakInfo(shared_handle); 1443 } 1444 return shared_handle; 1445 } 1446 } 1447 // If not, compile to reveal inner functions. 1448 HandleScope scope(isolate_); 1449 // Code that cannot be compiled lazily are internal and not debuggable. 1450 DCHECK(shared->allows_lazy_compilation()); 1451 if (!Compiler::Compile(handle(shared, isolate_), Compiler::CLEAR_EXCEPTION)) 1452 break; 1453 } 1454 return isolate_->factory()->undefined_value(); 1455 } 1456 1457 1458 // Ensures the debug information is present for shared. 1459 bool Debug::EnsureBreakInfo(Handle<SharedFunctionInfo> shared) { 1460 // Return if we already have the break info for shared. 1461 if (shared->HasBreakInfo()) return true; 1462 if (!shared->IsSubjectToDebugging() && !CanBreakAtEntry(shared)) { 1463 return false; 1464 } 1465 if (!shared->is_compiled() && 1466 !Compiler::Compile(shared, Compiler::CLEAR_EXCEPTION)) { 1467 return false; 1468 } 1469 if (shared->GetCode() == 1470 isolate_->builtins()->builtin(Builtins::kDeserializeLazy)) { 1471 Snapshot::EnsureBuiltinIsDeserialized(isolate_, shared); 1472 } 1473 CreateBreakInfo(shared); 1474 return true; 1475 } 1476 1477 void Debug::CreateBreakInfo(Handle<SharedFunctionInfo> shared) { 1478 HandleScope scope(isolate_); 1479 Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared); 1480 1481 // Initialize with break information. 1482 1483 DCHECK(!debug_info->HasBreakInfo()); 1484 1485 Factory* factory = isolate_->factory(); 1486 Handle<FixedArray> break_points( 1487 factory->NewFixedArray(DebugInfo::kEstimatedNofBreakPointsInFunction)); 1488 1489 int flags = debug_info->flags(); 1490 flags |= DebugInfo::kHasBreakInfo; 1491 if (CanBreakAtEntry(shared)) flags |= DebugInfo::kCanBreakAtEntry; 1492 debug_info->set_flags(flags); 1493 debug_info->set_break_points(*break_points); 1494 } 1495 1496 Handle<DebugInfo> Debug::GetOrCreateDebugInfo( 1497 Handle<SharedFunctionInfo> shared) { 1498 if (shared->HasDebugInfo()) return handle(shared->GetDebugInfo(), isolate_); 1499 1500 // Create debug info and add it to the list. 1501 Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared); 1502 DebugInfoListNode* node = new DebugInfoListNode(isolate_, *debug_info); 1503 node->set_next(debug_info_list_); 1504 debug_info_list_ = node; 1505 1506 return debug_info; 1507 } 1508 1509 void Debug::InstallCoverageInfo(Handle<SharedFunctionInfo> shared, 1510 Handle<CoverageInfo> coverage_info) { 1511 DCHECK(!coverage_info.is_null()); 1512 1513 Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared); 1514 1515 DCHECK(!debug_info->HasCoverageInfo()); 1516 1517 debug_info->set_flags(debug_info->flags() | DebugInfo::kHasCoverageInfo); 1518 debug_info->set_coverage_info(*coverage_info); 1519 } 1520 1521 void Debug::RemoveAllCoverageInfos() { 1522 ClearAllDebugInfos( 1523 [=](Handle<DebugInfo> info) { info->ClearCoverageInfo(isolate_); }); 1524 } 1525 1526 void Debug::ClearAllDebuggerHints() { 1527 ClearAllDebugInfos( 1528 [=](Handle<DebugInfo> info) { info->set_debugger_hints(0); }); 1529 } 1530 1531 void Debug::FindDebugInfo(Handle<DebugInfo> debug_info, 1532 DebugInfoListNode** prev, DebugInfoListNode** curr) { 1533 HandleScope scope(isolate_); 1534 *prev = nullptr; 1535 *curr = debug_info_list_; 1536 while (*curr != nullptr) { 1537 if ((*curr)->debug_info().is_identical_to(debug_info)) return; 1538 *prev = *curr; 1539 *curr = (*curr)->next(); 1540 } 1541 1542 UNREACHABLE(); 1543 } 1544 1545 void Debug::ClearAllDebugInfos(DebugInfoClearFunction clear_function) { 1546 DebugInfoListNode* prev = nullptr; 1547 DebugInfoListNode* current = debug_info_list_; 1548 while (current != nullptr) { 1549 DebugInfoListNode* next = current->next(); 1550 Handle<DebugInfo> debug_info = current->debug_info(); 1551 clear_function(debug_info); 1552 if (debug_info->IsEmpty()) { 1553 FreeDebugInfoListNode(prev, current); 1554 current = next; 1555 } else { 1556 prev = current; 1557 current = next; 1558 } 1559 } 1560 } 1561 1562 void Debug::RemoveBreakInfoAndMaybeFree(Handle<DebugInfo> debug_info) { 1563 debug_info->ClearBreakInfo(isolate_); 1564 if (debug_info->IsEmpty()) { 1565 DebugInfoListNode* prev; 1566 DebugInfoListNode* node; 1567 FindDebugInfo(debug_info, &prev, &node); 1568 FreeDebugInfoListNode(prev, node); 1569 } 1570 } 1571 1572 void Debug::FreeDebugInfoListNode(DebugInfoListNode* prev, 1573 DebugInfoListNode* node) { 1574 DCHECK(node->debug_info()->IsEmpty()); 1575 1576 // Unlink from list. If prev is nullptr we are looking at the first element. 1577 if (prev == nullptr) { 1578 debug_info_list_ = node->next(); 1579 } else { 1580 prev->set_next(node->next()); 1581 } 1582 1583 // Pack script back into the 1584 // SFI::script_or_debug_info field. 1585 Handle<DebugInfo> debug_info(node->debug_info()); 1586 debug_info->shared()->set_script_or_debug_info(debug_info->script()); 1587 1588 delete node; 1589 } 1590 1591 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { 1592 HandleScope scope(isolate_); 1593 1594 // Get the executing function in which the debug break occurred. 1595 Handle<SharedFunctionInfo> shared(frame->function()->shared(), isolate_); 1596 1597 // With no debug info there are no break points, so we can't be at a return. 1598 if (!shared->HasBreakInfo()) return false; 1599 1600 DCHECK(!frame->is_optimized()); 1601 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); 1602 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); 1603 return location.IsReturn(); 1604 } 1605 1606 void Debug::ScheduleFrameRestart(StackFrame* frame) { 1607 // Set a target FP for the FrameDropperTrampoline builtin to drop to once 1608 // we return from the debugger. 1609 DCHECK(frame->is_java_script()); 1610 // Only reschedule to a frame further below a frame we already scheduled for. 1611 if (frame->fp() <= thread_local_.restart_fp_) return; 1612 // If the frame is optimized, trigger a deopt and jump into the 1613 // FrameDropperTrampoline in the deoptimizer. 1614 thread_local_.restart_fp_ = frame->fp(); 1615 1616 // Reset break frame ID to the frame below the restarted frame. 1617 StackTraceFrameIterator it(isolate_); 1618 thread_local_.break_frame_id_ = StackFrame::NO_ID; 1619 for (StackTraceFrameIterator it(isolate_); !it.done(); it.Advance()) { 1620 if (it.frame()->fp() > thread_local_.restart_fp_) { 1621 thread_local_.break_frame_id_ = it.frame()->id(); 1622 return; 1623 } 1624 } 1625 } 1626 1627 Handle<FixedArray> Debug::GetLoadedScripts() { 1628 isolate_->heap()->CollectAllGarbage(Heap::kFinalizeIncrementalMarkingMask, 1629 GarbageCollectionReason::kDebugger); 1630 Factory* factory = isolate_->factory(); 1631 if (!factory->script_list()->IsWeakArrayList()) { 1632 return factory->empty_fixed_array(); 1633 } 1634 Handle<WeakArrayList> array = 1635 Handle<WeakArrayList>::cast(factory->script_list()); 1636 Handle<FixedArray> results = factory->NewFixedArray(array->length()); 1637 int length = 0; 1638 { 1639 Script::Iterator iterator(isolate_); 1640 Script* script; 1641 while ((script = iterator.Next()) != nullptr) { 1642 if (script->HasValidSource()) results->set(length++, script); 1643 } 1644 } 1645 return FixedArray::ShrinkOrEmpty(isolate_, results, length); 1646 } 1647 1648 void Debug::OnThrow(Handle<Object> exception) { 1649 if (in_debug_scope() || ignore_events()) return; 1650 // Temporarily clear any scheduled_exception to allow evaluating 1651 // JavaScript from the debug event handler. 1652 HandleScope scope(isolate_); 1653 Handle<Object> scheduled_exception; 1654 if (isolate_->has_scheduled_exception()) { 1655 scheduled_exception = handle(isolate_->scheduled_exception(), isolate_); 1656 isolate_->clear_scheduled_exception(); 1657 } 1658 OnException(exception, isolate_->GetPromiseOnStackOnThrow()); 1659 if (!scheduled_exception.is_null()) { 1660 isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception; 1661 } 1662 PrepareStepOnThrow(); 1663 } 1664 1665 void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) { 1666 if (in_debug_scope() || ignore_events()) return; 1667 HandleScope scope(isolate_); 1668 // Check whether the promise has been marked as having triggered a message. 1669 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); 1670 if (!promise->IsJSObject() || 1671 JSReceiver::GetDataProperty(Handle<JSObject>::cast(promise), key) 1672 ->IsUndefined(isolate_)) { 1673 OnException(value, promise); 1674 } 1675 } 1676 1677 bool Debug::IsExceptionBlackboxed(bool uncaught) { 1678 // Uncaught exception is blackboxed if all current frames are blackboxed, 1679 // caught exception if top frame is blackboxed. 1680 StackTraceFrameIterator it(isolate_); 1681 while (!it.done() && it.is_wasm()) it.Advance(); 1682 bool is_top_frame_blackboxed = 1683 !it.done() ? IsFrameBlackboxed(it.javascript_frame()) : true; 1684 if (!uncaught || !is_top_frame_blackboxed) return is_top_frame_blackboxed; 1685 return AllFramesOnStackAreBlackboxed(); 1686 } 1687 1688 bool Debug::IsFrameBlackboxed(JavaScriptFrame* frame) { 1689 HandleScope scope(isolate_); 1690 std::vector<Handle<SharedFunctionInfo>> infos; 1691 frame->GetFunctions(&infos); 1692 for (const auto& info : infos) { 1693 if (!IsBlackboxed(info)) return false; 1694 } 1695 return true; 1696 } 1697 1698 void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { 1699 // TODO(kozyatinskiy): regress-662674.js test fails on arm without this. 1700 if (!AllowJavascriptExecution::IsAllowed(isolate_)) return; 1701 1702 Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher(); 1703 1704 // Don't notify listener of exceptions that are internal to a desugaring. 1705 if (catch_type == Isolate::CAUGHT_BY_DESUGARING) return; 1706 1707 bool uncaught = catch_type == Isolate::NOT_CAUGHT; 1708 if (promise->IsJSObject()) { 1709 Handle<JSObject> jspromise = Handle<JSObject>::cast(promise); 1710 // Mark the promise as already having triggered a message. 1711 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); 1712 JSObject::SetProperty(isolate_, jspromise, key, key, LanguageMode::kStrict) 1713 .Assert(); 1714 // Check whether the promise reject is considered an uncaught exception. 1715 uncaught = !isolate_->PromiseHasUserDefinedRejectHandler(jspromise); 1716 } 1717 1718 if (!debug_delegate_) return; 1719 1720 // Bail out if exception breaks are not active 1721 if (uncaught) { 1722 // Uncaught exceptions are reported by either flags. 1723 if (!(break_on_uncaught_exception_ || break_on_exception_)) return; 1724 } else { 1725 // Caught exceptions are reported is activated. 1726 if (!break_on_exception_) return; 1727 } 1728 1729 { 1730 JavaScriptFrameIterator it(isolate_); 1731 // Check whether the top frame is blackboxed or the break location is muted. 1732 if (!it.done() && (IsMutedAtCurrentLocation(it.frame()) || 1733 IsExceptionBlackboxed(uncaught))) { 1734 return; 1735 } 1736 if (it.done()) return; // Do not trigger an event with an empty stack. 1737 } 1738 1739 DebugScope debug_scope(this); 1740 HandleScope scope(isolate_); 1741 DisableBreak no_recursive_break(this); 1742 1743 Handle<Context> native_context(isolate_->native_context()); 1744 debug_delegate_->ExceptionThrown(v8::Utils::ToLocal(native_context), 1745 v8::Utils::ToLocal(exception), 1746 v8::Utils::ToLocal(promise), uncaught); 1747 } 1748 1749 void Debug::OnDebugBreak(Handle<FixedArray> break_points_hit) { 1750 DCHECK(!break_points_hit.is_null()); 1751 // The caller provided for DebugScope. 1752 AssertDebugContext(); 1753 // Bail out if there is no listener for this event 1754 if (ignore_events()) return; 1755 1756 #ifdef DEBUG 1757 PrintBreakLocation(); 1758 #endif // DEBUG 1759 1760 if (!debug_delegate_) return; 1761 HandleScope scope(isolate_); 1762 PostponeInterruptsScope no_interrupts(isolate_); 1763 DisableBreak no_recursive_break(this); 1764 1765 std::vector<int> inspector_break_points_hit; 1766 int inspector_break_points_count = 0; 1767 // This array contains breakpoints installed using JS debug API. 1768 for (int i = 0; i < break_points_hit->length(); ++i) { 1769 BreakPoint* break_point = BreakPoint::cast(break_points_hit->get(i)); 1770 inspector_break_points_hit.push_back(break_point->id()); 1771 ++inspector_break_points_count; 1772 } 1773 1774 Handle<Context> native_context(isolate_->native_context()); 1775 debug_delegate_->BreakProgramRequested(v8::Utils::ToLocal(native_context), 1776 inspector_break_points_hit); 1777 } 1778 1779 namespace { 1780 debug::Location GetDebugLocation(Handle<Script> script, int source_position) { 1781 Script::PositionInfo info; 1782 Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET); 1783 // V8 provides ScriptCompiler::CompileFunctionInContext method which takes 1784 // expression and compile it as anonymous function like (function() .. 1785 // expression ..). To produce correct locations for stmts inside of this 1786 // expression V8 compile this function with negative offset. Instead of stmt 1787 // position blackboxing use function start position which is negative in 1788 // described case. 1789 return debug::Location(std::max(info.line, 0), std::max(info.column, 0)); 1790 } 1791 } // namespace 1792 1793 bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) { 1794 if (!debug_delegate_) return !shared->IsSubjectToDebugging(); 1795 Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared); 1796 if (!debug_info->computed_debug_is_blackboxed()) { 1797 bool is_blackboxed = 1798 !shared->IsSubjectToDebugging() || !shared->script()->IsScript(); 1799 if (!is_blackboxed) { 1800 SuppressDebug while_processing(this); 1801 HandleScope handle_scope(isolate_); 1802 PostponeInterruptsScope no_interrupts(isolate_); 1803 DisableBreak no_recursive_break(this); 1804 DCHECK(shared->script()->IsScript()); 1805 Handle<Script> script(Script::cast(shared->script()), isolate_); 1806 DCHECK(script->IsUserJavaScript()); 1807 debug::Location start = GetDebugLocation(script, shared->StartPosition()); 1808 debug::Location end = GetDebugLocation(script, shared->EndPosition()); 1809 is_blackboxed = debug_delegate_->IsFunctionBlackboxed( 1810 ToApiHandle<debug::Script>(script), start, end); 1811 } 1812 debug_info->set_debug_is_blackboxed(is_blackboxed); 1813 debug_info->set_computed_debug_is_blackboxed(true); 1814 } 1815 return debug_info->debug_is_blackboxed(); 1816 } 1817 1818 bool Debug::AllFramesOnStackAreBlackboxed() { 1819 HandleScope scope(isolate_); 1820 for (StackTraceFrameIterator it(isolate_); !it.done(); it.Advance()) { 1821 if (!IsFrameBlackboxed(it.javascript_frame())) return false; 1822 } 1823 return true; 1824 } 1825 1826 bool Debug::CanBreakAtEntry(Handle<SharedFunctionInfo> shared) { 1827 // Allow break at entry for builtin functions. 1828 if (shared->native() || shared->IsApiFunction()) { 1829 // Functions that are subject to debugging can have regular breakpoints. 1830 DCHECK(!shared->IsSubjectToDebugging()); 1831 return true; 1832 } 1833 return false; 1834 } 1835 1836 bool Debug::SetScriptSource(Handle<Script> script, Handle<String> source, 1837 bool preview, debug::LiveEditResult* result) { 1838 DebugScope debug_scope(this); 1839 running_live_edit_ = true; 1840 LiveEdit::PatchScript(isolate_, script, source, preview, result); 1841 running_live_edit_ = false; 1842 return result->status == debug::LiveEditResult::OK; 1843 } 1844 1845 void Debug::OnCompileError(Handle<Script> script) { 1846 ProcessCompileEvent(true, script); 1847 } 1848 1849 void Debug::OnAfterCompile(Handle<Script> script) { 1850 ProcessCompileEvent(false, script); 1851 } 1852 1853 void Debug::ProcessCompileEvent(bool has_compile_error, Handle<Script> script) { 1854 // TODO(kozyatinskiy): teach devtools to work with liveedit scripts better 1855 // first and then remove this fast return. 1856 if (running_live_edit_) return; 1857 // Attach the correct debug id to the script. The debug id is used by the 1858 // inspector to filter scripts by native context. 1859 script->set_context_data(isolate_->native_context()->debug_context_id()); 1860 if (ignore_events()) return; 1861 if (!script->IsUserJavaScript() && script->type() != i::Script::TYPE_WASM) { 1862 return; 1863 } 1864 if (!debug_delegate_) return; 1865 SuppressDebug while_processing(this); 1866 DebugScope debug_scope(this); 1867 HandleScope scope(isolate_); 1868 DisableBreak no_recursive_break(this); 1869 AllowJavascriptExecution allow_script(isolate_); 1870 debug_delegate_->ScriptCompiled(ToApiHandle<debug::Script>(script), 1871 running_live_edit_, has_compile_error); 1872 } 1873 1874 int Debug::CurrentFrameCount() { 1875 StackTraceFrameIterator it(isolate_); 1876 if (break_frame_id() != StackFrame::NO_ID) { 1877 // Skip to break frame. 1878 DCHECK(in_debug_scope()); 1879 while (!it.done() && it.frame()->id() != break_frame_id()) it.Advance(); 1880 } 1881 int counter = 0; 1882 while (!it.done()) { 1883 if (it.frame()->is_optimized()) { 1884 std::vector<SharedFunctionInfo*> infos; 1885 OptimizedFrame::cast(it.frame())->GetFunctions(&infos); 1886 counter += infos.size(); 1887 } else { 1888 counter++; 1889 } 1890 it.Advance(); 1891 } 1892 return counter; 1893 } 1894 1895 void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) { 1896 debug_delegate_ = delegate; 1897 UpdateState(); 1898 } 1899 1900 void Debug::UpdateState() { 1901 bool is_active = debug_delegate_ != nullptr; 1902 if (is_active == is_active_) return; 1903 if (is_active) { 1904 // Note that the debug context could have already been loaded to 1905 // bootstrap test cases. 1906 isolate_->compilation_cache()->Disable(); 1907 is_active = true; 1908 feature_tracker()->Track(DebugFeatureTracker::kActive); 1909 } else { 1910 isolate_->compilation_cache()->Enable(); 1911 Unload(); 1912 } 1913 is_active_ = is_active; 1914 if (is_active && isolate_->IsPromiseHookProtectorIntact()) { 1915 isolate_->InvalidatePromiseHookProtector(); 1916 } 1917 } 1918 1919 void Debug::UpdateHookOnFunctionCall() { 1920 STATIC_ASSERT(LastStepAction == StepIn); 1921 hook_on_function_call_ = 1922 thread_local_.last_step_action_ == StepIn || 1923 isolate_->debug_execution_mode() == DebugInfo::kSideEffects || 1924 thread_local_.break_on_next_function_call_; 1925 } 1926 1927 void Debug::HandleDebugBreak(IgnoreBreakMode ignore_break_mode) { 1928 // Initialize LiveEdit. 1929 LiveEdit::InitializeThreadLocal(this); 1930 // Ignore debug break during bootstrapping. 1931 if (isolate_->bootstrapper()->IsActive()) return; 1932 // Just continue if breaks are disabled. 1933 if (break_disabled()) return; 1934 // Ignore debug break if debugger is not active. 1935 if (!is_active()) return; 1936 1937 StackLimitCheck check(isolate_); 1938 if (check.HasOverflowed()) return; 1939 1940 { JavaScriptFrameIterator it(isolate_); 1941 DCHECK(!it.done()); 1942 Object* fun = it.frame()->function(); 1943 if (fun && fun->IsJSFunction()) { 1944 HandleScope scope(isolate_); 1945 Handle<JSFunction> function(JSFunction::cast(fun), isolate_); 1946 // Don't stop in builtin and blackboxed functions. 1947 Handle<SharedFunctionInfo> shared(function->shared(), isolate_); 1948 bool ignore_break = ignore_break_mode == kIgnoreIfTopFrameBlackboxed 1949 ? IsBlackboxed(shared) 1950 : AllFramesOnStackAreBlackboxed(); 1951 if (ignore_break) return; 1952 // Don't stop if the break location is muted. 1953 if (IsMutedAtCurrentLocation(it.frame())) return; 1954 } 1955 } 1956 1957 // Clear stepping to avoid duplicate breaks. 1958 ClearStepping(); 1959 1960 HandleScope scope(isolate_); 1961 DebugScope debug_scope(this); 1962 1963 OnDebugBreak(isolate_->factory()->empty_fixed_array()); 1964 } 1965 1966 #ifdef DEBUG 1967 void Debug::PrintBreakLocation() { 1968 if (!FLAG_print_break_location) return; 1969 HandleScope scope(isolate_); 1970 StackTraceFrameIterator iterator(isolate_); 1971 if (iterator.done()) return; 1972 StandardFrame* frame = iterator.frame(); 1973 FrameSummary summary = FrameSummary::GetTop(frame); 1974 int source_position = summary.SourcePosition(); 1975 Handle<Object> script_obj = summary.script(); 1976 PrintF("[debug] break in function '"); 1977 summary.FunctionName()->PrintOn(stdout); 1978 PrintF("'.\n"); 1979 if (script_obj->IsScript()) { 1980 Handle<Script> script = Handle<Script>::cast(script_obj); 1981 Handle<String> source(String::cast(script->source()), isolate_); 1982 Script::InitLineEnds(script); 1983 int line = 1984 Script::GetLineNumber(script, source_position) - script->line_offset(); 1985 int column = Script::GetColumnNumber(script, source_position) - 1986 (line == 0 ? script->column_offset() : 0); 1987 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()), 1988 isolate_); 1989 int line_start = line == 0 ? 0 : Smi::ToInt(line_ends->get(line - 1)) + 1; 1990 int line_end = Smi::ToInt(line_ends->get(line)); 1991 DisallowHeapAllocation no_gc; 1992 String::FlatContent content = source->GetFlatContent(); 1993 if (content.IsOneByte()) { 1994 PrintF("[debug] %.*s\n", line_end - line_start, 1995 content.ToOneByteVector().start() + line_start); 1996 PrintF("[debug] "); 1997 for (int i = 0; i < column; i++) PrintF(" "); 1998 PrintF("^\n"); 1999 } else { 2000 PrintF("[debug] at line %d column %d\n", line, column); 2001 } 2002 } 2003 } 2004 #endif // DEBUG 2005 2006 DebugScope::DebugScope(Debug* debug) 2007 : debug_(debug), 2008 prev_(reinterpret_cast<DebugScope*>( 2009 base::Relaxed_Load(&debug->thread_local_.current_debug_scope_))), 2010 no_interrupts_(debug_->isolate_) { 2011 // Link recursive debugger entry. 2012 base::Relaxed_Store(&debug_->thread_local_.current_debug_scope_, 2013 reinterpret_cast<base::AtomicWord>(this)); 2014 2015 // Store the previous frame id and return value. 2016 break_frame_id_ = debug_->break_frame_id(); 2017 2018 // Create the new break info. If there is no proper frames there is no break 2019 // frame id. 2020 StackTraceFrameIterator it(isolate()); 2021 bool has_frames = !it.done(); 2022 debug_->thread_local_.break_frame_id_ = 2023 has_frames ? it.frame()->id() : StackFrame::NO_ID; 2024 2025 debug_->UpdateState(); 2026 } 2027 2028 2029 DebugScope::~DebugScope() { 2030 // Leaving this debugger entry. 2031 base::Relaxed_Store(&debug_->thread_local_.current_debug_scope_, 2032 reinterpret_cast<base::AtomicWord>(prev_)); 2033 2034 // Restore to the previous break state. 2035 debug_->thread_local_.break_frame_id_ = break_frame_id_; 2036 2037 debug_->UpdateState(); 2038 } 2039 2040 ReturnValueScope::ReturnValueScope(Debug* debug) : debug_(debug) { 2041 return_value_ = debug_->return_value_handle(); 2042 } 2043 2044 ReturnValueScope::~ReturnValueScope() { 2045 debug_->set_return_value(*return_value_); 2046 } 2047 2048 void Debug::UpdateDebugInfosForExecutionMode() { 2049 // Walk all debug infos and update their execution mode if it is different 2050 // from the isolate execution mode. 2051 DebugInfoListNode* current = debug_info_list_; 2052 while (current != nullptr) { 2053 Handle<DebugInfo> debug_info = current->debug_info(); 2054 if (debug_info->HasInstrumentedBytecodeArray() && 2055 debug_info->DebugExecutionMode() != isolate_->debug_execution_mode()) { 2056 DCHECK(debug_info->shared()->HasBytecodeArray()); 2057 if (isolate_->debug_execution_mode() == DebugInfo::kBreakpoints) { 2058 ClearSideEffectChecks(debug_info); 2059 ApplyBreakPoints(debug_info); 2060 } else { 2061 ClearBreakPoints(debug_info); 2062 ApplySideEffectChecks(debug_info); 2063 } 2064 } 2065 current = current->next(); 2066 } 2067 } 2068 2069 void Debug::StartSideEffectCheckMode() { 2070 DCHECK(isolate_->debug_execution_mode() != DebugInfo::kSideEffects); 2071 isolate_->set_debug_execution_mode(DebugInfo::kSideEffects); 2072 UpdateHookOnFunctionCall(); 2073 side_effect_check_failed_ = false; 2074 2075 DCHECK(!temporary_objects_); 2076 temporary_objects_.reset(new TemporaryObjectsTracker()); 2077 isolate_->heap()->AddHeapObjectAllocationTracker(temporary_objects_.get()); 2078 Handle<FixedArray> array(isolate_->native_context()->regexp_last_match_info(), 2079 isolate_); 2080 regexp_match_info_ = 2081 Handle<RegExpMatchInfo>::cast(isolate_->factory()->CopyFixedArray(array)); 2082 2083 // Update debug infos to have correct execution mode. 2084 UpdateDebugInfosForExecutionMode(); 2085 } 2086 2087 void Debug::StopSideEffectCheckMode() { 2088 DCHECK(isolate_->debug_execution_mode() == DebugInfo::kSideEffects); 2089 if (side_effect_check_failed_) { 2090 DCHECK(isolate_->has_pending_exception()); 2091 DCHECK_EQ(ReadOnlyRoots(isolate_).termination_exception(), 2092 isolate_->pending_exception()); 2093 // Convert the termination exception into a regular exception. 2094 isolate_->CancelTerminateExecution(); 2095 isolate_->Throw(*isolate_->factory()->NewEvalError( 2096 MessageTemplate::kNoSideEffectDebugEvaluate)); 2097 } 2098 isolate_->set_debug_execution_mode(DebugInfo::kBreakpoints); 2099 UpdateHookOnFunctionCall(); 2100 side_effect_check_failed_ = false; 2101 2102 DCHECK(temporary_objects_); 2103 isolate_->heap()->RemoveHeapObjectAllocationTracker(temporary_objects_.get()); 2104 temporary_objects_.reset(); 2105 isolate_->native_context()->set_regexp_last_match_info(*regexp_match_info_); 2106 regexp_match_info_ = Handle<RegExpMatchInfo>::null(); 2107 2108 // Update debug infos to have correct execution mode. 2109 UpdateDebugInfosForExecutionMode(); 2110 } 2111 2112 void Debug::ApplySideEffectChecks(Handle<DebugInfo> debug_info) { 2113 DCHECK(debug_info->HasInstrumentedBytecodeArray()); 2114 Handle<BytecodeArray> debug_bytecode(debug_info->DebugBytecodeArray(), 2115 isolate_); 2116 DebugEvaluate::ApplySideEffectChecks(debug_bytecode); 2117 debug_info->SetDebugExecutionMode(DebugInfo::kSideEffects); 2118 } 2119 2120 void Debug::ClearSideEffectChecks(Handle<DebugInfo> debug_info) { 2121 DCHECK(debug_info->HasInstrumentedBytecodeArray()); 2122 Handle<BytecodeArray> debug_bytecode(debug_info->DebugBytecodeArray(), 2123 isolate_); 2124 Handle<BytecodeArray> original(debug_info->OriginalBytecodeArray(), isolate_); 2125 for (interpreter::BytecodeArrayIterator it(debug_bytecode); !it.done(); 2126 it.Advance()) { 2127 // Restore from original. This may copy only the scaling prefix, which is 2128 // correct, since we patch scaling prefixes to debug breaks if exists. 2129 debug_bytecode->set(it.current_offset(), 2130 original->get(it.current_offset())); 2131 } 2132 } 2133 2134 bool Debug::PerformSideEffectCheck(Handle<JSFunction> function, 2135 Handle<Object> receiver) { 2136 DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects); 2137 DisallowJavascriptExecution no_js(isolate_); 2138 if (!function->is_compiled() && 2139 !Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) { 2140 return false; 2141 } 2142 Handle<SharedFunctionInfo> shared(function->shared(), isolate_); 2143 Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared); 2144 DebugInfo::SideEffectState side_effect_state = 2145 debug_info->GetSideEffectState(isolate_); 2146 switch (side_effect_state) { 2147 case DebugInfo::kHasSideEffects: 2148 if (FLAG_trace_side_effect_free_debug_evaluate) { 2149 PrintF("[debug-evaluate] Function %s failed side effect check.\n", 2150 function->shared()->DebugName()->ToCString().get()); 2151 } 2152 side_effect_check_failed_ = true; 2153 // Throw an uncatchable termination exception. 2154 isolate_->TerminateExecution(); 2155 return false; 2156 case DebugInfo::kRequiresRuntimeChecks: { 2157 if (!shared->HasBytecodeArray()) { 2158 return PerformSideEffectCheckForObject(receiver); 2159 } 2160 // If function has bytecode array then prepare function for debug 2161 // execution to perform runtime side effect checks. 2162 DCHECK(shared->is_compiled()); 2163 if (shared->GetCode() == 2164 isolate_->builtins()->builtin(Builtins::kDeserializeLazy)) { 2165 Snapshot::EnsureBuiltinIsDeserialized(isolate_, shared); 2166 } 2167 PrepareFunctionForDebugExecution(shared); 2168 ApplySideEffectChecks(debug_info); 2169 return true; 2170 } 2171 case DebugInfo::kHasNoSideEffect: 2172 return true; 2173 case DebugInfo::kNotComputed: 2174 UNREACHABLE(); 2175 return false; 2176 } 2177 UNREACHABLE(); 2178 return false; 2179 } 2180 2181 Handle<Object> Debug::return_value_handle() { 2182 return handle(thread_local_.return_value_, isolate_); 2183 } 2184 2185 bool Debug::PerformSideEffectCheckForCallback(Handle<Object> callback_info) { 2186 DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects); 2187 if (!callback_info.is_null() && callback_info->IsCallHandlerInfo() && 2188 i::CallHandlerInfo::cast(*callback_info)->NextCallHasNoSideEffect()) { 2189 return true; 2190 } 2191 // TODO(7515): always pass a valid callback info object. 2192 if (!callback_info.is_null() && 2193 DebugEvaluate::CallbackHasNoSideEffect(*callback_info)) { 2194 return true; 2195 } 2196 side_effect_check_failed_ = true; 2197 // Throw an uncatchable termination exception. 2198 isolate_->TerminateExecution(); 2199 isolate_->OptionalRescheduleException(false); 2200 return false; 2201 } 2202 2203 bool Debug::PerformSideEffectCheckAtBytecode(InterpretedFrame* frame) { 2204 using interpreter::Bytecode; 2205 2206 DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects); 2207 SharedFunctionInfo* shared = frame->function()->shared(); 2208 BytecodeArray* bytecode_array = shared->GetBytecodeArray(); 2209 int offset = frame->GetBytecodeOffset(); 2210 interpreter::BytecodeArrayAccessor bytecode_accessor( 2211 handle(bytecode_array, isolate_), offset); 2212 2213 Bytecode bytecode = bytecode_accessor.current_bytecode(); 2214 interpreter::Register reg; 2215 switch (bytecode) { 2216 case Bytecode::kStaCurrentContextSlot: 2217 reg = interpreter::Register::current_context(); 2218 break; 2219 default: 2220 reg = bytecode_accessor.GetRegisterOperand(0); 2221 break; 2222 } 2223 Handle<Object> object = 2224 handle(frame->ReadInterpreterRegister(reg.index()), isolate_); 2225 return PerformSideEffectCheckForObject(object); 2226 } 2227 2228 bool Debug::PerformSideEffectCheckForObject(Handle<Object> object) { 2229 DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects); 2230 2231 if (object->IsHeapObject()) { 2232 if (temporary_objects_->HasObject(Handle<HeapObject>::cast(object))) { 2233 return true; 2234 } 2235 } 2236 if (FLAG_trace_side_effect_free_debug_evaluate) { 2237 PrintF("[debug-evaluate] failed runtime side effect check.\n"); 2238 } 2239 side_effect_check_failed_ = true; 2240 // Throw an uncatchable termination exception. 2241 isolate_->TerminateExecution(); 2242 return false; 2243 } 2244 } // namespace internal 2245 } // namespace v8 2246