v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
debug.cc
Go to the documentation of this file.
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 <optional>
9
10#include "src/api/api-inl.h"
16#include "src/common/globals.h"
19#include "src/debug/liveedit.h"
28#include "src/heap/heap-inl.h" // For NextDebuggingId.
37#include "src/objects/slots.h"
39
40#if V8_ENABLE_WEBASSEMBLY
41#include "src/wasm/wasm-debug.h"
43#endif // V8_ENABLE_WEBASSEMBLY
44
45namespace v8 {
46namespace internal {
47
49 public:
51 ~TemporaryObjectsTracker() override = default;
54
55 void AllocationEvent(Address addr, int size) override {
56 if (disabled) return;
57 AddRegion(addr, addr + size);
58 }
59
60 void MoveEvent(Address from, Address to, int size) override {
61 if (from == to) return;
63 if (RemoveFromRegions(from, from + size)) {
64 // We had the object tracked as temporary, so we will track the
65 // new location as temporary, too.
66 AddRegion(to, to + size);
67 } else {
68 // The object we moved is a non-temporary, so the new location is also
69 // non-temporary. Thus we remove everything we track there (because it
70 // must have become dead).
71 RemoveFromRegions(to, to + size);
72 }
73 }
74
76 if (IsJSObject(*obj) && Cast<JSObject>(obj)->GetEmbedderFieldCount()) {
77 // Embedder may store any pointers using embedder fields and implements
78 // non trivial logic, e.g. create wrappers lazily and store pointer to
79 // native object inside embedder field. We should consider all objects
80 // with embedder fields as non temporary.
81 return false;
82 }
83 Address addr = obj->address();
84 return HasRegionContainingObject(addr, addr + obj->Size());
85 }
86
87 bool disabled = false;
88
89 private:
91 // Check if there is a region that contains (overlaps) this object's space.
92 auto it = FindOverlappingRegion(start, end, false);
93 // If there is, we expect the region to contain the entire object.
94 DCHECK_IMPLIES(it != regions_.end(),
95 it->second <= start && end <= it->first);
96 return it != regions_.end();
97 }
98
99 // This function returns any one of the overlapping regions (there might be
100 // multiple). If {include_adjacent} is true, it will also consider regions
101 // that have no overlap but are directly connected.
102 std::map<Address, Address>::iterator FindOverlappingRegion(
103 Address start, Address end, bool include_adjacent) {
104 // Region A = [start, end) overlaps with an existing region [existing_start,
105 // existing_end) iff (start <= existing_end) && (existing_start <= end).
106 // Since we index {regions_} by end address, we can find a candidate that
107 // satisfies the first condition using lower_bound.
108 if (include_adjacent) {
109 auto it = regions_.lower_bound(start);
110 if (it == regions_.end()) return regions_.end();
111 if (it->second <= end) return it;
112 } else {
113 auto it = regions_.upper_bound(start);
114 if (it == regions_.end()) return regions_.end();
115 if (it->second < end) return it;
116 }
117 return regions_.end();
118 }
119
122
123 // Region [start, end) can be combined with an existing region if they
124 // overlap.
125 while (true) {
126 auto it = FindOverlappingRegion(start, end, true);
127 // If there is no such region, we don't need to merge anything.
128 if (it == regions_.end()) break;
129
130 // Otherwise, we found an overlapping region. We remove the old one and
131 // add the new region recursively (to handle cases where the new region
132 // overlaps multiple existing ones).
133 start = std::min(start, it->second);
134 end = std::max(end, it->first);
135 regions_.erase(it);
136 }
137
138 // Add the new (possibly combined) region.
139 regions_.emplace(end, start);
140 }
141
143 // Check if we have anything that overlaps with [start, end).
144 auto it = FindOverlappingRegion(start, end, false);
145 if (it == regions_.end()) return false;
146
147 // We need to update all overlapping regions.
148 for (; it != regions_.end();
149 it = FindOverlappingRegion(start, end, false)) {
150 Address existing_start = it->second;
151 Address existing_end = it->first;
152 // If we remove the region [start, end) from an existing region
153 // [existing_start, existing_end), there can be at most 2 regions left:
154 regions_.erase(it);
155 // The one before {start} is: [existing_start, start)
156 if (existing_start < start) AddRegion(existing_start, start);
157 // And the one after {end} is: [end, existing_end)
158 if (end < existing_end) AddRegion(end, existing_end);
159 }
160 return true;
161 }
162
163 // Tracking addresses is not enough, because a single allocation may combine
164 // multiple objects due to allocation folding. We track both start and end
165 // (exclusive) address of regions. We index by end address for faster lookup.
166 // Map: end address => start address
167 std::map<Address, Address> regions_;
169};
170
172 : is_active_(false),
173 hook_on_function_call_(false),
174 is_suppressed_(false),
175 break_disabled_(false),
176 break_points_active_(true),
177 break_on_caught_exception_(false),
178 break_on_uncaught_exception_(false),
179 side_effect_check_failed_(false),
180 debug_infos_(isolate),
181 isolate_(isolate),
182 isolate_id_(0) {
183 ThreadInit();
184}
185
187
189 JavaScriptFrame* frame) {
190 if (debug_info->CanBreakAtEntry()) {
192 }
193 auto summary = FrameSummary::GetTop(frame).AsJavaScript();
194 int offset = summary.code_offset();
195 DirectHandle<AbstractCode> abstract_code = summary.abstract_code();
196 BreakIterator it(debug_info);
197 it.SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset));
198 return it.GetBreakLocation();
199}
200
202 auto summary = FrameSummary::GetTop(frame);
203 return summary.code_offset() == kFunctionEntryBytecodeOffset;
204}
205
207 Handle<DebugInfo> debug_info, std::vector<BreakLocation>& break_locations,
208 bool* has_break_points) {
209 DirectHandle<FixedArray> break_points_hit =
211 debug_info->GetBreakPointCount(isolate_));
212 int break_points_hit_count = 0;
213 bool has_break_points_at_all = false;
214 for (size_t i = 0; i < break_locations.size(); i++) {
215 bool location_has_break_points;
217 debug_info, &break_locations[i], &location_has_break_points);
218 has_break_points_at_all |= location_has_break_points;
219 if (!check_result.is_null()) {
220 DirectHandle<FixedArray> break_points_current_hit =
221 check_result.ToHandleChecked();
222 int num_objects = break_points_current_hit->length();
223 for (int j = 0; j < num_objects; ++j) {
224 break_points_hit->set(break_points_hit_count++,
225 break_points_current_hit->get(j));
226 }
227 }
228 }
229 *has_break_points = has_break_points_at_all;
230 if (break_points_hit_count == 0) return {};
231
232 break_points_hit->RightTrim(isolate_, break_points_hit_count);
233 return break_points_hit;
234}
235
237 Handle<DebugInfo> debug_info, JavaScriptFrame* frame,
238 std::vector<BreakLocation>* result_out) {
239 DCHECK(!debug_info->CanBreakAtEntry());
240 auto summary = FrameSummary::GetTop(frame).AsJavaScript();
241 int offset = summary.code_offset();
242 DirectHandle<AbstractCode> abstract_code = summary.abstract_code();
243 PtrComprCageBase cage_base = GetPtrComprCageBase(*debug_info);
244 if (IsCode(*abstract_code, cage_base)) offset = offset - 1;
245 int statement_position;
246 {
247 BreakIterator it(debug_info);
248 it.SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset));
249 statement_position = it.statement_position();
250 }
251 for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
252 if (it.statement_position() == statement_position) {
253 result_out->push_back(it.GetBreakLocation());
254 }
255 }
256}
257
269
271 Handle<DebugInfo> debug_info, DirectHandle<AbstractCode> abstract_code,
272 int offset) {
273 // Run through all break points to locate the one closest to the address.
274 int closest_break = 0;
275 int distance = kMaxInt;
278 for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
279 // Check if this break point is closer that what was previously found.
280 if (it.code_offset() <= offset && offset - it.code_offset() < distance) {
281 closest_break = it.break_index();
282 distance = offset - it.code_offset();
283 // Check whether we can't get any closer.
284 if (distance == 0) break;
285 }
286 }
287 return closest_break;
288}
289
291 Handle<DebugInfo> debug_info) const {
292 // First check whether there is a break point with the same source position.
293 if (!debug_info->HasBreakInfo() ||
294 !debug_info->HasBreakPoint(isolate, position_)) {
295 return false;
296 }
297 if (debug_info->CanBreakAtEntry()) {
299 return debug_info->BreakAtEntry();
300 } else {
301 // Then check whether a break point at that source position would have
302 // the same code offset. Otherwise it's just a break location that we can
303 // step to, but not actually a location where we can put a break point.
304 DCHECK(IsBytecodeArray(*abstract_code_, isolate));
305 BreakIterator it(debug_info);
306 it.SkipToPosition(position_);
307 return it.code_offset() == code_offset_;
308 }
309}
310
312 switch (type_) {
319
320 // Externally, suspend breaks should look like normal breaks.
322 default:
324 }
325}
326
328 : debug_info_(debug_info),
329 break_index_(-1),
330 source_position_iterator_(
331 debug_info->DebugBytecodeArray(isolate())->SourcePositionTable()) {
332 position_ = debug_info->shared()->StartPosition();
334 // There is at least one break location.
335 DCHECK(!Done());
336 Next();
337}
338
340 for (; !Done(); Next()) {
342 if (source_position <= position()) {
343 int first_break = break_index();
344 for (; !Done(); Next()) {
346 if (source_position == position()) return break_index();
347 }
348 return first_break;
349 }
350 }
351 return break_index();
352}
353
356 DCHECK(!Done());
357 bool first = break_index_ == -1;
358 while (!Done()) {
360 first = false;
361 if (Done()) return;
365 }
368
370 if (type != NOT_DEBUG_BREAK) break;
371 }
372 break_index_++;
373}
374
376 Tagged<BytecodeArray> bytecode_array =
377 debug_info_->OriginalBytecodeArray(isolate());
378 interpreter::Bytecode bytecode =
379 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
380
381 // Make sure we read the actual bytecode, not a prefix scaling bytecode.
384 bytecode_array->get(code_offset() + 1));
385 }
386
387 if (bytecode == interpreter::Bytecode::kDebugger) {
388 return DEBUGGER_STATEMENT;
389 } else if (bytecode == interpreter::Bytecode::kReturn) {
391 } else if (bytecode == interpreter::Bytecode::kSuspendGenerator) {
392 // SuspendGenerator should always only carry an expression position that
393 // is used in stack trace construction, but should never be a breakable
394 // position reported to the debugger front-end.
397 } else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) {
400 return DEBUG_BREAK_SLOT;
401 } else {
402 return NOT_DEBUG_BREAK;
403 }
404}
405
408 SkipTo(it.BreakIndexFromPosition(position));
409}
410
413 HandleScope scope(isolate());
414 Handle<BytecodeArray> bytecode_array(
415 debug_info_->DebugBytecodeArray(isolate()), isolate());
418}
419
422 Tagged<BytecodeArray> bytecode_array =
423 debug_info_->DebugBytecodeArray(isolate());
424 Tagged<BytecodeArray> original =
425 debug_info_->OriginalBytecodeArray(isolate());
426 bytecode_array->set(code_offset(), original->get(code_offset()));
427}
428
431 Cast<AbstractCode>(debug_info_->DebugBytecodeArray(isolate())),
432 isolate());
434 int generator_object_reg_index = -1;
435 int generator_suspend_id = -1;
436 if (type == DEBUG_BREAK_SLOT_AT_SUSPEND) {
437 // For suspend break, we'll need the generator object to be able to step
438 // over the suspend as if it didn't return. We get the interpreter register
439 // index that holds the generator object by reading it directly off the
440 // bytecode array, and we'll read the actual generator object off the
441 // interpreter stack frame in GetGeneratorObjectForSuspendedFrame.
442 Tagged<BytecodeArray> bytecode_array =
443 debug_info_->OriginalBytecodeArray(isolate());
445 handle(bytecode_array, isolate()), code_offset());
446
447 DCHECK_EQ(iterator.current_bytecode(),
448 interpreter::Bytecode::kSuspendGenerator);
449 interpreter::Register generator_obj_reg = iterator.GetRegisterOperand(0);
450 generator_object_reg_index = generator_obj_reg.index();
451
452 // Also memorize the suspend ID, to be able to decide whether
453 // we are paused on the implicit initial yield later.
454 generator_suspend_id = iterator.GetUnsignedImmediateOperand(3);
455 }
456 return BreakLocation(code, type, code_offset(), position_,
457 generator_object_reg_index, generator_suspend_id);
458}
459
460Isolate* BreakIterator::isolate() { return debug_info_->GetIsolate(); }
461
462// Threading support.
484
485char* Debug::ArchiveDebug(char* storage) {
486 MemCopy(storage, reinterpret_cast<char*>(&thread_local_),
488 return storage + ArchiveSpacePerThread();
489}
490
491char* Debug::RestoreDebug(char* storage) {
492 MemCopy(reinterpret_cast<char*>(&thread_local_), storage,
494
495 // Enter the isolate.
496 v8::Isolate::Scope isolate_scope(reinterpret_cast<v8::Isolate*>(isolate_));
497 // Enter the debugger.
498 DebugScope debug_scope(this);
499
500 // Clear any one-shot breakpoints that may have been set by the other
501 // thread, and reapply breakpoints for this thread.
502 ClearOneShot();
503
505 int current_frame_count = CurrentFrameCount();
506 int target_frame_count = thread_local_.target_frame_count_;
507 DCHECK(current_frame_count >= target_frame_count);
509 while (current_frame_count > target_frame_count) {
510 current_frame_count -= frames_it.FrameFunctionCount();
511 frames_it.Advance();
512 }
513 DCHECK(current_frame_count == target_frame_count);
514 // Set frame to what it was at Step break
515 thread_local_.break_frame_id_ = frames_it.frame()->id();
516
517 // Reset the previous step action for this thread.
519 }
520
521 return storage + ArchiveSpacePerThread();
522}
523
525
527
528char* Debug::Iterate(RootVisitor* v, char* thread_storage) {
529 ThreadLocal* thread_local_data =
530 reinterpret_cast<ThreadLocal*>(thread_storage);
531 Iterate(v, thread_local_data);
532 return thread_storage + ArchiveSpacePerThread();
533}
534
535void Debug::Iterate(RootVisitor* v, ThreadLocal* thread_local_data) {
536 v->VisitRootPointer(Root::kDebug, nullptr,
537 FullObjectSlot(&thread_local_data->return_value_));
538 v->VisitRootPointer(Root::kDebug, nullptr,
539 FullObjectSlot(&thread_local_data->suspended_generator_));
541 Root::kDebug, nullptr,
542 FullObjectSlot(&thread_local_data->ignore_step_into_function_));
543 v->VisitRootPointer(Root::kDebug, nullptr,
544 FullObjectSlot(&thread_local_data->muted_function_));
545}
546
548 Tagged<DebugInfo> debug_info) {
551
552 DCHECK_EQ(sfi, debug_info->shared());
553 DCHECK(!Contains(sfi));
554 HandleLocation location =
555 isolate_->global_handles()->Create(debug_info).location();
556 list_.push_back(location);
557 map_.emplace(sfi->unique_id(), location);
558 DCHECK(Contains(sfi));
559 DCHECK_EQ(list_.size(), map_.size());
560}
561
563 auto it = map_.find(sfi->unique_id());
564 if (it == map_.end()) return false;
565 DCHECK_EQ(Cast<DebugInfo>(Tagged<Object>(*it->second))->shared(), sfi);
566 return true;
567}
568
569std::optional<Tagged<DebugInfo>> DebugInfoCollection::Find(
570 Tagged<SharedFunctionInfo> sfi) const {
571 auto it = map_.find(sfi->unique_id());
572 if (it == map_.end()) return {};
574 DCHECK_EQ(di->shared(), sfi);
575 return di;
576}
577
580 for (; it.HasNext(); it.Advance()) {
581 Tagged<DebugInfo> debug_info = it.Next();
582 if (debug_info->shared() != sfi) continue;
583 it.DeleteNext();
584 return;
585 }
586 UNREACHABLE();
587}
588
590 DCHECK_LT(index, list_.size());
591 return Cast<DebugInfo>(Tagged<Object>(*list_[index]));
592}
593
596
597 Tagged<DebugInfo> debug_info = EntryAsDebugInfo(index);
598 Tagged<SharedFunctionInfo> sfi = debug_info->shared();
599 DCHECK(Contains(sfi));
600
601 auto it = map_.find(sfi->unique_id());
602 HandleLocation location = it->second;
603 DCHECK_EQ(location, list_[index]);
604 map_.erase(it);
605
606 list_[index] = list_.back();
607 list_.pop_back();
608
609 GlobalHandles::Destroy(location);
610 DCHECK(!Contains(sfi));
611 DCHECK_EQ(list_.size(), map_.size());
612}
613
615 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
620 debug_delegate_ = nullptr;
621}
622
625 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
626 if (!debug_delegate_) {
629 }
631 HandleScope scope(isolate_);
632 DisableBreak no_recursive_break(this);
633
635 v8::Utils::ToLocal(isolate_->native_context()), kInstrumentationId);
636}
637
639 DirectHandle<JSFunction> break_target) {
640 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
641 // Just continue if breaks are disabled or debugger cannot be loaded.
642 if (break_disabled()) return;
643
644 // Enter the debugger.
645 DebugScope debug_scope(this);
646 DisableBreak no_recursive_break(this);
647
648 // Return if we fail to retrieve debug info.
649 Handle<SharedFunctionInfo> shared(break_target->shared(), isolate_);
650 if (!EnsureBreakInfo(shared)) return;
652
653 Handle<DebugInfo> debug_info(TryGetDebugInfo(*shared).value(), isolate_);
654
655 // Find the break location where execution has stopped.
656 BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
657 const bool hitInstrumentationBreak =
658 IsBreakOnInstrumentation(debug_info, location);
659 bool shouldPauseAfterInstrumentation = false;
660 if (hitInstrumentationBreak) {
663 switch (action) {
665 shouldPauseAfterInstrumentation = true;
666 break;
669 shouldPauseAfterInstrumentation = false;
670 break;
672 return;
673 }
674 }
675
676 // Find actual break points, if any, and trigger debug break event.
678 bool has_break_points;
679 bool scheduled_break =
680 scheduled_break_on_function_call() || shouldPauseAfterInstrumentation;
681 MaybeHandle<FixedArray> break_points_hit =
682 CheckBreakPoints(debug_info, &location, &has_break_points);
683 if (!break_points_hit.is_null() || break_on_next_function_call() ||
684 scheduled_break) {
685 StepAction lastStepAction = last_step_action();
686 debug::BreakReasons break_reasons;
687 if (scheduled_break) {
688 break_reasons.Add(debug::BreakReason::kScheduled);
689 }
690 // If it's a debugger statement, add the reason and then mute the location
691 // so we don't stop a second time.
692 bool is_debugger_statement = IsBreakOnDebuggerStatement(shared, location);
693 if (is_debugger_statement) {
695 }
696
697 // Clear all current stepping setup.
699 // Notify the debug event listeners.
700 OnDebugBreak(!break_points_hit.is_null()
701 ? break_points_hit.ToHandleChecked()
702 : isolate_->factory()->empty_fixed_array(),
703 lastStepAction, break_reasons);
704
705 if (is_debugger_statement) {
706 // Don't pause here a second time
707 SetMutedLocation(shared, location);
708 }
709 return;
710 }
711
712 // Debug break at function entry, do not worry about stepping.
713 if (location.IsDebugBreakAtEntry()) {
714 DCHECK(debug_info->BreakAtEntry());
715 return;
716 }
717
718 DCHECK_NOT_NULL(frame);
719
720 // No break point. Check for stepping.
721 StepAction step_action = last_step_action();
722 int current_frame_count = CurrentFrameCount();
723 int target_frame_count = thread_local_.target_frame_count_;
724 int last_frame_count = thread_local_.last_frame_count_;
725
726 // StepOut at not return position was requested and return break locations
727 // were flooded with one shots.
729 // We might hit an instrumentation breakpoint before running into a
730 // return/suspend location.
731 DCHECK(location.IsReturnOrSuspend() || hitInstrumentationBreak);
732 // We have to ignore recursive calls to function.
733 if (current_frame_count > target_frame_count) return;
736 return;
737 }
738
739 bool step_break = false;
740 switch (step_action) {
741 case StepNone:
742 if (has_break_points) {
743 SetMutedLocation(shared, location);
744 }
745 return;
746 case StepOut:
747 // StepOut should not break in a deeper frame than target frame.
748 if (current_frame_count > target_frame_count) return;
749 step_break = true;
750 break;
751 case StepOver:
752 // StepOver should not break in a deeper frame than target frame.
753 if (current_frame_count > target_frame_count) return;
754 [[fallthrough]];
755 case StepInto: {
756 // StepInto and StepOver should enter "generator stepping" mode, except
757 // for the implicit initial yield in generators, where it should simply
758 // step out of the generator function.
759 if (location.IsSuspend()) {
762 if (!IsGeneratorFunction(shared->kind()) ||
763 location.generator_suspend_id() > 0) {
766 } else {
768 }
769 return;
770 }
771 FrameSummary summary = FrameSummary::GetTop(frame);
772 const bool frame_or_statement_changed =
773 current_frame_count != last_frame_count ||
775 summary.SourceStatementPosition();
776 // If we stayed on the same frame and reached the same bytecode offset
777 // since the last step, we are in a loop and should pause. Otherwise
778 // we keep "stepping" through the loop without ever actually pausing.
779 const bool potential_single_statement_loop =
780 current_frame_count == last_frame_count &&
782 step_break = step_break || location.IsReturn() ||
783 potential_single_statement_loop ||
784 frame_or_statement_changed;
785 break;
786 }
787 }
788
789 StepAction lastStepAction = last_step_action();
790 // Clear all current stepping setup.
792
793 if (step_break) {
794 // If it's a debugger statement, add the reason and then mute the location
795 // so we don't stop a second time.
796 debug::BreakReasons break_reasons;
797 bool is_debugger_statement = IsBreakOnDebuggerStatement(shared, location);
798 if (is_debugger_statement) {
800 }
801 // Notify the debug event listeners.
802 OnDebugBreak(isolate_->factory()->empty_fixed_array(), lastStepAction,
803 break_reasons);
804
805 if (is_debugger_statement) {
806 // Don't pause here a second time
807 SetMutedLocation(shared, location);
808 }
809 } else {
810 // Re-prepare to continue.
811 PrepareStep(step_action);
812 }
813}
814
816 const BreakLocation& location) {
817 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
818 bool has_break_points_to_check =
819 break_points_active_ && location.HasBreakPoint(isolate_, debug_info);
820 if (!has_break_points_to_check) return {};
821
822 DirectHandle<Object> break_points =
823 debug_info->GetBreakPoints(isolate_, location.position());
824 DCHECK(!IsUndefined(*break_points, isolate_));
825 if (!IsFixedArray(*break_points)) {
826 const auto break_point = Cast<BreakPoint>(break_points);
827 return break_point->id() == kInstrumentationId;
828 }
829
831 for (int i = 0; i < array->length(); ++i) {
832 const auto break_point =
834 if (break_point->id() == kInstrumentationId) {
835 return true;
836 }
837 }
838 return false;
839}
840
842 DirectHandle<SharedFunctionInfo> function, const BreakLocation& location) {
843 if (!function->HasBytecodeArray()) {
844 return false;
845 }
846 Tagged<BytecodeArray> original_bytecode =
847 function->GetBytecodeArray(isolate_);
849 original_bytecode->get(location.code_offset()));
850 return bytecode == interpreter::Bytecode::kDebugger;
851}
852
853// Find break point objects for this location, if any, and evaluate them.
854// Return an array of break point objects that evaluated true, or an empty
855// handle if none evaluated true.
856// has_break_points will be true, if there is any (non-instrumentation)
857// breakpoint.
859 BreakLocation* location,
860 bool* has_break_points) {
861 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
862 bool has_break_points_to_check =
863 break_points_active_ && location->HasBreakPoint(isolate_, debug_info);
864 if (!has_break_points_to_check) {
865 *has_break_points = false;
866 return {};
867 }
868
869 return Debug::GetHitBreakPoints(debug_info, location->position(),
870 has_break_points);
871}
872
875 const std::vector<BreakLocation>& locations) {
876 // A break location is considered muted if break locations on the current
877 // statement have at least one break point, and all of these break points
878 // evaluate to false. Aside from not triggering a debug break event at the
879 // break location, we also do not trigger one for debugger statements, nor
880 // an exception event on exception at this location.
881 // This should have been computed at last break, and we should just
882 // check that we are not at that location.
883
885 *function != thread_local_.muted_function_) {
886 return false;
887 }
888
889 for (const BreakLocation& location : locations) {
890 if (location.position() == thread_local_.muted_position_) {
891 return true;
892 }
893 }
894
895 return false;
896}
897
898#if V8_ENABLE_WEBASSEMBLY
899void Debug::SetMutedWasmLocation(DirectHandle<Script> script, int position) {
902}
903
904bool Debug::IsMutedAtWasmLocation(Tagged<Script> script, int position) {
905 return script == thread_local_.muted_function_ &&
907}
908#endif // V8_ENABLE_WEBASSEMBLY
909
910namespace {
911
912// Convenience helper for easier std::optional translation.
913bool ToHandle(Isolate* isolate, std::optional<Tagged<DebugInfo>> debug_info,
914 Handle<DebugInfo>* out) {
915 if (!debug_info.has_value()) return false;
916 *out = handle(debug_info.value(), isolate);
917 return true;
918}
919
920} // namespace
921
922// Check whether a single break point object is triggered.
924 bool is_break_at_entry) {
925 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
926 HandleScope scope(isolate_);
927
928 // Instrumentation breakpoints are handled separately.
929 if (break_point->id() == kInstrumentationId) {
930 return false;
931 }
932
933 if (!break_point->condition()->length()) return true;
934 DirectHandle<String> condition(break_point->condition(), isolate_);
935 MaybeDirectHandle<Object> maybe_result;
937
938 if (is_break_at_entry) {
940 } else {
941 // Since we call CheckBreakpoint only for deoptimized frame on top of stack,
942 // we can use 0 as index of inlined frame.
943 const int inlined_jsframe_index = 0;
944 const bool throw_on_side_effect = false;
945 maybe_result =
946 DebugEvaluate::Local(isolate_, break_frame_id(), inlined_jsframe_index,
947 condition, throw_on_side_effect);
948 }
949
950 DirectHandle<Object> maybe_exception;
951 bool exception_thrown = true;
952 if (maybe_result.ToHandle(&result)) {
953 exception_thrown = false;
954 } else if (isolate_->has_exception()) {
955 maybe_exception = direct_handle(isolate_->exception(), isolate_);
957 }
958
960 DisableBreak no_recursive_break(this);
961
962 {
963 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebuggerCallback);
965 v8::Utils::ToLocal(isolate_->native_context()), break_point->id(),
966 exception_thrown, v8::Utils::ToLocal(maybe_exception));
967 }
968
969 return !result.is_null() ? Object::BooleanValue(*result, isolate_) : false;
970}
971
973 DirectHandle<BreakPoint> break_point,
974 int* source_position) {
975 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
976 HandleScope scope(isolate_);
977
978 // Make sure the function is compiled and has set up the debug info.
979 if (!EnsureBreakInfo(shared)) return false;
981
982 Handle<DebugInfo> debug_info(TryGetDebugInfo(*shared).value(), isolate_);
983 // Source positions starts with zero.
984 DCHECK_LE(0, *source_position);
985
986 // Find the break point and change it.
987 *source_position = FindBreakablePosition(debug_info, *source_position);
988 DebugInfo::SetBreakPoint(isolate_, debug_info, *source_position, break_point);
989 // At least one active break point now.
990 DCHECK_LT(0, debug_info->GetBreakPointCount(isolate_));
991
992 ClearBreakPoints(debug_info);
993 ApplyBreakPoints(debug_info);
994 return true;
995}
996
999 int* source_position, int* id) {
1000 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1002 DirectHandle<BreakPoint> break_point =
1004#if V8_ENABLE_WEBASSEMBLY
1005 if (script->type() == Script::Type::kWasm) {
1006 RecordWasmScriptWithBreakpoints(script);
1007 return WasmScript::SetBreakPoint(script, source_position, break_point);
1008 }
1009#endif // V8_ENABLE_WEBASSEMBLY
1010
1011 HandleScope scope(isolate_);
1012
1013 // Obtain shared function info for the innermost function containing this
1014 // position.
1016 FindInnermostContainingFunctionInfo(script, *source_position);
1017 if (IsUndefined(*result, isolate_)) return false;
1018
1019 auto shared = Cast<SharedFunctionInfo>(result);
1020 if (!EnsureBreakInfo(shared)) return false;
1022
1023 // Find the nested shared function info that is closest to the position within
1024 // the containing function.
1025 shared = FindClosestSharedFunctionInfoFromPosition(*source_position, script,
1026 shared);
1027
1028 // Set the breakpoint in the function.
1029 return SetBreakpoint(shared, break_point, source_position);
1030}
1031
1033 int source_position) {
1034 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1035 if (debug_info->CanBreakAtEntry()) {
1036 return kBreakAtEntryPosition;
1037 } else {
1038 DCHECK(debug_info->HasInstrumentedBytecodeArray());
1039 BreakIterator it(debug_info);
1040 it.SkipToPosition(source_position);
1041 return it.position();
1042 }
1043}
1044
1046 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1048 if (debug_info->CanBreakAtEntry()) {
1049 debug_info->SetBreakAtEntry();
1050 } else {
1051 if (!debug_info->HasInstrumentedBytecodeArray()) return;
1052 Tagged<FixedArray> break_points = debug_info->break_points();
1053 for (int i = 0; i < break_points->length(); i++) {
1054 if (IsUndefined(break_points->get(i), isolate_)) continue;
1055 Tagged<BreakPointInfo> info = Cast<BreakPointInfo>(break_points->get(i));
1056 if (info->GetBreakPointCount(isolate_) == 0) continue;
1057 DCHECK(debug_info->HasInstrumentedBytecodeArray());
1058 BreakIterator it(debug_info);
1059 it.SkipToPosition(info->source_position());
1060 it.SetDebugBreak();
1061 }
1062 }
1063 debug_info->SetDebugExecutionMode(DebugInfo::kBreakpoints);
1064}
1065
1067 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1068 if (debug_info->CanBreakAtEntry()) {
1069 debug_info->ClearBreakAtEntry();
1070 } else {
1071 // If we attempt to clear breakpoints but none exist, simply return. This
1072 // can happen e.g. CoverageInfos exist but no breakpoints are set.
1073 if (!debug_info->HasInstrumentedBytecodeArray() ||
1074 !debug_info->HasBreakInfo()) {
1075 return;
1076 }
1077
1079 for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
1080 it.ClearDebugBreak();
1081 }
1082 }
1083}
1084
1086 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1087 HandleScope scope(isolate_);
1088
1090 for (; it.HasNext(); it.Advance()) {
1091 Handle<DebugInfo> debug_info(it.Next(), isolate_);
1092 if (!debug_info->HasBreakInfo()) continue;
1093
1095 DebugInfo::FindBreakPointInfo(isolate_, debug_info, break_point);
1096 if (IsUndefined(*result, isolate_)) continue;
1097
1098 if (DebugInfo::ClearBreakPoint(isolate_, debug_info, break_point)) {
1099 ClearBreakPoints(debug_info);
1100 if (debug_info->GetBreakPointCount(isolate_) == 0) {
1101 debug_info->ClearBreakInfo(isolate_);
1102 if (debug_info->IsEmpty()) it.DeleteNext();
1103 } else {
1104 ApplyBreakPoints(debug_info);
1105 }
1106 return;
1107 }
1108 }
1109}
1110
1112 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1114 DirectHandle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
1115 int id = debug_info->debugging_id();
1116 if (id == DebugInfo::kNoDebuggingId) {
1117 id = isolate_->heap()->NextDebuggingId();
1118 debug_info->set_debugging_id(id);
1119 }
1120 return id;
1121}
1122
1126 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1127 if (kind == kInstrumentation) {
1128 *id = kInstrumentationId;
1129 } else {
1131 }
1132 DirectHandle<BreakPoint> breakpoint =
1134 int source_position = 0;
1135#if V8_ENABLE_WEBASSEMBLY
1136 if (shared->HasWasmExportedFunctionData()) {
1137 Tagged<WasmExportedFunctionData> function_data =
1138 shared->wasm_exported_function_data();
1139 int func_index = function_data->function_index();
1140 // TODO(42204563): Avoid crashing if the instance object is not available.
1141 CHECK(function_data->instance_data()->has_instance_object());
1142 Tagged<WasmModuleObject> module_obj =
1143 function_data->instance_data()->instance_object()->module_object();
1144 DirectHandle<Script> script(module_obj->script(), isolate_);
1146 script, func_index, breakpoint);
1147 }
1148#endif // V8_ENABLE_WEBASSEMBLY
1149 return SetBreakpoint(shared, breakpoint, &source_position);
1150}
1151
1153 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1155 id, isolate_->factory()->empty_string());
1156 ClearBreakPoint(breakpoint);
1157}
1158
1159#if V8_ENABLE_WEBASSEMBLY
1160void Debug::SetInstrumentationBreakpointForWasmScript(
1161 DirectHandle<Script> script, int* id) {
1162 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1163 DCHECK_EQ(Script::Type::kWasm, script->type());
1164 *id = kInstrumentationId;
1165
1167 *id, isolate_->factory()->empty_string());
1168 RecordWasmScriptWithBreakpoints(script);
1169 WasmScript::SetInstrumentationBreakpoint(script, break_point);
1170}
1171
1172void Debug::RemoveBreakpointForWasmScript(DirectHandle<Script> script, int id) {
1173 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1174 if (script->type() == Script::Type::kWasm) {
1176 }
1177}
1178
1179void Debug::RecordWasmScriptWithBreakpoints(DirectHandle<Script> script) {
1180 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1181 if (wasm_scripts_with_break_points_.is_null()) {
1182 DirectHandle<WeakArrayList> new_list =
1184 wasm_scripts_with_break_points_ =
1185 isolate_->global_handles()->Create(*new_list);
1186 }
1187 {
1189 for (int idx = wasm_scripts_with_break_points_->length() - 1; idx >= 0;
1190 --idx) {
1191 Tagged<HeapObject> wasm_script;
1192 if (wasm_scripts_with_break_points_->Get(idx).GetHeapObject(
1193 &wasm_script) &&
1194 wasm_script == *script) {
1195 return;
1196 }
1197 }
1198 }
1199 DirectHandle<WeakArrayList> new_list =
1200 WeakArrayList::Append(isolate_, wasm_scripts_with_break_points_,
1201 MaybeObjectDirectHandle{script});
1202 if (*new_list != *wasm_scripts_with_break_points_) {
1204 wasm_scripts_with_break_points_.location());
1205 wasm_scripts_with_break_points_ =
1206 isolate_->global_handles()->Create(*new_list);
1207 }
1208}
1209#endif // V8_ENABLE_WEBASSEMBLY
1210
1211// Clear out all the debug break code.
1213 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1214 ClearAllDebugInfos([=, this](Handle<DebugInfo> info) {
1215 ClearBreakPoints(info);
1216 info->ClearBreakInfo(isolate_);
1217 });
1218#if V8_ENABLE_WEBASSEMBLY
1219 // Clear all wasm breakpoints.
1220 if (!wasm_scripts_with_break_points_.is_null()) {
1222 for (int idx = wasm_scripts_with_break_points_->length() - 1; idx >= 0;
1223 --idx) {
1224 Tagged<HeapObject> raw_wasm_script;
1225 if (wasm_scripts_with_break_points_->Get(idx).GetHeapObject(
1226 &raw_wasm_script)) {
1227 Tagged<Script> wasm_script = Cast<Script>(raw_wasm_script);
1229 wasm_script->wasm_native_module()->GetDebugInfo()->RemoveIsolate(
1230 isolate_);
1231 }
1232 }
1233 wasm_scripts_with_break_points_ = Handle<WeakArrayList>{};
1234 }
1235#endif // V8_ENABLE_WEBASSEMBLY
1236}
1237
1239 bool returns_only) {
1240 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1241 if (IsBlackboxed(shared)) return;
1242 // Make sure the function is compiled and has set up the debug info.
1243 if (!EnsureBreakInfo(shared)) return;
1245
1246 Handle<DebugInfo> debug_info(TryGetDebugInfo(*shared).value(), isolate_);
1247 // Flood the function with break points.
1248 DCHECK(debug_info->HasInstrumentedBytecodeArray());
1249 for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
1250 if (returns_only && !it.GetBreakLocation().IsReturnOrSuspend()) continue;
1251 it.SetDebugBreak();
1252 }
1253}
1254
1256 if (type == BreakUncaughtException) {
1258 } else {
1260 }
1261}
1262
1264 if (type == BreakUncaughtException) {
1266 } else {
1268 }
1269}
1270
1272 DirectHandle<DebugInfo> debug_info, int position, bool* has_break_points) {
1273 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1274 DirectHandle<Object> break_points =
1275 debug_info->GetBreakPoints(isolate_, position);
1276 bool is_break_at_entry = debug_info->BreakAtEntry();
1277 DCHECK(!IsUndefined(*break_points, isolate_));
1278 if (!IsFixedArray(*break_points)) {
1279 const auto break_point = Cast<BreakPoint>(break_points);
1280 *has_break_points = break_point->id() != kInstrumentationId;
1281 if (!CheckBreakPoint(break_point, is_break_at_entry)) {
1282 return {};
1283 }
1284 Handle<FixedArray> break_points_hit = isolate_->factory()->NewFixedArray(1);
1285 break_points_hit->set(0, *break_points);
1286 return break_points_hit;
1287 }
1288
1289 DirectHandle<FixedArray> array(Cast<FixedArray>(*break_points), isolate_);
1290 int num_objects = array->length();
1291 Handle<FixedArray> break_points_hit =
1292 isolate_->factory()->NewFixedArray(num_objects);
1293 int break_points_hit_count = 0;
1294 *has_break_points = false;
1295 for (int i = 0; i < num_objects; ++i) {
1296 const auto break_point =
1298 *has_break_points |= break_point->id() != kInstrumentationId;
1299 if (CheckBreakPoint(break_point, is_break_at_entry)) {
1300 break_points_hit->set(break_points_hit_count++, *break_point);
1301 }
1302 }
1303 if (break_points_hit_count == 0) return {};
1304 break_points_hit->RightTrim(isolate_, break_points_hit_count);
1305 return break_points_hit;
1306}
1307
1309 // This method forces V8 to break on next function call regardless current
1310 // last_step_action_. If any break happens between SetBreakOnNextFunctionCall
1311 // and ClearBreakOnNextFunctionCall, we will clear this flag and stepping. If
1312 // break does not happen, e.g. all called functions are blackboxed or no
1313 // function is called, then we will clear this flag and let stepping continue
1314 // its normal business.
1317}
1318
1323
1325 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1328 if (ignore_events()) return;
1329 if (in_debug_scope()) return;
1330 if (break_disabled()) return;
1331 Handle<SharedFunctionInfo> shared(function->shared(), isolate_);
1332 if (IsBlackboxed(shared)) return;
1333 if (*function == thread_local_.ignore_step_into_function_) return;
1335 FloodWithOneShot(shared);
1336}
1337
1339 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1341 if (ignore_events()) return;
1342 if (in_debug_scope()) return;
1343 if (break_disabled()) return;
1346 DirectHandle<JSFunction> function(
1348 isolate_);
1349 FloodWithOneShot(handle(function->shared(), isolate_));
1351}
1352
1354 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1355 if (last_step_action() == StepNone) return;
1356 if (ignore_events()) return;
1357 if (in_debug_scope()) return;
1358 if (break_disabled()) return;
1359
1360 ClearOneShot();
1361
1362 int current_frame_count = CurrentFrameCount();
1363
1364 // Iterate through the JavaScript stack looking for handlers.
1366 while (!it.done()) {
1367 JavaScriptFrame* frame = it.frame();
1368 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break;
1369 std::vector<Tagged<SharedFunctionInfo>> infos;
1370 frame->GetFunctions(&infos);
1371 current_frame_count -= infos.size();
1372 it.Advance();
1373 }
1374
1375 // No handler found. Nothing to instrument.
1376 if (it.done()) return;
1377
1378 bool found_handler = false;
1379 // Iterate frames, including inlined frames. First, find the handler frame.
1380 // Then skip to the frame we want to break in, then instrument for stepping.
1381 for (; !it.done(); it.Advance()) {
1382 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
1383 if (last_step_action() == StepInto) {
1384 // Deoptimize frame to ensure calls are checked for step-in.
1386 LazyDeoptimizeReason::kDebugger);
1387 }
1388 FrameSummaries summaries = frame->Summarize();
1389 for (size_t i = summaries.size(); i != 0; i--, current_frame_count--) {
1390 const FrameSummary& summary = summaries.frames[i - 1];
1391 if (!found_handler) {
1392 // We have yet to find the handler. If the frame inlines multiple
1393 // functions, we have to check each one for the handler.
1394 // If it only contains one function, we already found the handler.
1395 if (summaries.size() > 1) {
1397 summary.AsJavaScript().abstract_code();
1398 CHECK_EQ(CodeKind::INTERPRETED_FUNCTION, code->kind(isolate_));
1399 HandlerTable table(code->GetBytecodeArray());
1400 int code_offset = summary.code_offset();
1401 found_handler = table.LookupHandlerIndexForRange(code_offset) !=
1403 } else {
1404 found_handler = true;
1405 }
1406 }
1407
1408 if (found_handler) {
1409 // We found the handler. If we are stepping next or out, we need to
1410 // iterate until we found the suitable target frame to break in.
1412 current_frame_count > thread_local_.target_frame_count_) {
1413 continue;
1414 }
1416 summary.AsJavaScript().function()->shared(), isolate_);
1417 if (IsBlackboxed(info)) continue;
1418 FloodWithOneShot(info);
1419 return;
1420 }
1421 }
1422 }
1423}
1424
1426 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1427 HandleScope scope(isolate_);
1428
1430
1431 // Get the frame where the execution has stopped and skip the debug frame if
1432 // any. The debug frame will only be present if execution was stopped due to
1433 // hitting a break point. In other situations (e.g. unhandled exception) the
1434 // debug frame is not present.
1435 StackFrameId frame_id = break_frame_id();
1436 // If there is no JavaScript stack don't do anything.
1437 if (frame_id == StackFrameId::NO_ID) return;
1438
1439 thread_local_.last_step_action_ = step_action;
1440
1441 DebuggableStackFrameIterator frames_it(isolate_, frame_id);
1442 CommonFrame* frame = frames_it.frame();
1443
1446 int current_frame_count = CurrentFrameCount();
1447
1448 if (frame->is_javascript()) {
1449 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
1450 DCHECK(IsJSFunction(js_frame->function()));
1451
1452 // Get the debug info (create it if it does not exist).
1453 auto summary = FrameSummary::GetTop(frame).AsJavaScript();
1454 DirectHandle<JSFunction> function(summary.function());
1455 shared = Handle<SharedFunctionInfo>(function->shared(), isolate_);
1456 if (!EnsureBreakInfo(shared)) return;
1458
1459 // PrepareFunctionForDebugExecution can invalidate Baseline frames
1460 js_frame = JavaScriptFrame::cast(frames_it.Reframe());
1461
1462 Handle<DebugInfo> debug_info(TryGetDebugInfo(*shared).value(), isolate_);
1463 location = BreakLocation::FromFrame(debug_info, js_frame);
1464
1465 // Any step at a return is a step-out, and a step-out at a suspend behaves
1466 // like a return.
1467 if (location.IsReturn() ||
1468 (location.IsSuspend() && step_action == StepOut)) {
1469 // On StepOut we'll ignore our further calls to current function in
1470 // PrepareStepIn callback.
1471 if (last_step_action() == StepOut) {
1473 }
1474 step_action = StepOut;
1476 }
1477
1478 // We need to schedule DebugOnFunction call callback
1480
1481 // A step-next in blackboxed function is a step-out.
1482 if (step_action == StepOver && IsBlackboxed(shared)) step_action = StepOut;
1483
1484 thread_local_.last_statement_position_ = summary.SourceStatementPosition();
1485 thread_local_.last_bytecode_offset_ = summary.code_offset();
1486 thread_local_.last_frame_count_ = current_frame_count;
1487 // No longer perform the current async step.
1489#if V8_ENABLE_WEBASSEMBLY
1490 } else if (frame->is_wasm() && step_action != StepOut) {
1491#if V8_ENABLE_DRUMBRAKE
1492 // TODO(paolosev@microsoft.com) - If we are running with the interpreter, we
1493 // cannot step.
1494 if (frame->is_wasm_interpreter_entry()) return;
1495#endif // V8_ENABLE_DRUMBRAKE
1496 // Handle stepping in wasm.
1497 WasmFrame* wasm_frame = WasmFrame::cast(frame);
1498 auto* debug_info = wasm_frame->native_module()->GetDebugInfo();
1499 if (debug_info->PrepareStep(wasm_frame)) {
1501 return;
1502 }
1503 // If the wasm code is not debuggable or will return after this step
1504 // (indicated by {PrepareStep} returning false), then step out of that frame
1505 // instead.
1506 step_action = StepOut;
1508#endif // V8_ENABLE_WEBASSEMBLY
1509 }
1510
1511 switch (step_action) {
1512 case StepNone:
1513 UNREACHABLE();
1514 case StepOut: {
1515 // Clear last position info. For stepping out it does not matter.
1519 if (!shared.is_null()) {
1520 if (!location.IsReturnOrSuspend() && !IsBlackboxed(shared)) {
1521 // At not return position we flood return positions with one shots and
1522 // will repeat StepOut automatically at next break.
1523 thread_local_.target_frame_count_ = current_frame_count;
1525 FloodWithOneShot(shared, true);
1526 return;
1527 }
1528 if (IsAsyncFunction(shared->kind())) {
1529 // Stepping out of an async function whose implicit promise is awaited
1530 // by some other async function, should resume the latter. The return
1531 // value here is either a JSPromise or a JSGeneratorObject (for the
1532 // initial yield of async generators).
1537 isolate_->factory()->promise_awaited_by_symbol());
1538 if (IsWeakFixedArray(*awaited_by_holder, isolate_)) {
1539 auto weak_fixed_array = Cast<WeakFixedArray>(awaited_by_holder);
1540 if (weak_fixed_array->length() == 1 &&
1541 weak_fixed_array->get(0).IsWeak()) {
1542 DirectHandle<HeapObject> awaited_by(
1543 weak_fixed_array->get(0).GetHeapObjectAssumeWeak(isolate_),
1544 isolate_);
1545 if (IsJSGeneratorObject(*awaited_by)) {
1547 thread_local_.suspended_generator_ = *awaited_by;
1548 ClearStepping();
1549 return;
1550 }
1551 }
1552 }
1553 }
1554 }
1555 // Skip the current frame, find the first frame we want to step out to
1556 // and deoptimize every frame along the way.
1557 bool in_current_frame = true;
1558 for (; !frames_it.done(); frames_it.Advance()) {
1559#if V8_ENABLE_WEBASSEMBLY
1560#if V8_ENABLE_DRUMBRAKE
1561 // TODO(paolosev@microsoft.com): Implement stepping out from JS to wasm
1562 // interpreter.
1563 if (frame->is_wasm_interpreter_entry()) continue;
1564#endif // V8_ENABLE_DRUMBRAKE
1565 if (frames_it.frame()->is_wasm()) {
1566 if (in_current_frame) {
1567 in_current_frame = false;
1568 continue;
1569 }
1570 // Handle stepping out into Wasm.
1571 WasmFrame* wasm_frame = WasmFrame::cast(frames_it.frame());
1572 auto* debug_info = wasm_frame->native_module()->GetDebugInfo();
1573 if (debug_info->IsFrameBlackboxed(wasm_frame)) continue;
1574 debug_info->PrepareStepOutTo(wasm_frame);
1575 return;
1576 }
1577#endif // V8_ENABLE_WEBASSEMBLY
1578 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frames_it.frame());
1579 if (last_step_action() == StepInto) {
1580 // Deoptimize frame to ensure calls are checked for step-in.
1582 LazyDeoptimizeReason::kDebugger);
1583 }
1584 HandleScope inner_scope(isolate_);
1585 std::vector<Handle<SharedFunctionInfo>> infos;
1586 js_frame->GetFunctions(&infos);
1587 for (; !infos.empty(); current_frame_count--) {
1588 Handle<SharedFunctionInfo> info = infos.back();
1589 infos.pop_back();
1590 if (in_current_frame) {
1591 // We want to step out, so skip the current frame.
1592 in_current_frame = false;
1593 continue;
1594 }
1595 if (IsBlackboxed(info)) continue;
1596 FloodWithOneShot(info);
1597 thread_local_.target_frame_count_ = current_frame_count;
1598 return;
1599 }
1600 }
1601 break;
1602 }
1603 case StepOver:
1604 thread_local_.target_frame_count_ = current_frame_count;
1605 [[fallthrough]];
1606 case StepInto:
1607 FloodWithOneShot(shared);
1608 break;
1609 }
1610}
1611
1612// Simple function for returning the source positions for active break points.
1613// static
1615 Isolate* isolate, DirectHandle<SharedFunctionInfo> shared) {
1616 RCS_SCOPE(isolate, RuntimeCallCounterId::kDebugger);
1617 if (!shared->HasBreakInfo(isolate)) {
1618 return isolate->factory()->undefined_value();
1619 }
1620
1621 DirectHandle<DebugInfo> debug_info(
1622 isolate->debug()->TryGetDebugInfo(*shared).value(), isolate);
1623 if (debug_info->GetBreakPointCount(isolate) == 0) {
1624 return isolate->factory()->undefined_value();
1625 }
1626 DirectHandle<FixedArray> locations = isolate->factory()->NewFixedArray(
1627 debug_info->GetBreakPointCount(isolate));
1628 int count = 0;
1629 for (int i = 0; i < debug_info->break_points()->length(); ++i) {
1630 if (!IsUndefined(debug_info->break_points()->get(i), isolate)) {
1631 Tagged<BreakPointInfo> break_point_info =
1632 Cast<BreakPointInfo>(debug_info->break_points()->get(i));
1633 int break_points = break_point_info->GetBreakPointCount(isolate);
1634 if (break_points == 0) continue;
1635 for (int j = 0; j < break_points; ++j) {
1636 locations->set(count++,
1637 Smi::FromInt(break_point_info->source_position()));
1638 }
1639 }
1640 }
1641 return locations;
1642}
1643
1662
1663// Clears all the one-shot break points that are currently set. Normally this
1664// function is called each time a break point is hit as one shot break points
1665// are used to support stepping.
1667 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1668 // The current implementation just runs through all the breakpoints. When the
1669 // last break point for a function is removed that function is automatically
1670 // removed from the list.
1671 HandleScope scope(isolate_);
1673 for (; it.HasNext(); it.Advance()) {
1674 Handle<DebugInfo> debug_info(it.Next(), isolate_);
1675 ClearBreakPoints(debug_info);
1676 ApplyBreakPoints(debug_info);
1677 }
1678}
1679
1684
1690
1691namespace {
1692class DiscardBaselineCodeVisitor : public ThreadVisitor {
1693 public:
1694 explicit DiscardBaselineCodeVisitor(Tagged<SharedFunctionInfo> shared)
1695 : shared_(shared) {}
1696 DiscardBaselineCodeVisitor() : shared_(SharedFunctionInfo()) {}
1697
1698 void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
1699 DisallowGarbageCollection diallow_gc;
1700 bool deopt_all = shared_ == SharedFunctionInfo();
1701 for (JavaScriptStackFrameIterator it(isolate, top); !it.done();
1702 it.Advance()) {
1703 if (!deopt_all && it.frame()->function()->shared() != shared_) continue;
1704 if (it.frame()->type() != StackFrame::BASELINE &&
1705 it.frame()->type() != StackFrame::INTERPRETED) {
1706 continue;
1707 }
1708
1709 Tagged<Code> code = it.frame()->LookupCode();
1710 // We need to check CodeKind rather than StackFrame type here since
1711 // previous iterations might already patched this baseline code,
1712 // but we need to update remaining baseline stack frames as well.
1713 if (code->kind() == CodeKind::BASELINE) {
1714 UnoptimizedJSFrame* frame = UnoptimizedJSFrame::cast(it.frame());
1715 int bytecode_offset = code->GetBytecodeOffsetForBaselinePC(
1716 frame->pc(), frame->GetBytecodeArray());
1717 Address* pc_addr = frame->pc_address();
1718 Address advance;
1719 if (bytecode_offset == kFunctionEntryBytecodeOffset) {
1720 advance = BUILTIN_CODE(isolate, BaselineOutOfLinePrologueDeopt)
1721 ->instruction_start();
1722 } else {
1723 advance = BUILTIN_CODE(isolate, InterpreterEnterAtNextBytecode)
1724 ->instruction_start();
1725 }
1726 if (v8_flags.cet_compatible) {
1727 Deoptimizer::PatchToJump(*pc_addr, advance);
1728 frame->LookupCode()->SetMarkedForDeoptimization(
1729 isolate, LazyDeoptimizeReason::kDebugger);
1730 } else {
1731 PointerAuthentication::ReplacePC(pc_addr, advance,
1733 }
1734 InterpretedFrame::cast(it.Reframe())
1735 ->PatchBytecodeOffset(bytecode_offset);
1736 }
1737 }
1738 }
1739
1740 private:
1742};
1743} // namespace
1744
1746 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1747 DCHECK(shared->HasBaselineCode());
1748 DiscardBaselineCodeVisitor visitor(shared);
1749 visitor.VisitThread(isolate_, isolate_->thread_local_top());
1751 // TODO(v8:11429): Avoid this heap walk somehow.
1752 HeapObjectIterator iterator(isolate_->heap());
1753 auto trampoline = BUILTIN_CODE(isolate_, InterpreterEntryTrampoline);
1754 shared->FlushBaselineCode();
1755 for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
1756 obj = iterator.Next()) {
1757 if (IsJSFunction(obj)) {
1759 if (fun->shared() == shared && fun->ActiveTierIsBaseline(isolate_)) {
1760 fun->UpdateCode(*trampoline);
1761 }
1762 }
1763 }
1764}
1765
1767 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1768 DiscardBaselineCodeVisitor visitor;
1769 visitor.VisitThread(isolate_, isolate_->thread_local_top());
1770 HeapObjectIterator iterator(isolate_->heap());
1771 auto trampoline = BUILTIN_CODE(isolate_, InterpreterEntryTrampoline);
1773 for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
1774 obj = iterator.Next()) {
1775 if (IsJSFunction(obj)) {
1777 if (fun->ActiveTierIsBaseline(isolate_)) {
1778 fun->UpdateCode(*trampoline);
1779 }
1780 } else if (IsSharedFunctionInfo(obj)) {
1782 if (shared->HasBaselineCode()) {
1783 shared->FlushBaselineCode();
1784 }
1785 }
1786 }
1787}
1788
1790 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1791
1792 if (shared->HasBaselineCode()) {
1793 DiscardBaselineCode(*shared);
1794 }
1796}
1797
1800 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1801 // To prepare bytecode for debugging, we already need to have the debug
1802 // info (containing the debug copy) upfront, but since we do not recompile,
1803 // preparing for break points cannot fail.
1804 DCHECK(shared->is_compiled());
1805 DirectHandle<DebugInfo> debug_info(TryGetDebugInfo(*shared).value(),
1806 isolate_);
1807 if (debug_info->flags(kRelaxedLoad) & DebugInfo::kPreparedForDebugExecution) {
1808 return;
1809 }
1810
1811 // Have to discard baseline code before installing debug bytecode, since the
1812 // bytecode array field on the baseline code object is immutable.
1813 if (debug_info->CanBreakAtEntry()) {
1814 // Deopt everything in case the function is inlined anywhere.
1817 } else {
1818 DeoptimizeFunction(shared);
1819 }
1820
1821 if (shared->HasBytecodeArray()) {
1822 DCHECK(!shared->HasBaselineCode());
1824 }
1825
1826 if (debug_info->CanBreakAtEntry()) {
1828 } else {
1829 // Update PCs on the stack to point to recompiled code.
1830 RedirectActiveFunctions redirect_visitor(
1832 redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top());
1833 isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor);
1834 }
1835
1836 debug_info->set_flags(
1837 debug_info->flags(kRelaxedLoad) | DebugInfo::kPreparedForDebugExecution,
1839}
1840
1841namespace {
1842
1843bool IsJSFunctionAndNeedsTrampoline(Isolate* isolate,
1844 Tagged<Object> maybe_function) {
1845 if (!IsJSFunction(maybe_function)) return false;
1846 std::optional<Tagged<DebugInfo>> debug_info =
1847 isolate->debug()->TryGetDebugInfo(
1848 Cast<JSFunction>(maybe_function)->shared());
1849 return debug_info.has_value() && debug_info.value()->CanBreakAtEntry();
1850}
1851
1852} // namespace
1853
1855 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
1856 // Check the list of debug infos whether the debug break trampoline needs to
1857 // be installed. If that's the case, iterate the heap for functions to rewire
1858 // to the trampoline.
1859 // If there is a breakpoint at function entry, we need to install trampoline.
1860 bool needs_to_use_trampoline = false;
1861 // If there we break at entry to an api callback, we need to clear ICs.
1862 bool needs_to_clear_ic = false;
1863
1865 for (; it.HasNext(); it.Advance()) {
1866 Tagged<DebugInfo> debug_info = it.Next();
1867 if (debug_info->CanBreakAtEntry()) {
1868 needs_to_use_trampoline = true;
1869 if (debug_info->shared()->IsApiFunction()) {
1870 needs_to_clear_ic = true;
1871 break;
1872 }
1873 }
1874 }
1875
1876 if (!needs_to_use_trampoline) return;
1877
1878 HandleScope scope(isolate_);
1879 DirectHandle<Code> trampoline = BUILTIN_CODE(isolate_, DebugBreakTrampoline);
1880 std::vector<Handle<JSFunction>> needs_compile;
1881 using AccessorPairWithContext =
1882 std::pair<Handle<AccessorPair>, Handle<NativeContext>>;
1883 std::vector<AccessorPairWithContext> needs_instantiate;
1884 {
1885 // Deduplicate {needs_instantiate} by recording all collected AccessorPairs.
1886 std::set<Tagged<AccessorPair>> recorded;
1887 HeapObjectIterator iterator(isolate_->heap());
1889 for (Tagged<HeapObject> obj = iterator.Next(); !obj.is_null();
1890 obj = iterator.Next()) {
1891 if (needs_to_clear_ic && IsFeedbackVector(obj)) {
1892 Cast<FeedbackVector>(obj)->ClearSlots(isolate_);
1893 continue;
1894 } else if (IsJSFunctionAndNeedsTrampoline(isolate_, obj)) {
1896 if (!fun->is_compiled(isolate_)) {
1897 needs_compile.push_back(handle(fun, isolate_));
1898 } else {
1899 fun->UpdateCode(*trampoline);
1900 }
1901 } else if (IsJSObject(obj)) {
1902 Tagged<JSObject> object = Cast<JSObject>(obj);
1903 Tagged<DescriptorArray> descriptors =
1904 object->map()->instance_descriptors(kRelaxedLoad);
1905
1906 for (InternalIndex i : object->map()->IterateOwnDescriptors()) {
1907 if (descriptors->GetDetails(i).kind() == PropertyKind::kAccessor) {
1908 Tagged<Object> value = descriptors->GetStrongValue(i);
1909 if (!IsAccessorPair(value)) continue;
1910
1911 Tagged<AccessorPair> accessor_pair = Cast<AccessorPair>(value);
1912 if (!IsFunctionTemplateInfo(accessor_pair->getter()) &&
1913 !IsFunctionTemplateInfo(accessor_pair->setter())) {
1914 continue;
1915 }
1916 if (recorded.find(accessor_pair) != recorded.end()) continue;
1917
1918 needs_instantiate.emplace_back(
1919 handle(accessor_pair, isolate_),
1920 handle(object->GetCreationContext().value(), isolate_));
1921 recorded.insert(accessor_pair);
1922 }
1923 }
1924 }
1925 }
1926 }
1927
1928 // Forcibly instantiate all lazy accessor pairs to make sure that they
1929 // properly hit the debug break trampoline.
1930 for (AccessorPairWithContext tuple : needs_instantiate) {
1931 DirectHandle<AccessorPair> accessor_pair = tuple.first;
1934 isolate_, native_context, accessor_pair, ACCESSOR_GETTER);
1935 if (IsJSFunctionAndNeedsTrampoline(isolate_, *getter)) {
1936 Cast<JSFunction>(getter)->UpdateCode(*trampoline);
1937 }
1938
1940 isolate_, native_context, accessor_pair, ACCESSOR_SETTER);
1941 if (IsJSFunctionAndNeedsTrampoline(isolate_, *setter)) {
1942 Cast<JSFunction>(setter)->UpdateCode(*trampoline);
1943 }
1944 }
1945
1946 // By overwriting the function code with DebugBreakTrampoline, which tailcalls
1947 // to shared code, we bypass CompileLazy. Perform CompileLazy here instead.
1948 for (DirectHandle<JSFunction> fun : needs_compile) {
1949 IsCompiledScope is_compiled_scope;
1951 &is_compiled_scope);
1952 DCHECK(is_compiled_scope.is_compiled());
1953 fun->UpdateCode(*trampoline);
1954 }
1955}
1956
1957namespace {
1958void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position,
1959 int end_position,
1960 std::vector<BreakLocation>* locations) {
1961 DCHECK(debug_info->HasInstrumentedBytecodeArray());
1962 BreakIterator it(debug_info);
1963 while (!it.Done()) {
1964 if (it.GetDebugBreakType() != DEBUG_BREAK_SLOT_AT_SUSPEND &&
1965 it.position() >= start_position && it.position() < end_position) {
1966 locations->push_back(it.GetBreakLocation());
1967 }
1968 it.Next();
1969 }
1970}
1971
1972bool CompileTopLevel(Isolate* isolate, Handle<Script> script,
1973 MaybeHandle<SharedFunctionInfo>* result = nullptr) {
1974 if (script->compilation_type() == Script::CompilationType::kEval ||
1975 script->is_wrapped()) {
1976 return false;
1977 }
1978 UnoptimizedCompileState compile_state;
1979 ReusableUnoptimizedCompileState reusable_state(isolate);
1980 UnoptimizedCompileFlags flags =
1982 flags.set_is_reparse(true);
1983 ParseInfo parse_info(isolate, flags, &compile_state, &reusable_state);
1984 IsCompiledScope is_compiled_scope;
1985 const MaybeHandle<SharedFunctionInfo> maybe_result =
1986 Compiler::CompileToplevel(&parse_info, script, isolate,
1987 &is_compiled_scope);
1988 if (maybe_result.is_null()) {
1989 if (isolate->has_exception()) {
1990 isolate->clear_exception();
1991 }
1992 return false;
1993 }
1994 if (result) *result = maybe_result;
1995 return true;
1996}
1997} // namespace
1998
1999bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
2000 int end_position, bool restrict_to_function,
2001 std::vector<BreakLocation>* locations) {
2002 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2003 if (restrict_to_function) {
2005 FindInnermostContainingFunctionInfo(script, start_position);
2006 if (IsUndefined(*result, isolate_)) return false;
2007
2008 // Make sure the function has set up the debug info.
2010 if (!EnsureBreakInfo(shared)) return false;
2012
2013 Handle<DebugInfo> debug_info(TryGetDebugInfo(*shared).value(), isolate_);
2014 FindBreakablePositions(debug_info, start_position, end_position, locations);
2015 return true;
2016 }
2017
2018 HandleScope scope(isolate_);
2019 std::vector<Handle<SharedFunctionInfo>> candidates;
2020 if (!FindSharedFunctionInfosIntersectingRange(script, start_position,
2021 end_position, &candidates)) {
2022 return false;
2023 }
2024 for (const auto& candidate : candidates) {
2025 CHECK(candidate->HasBreakInfo(isolate_));
2026 Handle<DebugInfo> debug_info(TryGetDebugInfo(*candidate).value(), isolate_);
2027 FindBreakablePositions(debug_info, start_position, end_position, locations);
2028 }
2029 return true;
2030}
2031
2033 public:
2034 explicit SharedFunctionInfoFinder(int target_position)
2036 target_position_(target_position) {}
2037
2039 Tagged<JSFunction> closure = JSFunction()) {
2040 if (!shared->IsSubjectToDebugging()) return;
2041 int start_position = shared->function_token_position();
2042 if (start_position == kNoSourcePosition) {
2043 start_position = shared->StartPosition();
2044 }
2045
2046 if (start_position > target_position_) return;
2047 if (target_position_ >= shared->EndPosition()) {
2048 // The SharedFunctionInfo::EndPosition() is generally exclusive, but there
2049 // are assumptions in various places in the debugger that for script level
2050 // (toplevel function) there's an end position that is technically outside
2051 // the script. It might be worth revisiting the overall design here at
2052 // some point in the future.
2053 if (!shared->is_toplevel() || target_position_ > shared->EndPosition()) {
2054 return;
2055 }
2056 }
2057
2058 if (!current_candidate_.is_null()) {
2059 if (current_start_position_ == start_position &&
2060 shared->EndPosition() == current_candidate_->EndPosition()) {
2061 // If we already have a matching closure, do not throw it away.
2062 if (!current_candidate_closure_.is_null() && closure.is_null()) return;
2063 // If a top-level function contains only one function
2064 // declaration the source for the top-level and the function
2065 // is the same. In that case prefer the non top-level function.
2066 if (!current_candidate_->is_toplevel() && shared->is_toplevel()) return;
2067 } else if (start_position < current_start_position_ ||
2068 current_candidate_->EndPosition() < shared->EndPosition()) {
2069 return;
2070 }
2071 }
2072
2073 current_start_position_ = start_position;
2076 }
2077
2079
2081
2082 private:
2088};
2089
2090namespace {
2091Tagged<SharedFunctionInfo> FindSharedFunctionInfoCandidate(
2092 int position, DirectHandle<Script> script, Isolate* isolate) {
2094 SharedFunctionInfo::ScriptIterator iterator(isolate, *script);
2095 for (Tagged<SharedFunctionInfo> info = iterator.Next(); !info.is_null();
2096 info = iterator.Next()) {
2097 finder.NewCandidate(info);
2098 }
2099 return finder.Result();
2100}
2101} // namespace
2102
2104 int position, Handle<Script> script,
2105 Handle<SharedFunctionInfo> outer_shared) {
2106 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2107 Handle<DebugInfo> outer_debug_info(TryGetDebugInfo(*outer_shared).value(),
2108 isolate_);
2109 CHECK(outer_debug_info->HasBreakInfo());
2110 int closest_position = FindBreakablePosition(outer_debug_info, position);
2111 Handle<SharedFunctionInfo> closest_candidate = outer_shared;
2112 if (closest_position == position) return outer_shared;
2113
2114 const int start_position = outer_shared->StartPosition();
2115 const int end_position = outer_shared->EndPosition();
2116 if (start_position == end_position) return outer_shared;
2117
2118 if (closest_position == 0) closest_position = end_position;
2119 std::vector<Handle<SharedFunctionInfo>> candidates;
2120 // Find all shared function infos of functions that are intersecting from
2121 // the requested position until the end of the enclosing function.
2123 script, position, closest_position, &candidates)) {
2124 return outer_shared;
2125 }
2126
2127 for (auto candidate : candidates) {
2128 Handle<DebugInfo> debug_info(TryGetDebugInfo(*candidate).value(), isolate_);
2129 CHECK(debug_info->HasBreakInfo());
2130 const int candidate_position = FindBreakablePosition(debug_info, position);
2131 if (candidate_position >= position &&
2132 candidate_position < closest_position) {
2133 closest_position = candidate_position;
2134 closest_candidate = candidate;
2135 }
2136 if (closest_position == position) break;
2137 }
2138 return closest_candidate;
2139}
2140
2142 Handle<Script> script, int start_position, int end_position,
2143 std::vector<Handle<SharedFunctionInfo>>* intersecting_shared) {
2144 bool candidateSubsumesRange = false;
2145 bool triedTopLevelCompile = false;
2146
2147 while (true) {
2148 std::vector<Handle<SharedFunctionInfo>> candidates;
2149 std::vector<IsCompiledScope> compiled_scopes;
2150 {
2153 for (Tagged<SharedFunctionInfo> info = iterator.Next(); !info.is_null();
2154 info = iterator.Next()) {
2155 if (info->EndPosition() < start_position ||
2156 info->StartPosition() >= end_position) {
2157 continue;
2158 }
2159 candidateSubsumesRange |= info->StartPosition() <= start_position &&
2160 info->EndPosition() >= end_position;
2161 if (!info->IsSubjectToDebugging()) continue;
2162 if (!info->is_compiled() && !info->allows_lazy_compilation()) continue;
2163 candidates.push_back(i::handle(info, isolate_));
2164 }
2165 }
2166
2167 if (!triedTopLevelCompile && !candidateSubsumesRange &&
2168 script->infos()->length() > 0) {
2170 GetTopLevelWithRecompile(script, &triedTopLevelCompile);
2171 if (shared.is_null()) return false;
2172 if (triedTopLevelCompile) continue;
2173 }
2174
2175 bool was_compiled = false;
2176 for (const auto& candidate : candidates) {
2177 IsCompiledScope is_compiled_scope(candidate->is_compiled_scope(isolate_));
2178 if (!is_compiled_scope.is_compiled()) {
2179 // InstructionStream that cannot be compiled lazily are internal and not
2180 // debuggable.
2181 DCHECK(candidate->allows_lazy_compilation());
2183 &is_compiled_scope)) {
2184 return false;
2185 } else {
2186 was_compiled = true;
2187 }
2188 }
2189 DCHECK(is_compiled_scope.is_compiled());
2190 compiled_scopes.push_back(is_compiled_scope);
2191 if (!EnsureBreakInfo(candidate)) return false;
2193 }
2194 if (was_compiled) continue;
2195 *intersecting_shared = std::move(candidates);
2196 return true;
2197 }
2198 UNREACHABLE();
2199}
2200
2202 Handle<Script> script, bool* did_compile) {
2203 DCHECK_LE(kFunctionLiteralIdTopLevel, script->infos()->length());
2204 Tagged<MaybeObject> maybeToplevel =
2205 script->infos()->get(kFunctionLiteralIdTopLevel);
2206 Tagged<HeapObject> heap_object;
2207 const bool topLevelInfoExists =
2208 maybeToplevel.GetHeapObject(&heap_object) && !IsUndefined(heap_object);
2209 if (topLevelInfoExists) {
2210 if (did_compile) *did_compile = false;
2211 return direct_handle(Cast<SharedFunctionInfo>(heap_object), isolate_);
2212 }
2213
2215 CompileTopLevel(isolate_, script, &shared);
2216 if (did_compile) *did_compile = true;
2217 return shared;
2218}
2219
2220// We need to find a SFI for a literal that may not yet have been compiled yet,
2221// and there may not be a JSFunction referencing it. Find the SFI closest to
2222// the given position, compile it to reveal possible inner SFIs and repeat.
2223// While we are at this, also ensure code with debug break slots so that we do
2224// not have to compile a SFI without JSFunction, which is paifu for those that
2225// cannot be compiled without context (need to find outer compilable SFI etc.)
2227 int position) {
2228 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2229 for (int iteration = 0;; iteration++) {
2230 // Go through all shared function infos associated with this script to
2231 // find the innermost function containing this position.
2232 // If there is no shared function info for this script at all, there is
2233 // no point in looking for it by walking the heap.
2234
2236 IsCompiledScope is_compiled_scope;
2237 {
2238 shared = FindSharedFunctionInfoCandidate(position, script, isolate_);
2239 if (shared.is_null()) {
2240 if (iteration > 0) break;
2241 // It might be that the shared function info is not available as the
2242 // top level functions are removed due to the GC. Try to recompile
2243 // the top level functions.
2244 const bool success = CompileTopLevel(isolate_, script);
2245 if (!success) break;
2246 continue;
2247 }
2248 // We found it if it's already compiled.
2249 is_compiled_scope = shared->is_compiled_scope(isolate_);
2250 if (is_compiled_scope.is_compiled()) {
2251 Handle<SharedFunctionInfo> shared_handle(shared, isolate_);
2252 // If the iteration count is larger than 1, we had to compile the outer
2253 // function in order to create this shared function info. So there can
2254 // be no JSFunction referencing it. We can anticipate creating a debug
2255 // info while bypassing PrepareFunctionForDebugExecution.
2256 if (iteration > 1) {
2257 CreateBreakInfo(shared_handle);
2258 }
2259 return shared_handle;
2260 }
2261 }
2262 // If not, compile to reveal inner functions.
2263 HandleScope scope(isolate_);
2264 // InstructionStream that cannot be compiled lazily are internal and not
2265 // debuggable.
2266 DCHECK(shared->allows_lazy_compilation());
2268 Compiler::CLEAR_EXCEPTION, &is_compiled_scope)) {
2269 break;
2270 }
2271 }
2272 return isolate_->factory()->undefined_value();
2273}
2274
2275// Ensures the debug information is present for shared.
2277 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2278 // Return if we already have the break info for shared.
2279 if (shared->HasBreakInfo(isolate_)) {
2280 DCHECK(shared->is_compiled());
2281 return true;
2282 }
2283 if (!shared->IsSubjectToDebugging() && !CanBreakAtEntry(shared)) {
2284 return false;
2285 }
2286 IsCompiledScope is_compiled_scope = shared->is_compiled_scope(isolate_);
2287 if (!is_compiled_scope.is_compiled() &&
2289 &is_compiled_scope, CreateSourcePositions::kYes)) {
2290 return false;
2291 }
2292 CreateBreakInfo(shared);
2293 return true;
2294}
2295
2297 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2298 HandleScope scope(isolate_);
2299 DirectHandle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
2300
2301 // Initialize with break information.
2302
2303 DCHECK(!debug_info->HasBreakInfo());
2304
2305 Factory* factory = isolate_->factory();
2306 DirectHandle<FixedArray> break_points(
2308
2309 int flags = debug_info->flags(kRelaxedLoad);
2310 flags |= DebugInfo::kHasBreakInfo;
2311 if (CanBreakAtEntry(shared)) flags |= DebugInfo::kCanBreakAtEntry;
2312 debug_info->set_flags(flags, kRelaxedStore);
2313 debug_info->set_break_points(*break_points);
2314
2316}
2317
2320 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2321
2322 if (std::optional<Tagged<DebugInfo>> di = debug_infos_.Find(*shared)) {
2323 return handle(di.value(), isolate_);
2324 }
2325
2326 Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared);
2327 debug_infos_.Insert(*shared, *debug_info);
2328 return debug_info;
2329}
2330
2332 DirectHandle<CoverageInfo> coverage_info) {
2333 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2334 DCHECK(!coverage_info.is_null());
2335
2336 DirectHandle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
2337
2338 DCHECK(!debug_info->HasCoverageInfo());
2339
2340 debug_info->set_flags(
2341 debug_info->flags(kRelaxedLoad) | DebugInfo::kHasCoverageInfo,
2343 debug_info->set_coverage_info(*coverage_info);
2344}
2345
2348 info->ClearCoverageInfo(isolate_);
2349 });
2350}
2351
2354 [=](DirectHandle<DebugInfo> info) { info->set_debugger_hints(0); });
2355}
2356
2358 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2359
2360 HandleScope scope(isolate_);
2362 for (; it.HasNext(); it.Advance()) {
2363 Handle<DebugInfo> debug_info(it.Next(), isolate_);
2364 clear_function(debug_info);
2365 if (debug_info->IsEmpty()) it.DeleteNext();
2366 }
2367}
2368
2370 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2371 debug_info->ClearBreakInfo(isolate_);
2372 if (debug_info->IsEmpty()) {
2373 debug_infos_.DeleteSlow(debug_info->shared());
2374 }
2375}
2376
2378 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2379 HandleScope scope(isolate_);
2380
2381 // Get the executing function in which the debug break occurred.
2383 isolate_);
2384
2385 // With no debug info there are no break points, so we can't be at a return.
2386 Handle<DebugInfo> debug_info;
2387 if (!ToHandle(isolate_, TryGetDebugInfo(*shared), &debug_info) ||
2388 !debug_info->HasBreakInfo()) {
2389 return false;
2390 }
2391
2392 DCHECK(!frame->is_optimized());
2393 BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
2394 return location.IsReturn();
2395}
2396
2398 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2401 Factory* factory = isolate_->factory();
2402 if (!IsWeakArrayList(*factory->script_list())) {
2403 return factory->empty_fixed_array();
2404 }
2405 auto array = Cast<WeakArrayList>(factory->script_list());
2406 Handle<FixedArray> results = factory->NewFixedArray(array->length());
2407 int length = 0;
2408 {
2409 Script::Iterator iterator(isolate_);
2410 for (Tagged<Script> script = iterator.Next(); !script.is_null();
2411 script = iterator.Next()) {
2412 if (script->HasValidSource()) results->set(length++, script);
2413 }
2414 }
2415 return FixedArray::RightTrimOrEmpty(isolate_, results, length);
2416}
2417
2418std::optional<Tagged<DebugInfo>> Debug::TryGetDebugInfo(
2420 return debug_infos_.Find(sfi);
2421}
2422
2424 return TryGetDebugInfo(sfi).has_value();
2425}
2426
2428 if (std::optional<Tagged<DebugInfo>> debug_info = TryGetDebugInfo(sfi)) {
2429 return debug_info.value()->HasCoverageInfo();
2430 }
2431 return false;
2432}
2433
2435 if (std::optional<Tagged<DebugInfo>> debug_info = TryGetDebugInfo(sfi)) {
2436 return debug_info.value()->HasBreakInfo();
2437 }
2438 return false;
2439}
2440
2442 if (std::optional<Tagged<DebugInfo>> debug_info = TryGetDebugInfo(sfi)) {
2443 return debug_info.value()->BreakAtEntry();
2444 }
2445 return false;
2446}
2447
2448std::optional<Tagged<Object>> Debug::OnThrow(DirectHandle<Object> exception) {
2449 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2450 if (in_debug_scope() || ignore_events()) return {};
2451 // Temporarily clear any exception to allow evaluating
2452 // JavaScript from the debug event handler.
2453 HandleScope scope(isolate_);
2454 {
2455 std::optional<Isolate::ExceptionScope> exception_scope;
2456 if (isolate_->has_exception()) exception_scope.emplace(isolate_);
2459 catch_type == Isolate::CAUGHT_BY_ASYNC_AWAIT ||
2460 catch_type == Isolate::CAUGHT_BY_PROMISE
2463 }
2465 // If the OnException handler requested termination, then indicated this to
2466 // our caller Isolate::Throw so it can deal with it immediately instead of
2467 // throwing the original exception.
2468 if (isolate_->stack_guard()->CheckTerminateExecution()) {
2469 isolate_->stack_guard()->ClearTerminateExecution();
2470 return isolate_->TerminateExecution();
2471 }
2472 return {};
2473}
2474
2476 DirectHandle<Object> value) {
2477 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2478 if (in_debug_scope() || ignore_events()) return;
2479 MaybeDirectHandle<JSPromise> maybe_promise;
2480 if (IsJSPromise(*promise)) {
2481 DirectHandle<JSPromise> js_promise = Cast<JSPromise>(promise);
2482 if (js_promise->is_silent()) {
2483 return;
2484 }
2485 maybe_promise = js_promise;
2486 }
2487 OnException(value, maybe_promise, v8::debug::kPromiseRejection);
2488}
2489
2491 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2492 HandleScope scope(isolate_);
2493 std::vector<Handle<SharedFunctionInfo>> infos;
2494 frame->GetFunctions(&infos);
2495 for (const auto& info : infos) {
2496 if (!IsBlackboxed(info)) return false;
2497 }
2498 return true;
2499}
2500
2503 v8::debug::ExceptionType exception_type) {
2504 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2505 // Do not trigger exception event on stack overflow. We cannot perform
2506 // anything useful for debugging in that situation.
2507 StackLimitCheck stack_limit_check(isolate_);
2508 if (stack_limit_check.JsHasOverflowed()) return;
2509
2510 // Return if the event has nowhere to go.
2511 if (!debug_delegate_) return;
2512
2513 // Return if we are not interested in exception events.
2515
2516 HandleScope scope(isolate_);
2517
2518 bool all_frames_ignored = true;
2519 bool is_debuggable = false;
2520 bool uncaught = !isolate_->WalkCallStackAndPromiseTree(
2521 promise, [this, &all_frames_ignored,
2522 &is_debuggable](Isolate::PromiseHandler handler) {
2523 if (!handler.async) {
2524 is_debuggable = true;
2525 } else if (!is_debuggable) {
2526 // Don't bother checking ignore listing if there are no debuggable
2527 // frames on the callstack
2528 return;
2529 }
2530 all_frames_ignored =
2531 all_frames_ignored &&
2532 IsBlackboxed(direct_handle(handler.function_info, isolate_));
2533 });
2534
2535 if (all_frames_ignored || !is_debuggable) {
2536 return;
2537 }
2538
2539 if (!uncaught) {
2541 return;
2542 }
2543 } else {
2545 return;
2546 }
2547 }
2548
2549 {
2551 for (; !it.done(); it.Advance()) {
2552 if (it.frame()->is_javascript()) {
2553 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
2554 FrameSummary summary = FrameSummary::GetTop(frame);
2556 summary.AsJavaScript().function()->shared(), isolate_};
2557 if (shared->IsSubjectToDebugging()) {
2558 Handle<DebugInfo> debug_info;
2559 std::vector<BreakLocation> break_locations;
2560 if (ToHandle(isolate_, TryGetDebugInfo(*shared), &debug_info) &&
2561 debug_info->HasBreakInfo()) {
2562 // Enter the debugger.
2563 DebugScope debug_scope(this);
2564 BreakLocation::AllAtCurrentStatement(debug_info, frame,
2565 &break_locations);
2566 }
2567 if (IsMutedAtAnyBreakLocation(shared, break_locations)) {
2568 return;
2569 }
2570 break; // Stop at first debuggable function
2571 }
2572 }
2573#if V8_ENABLE_WEBASSEMBLY
2574 else if (it.frame()->is_wasm()) {
2575 const WasmFrame* frame = WasmFrame::cast(it.frame());
2576 if (IsMutedAtWasmLocation(frame->script(), frame->position())) {
2577 return;
2578 }
2579 // Wasm is always subject to debugging
2580 break;
2581 }
2582#endif // V8_ENABLE_WEBASSEMBLY
2583 }
2584
2585 if (it.done()) return; // Do not trigger an event with an empty stack.
2586 }
2587
2588 DebugScope debug_scope(this);
2589 DisableBreak no_recursive_break(this);
2590
2591 {
2592 DirectHandle<Object> promise_object;
2593 if (!promise.ToHandle(&promise_object)) {
2594 promise_object = isolate_->factory()->undefined_value();
2595 }
2596 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebuggerCallback);
2598 v8::Utils::ToLocal(isolate_->native_context()),
2599 v8::Utils::ToLocal(exception), v8::Utils::ToLocal(promise_object),
2600 uncaught, exception_type);
2601 }
2602}
2603
2605 StepAction lastStepAction,
2606 v8::debug::BreakReasons break_reasons) {
2607 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2608 DCHECK(!break_points_hit.is_null());
2609 // The caller provided for DebugScope.
2611 // Bail out if there is no listener for this event
2612 if (ignore_events()) return;
2613
2614#ifdef DEBUG
2616#endif // DEBUG
2617
2618 if (!debug_delegate_) return;
2620 HandleScope scope(isolate_);
2621 DisableBreak no_recursive_break(this);
2622
2623 if ((lastStepAction == StepAction::StepOver ||
2624 lastStepAction == StepAction::StepInto) &&
2625 ShouldBeSkipped()) {
2626 PrepareStep(lastStepAction);
2627 return;
2628 }
2629
2630 std::vector<int> inspector_break_points_hit;
2631 // This array contains breakpoints installed using JS debug API.
2632 for (int i = 0; i < break_points_hit->length(); ++i) {
2633 Tagged<BreakPoint> break_point = Cast<BreakPoint>(break_points_hit->get(i));
2634 inspector_break_points_hit.push_back(break_point->id());
2635 }
2636 {
2637 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebuggerCallback);
2638 if (lastStepAction != StepAction::StepNone)
2639 break_reasons.Add(debug::BreakReason::kStep);
2641 v8::Utils::ToLocal(isolate_->native_context()),
2642 inspector_break_points_hit, break_reasons);
2643 }
2644}
2645
2646namespace {
2647debug::Location GetDebugLocation(DirectHandle<Script> script,
2648 int source_position) {
2650 Script::GetPositionInfo(script, source_position, &info);
2651 // V8 provides ScriptCompiler::CompileFunction method which takes
2652 // expression and compile it as anonymous function like (function() ..
2653 // expression ..). To produce correct locations for stmts inside of this
2654 // expression V8 compile this function with negative offset. Instead of stmt
2655 // position blackboxing use function start position which is negative in
2656 // described case.
2657 return debug::Location(std::max(info.line, 0), std::max(info.column, 0));
2658}
2659} // namespace
2660
2662 const int end) {
2663 debug::Location start_location = GetDebugLocation(script, start);
2664 debug::Location end_location = GetDebugLocation(script, end);
2666 ToApiHandle<debug::Script>(script), start_location, end_location);
2667}
2668
2670 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2671 if (!debug_delegate_) return !shared->IsSubjectToDebugging();
2672 DirectHandle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
2673 if (!debug_info->computed_debug_is_blackboxed()) {
2674 bool is_blackboxed =
2675 !shared->IsSubjectToDebugging() || !IsScript(shared->script());
2676 if (!is_blackboxed) {
2677 SuppressDebug while_processing(this);
2678 HandleScope handle_scope(isolate_);
2679 PostponeInterruptsScope no_interrupts(isolate_);
2680 DisableBreak no_recursive_break(this);
2681 DCHECK(IsScript(shared->script()));
2683 DCHECK(script->IsUserJavaScript());
2684 {
2685 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebuggerCallback);
2686 is_blackboxed = this->IsFunctionBlackboxed(
2687 script, shared->StartPosition(), shared->EndPosition());
2688 }
2689 }
2690 debug_info->set_debug_is_blackboxed(is_blackboxed);
2691 debug_info->set_computed_debug_is_blackboxed(true);
2692 }
2693 return debug_info->debug_is_blackboxed();
2694}
2695
2697 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2698 SuppressDebug while_processing(this);
2699 PostponeInterruptsScope no_interrupts(isolate_);
2700 DisableBreak no_recursive_break(this);
2701
2703 FrameSummary summary = iterator.GetTopValidFrame();
2704 DirectHandle<Object> script_obj = summary.script();
2705 if (!IsScript(*script_obj)) return false;
2706
2707 DirectHandle<Script> script = Cast<Script>(script_obj);
2709 int source_position = summary.SourcePosition();
2711 Script::GetPositionInfo(script, source_position, &info);
2712 {
2713 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebuggerCallback);
2715 info.line, info.column);
2716 }
2717}
2718
2720 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2721
2722 HandleScope scope(isolate_);
2724 !it.done(); it.Advance()) {
2725 StackFrame* frame = it.frame();
2726 if (frame->is_javascript() &&
2728 return false;
2729 }
2730 }
2731 return true;
2732}
2733
2735 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2736 // Allow break at entry for builtin functions.
2737 if (shared->native() || shared->IsApiFunction()) {
2738 // Functions that are subject to debugging can have regular breakpoints.
2739 DCHECK(!shared->IsSubjectToDebugging());
2740 return true;
2741 }
2742 return false;
2743}
2744
2746 bool preview, bool allow_top_frame_live_editing,
2748 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2749 DebugScope debug_scope(this);
2750 running_live_edit_ = true;
2751 LiveEdit::PatchScript(isolate_, script, source, preview,
2752 allow_top_frame_live_editing, result);
2753 running_live_edit_ = false;
2754 return result->status == debug::LiveEditResult::OK;
2755}
2756
2758 ProcessCompileEvent(true, script);
2759}
2760
2762 ProcessCompileEvent(false, script);
2763}
2764
2765void Debug::ProcessCompileEvent(bool has_compile_error,
2766 DirectHandle<Script> script) {
2767 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2768 // Ignore temporary scripts.
2769 if (script->id() == Script::kTemporaryScriptId) return;
2770 // TODO(kozyatinskiy): teach devtools to work with liveedit scripts better
2771 // first and then remove this fast return.
2772 if (running_live_edit_) return;
2773 // Attach the correct debug id to the script. The debug id is used by the
2774 // inspector to filter scripts by native context.
2775 script->set_context_data(isolate_->native_context()->debug_context_id());
2776 if (ignore_events()) return;
2777 if (!script->IsSubjectToDebugging()) return;
2778 if (!debug_delegate_) return;
2779 SuppressDebug while_processing(this);
2780 DebugScope debug_scope(this);
2781 HandleScope scope(isolate_);
2782 DisableBreak no_recursive_break(this);
2783 AllowJavascriptExecution allow_script(isolate_);
2784 {
2785 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebuggerCallback);
2787 running_live_edit_, has_compile_error);
2788 }
2789}
2790
2794 // Skip to break frame.
2796 while (!it.done() && it.frame()->id() != break_frame_id()) it.Advance();
2797 }
2798 int counter = 0;
2799 for (; !it.done(); it.Advance()) {
2800 counter += it.FrameFunctionCount();
2801 }
2802 return counter;
2803}
2804
2806 debug_delegate_ = delegate;
2807 UpdateState();
2808}
2809
2811 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2812 bool is_active = debug_delegate_ != nullptr;
2813 if (is_active == is_active_) return;
2814 if (is_active) {
2815 // Note that the debug context could have already been loaded to
2816 // bootstrap test cases.
2819 is_active = true;
2820 } else {
2822 Unload();
2823 }
2826}
2827
2835
2837 v8::debug::BreakReasons break_reasons) {
2838 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2839 // Ignore debug break during bootstrapping.
2840 if (isolate_->bootstrapper()->IsActive()) return;
2841 // Just continue if breaks are disabled.
2842 if (break_disabled()) return;
2843 // Ignore debug break if debugger is not active.
2844 if (!is_active()) return;
2845
2847 if (check.HasOverflowed()) return;
2848
2849 HandleScope scope(isolate_);
2850 MaybeHandle<FixedArray> break_points;
2851 {
2853 DCHECK(!it.done());
2854 JavaScriptFrame* frame = it.frame()->is_javascript()
2855 ? JavaScriptFrame::cast(it.frame())
2856 : nullptr;
2857 if (frame && IsJSFunction(frame->function())) {
2858 DirectHandle<JSFunction> function(frame->function(), isolate_);
2860
2861 // kScheduled breaks are triggered by the stack check. While we could
2862 // pause here, the JSFunction didn't have time yet to create and push
2863 // it's context. Instead, we step into the function and pause at the
2864 // first official breakable position.
2865 // This behavior mirrors "BreakOnNextFunctionCall".
2866 if (break_reasons.contains(v8::debug::BreakReason::kScheduled) &&
2869 PrepareStepIn(function);
2870 return;
2871 }
2872
2873 // Don't stop in builtin and blackboxed functions.
2874 bool ignore_break = ignore_break_mode == kIgnoreIfTopFrameBlackboxed
2875 ? IsBlackboxed(shared)
2877 if (ignore_break) return;
2878 Handle<DebugInfo> debug_info;
2879 if (ToHandle(isolate_, TryGetDebugInfo(*shared), &debug_info) &&
2880 debug_info->HasBreakInfo()) {
2881 // Enter the debugger.
2882 DebugScope debug_scope(this);
2883
2884 std::vector<BreakLocation> break_locations;
2885 BreakLocation::AllAtCurrentStatement(debug_info, frame,
2886 &break_locations);
2887
2888 if (IsMutedAtAnyBreakLocation(shared, break_locations)) {
2889 // If we get to this point, a break was triggered because e.g. of
2890 // a debugger statement, an assert, .. . However, we do not stop
2891 // if this position "is muted", which happens if a conditional
2892 // breakpoint at this point evaluated to false.
2893 return;
2894 }
2895 }
2896 }
2897 }
2898
2899 StepAction lastStepAction = last_step_action();
2900
2901 // Clear stepping to avoid duplicate breaks.
2902 ClearStepping();
2903
2904 DebugScope debug_scope(this);
2905 OnDebugBreak(break_points.is_null() ? isolate_->factory()->empty_fixed_array()
2906 : break_points.ToHandleChecked(),
2907 lastStepAction, break_reasons);
2908}
2909
2910#ifdef DEBUG
2912 if (!v8_flags.print_break_location) return;
2913 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
2914 HandleScope scope(isolate_);
2916 if (iterator.done()) return;
2917 CommonFrame* frame = iterator.frame();
2918 FrameSummaries summaries = frame->Summarize();
2919 int inlined_frame_index = static_cast<int>(summaries.size() - 1);
2920 FrameInspector inspector(frame, inlined_frame_index, isolate_);
2921 int source_position = inspector.GetSourcePosition();
2922 DirectHandle<Object> script_obj = inspector.GetScript();
2923 PrintF("[debug] break in function '");
2924 inspector.GetFunctionName()->PrintOn(stdout);
2925 PrintF("'.\n");
2926 if (IsScript(*script_obj)) {
2927 DirectHandle<Script> script = Cast<Script>(script_obj);
2931 Script::GetPositionInfo(script, source_position, &info,
2933 int line = info.line;
2934 int column = info.column;
2935 DirectHandle<FixedArray> line_ends(Cast<FixedArray>(script->line_ends()),
2936 isolate_);
2937 int line_start = line == 0 ? 0 : Smi::ToInt(line_ends->get(line - 1)) + 1;
2938 int line_end = Smi::ToInt(line_ends->get(line));
2940 String::FlatContent content = source->GetFlatContent(no_gc);
2941 if (content.IsOneByte()) {
2942 PrintF("[debug] %.*s\n", line_end - line_start,
2943 content.ToOneByteVector().begin() + line_start);
2944 PrintF("[debug] ");
2945 for (int i = 0; i < column; i++) PrintF(" ");
2946 PrintF("^\n");
2947 } else {
2948 PrintF("[debug] at line %d column %d\n", line, column);
2949 }
2950 }
2951}
2952#endif // DEBUG
2953
2955 : debug_(debug),
2956 prev_(reinterpret_cast<DebugScope*>(
2957 base::Relaxed_Load(&debug->thread_local_.current_debug_scope_))),
2958 no_interrupts_(debug_->isolate_) {
2959 timer_.Start();
2960 // Link recursive debugger entry.
2962 reinterpret_cast<base::AtomicWord>(this));
2963 // Store the previous frame id and return value.
2965
2966 // Create the new break info. If there is no proper frames there is no break
2967 // frame id.
2969 bool has_frames = !it.done();
2971 has_frames ? it.frame()->id() : StackFrameId::NO_ID;
2972
2974}
2975
2977
2981
2983 // Terminate on resume must have been handled by retrieving it, if this is
2984 // the outer scope.
2986 if (!prev_) {
2987 debug_->isolate_->stack_guard()->RequestTerminateExecution();
2988 } else {
2990 }
2991 }
2992 // Leaving this debugger entry.
2994 reinterpret_cast<base::AtomicWord>(prev_));
2995
2996 // Restore to the previous break state.
2998
3000}
3001
3005
3009
3011 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3012 // Walk all debug infos and update their execution mode if it is different
3013 // from the isolate execution mode.
3014 const DebugInfo::ExecutionMode current_debug_execution_mode =
3016
3017 HandleScope scope(isolate_);
3019 for (; it.HasNext(); it.Advance()) {
3020 Handle<DebugInfo> debug_info(it.Next(), isolate_);
3021 if (debug_info->HasInstrumentedBytecodeArray() &&
3022 debug_info->DebugExecutionMode() != current_debug_execution_mode) {
3023 DCHECK(debug_info->shared()->HasBytecodeArray());
3024 if (current_debug_execution_mode == DebugInfo::kBreakpoints) {
3025 ClearSideEffectChecks(debug_info);
3026 ApplyBreakPoints(debug_info);
3027 } else {
3028 ClearBreakPoints(debug_info);
3029 ApplySideEffectChecks(debug_info);
3030 }
3031 }
3032 }
3033}
3034
3036 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3037 DebugScope* scope = reinterpret_cast<DebugScope*>(
3039 CHECK_NOT_NULL(scope);
3040 scope->set_terminate_on_resume();
3041}
3042
3044 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3049
3053
3054 DirectHandle<RegExpMatchInfo> current_match_info(
3055 isolate_->native_context()->regexp_last_match_info(), isolate_);
3056 int register_count = current_match_info->number_of_capture_registers();
3059 JSRegExp::CaptureCountForRegisters(register_count)),
3060 isolate_);
3061 DCHECK_EQ(regexp_match_info_->number_of_capture_registers(),
3062 current_match_info->number_of_capture_registers());
3063 regexp_match_info_->set_last_subject(current_match_info->last_subject());
3064 regexp_match_info_->set_last_input(current_match_info->last_input());
3066 *current_match_info, 0, register_count,
3068
3069 // Update debug infos to have correct execution mode.
3071}
3072
3074 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3078 DCHECK_IMPLIES(v8_flags.strict_termination_checks,
3080 // Convert the termination exception into a regular exception.
3082 isolate_->Throw(*isolate_->factory()->NewEvalError(
3083 MessageTemplate::kNoSideEffectDebugEvaluate));
3084 }
3088
3091 temporary_objects_.reset();
3092 isolate_->native_context()->set_regexp_last_match_info(*regexp_match_info_);
3094
3095 // Update debug infos to have correct execution mode.
3097}
3098
3100 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3101 DCHECK(debug_info->HasInstrumentedBytecodeArray());
3102 Handle<BytecodeArray> debug_bytecode(debug_info->DebugBytecodeArray(isolate_),
3103 isolate_);
3105 debug_info->SetDebugExecutionMode(DebugInfo::kSideEffects);
3106}
3107
3109 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3110 DCHECK(debug_info->HasInstrumentedBytecodeArray());
3111 Handle<BytecodeArray> debug_bytecode(debug_info->DebugBytecodeArray(isolate_),
3112 isolate_);
3114 debug_info->OriginalBytecodeArray(isolate_), isolate_);
3115 for (interpreter::BytecodeArrayIterator it(debug_bytecode); !it.done();
3116 it.Advance()) {
3117 // Restore from original. This may copy only the scaling prefix, which is
3118 // correct, since we patch scaling prefixes to debug breaks if exists.
3119 debug_bytecode->set(it.current_offset(),
3120 original->get(it.current_offset()));
3121 }
3122}
3123
3126 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3128 DisallowJavascriptExecution no_js(isolate_);
3129 IsCompiledScope is_compiled_scope(
3130 function->shared()->is_compiled_scope(isolate_));
3131 if (!function->is_compiled(isolate_) &&
3133 &is_compiled_scope)) {
3134 return false;
3135 }
3136 DCHECK(is_compiled_scope.is_compiled());
3138 DirectHandle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
3139 DebugInfo::SideEffectState side_effect_state =
3140 debug_info->GetSideEffectState(isolate_);
3141 if (shared->HasBuiltinId()) {
3142 PrepareBuiltinForSideEffectCheck(isolate_, shared->builtin_id());
3143 }
3144 switch (side_effect_state) {
3146 if (v8_flags.trace_side_effect_free_debug_evaluate) {
3147 PrintF("[debug-evaluate] Function %s failed side effect check.\n",
3148 function->shared()->DebugNameCStr().get());
3149 }
3151 // Throw an uncatchable termination exception.
3153 return false;
3155 if (!shared->HasBytecodeArray()) {
3157 }
3158 // If function has bytecode array then prepare function for debug
3159 // execution to perform runtime side effect checks.
3160 DCHECK(shared->is_compiled());
3162 ApplySideEffectChecks(debug_info);
3163 return true;
3164 }
3166 return true;
3168 default:
3169 UNREACHABLE();
3170 }
3171}
3172
3176
3178 switch (id) {
3179 case Builtin::kStringPrototypeMatch:
3180 case Builtin::kStringPrototypeSearch:
3181 case Builtin::kStringPrototypeSplit:
3182 case Builtin::kStringPrototypeMatchAll:
3183 case Builtin::kStringPrototypeReplace:
3184 case Builtin::kStringPrototypeReplaceAll:
3185 if (Protectors::IsRegExpSpeciesLookupChainIntact(isolate_)) {
3186 // Force RegExps to go slow path so that we have a chance to perform
3187 // side-effect checks for the functions for Symbol.match,
3188 // Symbol.matchAll, Symbol.search, Symbol.split and Symbol.replace.
3189 if (v8_flags.trace_side_effect_free_debug_evaluate) {
3190 PrintF("[debug-evaluate] invalidating protector cell for RegExps\n");
3191 }
3192 Protectors::InvalidateRegExpSpeciesLookupChain(isolate_);
3193 }
3194 return;
3195 default:
3196 return;
3197 }
3198}
3199
3202 AccessorComponent component) {
3203 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3205
3206 // List of allowlisted internal accessors can be found in accessors.h.
3207 SideEffectType side_effect_type =
3209 ? accessor_info->setter_side_effect_type()
3210 : accessor_info->getter_side_effect_type();
3211
3212 switch (side_effect_type) {
3214 // We do not support setter accessors with no side effects, since
3215 // calling set accessors go through a store bytecode. Store bytecodes
3216 // are considered to cause side effects (to non-temporary objects).
3218 return true;
3219
3221 DCHECK(!receiver.is_null());
3222 if (PerformSideEffectCheckForObject(receiver)) return true;
3223 return false;
3224
3226 break;
3227 }
3228 if (v8_flags.trace_side_effect_free_debug_evaluate) {
3229 PrintF("[debug-evaluate] API Callback '");
3230 ShortPrint(accessor_info->name());
3231 PrintF("' may cause side effect.\n");
3232 }
3233
3235 // Throw an uncatchable termination exception.
3237 return false;
3238}
3239
3242 DCHECK(function->has_side_effects());
3243 // There must be only one such call handler info.
3246}
3247
3250 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3252
3253 // If an empty |function| handle is passed here then it means that
3254 // the callback IS side-effectful (see CallApiCallbackWithSideEffects
3255 // builtin).
3256 if (!function.is_null() && !function->has_side_effects()) {
3257 return true;
3258 }
3260 // If the |ignore_side_effects_for_function_template_info_| is set then
3261 // the next API callback call must be made to this function.
3263 function));
3265 return true;
3266 }
3267
3268 if (v8_flags.trace_side_effect_free_debug_evaluate) {
3269 PrintF("[debug-evaluate] FunctionTemplateInfo may cause side effect.\n");
3270 }
3271
3273 // Throw an uncatchable termination exception.
3275 return false;
3276}
3277
3279 DirectHandle<InterceptorInfo> interceptor_info) {
3280 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3282
3283 // Empty InterceptorInfo represents operations that do produce side effects.
3284 if (!interceptor_info.is_null()) {
3285 if (interceptor_info->has_no_side_effect()) return true;
3286 }
3287 if (v8_flags.trace_side_effect_free_debug_evaluate) {
3288 PrintF("[debug-evaluate] API Interceptor may cause side effect.\n");
3289 }
3290
3292 // Throw an uncatchable termination exception.
3294 return false;
3295}
3296
3298 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3300
3302 Tagged<SharedFunctionInfo> shared = frame->function()->shared();
3303 Tagged<BytecodeArray> bytecode_array = shared->GetBytecodeArray(isolate_);
3304 int offset = frame->GetBytecodeOffset();
3305 interpreter::BytecodeArrayIterator bytecode_iterator(
3306 handle(bytecode_array, isolate_), offset);
3307
3308 Bytecode bytecode = bytecode_iterator.current_bytecode();
3310 auto id = (bytecode == Bytecode::kInvokeIntrinsic)
3311 ? bytecode_iterator.GetIntrinsicIdOperand(0)
3312 : bytecode_iterator.GetRuntimeIdOperand(0);
3314 return true;
3315 }
3317 // Throw an uncatchable termination exception.
3319 return false;
3320 }
3322 switch (bytecode) {
3323 case Bytecode::kStaCurrentContextSlot:
3325 break;
3326 default:
3327 reg = bytecode_iterator.GetRegisterOperand(0);
3328 break;
3329 }
3330 DirectHandle<Object> object(frame->ReadInterpreterRegister(reg.index()),
3331 isolate_);
3332 return PerformSideEffectCheckForObject(object);
3333}
3334
3336 RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
3338
3339 // We expect no side-effects for primitives.
3340 if (IsNumber(*object)) return true;
3341 if (IsName(*object)) return true;
3342
3343 if (temporary_objects_->HasObject(Cast<HeapObject>(object))) {
3344 return true;
3345 }
3346
3347 if (v8_flags.trace_side_effect_free_debug_evaluate) {
3348 PrintF("[debug-evaluate] failed runtime side effect check.\n");
3349 }
3351 // Throw an uncatchable termination exception.
3353 return false;
3354}
3355
3357 if (temporary_objects_) {
3358 temporary_objects_->disabled = disabled;
3359 }
3360}
3361
3363 if (temporary_objects_) {
3364 return temporary_objects_->disabled;
3365 }
3366 return false;
3367}
3368
3370 int inlined_frame_index) {
3371 if (frame->is_optimized())
3373 LazyDeoptimizeReason::kDebugger);
3374
3376 thread_local_.restart_inline_frame_index_ = inlined_frame_index;
3377
3378 // TODO(crbug.com/1303521): A full "StepInto" is probably not needed. Get the
3379 // necessary bits out of PrepareSTep into a separate method or fold them
3380 // into Debug::PrepareRestartFrame.
3382}
3383
3385 DebugScope* scope = reinterpret_cast<DebugScope*>(
3387 CHECK(scope);
3388 isolate_->counters()->debug_pause_to_paused_event()->AddTimedSample(
3389 scope->ElapsedTimeSinceCreation());
3390}
3391
3392} // namespace internal
3393} // namespace v8
Isolate * isolate_
#define DISALLOW_GARBAGE_COLLECTION(name)
Builtins::Kind kind
Definition builtins.cc:40
#define BUILTIN_CODE(isolate, name)
Definition builtins.h:45
PropertyT * getter
TimeDelta Elapsed() const
constexpr void Add(E element)
Definition enum-set.h:50
constexpr bool contains(E element) const
Definition enum-set.h:35
constexpr T * begin() const
Definition vector.h:96
virtual ActionAfterInstrumentation BreakOnInstrumentation(v8::Local< v8::Context > paused_context, const debug::BreakpointId instrumentationId)
virtual void ScriptCompiled(v8::Local< Script > script, bool is_live_edited, bool has_compile_error)
virtual void BreakProgramRequested(v8::Local< v8::Context > paused_context, const std::vector< debug::BreakpointId > &inspector_break_points_hit, base::EnumSet< BreakReason > break_reasons={})
virtual bool ShouldBeSkipped(v8::Local< v8::debug::Script > script, int line, int column)
virtual void ExceptionThrown(v8::Local< v8::Context > paused_context, v8::Local< v8::Value > exception, v8::Local< v8::Value > promise, bool is_uncaught, ExceptionType exception_type)
virtual void BreakpointConditionEvaluated(v8::Local< v8::Context > context, debug::BreakpointId breakpoint_id, bool exception_thrown, v8::Local< v8::Value > exception)
virtual bool IsFunctionBlackboxed(v8::Local< debug::Script > script, const debug::Location &start, const debug::Location &end)
static Handle< JSAny > GetComponent(Isolate *isolate, DirectHandle< NativeContext > native_context, DirectHandle< AccessorPair > accessor_pair, AccessorComponent component)
Definition objects.cc:4015
BreakLocation GetBreakLocation()
Definition debug.cc:429
BreakIterator(Handle< DebugInfo > debug_info)
Definition debug.cc:327
SourcePositionTableIterator source_position_iterator_
Definition debug.h:170
DebugBreakType GetDebugBreakType()
Definition debug.cc:375
void SkipTo(int count)
Definition debug.h:147
Handle< DebugInfo > debug_info_
Definition debug.h:166
void SkipToPosition(int position)
Definition debug.cc:406
int break_index() const
Definition debug.h:152
int BreakIndexFromPosition(int position)
Definition debug.cc:339
Handle< AbstractCode > abstract_code_
Definition debug.h:126
static void AllAtCurrentStatement(Handle< DebugInfo > debug_info, JavaScriptFrame *frame, std::vector< BreakLocation > *result_out)
Definition debug.cc:236
BreakLocation(Handle< AbstractCode > abstract_code, DebugBreakType type, int code_offset, int position, int generator_obj_reg_index, int generator_suspend_id)
Definition debug.h:100
static bool IsPausedInJsFunctionEntry(JavaScriptFrame *frame)
Definition debug.cc:201
Tagged< JSGeneratorObject > GetGeneratorObjectForSuspendedFrame(JavaScriptFrame *frame) const
Definition debug.cc:258
static BreakLocation Invalid()
Definition debug.h:71
DebugBreakType type_
Definition debug.h:128
bool IsReturn() const
Definition debug.h:81
int code_offset() const
Definition debug.h:92
bool IsDebugBreakAtEntry() const
Definition debug.h:86
static int BreakIndexFromCodeOffset(Handle< DebugInfo > debug_info, DirectHandle< AbstractCode > abstract_code, int offset)
Definition debug.cc:270
bool IsSuspend() const
Definition debug.h:80
static BreakLocation FromFrame(Handle< DebugInfo > debug_info, JavaScriptFrame *frame)
Definition debug.cc:188
bool IsReturnOrSuspend() const
Definition debug.h:82
bool HasBreakPoint(Isolate *isolate, Handle< DebugInfo > debug_info) const
Definition debug.cc:290
debug::BreakLocationType type() const
Definition debug.cc:311
FrameSummaries Summarize() const override
Definition frames.cc:2479
virtual int LookupExceptionHandlerInTable(int *data, HandlerTable::CatchPrediction *prediction)
Definition frames.cc:2521
virtual FrameSummaries Summarize() const
Definition frames.cc:1508
static bool Compile(Isolate *isolate, Handle< SharedFunctionInfo > shared, ClearExceptionFlag flag, IsCompiledScope *is_compiled_scope, CreateSourcePositions create_source_positions_flag=CreateSourcePositions::kNo)
Definition compiler.cc:2906
static MaybeHandle< SharedFunctionInfo > CompileToplevel(ParseInfo *parse_info, Handle< Script > script, Isolate *isolate, IsCompiledScope *is_compiled_scope)
Definition compiler.cc:3151
static void ApplySideEffectChecks(Handle< BytecodeArray > bytecode_array)
static MaybeDirectHandle< Object > WithTopmostArguments(Isolate *isolate, DirectHandle< String > source)
static bool IsSideEffectFreeIntrinsic(Runtime::FunctionId id)
static V8_EXPORT_PRIVATE MaybeDirectHandle< Object > Local(Isolate *isolate, StackFrameId frame_id, int inlined_jsframe_index, DirectHandle< String > source, bool throw_on_side_effect)
void DeleteIndex(size_t index)
Definition debug.cc:594
void Insert(Tagged< SharedFunctionInfo > sfi, Tagged< DebugInfo > debug_info)
Definition debug.cc:547
std::unordered_map< SFIUniqueId, HandleLocation > map_
Definition debug.h:241
V8_EXPORT_PRIVATE Tagged< DebugInfo > EntryAsDebugInfo(size_t index) const
Definition debug.cc:589
bool Contains(Tagged< SharedFunctionInfo > sfi) const
Definition debug.cc:562
std::optional< Tagged< DebugInfo > > Find(Tagged< SharedFunctionInfo > sfi) const
Definition debug.cc:569
std::vector< HandleLocation > list_
Definition debug.h:240
void DeleteSlow(Tagged< SharedFunctionInfo > sfi)
Definition debug.cc:578
static const int kEstimatedNofBreakPointsInFunction
static bool ClearBreakPoint(Isolate *isolate, DirectHandle< DebugInfo > debug_info, DirectHandle< BreakPoint > break_point)
static DirectHandle< Object > FindBreakPointInfo(Isolate *isolate, DirectHandle< DebugInfo > debug_info, DirectHandle< BreakPoint > break_point)
static const int kNoDebuggingId
static void SetBreakPoint(Isolate *isolate, DirectHandle< DebugInfo > debug_info, int source_position, DirectHandle< BreakPoint > break_point)
Isolate * isolate()
Definition debug.h:751
base::TimeDelta ElapsedTimeSinceCreation()
Definition debug.cc:2978
StackFrameId break_frame_id_
Definition debug.h:755
base::ElapsedTimer timer_
Definition debug.h:762
DebugScope(Debug *debug)
Definition debug.cc:2954
DebugScope * prev_
Definition debug.h:754
TemporaryObjectsTracker & operator=(const TemporaryObjectsTracker &)=delete
bool RemoveFromRegions(Address start, Address end)
Definition debug.cc:142
std::map< Address, Address >::iterator FindOverlappingRegion(Address start, Address end, bool include_adjacent)
Definition debug.cc:102
bool HasRegionContainingObject(Address start, Address end)
Definition debug.cc:90
std::map< Address, Address > regions_
Definition debug.cc:167
TemporaryObjectsTracker(const TemporaryObjectsTracker &)=delete
void AllocationEvent(Address addr, int size) override
Definition debug.cc:55
bool HasObject(DirectHandle< HeapObject > obj)
Definition debug.cc:75
void MoveEvent(Address from, Address to, int size) override
Definition debug.cc:60
void AddRegion(Address start, Address end)
Definition debug.cc:120
Tagged< Object > ignore_step_into_function_
Definition debug.h:646
Tagged< Object > muted_function_
Definition debug.h:697
base::AtomicWord current_debug_scope_
Definition debug.h:636
Tagged< Object > return_value_
Definition debug.h:664
Tagged< Object > suspended_generator_
Definition debug.h:667
Debug(const Debug &)=delete
bool HasCoverageInfo(Tagged< SharedFunctionInfo > sfi)
Definition debug.cc:2427
std::optional< Tagged< Object > > OnThrow(DirectHandle< Object > exception) V8_WARN_UNUSED_RESULT
Definition debug.cc:2448
void OnException(DirectHandle< Object > exception, MaybeDirectHandle< JSPromise > promise, v8::debug::ExceptionType exception_type)
Definition debug.cc:2501
Handle< Object > FindInnermostContainingFunctionInfo(Handle< Script > script, int position)
Definition debug.cc:2226
void Break(JavaScriptFrame *frame, DirectHandle< JSFunction > break_target)
Definition debug.cc:638
Handle< Object > return_value_handle()
Definition debug.cc:3173
void ClearAllDebuggerHints()
Definition debug.cc:2352
DebugInfoCollection debug_infos_
Definition debug.h:624
void SetDebugDelegate(debug::DebugDelegate *delegate)
Definition debug.cc:2805
std::optional< Tagged< DebugInfo > > TryGetDebugInfo(Tagged< SharedFunctionInfo > sfi)
Definition debug.cc:2418
void OnCompileError(DirectHandle< Script > script)
Definition debug.cc:2757
void DeoptimizeFunction(DirectHandle< SharedFunctionInfo > shared)
Definition debug.cc:1789
void clear_restart_frame()
Definition debug.h:477
bool SetBreakpointForFunction(Handle< SharedFunctionInfo > shared, DirectHandle< String > condition, int *id, BreakPointKind kind=kRegular)
Definition debug.cc:1123
bool ignore_events() const
Definition debug.h:523
int FindBreakablePosition(Handle< DebugInfo > debug_info, int source_position)
Definition debug.cc:1032
void PrepareStep(StepAction step_action)
Definition debug.cc:1425
bool ShouldBeSkipped()
Definition debug.cc:2696
MaybeHandle< FixedArray > GetHitBreakPoints(DirectHandle< DebugInfo > debug_info, int position, bool *has_break_points)
Definition debug.cc:1271
void NotifyDebuggerPausedEventSent()
Definition debug.cc:3384
void SetTemporaryObjectTrackingDisabled(bool disabled)
Definition debug.cc:3356
void AssertDebugContext()
Definition debug.h:584
bool break_disabled() const
Definition debug.h:485
void FloodWithOneShot(Handle< SharedFunctionInfo > function, bool returns_only=false)
Definition debug.cc:1238
debug::DebugDelegate::ActionAfterInstrumentation OnInstrumentationBreak()
Definition debug.cc:624
void PrepareBuiltinForSideEffectCheck(Isolate *isolate, Builtin id)
Definition debug.cc:3177
bool running_live_edit_
Definition debug.h:611
void ClearBreakPoint(DirectHandle< BreakPoint > break_point)
Definition debug.cc:1085
void ClearAllBreakPoints()
Definition debug.cc:1212
Handle< SharedFunctionInfo > FindClosestSharedFunctionInfoFromPosition(int position, Handle< Script > script, Handle< SharedFunctionInfo > outer_shared)
Definition debug.cc:2103
void PrepareStepIn(DirectHandle< JSFunction > function)
Definition debug.cc:1324
void PrepareStepInSuspendedGenerator()
Definition debug.cc:1338
int CurrentFrameCount()
Definition debug.cc:2791
void StopSideEffectCheckMode()
Definition debug.cc:3073
void ApplyBreakPoints(Handle< DebugInfo > debug_info)
Definition debug.cc:1045
MaybeHandle< FixedArray > CheckBreakPoints(Handle< DebugInfo > debug_info, BreakLocation *location, bool *has_break_points)
Definition debug.cc:858
void RemoveAllCoverageInfos()
Definition debug.cc:2346
void ClearAllDebugInfos(const DebugInfoClearFunction &clear_function)
Definition debug.cc:2357
std::atomic< bool > is_active_
Definition debug.h:604
bool SetBreakpoint(Handle< SharedFunctionInfo > shared, DirectHandle< BreakPoint > break_point, int *source_position)
Definition debug.cc:972
void clear_suspended_generator()
Definition debug.h:528
ThreadLocal thread_local_
Definition debug.h:707
void StartSideEffectCheckMode()
Definition debug.cc:3043
void HandleDebugBreak(IgnoreBreakMode ignore_break_mode, debug::BreakReasons break_reasons)
Definition debug.cc:2836
bool break_on_next_function_call() const
Definition debug.h:463
bool break_points_active_
Definition debug.h:615
bool IsFunctionBlackboxed(DirectHandle< Script > script, const int start, const int end)
Definition debug.cc:2661
bool HasBreakInfo(Tagged< SharedFunctionInfo > sfi)
Definition debug.cc:2434
void OnPromiseReject(DirectHandle< Object > promise, DirectHandle< Object > value)
Definition debug.cc:2475
void ClearBreakPoints(Handle< DebugInfo > debug_info)
Definition debug.cc:1066
int GetFunctionDebuggingId(DirectHandle< JSFunction > function)
Definition debug.cc:1111
bool PerformSideEffectCheckForInterceptor(DirectHandle< InterceptorInfo > interceptor_info)
Definition debug.cc:3278
void RemoveBreakpoint(int id)
Definition debug.cc:1152
bool side_effect_check_failed_
Definition debug.h:621
bool HasDebugInfo(Tagged< SharedFunctionInfo > sfi)
Definition debug.cc:2423
static const int kBreakAtEntryPosition
Definition debug.h:489
std::unique_ptr< TemporaryObjectsTracker > temporary_objects_
Definition debug.h:628
char * ArchiveDebug(char *to)
Definition debug.cc:485
void InstallCoverageInfo(DirectHandle< SharedFunctionInfo > shared, DirectHandle< CoverageInfo > coverage_info)
Definition debug.cc:2331
bool GetPossibleBreakpoints(Handle< Script > script, int start_position, int end_position, bool restrict_to_function, std::vector< BreakLocation > *locations)
Definition debug.cc:1999
void SetTerminateOnResume()
Definition debug.cc:3035
bool break_on_caught_exception_
Definition debug.h:617
void OnDebugBreak(DirectHandle< FixedArray > break_points_hit, StepAction stepAction, debug::BreakReasons break_reasons={})
Definition debug.cc:2604
void ChangeBreakOnException(ExceptionBreakType type, bool enable)
Definition debug.cc:1255
StackFrameId break_frame_id()
Definition debug.h:443
void ProcessCompileEvent(bool has_compile_error, DirectHandle< Script > script)
Definition debug.cc:2765
void UpdateHookOnFunctionCall()
Definition debug.cc:2828
bool PerformSideEffectCheckForCallback(Handle< FunctionTemplateInfo > function)
Definition debug.cc:3248
DirectHandle< FixedArray > GetLoadedScripts()
Definition debug.cc:2397
StepAction last_step_action()
Definition debug.h:462
bool break_on_uncaught_exception_
Definition debug.h:619
static DirectHandle< Object > GetSourceBreakLocations(Isolate *isolate, DirectHandle< SharedFunctionInfo > shared)
Definition debug.cc:1614
void SetMutedLocation(DirectHandle< SharedFunctionInfo > function, const BreakLocation &location)
Definition debug.cc:1685
bool GetTemporaryObjectTrackingDisabled() const
Definition debug.cc:3362
void SetBreakOnNextFunctionCall()
Definition debug.cc:1308
bool scheduled_break_on_function_call() const
Definition debug.h:467
bool PerformSideEffectCheckForObject(DirectHandle< Object > object)
Definition debug.cc:3335
bool PerformSideEffectCheckAtBytecode(InterpretedFrame *frame)
Definition debug.cc:3297
bool AllFramesOnStackAreBlackboxed()
Definition debug.cc:2719
IndirectHandle< FunctionTemplateInfo > ignore_side_effects_for_function_template_info_
Definition debug.h:719
Tagged< Object > return_value()
Definition debug.h:446
bool has_suspended_generator() const
Definition debug.h:532
void Iterate(RootVisitor *v)
Definition debug.cc:526
debug::DebugDelegate * debug_delegate_
Definition debug.h:599
bool SetBreakPointForScript(Handle< Script > script, DirectHandle< String > condition, int *source_position, int *id)
Definition debug.cc:997
bool FindSharedFunctionInfosIntersectingRange(Handle< Script > script, int start_position, int end_position, std::vector< Handle< SharedFunctionInfo > > *candidates)
Definition debug.cc:2141
bool EnsureBreakInfo(Handle< SharedFunctionInfo > shared)
Definition debug.cc:2276
void UpdateDebugInfosForExecutionMode()
Definition debug.cc:3010
void OnAfterCompile(DirectHandle< Script > script)
Definition debug.cc:2761
void PrepareFunctionForDebugExecution(DirectHandle< SharedFunctionInfo > shared)
Definition debug.cc:1798
bool in_debug_scope() const
Definition debug.h:433
bool CanBreakAtEntry(DirectHandle< SharedFunctionInfo > shared)
Definition debug.cc:2734
bool hook_on_function_call_
Definition debug.h:607
Isolate * isolate_
Definition debug.h:721
void DiscardBaselineCode(Tagged< SharedFunctionInfo > shared)
Definition debug.cc:1745
MaybeDirectHandle< FixedArray > CheckBreakPointsForLocations(Handle< DebugInfo > debug_info, std::vector< BreakLocation > &break_locations, bool *has_break_points)
Definition debug.cc:206
void IgnoreSideEffectsOnNextCallTo(Handle< FunctionTemplateInfo > function)
Definition debug.cc:3240
void PrepareStepOnThrow()
Definition debug.cc:1353
std::function< void(Handle< DebugInfo >)> DebugInfoClearFunction
Definition debug.h:593
void InstallDebugBreakTrampoline()
Definition debug.cc:1854
bool is_active() const
Definition debug.h:432
bool SetScriptSource(Handle< Script > script, Handle< String > source, bool preview, bool allow_top_frame_live_editing, debug::LiveEditResult *result)
Definition debug.cc:2745
void RemoveBreakInfoAndMaybeFree(DirectHandle< DebugInfo > debug_info)
Definition debug.cc:2369
void ClearMutedLocation()
Definition debug.cc:1680
void CreateBreakInfo(DirectHandle< SharedFunctionInfo > shared)
Definition debug.cc:2296
static int ArchiveSpacePerThread()
Definition debug.cc:524
char * RestoreDebug(char *from)
Definition debug.cc:491
void ClearBreakOnNextFunctionCall()
Definition debug.cc:1319
bool IsBlackboxed(DirectHandle< SharedFunctionInfo > shared)
Definition debug.cc:2669
void ApplySideEffectChecks(DirectHandle< DebugInfo > debug_info)
Definition debug.cc:3099
bool IsFrameBlackboxed(JavaScriptFrame *frame)
Definition debug.cc:2490
static const int kInstrumentationId
Definition debug.h:492
bool BreakAtEntry(Tagged< SharedFunctionInfo > sfi)
Definition debug.cc:2441
void DiscardAllBaselineCode()
Definition debug.cc:1766
void PrepareRestartFrame(JavaScriptFrame *frame, int inlined_frame_index)
Definition debug.cc:3369
bool IsBreakOnException(ExceptionBreakType type)
Definition debug.cc:1263
MaybeDirectHandle< SharedFunctionInfo > GetTopLevelWithRecompile(Handle< Script > script, bool *did_compile=nullptr)
Definition debug.cc:2201
bool PerformSideEffectCheck(DirectHandle< JSFunction > function, DirectHandle< Object > receiver)
Definition debug.cc:3124
bool CheckBreakPoint(DirectHandle< BreakPoint > break_point, bool is_break_at_entry)
Definition debug.cc:923
Handle< DebugInfo > GetOrCreateDebugInfo(DirectHandle< SharedFunctionInfo > shared)
Definition debug.cc:2318
void set_return_value(Tagged< Object > value)
Definition debug.h:447
bool IsMutedAtAnyBreakLocation(DirectHandle< SharedFunctionInfo > function, const std::vector< BreakLocation > &locations)
Definition debug.cc:873
void ClearSideEffectChecks(DirectHandle< DebugInfo > debug_info)
Definition debug.cc:3108
bool IsBreakAtReturn(JavaScriptFrame *frame)
Definition debug.cc:2377
IndirectHandle< RegExpMatchInfo > regexp_match_info_
Definition debug.h:630
bool IsBreakOnDebuggerStatement(DirectHandle< SharedFunctionInfo > function, const BreakLocation &location)
Definition debug.cc:841
bool IsBreakOnInstrumentation(Handle< DebugInfo > debug_info, const BreakLocation &location)
Definition debug.cc:815
bool PerformSideEffectCheckForAccessor(DirectHandle< AccessorInfo > accessor_info, DirectHandle< Object > receiver, AccessorComponent component)
Definition debug.cc:3200
static void PatchToJump(Address pc, Address new_pc)
static void DeoptimizeAllOptimizedCodeWithFunction(Isolate *isolate, DirectHandle< SharedFunctionInfo > function)
static void DeoptimizeFunction(Tagged< JSFunction > function, LazyDeoptimizeReason reason, Tagged< Code > code={})
static V8_EXPORT_PRIVATE void DeoptimizeAll(Isolate *isolate)
V8_INLINE bool is_null() const
Definition handles.h:693
V8_INLINE Address address() const
Definition handles.h:695
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
DirectHandle< WeakArrayList > NewWeakArrayList(int capacity, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:2669
Handle< BreakPoint > NewBreakPoint(int id, DirectHandle< String > condition)
Definition factory.cc:4004
Handle< DebugInfo > NewDebugInfo(DirectHandle< SharedFunctionInfo > shared)
Definition factory.cc:3975
static HandleType< FixedArray > RightTrimOrEmpty(Isolate *isolate, HandleType< FixedArray > array, int new_length)
static FrameSummary GetTop(const CommonFrame *frame)
Definition frames.cc:2965
int SourceStatementPosition() const
Handle< Object > script() const
void EnsureSourcePositionsAvailable()
Definition frames.cc:2711
static void Destroy(Address *location)
IndirectHandle< Object > Create(Tagged< Object > value)
static const int kNoHandlerFound
Tagged< HeapObject > Next()
Definition heap.cc:6658
V8_EXPORT_PRIVATE void RemoveHeapObjectAllocationTracker(HeapObjectAllocationTracker *tracker)
Definition heap.cc:926
V8_EXPORT_PRIVATE void CollectAllGarbage(GCFlags gc_flags, GarbageCollectionReason gc_reason, const GCCallbackFlags gc_callback_flags=kNoGCCallbackFlags)
Definition heap.cc:1258
V8_EXPORT_PRIVATE void AddHeapObjectAllocationTracker(HeapObjectAllocationTracker *tracker)
Definition heap.cc:915
int NextDebuggingId()
Definition heap.cc:7417
static InterpretedFrame * cast(StackFrame *frame)
Definition frames.h:1152
void PatchBytecodeOffset(int new_offset)
Definition frames.cc:3335
int GetBytecodeOffset() const override
Definition frames.cc:3326
GlobalHandles * global_handles() const
Definition isolate.h:1416
DebugInfo::ExecutionMode debug_execution_mode() const
Definition isolate.h:1498
void set_debug_execution_mode(DebugInfo::ExecutionMode debug_execution_mode)
Definition isolate.h:1502
void CollectSourcePositionsForAllBytecodeArrays()
Definition isolate.cc:7184
Counters * counters()
Definition isolate.h:1180
CompilationCache * compilation_cache()
Definition isolate.h:1191
Bootstrapper * bootstrapper()
Definition isolate.h:1178
Tagged< Object > Throw(Tagged< Object > exception, MessageLocation *location=nullptr)
Definition isolate.cc:2091
void CancelTerminateExecution()
Definition isolate.cc:1954
Tagged< Object > exception()
bool WalkCallStackAndPromiseTree(MaybeDirectHandle< JSPromise > rejected_promise, const std::function< void(PromiseHandler)> &callback)
Definition isolate.cc:3487
ThreadManager * thread_manager() const
Definition isolate.h:1422
Handle< NativeContext > native_context()
Definition isolate-inl.h:48
StackGuard * stack_guard()
Definition isolate.h:1198
Tagged< Object > TerminateExecution()
Definition isolate.cc:1950
v8::internal::Factory * factory()
Definition isolate.h:1527
void PromiseHookStateUpdated()
Definition isolate.cc:6471
base::Mutex * shared_function_info_access()
Definition isolate.h:755
CatchType PredictExceptionCatcher()
Definition isolate.cc:2839
ThreadLocalTop * thread_local_top()
Definition isolate.h:1331
static Handle< Object > GetDataProperty(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Name > name)
static constexpr int CaptureCountForRegisters(int register_count)
Definition js-regexp.h:93
Tagged< JSFunction > function() const override
Definition frames.cc:2492
virtual void GetFunctions(std::vector< Tagged< SharedFunctionInfo > > *functions) const
Definition frames.cc:2436
static JavaScriptFrame * cast(StackFrame *frame)
Definition frames.h:805
static void PatchScript(Isolate *isolate, Handle< Script > script, Handle< String > source, bool preview, bool allow_top_frame_live_editing, debug::LiveEditResult *result)
Definition liveedit.cc:834
V8_INLINE DirectHandle< T > ToHandleChecked() const
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(DirectHandle< S > *out) const
V8_INLINE bool is_null() const
V8_INLINE Handle< T > ToHandleChecked() const
static V8_EXPORT_PRIVATE bool BooleanValue(Tagged< Object > obj, IsolateT *isolate)
static V8_INLINE void ReplacePC(Address *pc_address, Address new_pc, int offset_from_sp)
void VisitThread(Isolate *isolate, ThreadLocalTop *top) override
static V8_EXPORT_PRIVATE DirectHandle< RegExpMatchInfo > New(Isolate *isolate, int capture_count, AllocationType allocation=AllocationType::kYoung)
ReturnValueScope(Debug *debug)
Definition debug.cc:3002
Handle< Object > return_value_
Definition debug.h:776
virtual void VisitRootPointer(Root root, const char *description, FullObjectSlot p)
Definition visitors.h:75
Tagged< Script > Next()
Definition objects.cc:4795
static void InitLineEnds(Isolate *isolate, DirectHandle< Script > script)
Definition script-inl.h:201
static constexpr int kTemporaryScriptId
Definition script.h:42
static bool GetPositionInfo(DirectHandle< Script > script, int position, PositionInfo *info, OffsetFlag offset_flag=OffsetFlag::kWithOffset)
Definition objects.cc:4367
Tagged< SharedFunctionInfo > Result()
Definition debug.cc:2078
Tagged< JSFunction > current_candidate_closure_
Definition debug.cc:2084
SharedFunctionInfoFinder(int target_position)
Definition debug.cc:2034
Tagged< JSFunction > ResultClosure()
Definition debug.cc:2080
Tagged< SharedFunctionInfo > current_candidate_
Definition debug.cc:2083
void NewCandidate(Tagged< SharedFunctionInfo > shared, Tagged< JSFunction > closure=JSFunction())
Definition debug.cc:2038
V8_EXPORT_PRIVATE Tagged< SharedFunctionInfo > Next()
static void InstallDebugBytecode(DirectHandle< SharedFunctionInfo > shared, Isolate *isolate)
static void EnsureSourcePositionsAvailable(Isolate *isolate, DirectHandle< SharedFunctionInfo > shared_info)
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr Tagged< Smi > zero()
Definition smi.h:99
bool is_javascript() const
Definition frames.h:290
StackFrameId id() const
Definition frames.h:334
bool JsHasOverflowed(uintptr_t gap=0) const
Definition isolate.cc:7296
base::Vector< const uint8_t > ToOneByteVector() const
Definition string.h:139
static void CopyElements(Isolate *isolate, Tagged< RegExpMatchInfo > dst, int dst_index, Tagged< RegExpMatchInfo > src, int src_index, int len, WriteBarrierMode mode=kDefaultMode)
bool GetHeapObject(Tagged< HeapObject > *result) const
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
void IterateArchivedThreads(ThreadVisitor *v)
Definition v8threads.cc:315
static UnoptimizedCompileFlags ForScriptCompile(Isolate *isolate, Tagged< Script > script)
Definition parse-info.cc:69
static UnoptimizedJSFrame * cast(StackFrame *frame)
Definition frames.h:1123
Tagged< Object > ReadInterpreterRegister(int register_index) const
Definition frames.cc:3307
static V8_EXPORT_PRIVATE bool SetBreakPointOnFirstBreakableForFunction(DirectHandle< Script >, int function_index, DirectHandle< BreakPoint > break_point)
static V8_EXPORT_PRIVATE void SetInstrumentationBreakpoint(DirectHandle< Script >, DirectHandle< BreakPoint > break_point)
static void ClearAllBreakpoints(Tagged< Script >)
static V8_EXPORT_PRIVATE bool ClearBreakPointById(DirectHandle< Script >, int breakpoint_id)
static V8_EXPORT_PRIVATE bool SetBreakPoint(DirectHandle< Script >, int *position, DirectHandle< BreakPoint > break_point)
static V8_WARN_UNUSED_RESULT DirectHandle< WeakArrayList > Append(Isolate *isolate, DirectHandle< WeakArrayList > array, MaybeObjectDirectHandle value, AllocationType allocation=AllocationType::kYoung)
uint32_t GetUnsignedImmediateOperand(int operand_index) const
Runtime::FunctionId GetIntrinsicIdOperand(int operand_index) const
Runtime::FunctionId GetRuntimeIdOperand(int operand_index) const
static Bytecode FromByte(uint8_t value)
Definition bytecodes.h:624
static constexpr bool IsCallRuntime(Bytecode bytecode)
Definition bytecodes.h:858
static constexpr bool IsCallOrConstruct(Bytecode bytecode)
Definition bytecodes.h:840
static constexpr bool IsPrefixScalingBytecode(Bytecode bytecode)
Definition bytecodes.h:865
static constexpr Register current_context()
Handle< Code > code
int start
Handle< SharedFunctionInfo > info
int end
Tagged< SharedFunctionInfo > shared_
Definition debug.cc:1741
ZoneVector< OpIndex > candidates
DisallowGarbageCollection no_gc_
int32_t offset
TNode< Object > receiver
SharedFunctionInfoRef shared
ZoneVector< RpoNumber > & result
LiftoffRegister reg
int position
Definition liveedit.cc:290
InstructionOperand source
void Relaxed_Store(volatile Atomic8 *ptr, Atomic8 value)
Definition atomicops.h:189
Atomic32 AtomicWord
Definition atomicops.h:76
Atomic8 Relaxed_Load(volatile const Atomic8 *ptr)
Definition atomicops.h:234
Atomic8 Acquire_Load(volatile const Atomic8 *ptr)
Definition atomicops.h:249
@ kDebuggerStatementBreakLocation
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
constexpr int kFunctionEntryBytecodeOffset
Definition globals.h:854
IgnoreBreakMode
Definition debug.h:64
@ kIgnoreIfTopFrameBlackboxed
Definition debug.h:66
@ LastStepAction
Definition debug.h:43
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
@ SKIP_WRITE_BARRIER
Definition objects.h:52
constexpr int kNoSourcePosition
Definition globals.h:850
bool IsNumber(Tagged< Object > obj)
void PrintF(const char *format,...)
Definition utils.cc:39
Tagged(T object) -> Tagged< T >
bool IsGeneratorFunction(FunctionKind kind)
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
V8_INLINE IndirectHandle< T > indirect_handle(DirectHandle< T > handle)
Definition handles.h:757
kInterpreterTrampolineOffset Tagged< HeapObject >
bool IsAsyncFunction(FunctionKind kind)
ExceptionBreakType
Definition debug.h:47
@ BreakUncaughtException
Definition debug.h:49
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
constexpr int kSystemPointerSize
Definition globals.h:410
V8_INLINE PtrComprCageBase GetPtrComprCageBase()
void ShortPrint(Tagged< Object > obj, FILE *out)
Definition objects.cc:1865
constexpr int kFunctionLiteralIdTopLevel
Definition globals.h:2767
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr int kMaxInt
Definition globals.h:374
@ ACCESSOR_GETTER
Definition objects.h:879
@ ACCESSOR_SETTER
Definition objects.h:879
@ DEBUG_BREAK_SLOT
Definition debug.h:58
@ DEBUG_BREAK_SLOT_AT_CALL
Definition debug.h:59
@ DEBUG_BREAK_AT_ENTRY
Definition debug.h:56
@ DEBUGGER_STATEMENT
Definition debug.h:57
@ DEBUG_BREAK_SLOT_AT_SUSPEND
Definition debug.h:61
@ NOT_DEBUG_BREAK
Definition debug.h:55
@ DEBUG_BREAK_SLOT_AT_RETURN
Definition debug.h:60
void MemCopy(void *dest, const void *src, size_t size)
Definition memcopy.h:124
kInterpreterTrampolineOffset script
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Local< T > Handle
SideEffectType
Definition v8-object.h:198
static constexpr RelaxedLoadTag kRelaxedLoad
Definition globals.h:2909
static constexpr RelaxedStoreTag kRelaxedStore
Definition globals.h:2911
v8::Local< T > ToApiHandle(v8::internal::DirectHandle< v8::internal::Object > obj)
Definition api.h:297
Node * prev_
#define RCS_SCOPE(...)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define CHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
std::vector< FrameSummary > frames
Definition frames.h:631