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