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