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