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