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