xref: /third_party/node/deps/v8/src/debug/debug.cc (revision 1cb0ef41)
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
48namespace v8 {
49namespace internal {
50
51class 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
58  void AllocationEvent(Address addr, int) override {
59    if (disabled) return;
60    objects_.insert(addr);
61  }
62
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
78  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
97Debug::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
112Debug::~Debug() { DCHECK_NULL(debug_delegate_); }
113
114BreakLocation 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
127MaybeHandle<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
156void 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
177JSGeneratorObject 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
188int 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
207bool 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
225debug::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
241BreakIterator::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
253int 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
266void 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
287DebugBreakType 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
313void BreakIterator::SkipToPosition(int position) {
314  BreakIterator it(debug_info_);
315  SkipTo(it.BreakIndexFromPosition(position));
316}
317
318void 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
329void 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
338BreakLocation 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
367Isolate* BreakIterator::isolate() { return debug_info_->GetIsolate(); }
368
369void 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.
378void 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
396char* Debug::ArchiveDebug(char* storage) {
397  MemCopy(storage, reinterpret_cast<char*>(&thread_local_),
398          ArchiveSpacePerThread());
399  return storage + ArchiveSpacePerThread();
400}
401
402char* 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
433int Debug::ArchiveSpacePerThread() { return sizeof(ThreadLocal); }
434
435void Debug::Iterate(RootVisitor* v) { Iterate(v, &thread_local_); }
436
437char* 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
444void 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
456DebugInfoListNode::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
463DebugInfoListNode::~DebugInfoListNode() {
464  if (debug_info_ == nullptr) return;
465  GlobalHandles::Destroy(debug_info_);
466  debug_info_ = nullptr;
467}
468
469void Debug::Unload() {
470  RCS_SCOPE(isolate_, RuntimeCallCounterId::kDebugger);
471  ClearAllBreakPoints();
472  ClearStepping();
473  RemoveAllCoverageInfos();
474  ClearAllDebuggerHints();
475  debug_delegate_ = nullptr;
476}
477
478void 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
490void 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
607bool 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.
639MaybeHandle<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
654bool 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
668MaybeHandle<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.
687bool 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
723bool 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
750bool 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
785int 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
798void 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
819void 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
838void 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
861int 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
873bool 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
900void 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
908void 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
920void 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
927void 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.
958void 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
984void 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
1001void 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
1009bool Debug::IsBreakOnException(ExceptionBreakType type) {
1010  if (type == BreakUncaughtException) {
1011    return break_on_uncaught_exception_;
1012  } else {
1013    return break_on_exception_;
1014  }
1015}
1016
1017MaybeHandle<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
1055void 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
1066void Debug::ClearBreakOnNextFunctionCall() {
1067  thread_local_.break_on_next_function_call_ = false;
1068  UpdateHookOnFunctionCall();
1069}
1070
1071void 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
1084void 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
1099void 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
1171void 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.
1341Handle<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
1370void 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.
1388void 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
1401namespace {
1402class DiscardBaselineCodeVisitor : public ThreadVisitor {
1403 public:
1404  explicit DiscardBaselineCodeVisitor(SharedFunctionInfo shared)
1405      : shared_(shared) {}
1406  DiscardBaselineCodeVisitor() : shared_(SharedFunctionInfo()) {}
1407
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
1451void 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
1473void 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
1496void 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
1523void 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
1566void 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
1623namespace {
1624template <typename Iterator>
1625void 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
1635void 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
1643bool 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
1663bool 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
1697class SharedFunctionInfoFinder {
1698 public:
1699  explicit SharedFunctionInfoFinder(int target_position)
1700      : current_start_position_(kNoSourcePosition),
1701        target_position_(target_position) {}
1702
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
1743  SharedFunctionInfo Result() { return current_candidate_; }
1744
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
1755namespace {
1756SharedFunctionInfo 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
1769Handle<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
1806bool 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.)
1880Handle<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.
1929bool 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
1946void 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
1968Handle<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
1982void 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
1997void Debug::RemoveAllCoverageInfos() {
1998  ClearAllDebugInfos(
1999      [=](Handle<DebugInfo> info) { info->ClearCoverageInfo(isolate_); });
2000}
2001
2002void Debug::ClearAllDebuggerHints() {
2003  ClearAllDebugInfos(
2004      [=](Handle<DebugInfo> info) { info->set_debugger_hints(0); });
2005}
2006
2007void 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
2022void 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
2040void 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
2051void 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
2072bool 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
2088Handle<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
2110base::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
2139void 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
2153bool 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
2167bool 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
2178void 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
2245void 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
2288namespace {
2289debug::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
2302bool 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
2331bool 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
2355bool 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
2365bool 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
2376bool 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
2387void Debug::OnCompileError(Handle<Script> script) {
2388  ProcessCompileEvent(true, script);
2389}
2390
2391void Debug::OnAfterCompile(Handle<Script> script) {
2392  ProcessCompileEvent(false, script);
2393}
2394
2395void 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
2426int 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
2440void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) {
2441  debug_delegate_ = delegate;
2442  UpdateState();
2443}
2444
2445void 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
2464void 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
2472void 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
2541void 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
2584DebugScope::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
2605void DebugScope::set_terminate_on_resume() { terminate_on_resume_ = true; }
2606
2607DebugScope::~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
2627ReturnValueScope::ReturnValueScope(Debug* debug) : debug_(debug) {
2628  return_value_ = debug_->return_value_handle();
2629}
2630
2631ReturnValueScope::~ReturnValueScope() {
2632  debug_->set_return_value(*return_value_);
2633}
2634
2635void 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
2657void 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
2665void 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
2684void 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
2710void 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
2719void 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
2734bool 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
2780Handle<Object> Debug::return_value_handle() {
2781  return handle(thread_local_.return_value_, isolate_);
2782}
2783
2784bool 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
2842bool 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
2880bool 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
2901void Debug::SetTemporaryObjectTrackingDisabled(bool disabled) {
2902  if (temporary_objects_) {
2903    temporary_objects_->disabled = disabled;
2904  }
2905}
2906
2907bool 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