• 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 
9 #include "src/api.h"
10 #include "src/arguments.h"
11 #include "src/assembler-inl.h"
12 #include "src/bootstrapper.h"
13 #include "src/code-stubs.h"
14 #include "src/codegen.h"
15 #include "src/compilation-cache.h"
16 #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
17 #include "src/compiler.h"
18 #include "src/debug/debug-evaluate.h"
19 #include "src/debug/liveedit.h"
20 #include "src/deoptimizer.h"
21 #include "src/execution.h"
22 #include "src/frames-inl.h"
23 #include "src/full-codegen/full-codegen.h"
24 #include "src/global-handles.h"
25 #include "src/globals.h"
26 #include "src/interpreter/interpreter.h"
27 #include "src/isolate-inl.h"
28 #include "src/list.h"
29 #include "src/log.h"
30 #include "src/messages.h"
31 #include "src/snapshot/natives.h"
32 #include "src/wasm/wasm-module.h"
33 #include "src/wasm/wasm-objects.h"
34 
35 #include "include/v8-debug.h"
36 
37 namespace v8 {
38 namespace internal {
39 
Debug(Isolate * isolate)40 Debug::Debug(Isolate* isolate)
41     : debug_context_(Handle<Context>()),
42       is_active_(false),
43       hook_on_function_call_(false),
44       is_suppressed_(false),
45       live_edit_enabled_(true),  // TODO(yangguo): set to false by default.
46       break_disabled_(false),
47       break_points_active_(true),
48       break_on_exception_(false),
49       break_on_uncaught_exception_(false),
50       side_effect_check_failed_(false),
51       debug_info_list_(NULL),
52       feature_tracker_(isolate),
53       isolate_(isolate) {
54   ThreadInit();
55 }
56 
FromFrame(Handle<DebugInfo> debug_info,JavaScriptFrame * frame)57 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
58                                        JavaScriptFrame* frame) {
59   auto summary = FrameSummary::GetTop(frame).AsJavaScript();
60   int offset = summary.code_offset();
61   Handle<AbstractCode> abstract_code = summary.abstract_code();
62   if (abstract_code->IsCode()) offset = offset - 1;
63   auto it = BreakIterator::GetIterator(debug_info, abstract_code);
64   it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset));
65   return it->GetBreakLocation();
66 }
67 
AllAtCurrentStatement(Handle<DebugInfo> debug_info,JavaScriptFrame * frame,List<BreakLocation> * result_out)68 void BreakLocation::AllAtCurrentStatement(Handle<DebugInfo> debug_info,
69                                           JavaScriptFrame* frame,
70                                           List<BreakLocation>* result_out) {
71   auto summary = FrameSummary::GetTop(frame).AsJavaScript();
72   int offset = summary.code_offset();
73   Handle<AbstractCode> abstract_code = summary.abstract_code();
74   if (abstract_code->IsCode()) offset = offset - 1;
75   int statement_position;
76   {
77     auto it = BreakIterator::GetIterator(debug_info, abstract_code);
78     it->SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset));
79     statement_position = it->statement_position();
80   }
81   for (auto it = BreakIterator::GetIterator(debug_info, abstract_code);
82        !it->Done(); it->Next()) {
83     if (it->statement_position() == statement_position) {
84       result_out->Add(it->GetBreakLocation());
85     }
86   }
87 }
88 
BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info,Handle<AbstractCode> abstract_code,int offset)89 int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info,
90                                             Handle<AbstractCode> abstract_code,
91                                             int offset) {
92   // Run through all break points to locate the one closest to the address.
93   int closest_break = 0;
94   int distance = kMaxInt;
95   DCHECK(0 <= offset && offset < abstract_code->Size());
96   for (auto it = BreakIterator::GetIterator(debug_info, abstract_code);
97        !it->Done(); it->Next()) {
98     // Check if this break point is closer that what was previously found.
99     if (it->code_offset() <= offset && offset - it->code_offset() < distance) {
100       closest_break = it->break_index();
101       distance = offset - it->code_offset();
102       // Check whether we can't get any closer.
103       if (distance == 0) break;
104     }
105   }
106   return closest_break;
107 }
108 
HasBreakPoint(Handle<DebugInfo> debug_info) const109 bool BreakLocation::HasBreakPoint(Handle<DebugInfo> debug_info) const {
110   // First check whether there is a break point with the same source position.
111   if (!debug_info->HasBreakPoint(position_)) return false;
112   // Then check whether a break point at that source position would have
113   // the same code offset. Otherwise it's just a break location that we can
114   // step to, but not actually a location where we can put a break point.
115   if (abstract_code_->IsCode()) {
116     DCHECK_EQ(debug_info->DebugCode(), abstract_code_->GetCode());
117     CodeBreakIterator it(debug_info);
118     it.SkipToPosition(position_, BREAK_POSITION_ALIGNED);
119     return it.code_offset() == code_offset_;
120   } else {
121     DCHECK(abstract_code_->IsBytecodeArray());
122     BytecodeArrayBreakIterator it(debug_info);
123     it.SkipToPosition(position_, BREAK_POSITION_ALIGNED);
124     return it.code_offset() == code_offset_;
125   }
126 }
127 
GetIterator(Handle<DebugInfo> debug_info,Handle<AbstractCode> abstract_code)128 std::unique_ptr<BreakIterator> BreakIterator::GetIterator(
129     Handle<DebugInfo> debug_info, Handle<AbstractCode> abstract_code) {
130   if (abstract_code->IsBytecodeArray()) {
131     DCHECK(debug_info->HasDebugBytecodeArray());
132     return std::unique_ptr<BreakIterator>(
133         new BytecodeArrayBreakIterator(debug_info));
134   } else {
135     DCHECK(abstract_code->IsCode());
136     DCHECK(debug_info->HasDebugCode());
137     return std::unique_ptr<BreakIterator>(new CodeBreakIterator(debug_info));
138   }
139 }
140 
BreakIterator(Handle<DebugInfo> debug_info)141 BreakIterator::BreakIterator(Handle<DebugInfo> debug_info)
142     : debug_info_(debug_info), break_index_(-1) {
143   position_ = debug_info->shared()->start_position();
144   statement_position_ = position_;
145 }
146 
BreakIndexFromPosition(int source_position,BreakPositionAlignment alignment)147 int BreakIterator::BreakIndexFromPosition(int source_position,
148                                           BreakPositionAlignment alignment) {
149   int distance = kMaxInt;
150   int closest_break = break_index();
151   while (!Done()) {
152     int next_position;
153     if (alignment == STATEMENT_ALIGNED) {
154       next_position = statement_position();
155     } else {
156       DCHECK(alignment == BREAK_POSITION_ALIGNED);
157       next_position = position();
158     }
159     if (source_position <= next_position &&
160         next_position - source_position < distance) {
161       closest_break = break_index();
162       distance = next_position - source_position;
163       // Check whether we can't get any closer.
164       if (distance == 0) break;
165     }
166     Next();
167   }
168   return closest_break;
169 }
170 
CodeBreakIterator(Handle<DebugInfo> debug_info)171 CodeBreakIterator::CodeBreakIterator(Handle<DebugInfo> debug_info)
172     : BreakIterator(debug_info),
173       reloc_iterator_(debug_info->DebugCode(), GetModeMask()),
174       source_position_iterator_(
175           debug_info->DebugCode()->source_position_table()) {
176   // There is at least one break location.
177   DCHECK(!Done());
178   Next();
179 }
180 
GetModeMask()181 int CodeBreakIterator::GetModeMask() {
182   int mask = 0;
183   mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
184   mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL);
185   mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL);
186   mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
187   return mask;
188 }
189 
Next()190 void CodeBreakIterator::Next() {
191   DisallowHeapAllocation no_gc;
192   DCHECK(!Done());
193 
194   // Iterate through reloc info stopping at each breakable code target.
195   bool first = break_index_ == -1;
196 
197   if (!first) reloc_iterator_.next();
198   first = false;
199   if (Done()) return;
200 
201   int offset = code_offset();
202   while (!source_position_iterator_.done() &&
203          source_position_iterator_.code_offset() <= offset) {
204     position_ = source_position_iterator_.source_position().ScriptOffset();
205     if (source_position_iterator_.is_statement()) {
206       statement_position_ = position_;
207     }
208     source_position_iterator_.Advance();
209   }
210 
211   DCHECK(RelocInfo::IsDebugBreakSlot(rmode()));
212   break_index_++;
213 }
214 
GetDebugBreakType()215 DebugBreakType CodeBreakIterator::GetDebugBreakType() {
216   if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) {
217     return DEBUG_BREAK_SLOT_AT_RETURN;
218   } else if (RelocInfo::IsDebugBreakSlotAtCall(rmode())) {
219     return DEBUG_BREAK_SLOT_AT_CALL;
220   } else if (RelocInfo::IsDebugBreakSlotAtTailCall(rmode())) {
221     return isolate()->is_tail_call_elimination_enabled()
222                ? DEBUG_BREAK_SLOT_AT_TAIL_CALL
223                : DEBUG_BREAK_SLOT_AT_CALL;
224   } else if (RelocInfo::IsDebugBreakSlot(rmode())) {
225     return DEBUG_BREAK_SLOT;
226   } else {
227     return NOT_DEBUG_BREAK;
228   }
229 }
230 
SkipToPosition(int position,BreakPositionAlignment alignment)231 void CodeBreakIterator::SkipToPosition(int position,
232                                        BreakPositionAlignment alignment) {
233   CodeBreakIterator it(debug_info_);
234   SkipTo(it.BreakIndexFromPosition(position, alignment));
235 }
236 
SetDebugBreak()237 void CodeBreakIterator::SetDebugBreak() {
238   DebugBreakType debug_break_type = GetDebugBreakType();
239   DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
240   Builtins* builtins = isolate()->builtins();
241   Handle<Code> target = debug_break_type == DEBUG_BREAK_SLOT_AT_RETURN
242                             ? builtins->Return_DebugBreak()
243                             : builtins->Slot_DebugBreak();
244   DebugCodegen::PatchDebugBreakSlot(isolate(), rinfo()->pc(), target);
245 }
246 
ClearDebugBreak()247 void CodeBreakIterator::ClearDebugBreak() {
248   DCHECK(GetDebugBreakType() >= DEBUG_BREAK_SLOT);
249   DebugCodegen::ClearDebugBreakSlot(isolate(), rinfo()->pc());
250 }
251 
IsDebugBreak()252 bool CodeBreakIterator::IsDebugBreak() {
253   DCHECK(GetDebugBreakType() >= DEBUG_BREAK_SLOT);
254   return DebugCodegen::DebugBreakSlotIsPatched(rinfo()->pc());
255 }
256 
GetBreakLocation()257 BreakLocation CodeBreakIterator::GetBreakLocation() {
258   Handle<AbstractCode> code(AbstractCode::cast(debug_info_->DebugCode()));
259   return BreakLocation(code, GetDebugBreakType(), code_offset(), position_);
260 }
261 
BytecodeArrayBreakIterator(Handle<DebugInfo> debug_info)262 BytecodeArrayBreakIterator::BytecodeArrayBreakIterator(
263     Handle<DebugInfo> debug_info)
264     : BreakIterator(debug_info),
265       source_position_iterator_(
266           debug_info->DebugBytecodeArray()->source_position_table()) {
267   // There is at least one break location.
268   DCHECK(!Done());
269   Next();
270 }
271 
Next()272 void BytecodeArrayBreakIterator::Next() {
273   DisallowHeapAllocation no_gc;
274   DCHECK(!Done());
275   bool first = break_index_ == -1;
276   while (!Done()) {
277     if (!first) source_position_iterator_.Advance();
278     first = false;
279     if (Done()) return;
280     position_ = source_position_iterator_.source_position().ScriptOffset();
281     if (source_position_iterator_.is_statement()) {
282       statement_position_ = position_;
283     }
284     DCHECK(position_ >= 0);
285     DCHECK(statement_position_ >= 0);
286 
287     DebugBreakType type = GetDebugBreakType();
288     if (type != NOT_DEBUG_BREAK) break;
289   }
290   break_index_++;
291 }
292 
GetDebugBreakType()293 DebugBreakType BytecodeArrayBreakIterator::GetDebugBreakType() {
294   BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray();
295   interpreter::Bytecode bytecode =
296       interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
297 
298   if (bytecode == interpreter::Bytecode::kDebugger) {
299     return DEBUGGER_STATEMENT;
300   } else if (bytecode == interpreter::Bytecode::kReturn) {
301     return DEBUG_BREAK_SLOT_AT_RETURN;
302   } else if (bytecode == interpreter::Bytecode::kTailCall) {
303     return isolate()->is_tail_call_elimination_enabled()
304                ? DEBUG_BREAK_SLOT_AT_TAIL_CALL
305                : DEBUG_BREAK_SLOT_AT_CALL;
306   } else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) {
307     return DEBUG_BREAK_SLOT_AT_CALL;
308   } else if (source_position_iterator_.is_statement()) {
309     return DEBUG_BREAK_SLOT;
310   } else {
311     return NOT_DEBUG_BREAK;
312   }
313 }
314 
SkipToPosition(int position,BreakPositionAlignment alignment)315 void BytecodeArrayBreakIterator::SkipToPosition(
316     int position, BreakPositionAlignment alignment) {
317   BytecodeArrayBreakIterator it(debug_info_);
318   SkipTo(it.BreakIndexFromPosition(position, alignment));
319 }
320 
SetDebugBreak()321 void BytecodeArrayBreakIterator::SetDebugBreak() {
322   DebugBreakType debug_break_type = GetDebugBreakType();
323   if (debug_break_type == DEBUGGER_STATEMENT) return;
324   DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
325   BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray();
326   interpreter::Bytecode bytecode =
327       interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
328   if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return;
329   interpreter::Bytecode debugbreak =
330       interpreter::Bytecodes::GetDebugBreak(bytecode);
331   bytecode_array->set(code_offset(),
332                       interpreter::Bytecodes::ToByte(debugbreak));
333 }
334 
ClearDebugBreak()335 void BytecodeArrayBreakIterator::ClearDebugBreak() {
336   DebugBreakType debug_break_type = GetDebugBreakType();
337   if (debug_break_type == DEBUGGER_STATEMENT) return;
338   DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
339   BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray();
340   BytecodeArray* original = debug_info_->OriginalBytecodeArray();
341   bytecode_array->set(code_offset(), original->get(code_offset()));
342 }
343 
IsDebugBreak()344 bool BytecodeArrayBreakIterator::IsDebugBreak() {
345   DebugBreakType debug_break_type = GetDebugBreakType();
346   if (debug_break_type == DEBUGGER_STATEMENT) return false;
347   DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
348   BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray();
349   interpreter::Bytecode bytecode =
350       interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
351   return interpreter::Bytecodes::IsDebugBreak(bytecode);
352 }
353 
GetBreakLocation()354 BreakLocation BytecodeArrayBreakIterator::GetBreakLocation() {
355   Handle<AbstractCode> code(
356       AbstractCode::cast(debug_info_->DebugBytecodeArray()));
357   return BreakLocation(code, GetDebugBreakType(), code_offset(), position_);
358 }
359 
360 
Track(DebugFeatureTracker::Feature feature)361 void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) {
362   uint32_t mask = 1 << feature;
363   // Only count one sample per feature and isolate.
364   if (bitfield_ & mask) return;
365   isolate_->counters()->debug_feature_usage()->AddSample(feature);
366   bitfield_ |= mask;
367 }
368 
369 
370 // Threading support.
ThreadInit()371 void Debug::ThreadInit() {
372   thread_local_.break_count_ = 0;
373   thread_local_.break_id_ = 0;
374   thread_local_.break_frame_id_ = StackFrame::NO_ID;
375   thread_local_.last_step_action_ = StepNone;
376   thread_local_.last_statement_position_ = kNoSourcePosition;
377   thread_local_.last_frame_count_ = -1;
378   thread_local_.target_frame_count_ = -1;
379   thread_local_.return_value_ = Smi::kZero;
380   thread_local_.async_task_count_ = 0;
381   clear_suspended_generator();
382   thread_local_.restart_fp_ = nullptr;
383   base::NoBarrier_Store(&thread_local_.current_debug_scope_,
384                         static_cast<base::AtomicWord>(0));
385   UpdateHookOnFunctionCall();
386 }
387 
388 
ArchiveDebug(char * storage)389 char* Debug::ArchiveDebug(char* storage) {
390   // Simply reset state. Don't archive anything.
391   ThreadInit();
392   return storage + ArchiveSpacePerThread();
393 }
394 
395 
RestoreDebug(char * storage)396 char* Debug::RestoreDebug(char* storage) {
397   // Simply reset state. Don't restore anything.
398   ThreadInit();
399   return storage + ArchiveSpacePerThread();
400 }
401 
ArchiveSpacePerThread()402 int Debug::ArchiveSpacePerThread() { return 0; }
403 
Iterate(ObjectVisitor * v)404 void Debug::Iterate(ObjectVisitor* v) {
405   v->VisitPointer(&thread_local_.return_value_);
406   v->VisitPointer(&thread_local_.suspended_generator_);
407 }
408 
DebugInfoListNode(DebugInfo * debug_info)409 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
410   // Globalize the request debug info object and make it weak.
411   GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles();
412   debug_info_ =
413       Handle<DebugInfo>::cast(global_handles->Create(debug_info)).location();
414 }
415 
416 
~DebugInfoListNode()417 DebugInfoListNode::~DebugInfoListNode() {
418   if (debug_info_ == nullptr) return;
419   GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_));
420   debug_info_ = nullptr;
421 }
422 
423 
Load()424 bool Debug::Load() {
425   // Return if debugger is already loaded.
426   if (is_loaded()) return true;
427 
428   // Bail out if we're already in the process of compiling the native
429   // JavaScript source code for the debugger.
430   if (is_suppressed_) return false;
431   SuppressDebug while_loading(this);
432 
433   // Disable breakpoints and interrupts while compiling and running the
434   // debugger scripts including the context creation code.
435   DisableBreak disable(this);
436   PostponeInterruptsScope postpone(isolate_);
437 
438   // Create the debugger context.
439   HandleScope scope(isolate_);
440   ExtensionConfiguration no_extensions;
441   // TODO(yangguo): we rely on the fact that first context snapshot is usable
442   //                as debug context. This dependency is gone once we remove
443   //                debug context completely.
444   static const int kFirstContextSnapshotIndex = 0;
445   Handle<Context> context = isolate_->bootstrapper()->CreateEnvironment(
446       MaybeHandle<JSGlobalProxy>(), v8::Local<ObjectTemplate>(), &no_extensions,
447       kFirstContextSnapshotIndex, v8::DeserializeInternalFieldsCallback(),
448       DEBUG_CONTEXT);
449 
450   // Fail if no context could be created.
451   if (context.is_null()) return false;
452 
453   debug_context_ = Handle<Context>::cast(
454       isolate_->global_handles()->Create(*context));
455 
456   feature_tracker()->Track(DebugFeatureTracker::kActive);
457 
458   return true;
459 }
460 
461 
Unload()462 void Debug::Unload() {
463   ClearAllBreakPoints();
464   ClearStepping();
465   RemoveDebugDelegate();
466 
467   // Return debugger is not loaded.
468   if (!is_loaded()) return;
469 
470   // Clear debugger context global handle.
471   GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location());
472   debug_context_ = Handle<Context>();
473 }
474 
Break(JavaScriptFrame * frame)475 void Debug::Break(JavaScriptFrame* frame) {
476   // Initialize LiveEdit.
477   LiveEdit::InitializeThreadLocal(this);
478 
479   // Just continue if breaks are disabled or debugger cannot be loaded.
480   if (break_disabled()) return;
481 
482   // Enter the debugger.
483   DebugScope debug_scope(this);
484   if (debug_scope.failed()) return;
485 
486   // Postpone interrupt during breakpoint processing.
487   PostponeInterruptsScope postpone(isolate_);
488   DisableBreak no_recursive_break(this);
489 
490   // Return if we fail to retrieve debug info.
491   Handle<JSFunction> function(frame->function());
492   Handle<SharedFunctionInfo> shared(function->shared());
493   if (!EnsureDebugInfo(shared)) return;
494   Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_);
495 
496   // Find the break location where execution has stopped.
497   BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
498 
499   // Find actual break points, if any, and trigger debug break event.
500   MaybeHandle<FixedArray> break_points_hit =
501       CheckBreakPoints(debug_info, &location);
502   if (!break_points_hit.is_null()) {
503     // Clear all current stepping setup.
504     ClearStepping();
505     // Notify the debug event listeners.
506     Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements(
507         break_points_hit.ToHandleChecked());
508     OnDebugBreak(jsarr);
509     return;
510   }
511 
512   // No break point. Check for stepping.
513   StepAction step_action = last_step_action();
514   int current_frame_count = CurrentFrameCount();
515   int target_frame_count = thread_local_.target_frame_count_;
516   int last_frame_count = thread_local_.last_frame_count_;
517 
518   bool step_break = false;
519   switch (step_action) {
520     case StepNone:
521       return;
522     case StepOut:
523       // Step out should not break in a deeper frame than target frame.
524       if (current_frame_count > target_frame_count) return;
525       step_break = true;
526       break;
527     case StepNext:
528       // Step next should not break in a deeper frame than target frame.
529       if (current_frame_count > target_frame_count) return;
530       // For step-next, a tail call is like a return and should break.
531       step_break = location.IsTailCall();
532     // Fall through.
533     case StepIn: {
534       FrameSummary summary = FrameSummary::GetTop(frame);
535       step_break = step_break || location.IsReturn() ||
536                    current_frame_count != last_frame_count ||
537                    thread_local_.last_statement_position_ !=
538                        summary.SourceStatementPosition();
539       break;
540     }
541   }
542 
543   // Clear all current stepping setup.
544   ClearStepping();
545 
546   if (step_break) {
547     // Notify the debug event listeners.
548     OnDebugBreak(isolate_->factory()->undefined_value());
549   } else {
550     // Re-prepare to continue.
551     PrepareStep(step_action);
552   }
553 }
554 
555 
556 // Find break point objects for this location, if any, and evaluate them.
557 // Return an array of break point objects that evaluated true, or an empty
558 // handle if none evaluated true.
CheckBreakPoints(Handle<DebugInfo> debug_info,BreakLocation * location,bool * has_break_points)559 MaybeHandle<FixedArray> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info,
560                                                 BreakLocation* location,
561                                                 bool* has_break_points) {
562   bool has_break_points_to_check =
563       break_points_active_ && location->HasBreakPoint(debug_info);
564   if (has_break_points) *has_break_points = has_break_points_to_check;
565   if (!has_break_points_to_check) return {};
566 
567   Handle<Object> break_point_objects =
568       debug_info->GetBreakPointObjects(location->position());
569   return Debug::GetHitBreakPointObjects(break_point_objects);
570 }
571 
572 
IsMutedAtCurrentLocation(JavaScriptFrame * frame)573 bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) {
574   HandleScope scope(isolate_);
575   // A break location is considered muted if break locations on the current
576   // statement have at least one break point, and all of these break points
577   // evaluate to false. Aside from not triggering a debug break event at the
578   // break location, we also do not trigger one for debugger statements, nor
579   // an exception event on exception at this location.
580   FrameSummary summary = FrameSummary::GetTop(frame);
581   DCHECK(!summary.IsWasm());
582   Handle<JSFunction> function = summary.AsJavaScript().function();
583   if (!function->shared()->HasDebugInfo()) return false;
584   Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo());
585   // Enter the debugger.
586   DebugScope debug_scope(this);
587   if (debug_scope.failed()) return false;
588   List<BreakLocation> break_locations;
589   BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations);
590   bool has_break_points_at_all = false;
591   for (int i = 0; i < break_locations.length(); i++) {
592     bool has_break_points;
593     MaybeHandle<FixedArray> check_result =
594         CheckBreakPoints(debug_info, &break_locations[i], &has_break_points);
595     has_break_points_at_all |= has_break_points;
596     if (has_break_points && !check_result.is_null()) return false;
597   }
598   return has_break_points_at_all;
599 }
600 
601 
CallFunction(const char * name,int argc,Handle<Object> args[])602 MaybeHandle<Object> Debug::CallFunction(const char* name, int argc,
603                                         Handle<Object> args[]) {
604   PostponeInterruptsScope no_interrupts(isolate_);
605   AssertDebugContext();
606   Handle<JSReceiver> holder =
607       Handle<JSReceiver>::cast(isolate_->natives_utils_object());
608   Handle<JSFunction> fun = Handle<JSFunction>::cast(
609       JSReceiver::GetProperty(isolate_, holder, name).ToHandleChecked());
610   Handle<Object> undefined = isolate_->factory()->undefined_value();
611   MaybeHandle<Object> maybe_exception;
612   return Execution::TryCall(isolate_, fun, undefined, argc, args,
613                             Execution::MessageHandling::kReport,
614                             &maybe_exception);
615 }
616 
617 
618 // Check whether a single break point object is triggered.
CheckBreakPoint(Handle<Object> break_point_object)619 bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
620   Factory* factory = isolate_->factory();
621   HandleScope scope(isolate_);
622 
623   // Ignore check if break point object is not a JSObject.
624   if (!break_point_object->IsJSObject()) return true;
625 
626   // Get the break id as an object.
627   Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
628 
629   // Call IsBreakPointTriggered.
630   Handle<Object> argv[] = { break_id, break_point_object };
631   Handle<Object> result;
632   if (!CallFunction("IsBreakPointTriggered", arraysize(argv), argv)
633            .ToHandle(&result)) {
634     return false;
635   }
636 
637   // Return whether the break point is triggered.
638   return result->IsTrue(isolate_);
639 }
640 
641 
SetBreakPoint(Handle<JSFunction> function,Handle<Object> break_point_object,int * source_position)642 bool Debug::SetBreakPoint(Handle<JSFunction> function,
643                           Handle<Object> break_point_object,
644                           int* source_position) {
645   HandleScope scope(isolate_);
646 
647   // Make sure the function is compiled and has set up the debug info.
648   Handle<SharedFunctionInfo> shared(function->shared());
649   if (!EnsureDebugInfo(shared)) return true;
650   Handle<DebugInfo> debug_info(shared->GetDebugInfo());
651   // Source positions starts with zero.
652   DCHECK(*source_position >= 0);
653 
654   // Find the break point and change it.
655   *source_position =
656       FindBreakablePosition(debug_info, *source_position, STATEMENT_ALIGNED);
657   DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object);
658   // At least one active break point now.
659   DCHECK(debug_info->GetBreakPointCount() > 0);
660 
661   ClearBreakPoints(debug_info);
662   ApplyBreakPoints(debug_info);
663 
664   feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
665   return true;
666 }
667 
668 
SetBreakPointForScript(Handle<Script> script,Handle<Object> break_point_object,int * source_position,BreakPositionAlignment alignment)669 bool Debug::SetBreakPointForScript(Handle<Script> script,
670                                    Handle<Object> break_point_object,
671                                    int* source_position,
672                                    BreakPositionAlignment alignment) {
673   if (script->type() == Script::TYPE_WASM) {
674     Handle<WasmCompiledModule> compiled_module(
675         WasmCompiledModule::cast(script->wasm_compiled_module()), isolate_);
676     return WasmCompiledModule::SetBreakPoint(compiled_module, source_position,
677                                              break_point_object);
678   }
679 
680   HandleScope scope(isolate_);
681 
682   // Obtain shared function info for the function.
683   Handle<Object> result =
684       FindSharedFunctionInfoInScript(script, *source_position);
685   if (result->IsUndefined(isolate_)) return false;
686 
687   // Make sure the function has set up the debug info.
688   Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result);
689   if (!EnsureDebugInfo(shared)) return false;
690 
691   // Find position within function. The script position might be before the
692   // source position of the first function.
693   if (shared->start_position() > *source_position) {
694     *source_position = shared->start_position();
695   }
696 
697   Handle<DebugInfo> debug_info(shared->GetDebugInfo());
698 
699   // Find the break point and change it.
700   *source_position =
701       FindBreakablePosition(debug_info, *source_position, alignment);
702   DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object);
703   // At least one active break point now.
704   DCHECK(debug_info->GetBreakPointCount() > 0);
705 
706   ClearBreakPoints(debug_info);
707   ApplyBreakPoints(debug_info);
708 
709   feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
710   return true;
711 }
712 
FindBreakablePosition(Handle<DebugInfo> debug_info,int source_position,BreakPositionAlignment alignment)713 int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info,
714                                  int source_position,
715                                  BreakPositionAlignment alignment) {
716   int statement_position;
717   int position;
718   if (debug_info->HasDebugCode()) {
719     CodeBreakIterator it(debug_info);
720     it.SkipToPosition(source_position, alignment);
721     statement_position = it.statement_position();
722     position = it.position();
723   } else {
724     DCHECK(debug_info->HasDebugBytecodeArray());
725     BytecodeArrayBreakIterator it(debug_info);
726     it.SkipToPosition(source_position, alignment);
727     statement_position = it.statement_position();
728     position = it.position();
729   }
730   return alignment == STATEMENT_ALIGNED ? statement_position : position;
731 }
732 
ApplyBreakPoints(Handle<DebugInfo> debug_info)733 void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) {
734   DisallowHeapAllocation no_gc;
735   if (debug_info->break_points()->IsUndefined(isolate_)) return;
736   FixedArray* break_points = debug_info->break_points();
737   for (int i = 0; i < break_points->length(); i++) {
738     if (break_points->get(i)->IsUndefined(isolate_)) continue;
739     BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i));
740     if (info->GetBreakPointCount() == 0) continue;
741     if (debug_info->HasDebugCode()) {
742       CodeBreakIterator it(debug_info);
743       it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED);
744       it.SetDebugBreak();
745     }
746     if (debug_info->HasDebugBytecodeArray()) {
747       BytecodeArrayBreakIterator it(debug_info);
748       it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED);
749       it.SetDebugBreak();
750     }
751   }
752 }
753 
ClearBreakPoints(Handle<DebugInfo> debug_info)754 void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) {
755   DisallowHeapAllocation no_gc;
756   if (debug_info->HasDebugCode()) {
757     for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) {
758       it.ClearDebugBreak();
759     }
760   }
761   if (debug_info->HasDebugBytecodeArray()) {
762     for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) {
763       it.ClearDebugBreak();
764     }
765   }
766 }
767 
ClearBreakPoint(Handle<Object> break_point_object)768 void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
769   HandleScope scope(isolate_);
770 
771   for (DebugInfoListNode* node = debug_info_list_; node != NULL;
772        node = node->next()) {
773     Handle<Object> result =
774         DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object);
775     if (result->IsUndefined(isolate_)) continue;
776     Handle<DebugInfo> debug_info = node->debug_info();
777     if (DebugInfo::ClearBreakPoint(debug_info, break_point_object)) {
778       ClearBreakPoints(debug_info);
779       if (debug_info->GetBreakPointCount() == 0) {
780         RemoveDebugInfoAndClearFromShared(debug_info);
781       } else {
782         ApplyBreakPoints(debug_info);
783       }
784       return;
785     }
786   }
787 }
788 
789 // Clear out all the debug break code. This is ONLY supposed to be used when
790 // shutting down the debugger as it will leave the break point information in
791 // DebugInfo even though the code is patched back to the non break point state.
ClearAllBreakPoints()792 void Debug::ClearAllBreakPoints() {
793   for (DebugInfoListNode* node = debug_info_list_; node != NULL;
794        node = node->next()) {
795     ClearBreakPoints(node->debug_info());
796   }
797   // Remove all debug info.
798   while (debug_info_list_ != NULL) {
799     RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
800   }
801 }
802 
FloodWithOneShot(Handle<SharedFunctionInfo> shared)803 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
804   if (!shared->IsSubjectToDebugging() || IsBlackboxed(shared)) return;
805   // Make sure the function is compiled and has set up the debug info.
806   if (!EnsureDebugInfo(shared)) return;
807   Handle<DebugInfo> debug_info(shared->GetDebugInfo());
808   // Flood the function with break points.
809   if (debug_info->HasDebugCode()) {
810     for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) {
811       it.SetDebugBreak();
812     }
813   }
814   if (debug_info->HasDebugBytecodeArray()) {
815     for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) {
816       it.SetDebugBreak();
817     }
818   }
819 }
820 
ChangeBreakOnException(ExceptionBreakType type,bool enable)821 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
822   if (type == BreakUncaughtException) {
823     break_on_uncaught_exception_ = enable;
824   } else {
825     break_on_exception_ = enable;
826   }
827 }
828 
829 
IsBreakOnException(ExceptionBreakType type)830 bool Debug::IsBreakOnException(ExceptionBreakType type) {
831   if (type == BreakUncaughtException) {
832     return break_on_uncaught_exception_;
833   } else {
834     return break_on_exception_;
835   }
836 }
837 
GetHitBreakPointObjects(Handle<Object> break_point_objects)838 MaybeHandle<FixedArray> Debug::GetHitBreakPointObjects(
839     Handle<Object> break_point_objects) {
840   DCHECK(!break_point_objects->IsUndefined(isolate_));
841   if (!break_point_objects->IsFixedArray()) {
842     if (!CheckBreakPoint(break_point_objects)) return {};
843     Handle<FixedArray> break_points_hit = isolate_->factory()->NewFixedArray(1);
844     break_points_hit->set(0, *break_point_objects);
845     return break_points_hit;
846   }
847 
848   Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
849   int num_objects = array->length();
850   Handle<FixedArray> break_points_hit =
851       isolate_->factory()->NewFixedArray(num_objects);
852   int break_points_hit_count = 0;
853   for (int i = 0; i < num_objects; ++i) {
854     Handle<Object> break_point_object(array->get(i), isolate_);
855     if (CheckBreakPoint(break_point_object)) {
856       break_points_hit->set(break_points_hit_count++, *break_point_object);
857     }
858   }
859   if (break_points_hit_count == 0) return {};
860   break_points_hit->Shrink(break_points_hit_count);
861   return break_points_hit;
862 }
863 
PrepareStepIn(Handle<JSFunction> function)864 void Debug::PrepareStepIn(Handle<JSFunction> function) {
865   CHECK(last_step_action() >= StepIn);
866   if (ignore_events()) return;
867   if (in_debug_scope()) return;
868   if (break_disabled()) return;
869   FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_));
870 }
871 
PrepareStepInSuspendedGenerator()872 void Debug::PrepareStepInSuspendedGenerator() {
873   CHECK(has_suspended_generator());
874   if (ignore_events()) return;
875   if (in_debug_scope()) return;
876   if (break_disabled()) return;
877   thread_local_.last_step_action_ = StepIn;
878   UpdateHookOnFunctionCall();
879   Handle<JSFunction> function(
880       JSGeneratorObject::cast(thread_local_.suspended_generator_)->function());
881   FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_));
882   clear_suspended_generator();
883 }
884 
PrepareStepOnThrow()885 void Debug::PrepareStepOnThrow() {
886   if (last_step_action() == StepNone) return;
887   if (ignore_events()) return;
888   if (in_debug_scope()) return;
889   if (break_disabled()) return;
890 
891   ClearOneShot();
892 
893   int current_frame_count = CurrentFrameCount();
894 
895   // Iterate through the JavaScript stack looking for handlers.
896   JavaScriptFrameIterator it(isolate_);
897   while (!it.done()) {
898     JavaScriptFrame* frame = it.frame();
899     if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break;
900     List<SharedFunctionInfo*> infos;
901     frame->GetFunctions(&infos);
902     current_frame_count -= infos.length();
903     it.Advance();
904   }
905 
906   // No handler found. Nothing to instrument.
907   if (it.done()) return;
908 
909   bool found_handler = false;
910   // Iterate frames, including inlined frames. First, find the handler frame.
911   // Then skip to the frame we want to break in, then instrument for stepping.
912   for (; !it.done(); it.Advance()) {
913     JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame());
914     if (last_step_action() == StepIn) {
915       // Deoptimize frame to ensure calls are checked for step-in.
916       Deoptimizer::DeoptimizeFunction(frame->function());
917     }
918     List<FrameSummary> summaries;
919     frame->Summarize(&summaries);
920     for (int i = summaries.length() - 1; i >= 0; i--, current_frame_count--) {
921       if (!found_handler) {
922         // We have yet to find the handler. If the frame inlines multiple
923         // functions, we have to check each one for the handler.
924         // If it only contains one function, we already found the handler.
925         if (summaries.length() > 1) {
926           Handle<AbstractCode> code =
927               summaries[i].AsJavaScript().abstract_code();
928           CHECK_EQ(AbstractCode::INTERPRETED_FUNCTION, code->kind());
929           BytecodeArray* bytecode = code->GetBytecodeArray();
930           HandlerTable* table = HandlerTable::cast(bytecode->handler_table());
931           int code_offset = summaries[i].code_offset();
932           HandlerTable::CatchPrediction prediction;
933           int index = table->LookupRange(code_offset, nullptr, &prediction);
934           if (index > 0) found_handler = true;
935         } else {
936           found_handler = true;
937         }
938       }
939 
940       if (found_handler) {
941         // We found the handler. If we are stepping next or out, we need to
942         // iterate until we found the suitable target frame to break in.
943         if ((last_step_action() == StepNext || last_step_action() == StepOut) &&
944             current_frame_count > thread_local_.target_frame_count_) {
945           continue;
946         }
947         Handle<SharedFunctionInfo> info(
948             summaries[i].AsJavaScript().function()->shared());
949         if (!info->IsSubjectToDebugging() || IsBlackboxed(info)) continue;
950         FloodWithOneShot(info);
951         return;
952       }
953     }
954   }
955 }
956 
957 
PrepareStep(StepAction step_action)958 void Debug::PrepareStep(StepAction step_action) {
959   HandleScope scope(isolate_);
960 
961   DCHECK(in_debug_scope());
962 
963   // Get the frame where the execution has stopped and skip the debug frame if
964   // any. The debug frame will only be present if execution was stopped due to
965   // hitting a break point. In other situations (e.g. unhandled exception) the
966   // debug frame is not present.
967   StackFrame::Id frame_id = break_frame_id();
968   // If there is no JavaScript stack don't do anything.
969   if (frame_id == StackFrame::NO_ID) return;
970 
971   feature_tracker()->Track(DebugFeatureTracker::kStepping);
972 
973   thread_local_.last_step_action_ = step_action;
974   UpdateHookOnFunctionCall();
975 
976   StackTraceFrameIterator frames_it(isolate_, frame_id);
977   StandardFrame* frame = frames_it.frame();
978 
979   // Handle stepping in wasm functions via the wasm interpreter.
980   if (frame->is_wasm()) {
981     // If the top frame is compiled, we cannot step.
982     if (frame->is_wasm_compiled()) return;
983     WasmInterpreterEntryFrame* wasm_frame =
984         WasmInterpreterEntryFrame::cast(frame);
985     wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action);
986     return;
987   }
988 
989   JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame);
990   DCHECK(js_frame->function()->IsJSFunction());
991 
992   // Get the debug info (create it if it does not exist).
993   auto summary = FrameSummary::GetTop(frame).AsJavaScript();
994   Handle<JSFunction> function(summary.function());
995   Handle<SharedFunctionInfo> shared(function->shared());
996   if (!EnsureDebugInfo(shared)) return;
997   Handle<DebugInfo> debug_info(shared->GetDebugInfo());
998 
999   BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame);
1000 
1001   // Any step at a return is a step-out.
1002   if (location.IsReturn()) step_action = StepOut;
1003   // A step-next at a tail call is a step-out.
1004   if (location.IsTailCall() && step_action == StepNext) step_action = StepOut;
1005   // A step-next in blackboxed function is a step-out.
1006   if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut;
1007 
1008   thread_local_.last_statement_position_ =
1009       summary.abstract_code()->SourceStatementPosition(summary.code_offset());
1010   int current_frame_count = CurrentFrameCount();
1011   thread_local_.last_frame_count_ = current_frame_count;
1012   // No longer perform the current async step.
1013   clear_suspended_generator();
1014 
1015   switch (step_action) {
1016     case StepNone:
1017       UNREACHABLE();
1018       break;
1019     case StepOut: {
1020       // Clear last position info. For stepping out it does not matter.
1021       thread_local_.last_statement_position_ = kNoSourcePosition;
1022       thread_local_.last_frame_count_ = -1;
1023       // Skip the current frame, find the first frame we want to step out to
1024       // and deoptimize every frame along the way.
1025       bool in_current_frame = true;
1026       for (; !frames_it.done(); frames_it.Advance()) {
1027         // TODO(clemensh): Implement stepping out from JS to WASM.
1028         if (frames_it.frame()->is_wasm()) continue;
1029         JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame());
1030         if (last_step_action() == StepIn) {
1031           // Deoptimize frame to ensure calls are checked for step-in.
1032           Deoptimizer::DeoptimizeFunction(frame->function());
1033         }
1034         HandleScope scope(isolate_);
1035         List<Handle<SharedFunctionInfo>> infos;
1036         frame->GetFunctions(&infos);
1037         for (; !infos.is_empty(); current_frame_count--) {
1038           Handle<SharedFunctionInfo> info = infos.RemoveLast();
1039           if (in_current_frame) {
1040             // We want to skip out, so skip the current frame.
1041             in_current_frame = false;
1042             continue;
1043           }
1044           if (!info->IsSubjectToDebugging() || IsBlackboxed(info)) continue;
1045           FloodWithOneShot(info);
1046           thread_local_.target_frame_count_ = current_frame_count;
1047           return;
1048         }
1049       }
1050       break;
1051     }
1052     case StepNext:
1053       thread_local_.target_frame_count_ = current_frame_count;
1054     // Fall through.
1055     case StepIn:
1056       // TODO(clemensh): Implement stepping from JS into WASM.
1057       FloodWithOneShot(shared);
1058       break;
1059   }
1060 }
1061 
1062 // Simple function for returning the source positions for active break points.
GetSourceBreakLocations(Handle<SharedFunctionInfo> shared,BreakPositionAlignment position_alignment)1063 Handle<Object> Debug::GetSourceBreakLocations(
1064     Handle<SharedFunctionInfo> shared,
1065     BreakPositionAlignment position_alignment) {
1066   Isolate* isolate = shared->GetIsolate();
1067   if (!shared->HasDebugInfo()) {
1068     return isolate->factory()->undefined_value();
1069   }
1070   Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1071   if (debug_info->GetBreakPointCount() == 0) {
1072     return isolate->factory()->undefined_value();
1073   }
1074   Handle<FixedArray> locations =
1075       isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
1076   int count = 0;
1077   for (int i = 0; i < debug_info->break_points()->length(); ++i) {
1078     if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
1079       BreakPointInfo* break_point_info =
1080           BreakPointInfo::cast(debug_info->break_points()->get(i));
1081       int break_points = break_point_info->GetBreakPointCount();
1082       if (break_points == 0) continue;
1083       Smi* position = NULL;
1084       if (position_alignment == STATEMENT_ALIGNED) {
1085         if (debug_info->HasDebugCode()) {
1086           CodeBreakIterator it(debug_info);
1087           it.SkipToPosition(break_point_info->source_position(),
1088                             BREAK_POSITION_ALIGNED);
1089           position = Smi::FromInt(it.statement_position());
1090         } else {
1091           DCHECK(debug_info->HasDebugBytecodeArray());
1092           BytecodeArrayBreakIterator it(debug_info);
1093           it.SkipToPosition(break_point_info->source_position(),
1094                             BREAK_POSITION_ALIGNED);
1095           position = Smi::FromInt(it.statement_position());
1096         }
1097       } else {
1098         DCHECK_EQ(BREAK_POSITION_ALIGNED, position_alignment);
1099         position = Smi::FromInt(break_point_info->source_position());
1100       }
1101       for (int j = 0; j < break_points; ++j) locations->set(count++, position);
1102     }
1103   }
1104   return locations;
1105 }
1106 
ClearStepping()1107 void Debug::ClearStepping() {
1108   // Clear the various stepping setup.
1109   ClearOneShot();
1110 
1111   thread_local_.last_step_action_ = StepNone;
1112   thread_local_.last_statement_position_ = kNoSourcePosition;
1113   thread_local_.last_frame_count_ = -1;
1114   thread_local_.target_frame_count_ = -1;
1115   UpdateHookOnFunctionCall();
1116 }
1117 
1118 
1119 // Clears all the one-shot break points that are currently set. Normally this
1120 // function is called each time a break point is hit as one shot break points
1121 // are used to support stepping.
ClearOneShot()1122 void Debug::ClearOneShot() {
1123   // The current implementation just runs through all the breakpoints. When the
1124   // last break point for a function is removed that function is automatically
1125   // removed from the list.
1126   for (DebugInfoListNode* node = debug_info_list_; node != NULL;
1127        node = node->next()) {
1128     Handle<DebugInfo> debug_info = node->debug_info();
1129     ClearBreakPoints(debug_info);
1130     ApplyBreakPoints(debug_info);
1131   }
1132 }
1133 
1134 
MatchingCodeTargets(Code * target1,Code * target2)1135 bool MatchingCodeTargets(Code* target1, Code* target2) {
1136   if (target1 == target2) return true;
1137   if (target1->kind() != target2->kind()) return false;
1138   return target1->is_handler() || target1->is_inline_cache_stub();
1139 }
1140 
1141 
1142 // Count the number of calls before the current frame PC to find the
1143 // corresponding PC in the newly recompiled code.
ComputeNewPcForRedirect(Code * new_code,Code * old_code,Address old_pc)1144 static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code,
1145                                        Address old_pc) {
1146   DCHECK_EQ(old_code->kind(), Code::FUNCTION);
1147   DCHECK_EQ(new_code->kind(), Code::FUNCTION);
1148   DCHECK(new_code->has_debug_break_slots());
1149   static const int mask = RelocInfo::kCodeTargetMask;
1150 
1151   // Find the target of the current call.
1152   Code* target = NULL;
1153   intptr_t delta = 0;
1154   for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
1155     RelocInfo* rinfo = it.rinfo();
1156     Address current_pc = rinfo->pc();
1157     // The frame PC is behind the call instruction by the call instruction size.
1158     if (current_pc > old_pc) break;
1159     delta = old_pc - current_pc;
1160     target = Code::GetCodeFromTargetAddress(rinfo->target_address());
1161   }
1162 
1163   // Count the number of calls to the same target before the current call.
1164   int index = 0;
1165   for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
1166     RelocInfo* rinfo = it.rinfo();
1167     Address current_pc = rinfo->pc();
1168     if (current_pc > old_pc) break;
1169     Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
1170     if (MatchingCodeTargets(target, current)) index++;
1171   }
1172 
1173   DCHECK(index > 0);
1174 
1175   // Repeat the count on the new code to find corresponding call.
1176   for (RelocIterator it(new_code, mask); !it.done(); it.next()) {
1177     RelocInfo* rinfo = it.rinfo();
1178     Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
1179     if (MatchingCodeTargets(target, current)) index--;
1180     if (index == 0) return rinfo->pc() + delta;
1181   }
1182 
1183   UNREACHABLE();
1184   return NULL;
1185 }
1186 
1187 
1188 class RedirectActiveFunctions : public ThreadVisitor {
1189  public:
RedirectActiveFunctions(SharedFunctionInfo * shared)1190   explicit RedirectActiveFunctions(SharedFunctionInfo* shared)
1191       : shared_(shared) {
1192     DCHECK(shared->HasDebugCode());
1193   }
1194 
VisitThread(Isolate * isolate,ThreadLocalTop * top)1195   void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1196     for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1197       JavaScriptFrame* frame = it.frame();
1198       JSFunction* function = frame->function();
1199       if (frame->is_optimized()) continue;
1200       if (!function->Inlines(shared_)) continue;
1201 
1202       if (frame->is_interpreted()) {
1203         InterpretedFrame* interpreted_frame =
1204             reinterpret_cast<InterpretedFrame*>(frame);
1205         BytecodeArray* debug_copy =
1206             shared_->GetDebugInfo()->DebugBytecodeArray();
1207         interpreted_frame->PatchBytecodeArray(debug_copy);
1208         continue;
1209       }
1210 
1211       Code* frame_code = frame->LookupCode();
1212       DCHECK(frame_code->kind() == Code::FUNCTION);
1213       if (frame_code->has_debug_break_slots()) continue;
1214 
1215       Code* new_code = function->shared()->code();
1216       Address old_pc = frame->pc();
1217       Address new_pc = ComputeNewPcForRedirect(new_code, frame_code, old_pc);
1218 
1219       if (FLAG_trace_deopt) {
1220         PrintF("Replacing pc for debugging: %08" V8PRIxPTR " => %08" V8PRIxPTR
1221                "\n",
1222                reinterpret_cast<intptr_t>(old_pc),
1223                reinterpret_cast<intptr_t>(new_pc));
1224       }
1225 
1226       if (FLAG_enable_embedded_constant_pool) {
1227         // Update constant pool pointer for new code.
1228         frame->set_constant_pool(new_code->constant_pool());
1229       }
1230 
1231       // Patch the return address to return into the code with
1232       // debug break slots.
1233       frame->set_pc(new_pc);
1234     }
1235   }
1236 
1237  private:
1238   SharedFunctionInfo* shared_;
1239   DisallowHeapAllocation no_gc_;
1240 };
1241 
1242 
PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared)1243 bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
1244   DCHECK(shared->is_compiled());
1245 
1246   if (isolate_->concurrent_recompilation_enabled()) {
1247     isolate_->optimizing_compile_dispatcher()->Flush(
1248         OptimizingCompileDispatcher::BlockingBehavior::kBlock);
1249   }
1250 
1251   List<Handle<JSFunction> > functions;
1252 
1253   // Flush all optimized code maps. Note that the below heap iteration does not
1254   // cover this, because the given function might have been inlined into code
1255   // for which no JSFunction exists.
1256   {
1257     SharedFunctionInfo::GlobalIterator iterator(isolate_);
1258     while (SharedFunctionInfo* shared = iterator.Next()) {
1259       shared->ClearCodeFromOptimizedCodeMap();
1260     }
1261   }
1262 
1263   // The native context also has a list of OSR'd optimized code. Clear it.
1264   isolate_->ClearOSROptimizedCode();
1265 
1266   // Make sure we abort incremental marking.
1267   isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1268                                       GarbageCollectionReason::kDebugger);
1269 
1270   DCHECK(shared->is_compiled());
1271   bool baseline_exists = shared->HasBaselineCode();
1272 
1273   {
1274     // TODO(yangguo): with bytecode, we still walk the heap to find all
1275     // optimized code for the function to deoptimize. We can probably be
1276     // smarter here and avoid the heap walk.
1277     HeapIterator iterator(isolate_->heap());
1278     HeapObject* obj;
1279 
1280     while ((obj = iterator.next())) {
1281       if (obj->IsJSFunction()) {
1282         JSFunction* function = JSFunction::cast(obj);
1283         if (!function->Inlines(*shared)) continue;
1284         if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) {
1285           Deoptimizer::DeoptimizeFunction(function);
1286         }
1287         if (baseline_exists && function->shared() == *shared) {
1288           functions.Add(handle(function));
1289         }
1290       }
1291     }
1292   }
1293 
1294   // We do not need to replace code to debug bytecode.
1295   DCHECK(baseline_exists || functions.is_empty());
1296 
1297   // We do not need to recompile to debug bytecode.
1298   if (baseline_exists && !shared->code()->has_debug_break_slots()) {
1299     if (!Compiler::CompileDebugCode(shared)) return false;
1300   }
1301 
1302   for (Handle<JSFunction> const function : functions) {
1303     function->ReplaceCode(shared->code());
1304     JSFunction::EnsureLiterals(function);
1305   }
1306 
1307   // Update PCs on the stack to point to recompiled code.
1308   RedirectActiveFunctions redirect_visitor(*shared);
1309   redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top());
1310   isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor);
1311 
1312   return true;
1313 }
1314 
1315 namespace {
1316 template <typename Iterator>
GetBreakablePositions(Iterator * it,int start_position,int end_position,BreakPositionAlignment alignment,std::set<int> * positions)1317 void GetBreakablePositions(Iterator* it, int start_position, int end_position,
1318                            BreakPositionAlignment alignment,
1319                            std::set<int>* positions) {
1320   it->SkipToPosition(start_position, alignment);
1321   while (!it->Done() && it->position() < end_position &&
1322          it->position() >= start_position) {
1323     positions->insert(alignment == STATEMENT_ALIGNED ? it->statement_position()
1324                                                      : it->position());
1325     it->Next();
1326   }
1327 }
1328 
FindBreakablePositions(Handle<DebugInfo> debug_info,int start_position,int end_position,BreakPositionAlignment alignment,std::set<int> * positions)1329 void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position,
1330                             int end_position, BreakPositionAlignment alignment,
1331                             std::set<int>* positions) {
1332   if (debug_info->HasDebugCode()) {
1333     CodeBreakIterator it(debug_info);
1334     GetBreakablePositions(&it, start_position, end_position, alignment,
1335                           positions);
1336   } else {
1337     DCHECK(debug_info->HasDebugBytecodeArray());
1338     BytecodeArrayBreakIterator it(debug_info);
1339     GetBreakablePositions(&it, start_position, end_position, alignment,
1340                           positions);
1341   }
1342 }
1343 }  // namespace
1344 
GetPossibleBreakpoints(Handle<Script> script,int start_position,int end_position,std::set<int> * positions)1345 bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position,
1346                                    int end_position, std::set<int>* positions) {
1347   while (true) {
1348     HandleScope scope(isolate_);
1349     List<Handle<SharedFunctionInfo>> candidates;
1350     SharedFunctionInfo::ScriptIterator iterator(script);
1351     for (SharedFunctionInfo* info = iterator.Next(); info != nullptr;
1352          info = iterator.Next()) {
1353       if (info->end_position() < start_position ||
1354           info->start_position() >= end_position) {
1355         continue;
1356       }
1357       if (!info->IsSubjectToDebugging()) continue;
1358       if (!info->HasDebugCode() && !info->allows_lazy_compilation()) continue;
1359       candidates.Add(i::handle(info));
1360     }
1361 
1362     bool was_compiled = false;
1363     for (int i = 0; i < candidates.length(); ++i) {
1364       // Code that cannot be compiled lazily are internal and not debuggable.
1365       DCHECK(candidates[i]->allows_lazy_compilation());
1366       if (!candidates[i]->HasDebugCode()) {
1367         if (!Compiler::CompileDebugCode(candidates[i])) {
1368           return false;
1369         } else {
1370           was_compiled = true;
1371         }
1372       }
1373       if (!EnsureDebugInfo(candidates[i])) return false;
1374     }
1375     if (was_compiled) continue;
1376 
1377     for (int i = 0; i < candidates.length(); ++i) {
1378       CHECK(candidates[i]->HasDebugInfo());
1379       Handle<DebugInfo> debug_info(candidates[i]->GetDebugInfo());
1380       FindBreakablePositions(debug_info, start_position, end_position,
1381                              BREAK_POSITION_ALIGNED, positions);
1382     }
1383     return true;
1384   }
1385   UNREACHABLE();
1386   return false;
1387 }
1388 
RecordGenerator(Handle<JSGeneratorObject> generator_object)1389 void Debug::RecordGenerator(Handle<JSGeneratorObject> generator_object) {
1390   if (last_step_action() <= StepOut) return;
1391 
1392   if (last_step_action() == StepNext) {
1393     // Only consider this generator a step-next target if not stepping in.
1394     if (thread_local_.target_frame_count_ < CurrentFrameCount()) return;
1395   }
1396 
1397   DCHECK(!has_suspended_generator());
1398   thread_local_.suspended_generator_ = *generator_object;
1399   ClearStepping();
1400 }
1401 
1402 class SharedFunctionInfoFinder {
1403  public:
SharedFunctionInfoFinder(int target_position)1404   explicit SharedFunctionInfoFinder(int target_position)
1405       : current_candidate_(NULL),
1406         current_candidate_closure_(NULL),
1407         current_start_position_(kNoSourcePosition),
1408         target_position_(target_position) {}
1409 
NewCandidate(SharedFunctionInfo * shared,JSFunction * closure=NULL)1410   void NewCandidate(SharedFunctionInfo* shared, JSFunction* closure = NULL) {
1411     if (!shared->IsSubjectToDebugging()) return;
1412     int start_position = shared->function_token_position();
1413     if (start_position == kNoSourcePosition) {
1414       start_position = shared->start_position();
1415     }
1416 
1417     if (start_position > target_position_) return;
1418     if (target_position_ > shared->end_position()) return;
1419 
1420     if (current_candidate_ != NULL) {
1421       if (current_start_position_ == start_position &&
1422           shared->end_position() == current_candidate_->end_position()) {
1423         // If we already have a matching closure, do not throw it away.
1424         if (current_candidate_closure_ != NULL && closure == NULL) return;
1425         // If a top-level function contains only one function
1426         // declaration the source for the top-level and the function
1427         // is the same. In that case prefer the non top-level function.
1428         if (!current_candidate_->is_toplevel() && shared->is_toplevel()) return;
1429       } else if (start_position < current_start_position_ ||
1430                  current_candidate_->end_position() < shared->end_position()) {
1431         return;
1432       }
1433     }
1434 
1435     current_start_position_ = start_position;
1436     current_candidate_ = shared;
1437     current_candidate_closure_ = closure;
1438   }
1439 
Result()1440   SharedFunctionInfo* Result() { return current_candidate_; }
1441 
ResultClosure()1442   JSFunction* ResultClosure() { return current_candidate_closure_; }
1443 
1444  private:
1445   SharedFunctionInfo* current_candidate_;
1446   JSFunction* current_candidate_closure_;
1447   int current_start_position_;
1448   int target_position_;
1449   DisallowHeapAllocation no_gc_;
1450 };
1451 
1452 
1453 // We need to find a SFI for a literal that may not yet have been compiled yet,
1454 // and there may not be a JSFunction referencing it. Find the SFI closest to
1455 // the given position, compile it to reveal possible inner SFIs and repeat.
1456 // While we are at this, also ensure code with debug break slots so that we do
1457 // not have to compile a SFI without JSFunction, which is paifu for those that
1458 // cannot be compiled without context (need to find outer compilable SFI etc.)
FindSharedFunctionInfoInScript(Handle<Script> script,int position)1459 Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
1460                                                      int position) {
1461   for (int iteration = 0;; iteration++) {
1462     // Go through all shared function infos associated with this script to
1463     // find the inner most function containing this position.
1464     // If there is no shared function info for this script at all, there is
1465     // no point in looking for it by walking the heap.
1466 
1467     SharedFunctionInfo* shared;
1468     {
1469       SharedFunctionInfoFinder finder(position);
1470       SharedFunctionInfo::ScriptIterator iterator(script);
1471       for (SharedFunctionInfo* info = iterator.Next(); info != nullptr;
1472            info = iterator.Next()) {
1473         finder.NewCandidate(info);
1474       }
1475       shared = finder.Result();
1476       if (shared == NULL) break;
1477       // We found it if it's already compiled and has debug code.
1478       if (shared->HasDebugCode()) {
1479         Handle<SharedFunctionInfo> shared_handle(shared);
1480         // If the iteration count is larger than 1, we had to compile the outer
1481         // function in order to create this shared function info. So there can
1482         // be no JSFunction referencing it. We can anticipate creating a debug
1483         // info while bypassing PrepareFunctionForBreakpoints.
1484         if (iteration > 1) {
1485           AllowHeapAllocation allow_before_return;
1486           CreateDebugInfo(shared_handle);
1487         }
1488         return shared_handle;
1489       }
1490     }
1491     // If not, compile to reveal inner functions.
1492     HandleScope scope(isolate_);
1493     // Code that cannot be compiled lazily are internal and not debuggable.
1494     DCHECK(shared->allows_lazy_compilation());
1495     if (!Compiler::CompileDebugCode(handle(shared))) break;
1496   }
1497   return isolate_->factory()->undefined_value();
1498 }
1499 
1500 
1501 // Ensures the debug information is present for shared.
EnsureDebugInfo(Handle<SharedFunctionInfo> shared)1502 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1503   // Return if we already have the debug info for shared.
1504   if (shared->HasDebugInfo()) return true;
1505   if (!shared->IsSubjectToDebugging()) return false;
1506   if (!shared->is_compiled() && !Compiler::CompileDebugCode(shared)) {
1507     return false;
1508   }
1509 
1510   // To prepare bytecode for debugging, we already need to have the debug
1511   // info (containing the debug copy) upfront, but since we do not recompile,
1512   // preparing for break points cannot fail.
1513   CreateDebugInfo(shared);
1514   CHECK(PrepareFunctionForBreakPoints(shared));
1515   return true;
1516 }
1517 
1518 
CreateDebugInfo(Handle<SharedFunctionInfo> shared)1519 void Debug::CreateDebugInfo(Handle<SharedFunctionInfo> shared) {
1520   // Create the debug info object.
1521   Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared);
1522 
1523   // Add debug info to the list.
1524   DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1525   node->set_next(debug_info_list_);
1526   debug_info_list_ = node;
1527 }
1528 
1529 
RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info)1530 void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
1531   HandleScope scope(isolate_);
1532   Handle<SharedFunctionInfo> shared(debug_info->shared());
1533 
1534   DCHECK_NOT_NULL(debug_info_list_);
1535   // Run through the debug info objects to find this one and remove it.
1536   DebugInfoListNode* prev = NULL;
1537   DebugInfoListNode* current = debug_info_list_;
1538   while (current != NULL) {
1539     if (current->debug_info().is_identical_to(debug_info)) {
1540       // Unlink from list. If prev is NULL we are looking at the first element.
1541       if (prev == NULL) {
1542         debug_info_list_ = current->next();
1543       } else {
1544         prev->set_next(current->next());
1545       }
1546       shared->set_debug_info(Smi::FromInt(debug_info->debugger_hints()));
1547       delete current;
1548       return;
1549     }
1550     // Move to next in list.
1551     prev = current;
1552     current = current->next();
1553   }
1554 
1555   UNREACHABLE();
1556 }
1557 
IsBreakAtReturn(JavaScriptFrame * frame)1558 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
1559   HandleScope scope(isolate_);
1560 
1561   // Get the executing function in which the debug break occurred.
1562   Handle<SharedFunctionInfo> shared(frame->function()->shared());
1563 
1564   // With no debug info there are no break points, so we can't be at a return.
1565   if (!shared->HasDebugInfo()) return false;
1566 
1567   DCHECK(!frame->is_optimized());
1568   Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1569   BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
1570   return location.IsReturn() || location.IsTailCall();
1571 }
1572 
ScheduleFrameRestart(StackFrame * frame)1573 void Debug::ScheduleFrameRestart(StackFrame* frame) {
1574   // Set a target FP for the FrameDropperTrampoline builtin to drop to once
1575   // we return from the debugger.
1576   DCHECK(frame->is_java_script());
1577   // Only reschedule to a frame further below a frame we already scheduled for.
1578   if (frame->fp() <= thread_local_.restart_fp_) return;
1579   // If the frame is optimized, trigger a deopt and jump into the
1580   // FrameDropperTrampoline in the deoptimizer.
1581   thread_local_.restart_fp_ = frame->fp();
1582 
1583   // Reset break frame ID to the frame below the restarted frame.
1584   StackTraceFrameIterator it(isolate_);
1585   thread_local_.break_frame_id_ = StackFrame::NO_ID;
1586   for (StackTraceFrameIterator it(isolate_); !it.done(); it.Advance()) {
1587     if (it.frame()->fp() > thread_local_.restart_fp_) {
1588       thread_local_.break_frame_id_ = it.frame()->id();
1589       return;
1590     }
1591   }
1592 }
1593 
1594 
IsDebugGlobal(JSGlobalObject * global)1595 bool Debug::IsDebugGlobal(JSGlobalObject* global) {
1596   return is_loaded() && global == debug_context()->global_object();
1597 }
1598 
1599 
GetLoadedScripts()1600 Handle<FixedArray> Debug::GetLoadedScripts() {
1601   isolate_->heap()->CollectAllGarbage(Heap::kFinalizeIncrementalMarkingMask,
1602                                       GarbageCollectionReason::kDebugger);
1603   Factory* factory = isolate_->factory();
1604   if (!factory->script_list()->IsWeakFixedArray()) {
1605     return factory->empty_fixed_array();
1606   }
1607   Handle<WeakFixedArray> array =
1608       Handle<WeakFixedArray>::cast(factory->script_list());
1609   Handle<FixedArray> results = factory->NewFixedArray(array->Length());
1610   int length = 0;
1611   {
1612     Script::Iterator iterator(isolate_);
1613     Script* script;
1614     while ((script = iterator.Next())) {
1615       if (script->HasValidSource()) results->set(length++, script);
1616     }
1617   }
1618   results->Shrink(length);
1619   return results;
1620 }
1621 
1622 
MakeExecutionState()1623 MaybeHandle<Object> Debug::MakeExecutionState() {
1624   // Create the execution state object.
1625   Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()) };
1626   return CallFunction("MakeExecutionState", arraysize(argv), argv);
1627 }
1628 
1629 
MakeBreakEvent(Handle<Object> break_points_hit)1630 MaybeHandle<Object> Debug::MakeBreakEvent(Handle<Object> break_points_hit) {
1631   // Create the new break event object.
1632   Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
1633                             break_points_hit };
1634   return CallFunction("MakeBreakEvent", arraysize(argv), argv);
1635 }
1636 
1637 
MakeExceptionEvent(Handle<Object> exception,bool uncaught,Handle<Object> promise)1638 MaybeHandle<Object> Debug::MakeExceptionEvent(Handle<Object> exception,
1639                                               bool uncaught,
1640                                               Handle<Object> promise) {
1641   // Create the new exception event object.
1642   Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
1643                             exception,
1644                             isolate_->factory()->ToBoolean(uncaught),
1645                             promise };
1646   return CallFunction("MakeExceptionEvent", arraysize(argv), argv);
1647 }
1648 
1649 
MakeCompileEvent(Handle<Script> script,v8::DebugEvent type)1650 MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script,
1651                                             v8::DebugEvent type) {
1652   // Create the compile event object.
1653   Handle<Object> script_wrapper = Script::GetWrapper(script);
1654   Handle<Object> argv[] = { script_wrapper,
1655                             isolate_->factory()->NewNumberFromInt(type) };
1656   return CallFunction("MakeCompileEvent", arraysize(argv), argv);
1657 }
1658 
MakeAsyncTaskEvent(v8::debug::PromiseDebugActionType type,int id)1659 MaybeHandle<Object> Debug::MakeAsyncTaskEvent(
1660     v8::debug::PromiseDebugActionType type, int id) {
1661   // Create the async task event object.
1662   Handle<Object> argv[] = {Handle<Smi>(Smi::FromInt(type), isolate_),
1663                            Handle<Smi>(Smi::FromInt(id), isolate_)};
1664   return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv);
1665 }
1666 
1667 
OnThrow(Handle<Object> exception)1668 void Debug::OnThrow(Handle<Object> exception) {
1669   if (in_debug_scope() || ignore_events()) return;
1670   // Temporarily clear any scheduled_exception to allow evaluating
1671   // JavaScript from the debug event handler.
1672   HandleScope scope(isolate_);
1673   Handle<Object> scheduled_exception;
1674   if (isolate_->has_scheduled_exception()) {
1675     scheduled_exception = handle(isolate_->scheduled_exception(), isolate_);
1676     isolate_->clear_scheduled_exception();
1677   }
1678   OnException(exception, isolate_->GetPromiseOnStackOnThrow());
1679   if (!scheduled_exception.is_null()) {
1680     isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception;
1681   }
1682   PrepareStepOnThrow();
1683 }
1684 
OnPromiseReject(Handle<Object> promise,Handle<Object> value)1685 void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) {
1686   if (in_debug_scope() || ignore_events()) return;
1687   HandleScope scope(isolate_);
1688   // Check whether the promise has been marked as having triggered a message.
1689   Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
1690   if (!promise->IsJSObject() ||
1691       JSReceiver::GetDataProperty(Handle<JSObject>::cast(promise), key)
1692           ->IsUndefined(isolate_)) {
1693     OnException(value, promise);
1694   }
1695 }
1696 
1697 namespace {
GetDebugEventContext(Isolate * isolate)1698 v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
1699   Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
1700   // Isolate::context() may have been NULL when "script collected" event
1701   // occured.
1702   if (context.is_null()) return v8::Local<v8::Context>();
1703   Handle<Context> native_context(context->native_context());
1704   return v8::Utils::ToLocal(native_context);
1705 }
1706 }  // anonymous namespace
1707 
IsExceptionBlackboxed(bool uncaught)1708 bool Debug::IsExceptionBlackboxed(bool uncaught) {
1709   JavaScriptFrameIterator it(isolate_);
1710   if (it.done()) return false;
1711   // Uncaught exception is blackboxed if all current frames are blackboxed,
1712   // caught exception if top frame is blackboxed.
1713   bool is_top_frame_blackboxed = IsFrameBlackboxed(it.frame());
1714   if (!uncaught || !is_top_frame_blackboxed) return is_top_frame_blackboxed;
1715   it.Advance();
1716   while (!it.done()) {
1717     if (!IsFrameBlackboxed(it.frame())) return false;
1718     it.Advance();
1719   }
1720   return true;
1721 }
1722 
IsFrameBlackboxed(JavaScriptFrame * frame)1723 bool Debug::IsFrameBlackboxed(JavaScriptFrame* frame) {
1724   HandleScope scope(isolate_);
1725   if (!frame->HasInlinedFrames()) {
1726     Handle<SharedFunctionInfo> shared(frame->function()->shared(), isolate_);
1727     return IsBlackboxed(shared);
1728   }
1729   List<Handle<SharedFunctionInfo>> infos;
1730   frame->GetFunctions(&infos);
1731   for (const auto& info : infos)
1732     if (!IsBlackboxed(info)) return false;
1733   return true;
1734 }
1735 
OnException(Handle<Object> exception,Handle<Object> promise)1736 void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
1737   // We cannot generate debug events when JS execution is disallowed.
1738   // TODO(5530): Reenable debug events within DisallowJSScopes once relevant
1739   // code (MakeExceptionEvent and ProcessDebugEvent) have been moved to C++.
1740   if (!AllowJavascriptExecution::IsAllowed(isolate_)) return;
1741 
1742   Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher();
1743 
1744   // Don't notify listener of exceptions that are internal to a desugaring.
1745   if (catch_type == Isolate::CAUGHT_BY_DESUGARING) return;
1746 
1747   bool uncaught = catch_type == Isolate::NOT_CAUGHT;
1748   if (promise->IsJSObject()) {
1749     Handle<JSObject> jspromise = Handle<JSObject>::cast(promise);
1750     // Mark the promise as already having triggered a message.
1751     Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
1752     JSObject::SetProperty(jspromise, key, key, STRICT).Assert();
1753     // Check whether the promise reject is considered an uncaught exception.
1754     uncaught = !isolate_->PromiseHasUserDefinedRejectHandler(jspromise);
1755   }
1756 
1757   if (!debug_delegate_) return;
1758 
1759   // Bail out if exception breaks are not active
1760   if (uncaught) {
1761     // Uncaught exceptions are reported by either flags.
1762     if (!(break_on_uncaught_exception_ || break_on_exception_)) return;
1763   } else {
1764     // Caught exceptions are reported is activated.
1765     if (!break_on_exception_) return;
1766   }
1767 
1768   {
1769     JavaScriptFrameIterator it(isolate_);
1770     // Check whether the top frame is blackboxed or the break location is muted.
1771     if (!it.done() && (IsMutedAtCurrentLocation(it.frame()) ||
1772                        IsExceptionBlackboxed(uncaught))) {
1773       return;
1774     }
1775     if (it.done()) return;  // Do not trigger an event with an empty stack.
1776   }
1777 
1778   DebugScope debug_scope(this);
1779   if (debug_scope.failed()) return;
1780   HandleScope scope(isolate_);
1781   PostponeInterruptsScope postpone(isolate_);
1782   DisableBreak no_recursive_break(this);
1783 
1784   // Create the execution state.
1785   Handle<Object> exec_state;
1786   // Bail out and don't call debugger if exception.
1787   if (!MakeExecutionState().ToHandle(&exec_state)) return;
1788 
1789   debug_delegate_->ExceptionThrown(
1790       GetDebugEventContext(isolate_),
1791       v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
1792       v8::Utils::ToLocal(exception), v8::Utils::ToLocal(promise), uncaught);
1793 }
1794 
OnDebugBreak(Handle<Object> break_points_hit)1795 void Debug::OnDebugBreak(Handle<Object> break_points_hit) {
1796   // The caller provided for DebugScope.
1797   AssertDebugContext();
1798   // Bail out if there is no listener for this event
1799   if (ignore_events()) return;
1800 
1801 #ifdef DEBUG
1802   PrintBreakLocation();
1803 #endif  // DEBUG
1804 
1805   if (!debug_delegate_) return;
1806   HandleScope scope(isolate_);
1807   PostponeInterruptsScope no_interrupts(isolate_);
1808   DisableBreak no_recursive_break(this);
1809 
1810   // Create the execution state.
1811   Handle<Object> exec_state;
1812   // Bail out and don't call debugger if exception.
1813   if (!MakeExecutionState().ToHandle(&exec_state)) return;
1814 
1815   debug_delegate_->BreakProgramRequested(
1816       GetDebugEventContext(isolate_),
1817       v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
1818       v8::Utils::ToLocal(break_points_hit));
1819 }
1820 
1821 
OnCompileError(Handle<Script> script)1822 void Debug::OnCompileError(Handle<Script> script) {
1823   ProcessCompileEvent(v8::CompileError, script);
1824 }
1825 
1826 
1827 // Handle debugger actions when a new script is compiled.
OnAfterCompile(Handle<Script> script)1828 void Debug::OnAfterCompile(Handle<Script> script) {
1829   ProcessCompileEvent(v8::AfterCompile, script);
1830 }
1831 
1832 namespace {
1833 struct CollectedCallbackData {
1834   Object** location;
1835   int id;
1836   Debug* debug;
1837   Isolate* isolate;
1838 
CollectedCallbackDatav8::internal::__anon9c9be6950311::CollectedCallbackData1839   CollectedCallbackData(Object** location, int id, Debug* debug,
1840                         Isolate* isolate)
1841       : location(location), id(id), debug(debug), isolate(isolate) {}
1842 };
1843 
SendAsyncTaskEventCancel(const v8::WeakCallbackInfo<void> & info)1844 void SendAsyncTaskEventCancel(const v8::WeakCallbackInfo<void>& info) {
1845   std::unique_ptr<CollectedCallbackData> data(
1846       reinterpret_cast<CollectedCallbackData*>(info.GetParameter()));
1847   if (!data->debug->is_active()) return;
1848   HandleScope scope(data->isolate);
1849   data->debug->OnAsyncTaskEvent(debug::kDebugPromiseCollected, data->id, 0);
1850 }
1851 
ResetPromiseHandle(const v8::WeakCallbackInfo<void> & info)1852 void ResetPromiseHandle(const v8::WeakCallbackInfo<void>& info) {
1853   CollectedCallbackData* data =
1854       reinterpret_cast<CollectedCallbackData*>(info.GetParameter());
1855   GlobalHandles::Destroy(data->location);
1856   info.SetSecondPassCallback(&SendAsyncTaskEventCancel);
1857 }
1858 
1859 // In an async function, reuse the existing stack related to the outer
1860 // Promise. Otherwise, e.g. in a direct call to then, save a new stack.
1861 // Promises with multiple reactions with one or more of them being async
1862 // functions will not get a good stack trace, as async functions require
1863 // different stacks from direct Promise use, but we save and restore a
1864 // stack once for all reactions.
1865 //
1866 // If this isn't a case of async function, we return false, otherwise
1867 // we set the correct id and return true.
1868 //
1869 // TODO(littledan): Improve this case.
GetReferenceAsyncTaskId(Isolate * isolate,Handle<JSPromise> promise)1870 int GetReferenceAsyncTaskId(Isolate* isolate, Handle<JSPromise> promise) {
1871   Handle<Symbol> handled_by_symbol =
1872       isolate->factory()->promise_handled_by_symbol();
1873   Handle<Object> handled_by_promise =
1874       JSObject::GetDataProperty(promise, handled_by_symbol);
1875   if (!handled_by_promise->IsJSPromise()) {
1876     return isolate->debug()->NextAsyncTaskId(promise);
1877   }
1878   Handle<JSPromise> handled_by_promise_js =
1879       Handle<JSPromise>::cast(handled_by_promise);
1880   Handle<Symbol> async_stack_id_symbol =
1881       isolate->factory()->promise_async_stack_id_symbol();
1882   Handle<Object> async_task_id =
1883       JSObject::GetDataProperty(handled_by_promise_js, async_stack_id_symbol);
1884   if (!async_task_id->IsSmi()) {
1885     return isolate->debug()->NextAsyncTaskId(promise);
1886   }
1887   return Handle<Smi>::cast(async_task_id)->value();
1888 }
1889 }  //  namespace
1890 
RunPromiseHook(PromiseHookType type,Handle<JSPromise> promise,Handle<Object> parent)1891 void Debug::RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise,
1892                            Handle<Object> parent) {
1893   if (!debug_delegate_) return;
1894   int id = GetReferenceAsyncTaskId(isolate_, promise);
1895   switch (type) {
1896     case PromiseHookType::kInit:
1897       OnAsyncTaskEvent(debug::kDebugPromiseCreated, id,
1898                        parent->IsJSPromise()
1899                            ? GetReferenceAsyncTaskId(
1900                                  isolate_, Handle<JSPromise>::cast(parent))
1901                            : 0);
1902       return;
1903     case PromiseHookType::kResolve:
1904       // We can't use this hook because it's called before promise object will
1905       // get resolved status.
1906       return;
1907     case PromiseHookType::kBefore:
1908       OnAsyncTaskEvent(debug::kDebugWillHandle, id, 0);
1909       return;
1910     case PromiseHookType::kAfter:
1911       OnAsyncTaskEvent(debug::kDebugDidHandle, id, 0);
1912       return;
1913   }
1914 }
1915 
NextAsyncTaskId(Handle<JSObject> promise)1916 int Debug::NextAsyncTaskId(Handle<JSObject> promise) {
1917   LookupIterator it(promise, isolate_->factory()->promise_async_id_symbol());
1918   Maybe<bool> maybe = JSReceiver::HasProperty(&it);
1919   if (maybe.ToChecked()) {
1920     MaybeHandle<Object> result = Object::GetProperty(&it);
1921     return Handle<Smi>::cast(result.ToHandleChecked())->value();
1922   }
1923   Handle<Smi> async_id =
1924       handle(Smi::FromInt(++thread_local_.async_task_count_), isolate_);
1925   Object::SetProperty(&it, async_id, SLOPPY, Object::MAY_BE_STORE_FROM_KEYED)
1926       .ToChecked();
1927   Handle<Object> global_handle = isolate_->global_handles()->Create(*promise);
1928   // We send EnqueueRecurring async task event when promise is fulfilled or
1929   // rejected, WillHandle and DidHandle for every scheduled microtask for this
1930   // promise.
1931   // We need to send a cancel event when no other microtasks can be
1932   // started for this promise and all current microtasks are finished.
1933   // Since we holding promise when at least one microtask is scheduled (inside
1934   // PromiseReactionJobInfo), we can send cancel event in weak callback.
1935   GlobalHandles::MakeWeak(
1936       global_handle.location(),
1937       new CollectedCallbackData(global_handle.location(), async_id->value(),
1938                                 this, isolate_),
1939       &ResetPromiseHandle, v8::WeakCallbackType::kParameter);
1940   return async_id->value();
1941 }
1942 
1943 namespace {
GetDebugLocation(Handle<Script> script,int source_position)1944 debug::Location GetDebugLocation(Handle<Script> script, int source_position) {
1945   Script::PositionInfo info;
1946   Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET);
1947   return debug::Location(info.line, info.column);
1948 }
1949 }  // namespace
1950 
IsBlackboxed(Handle<SharedFunctionInfo> shared)1951 bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) {
1952   if (!debug_delegate_) return false;
1953   if (!shared->computed_debug_is_blackboxed()) {
1954     bool is_blackboxed = false;
1955     if (shared->script()->IsScript()) {
1956       SuppressDebug while_processing(this);
1957       HandleScope handle_scope(isolate_);
1958       PostponeInterruptsScope no_interrupts(isolate_);
1959       DisableBreak no_recursive_break(this);
1960       Handle<Script> script(Script::cast(shared->script()));
1961       if (script->type() == i::Script::TYPE_NORMAL) {
1962         debug::Location start =
1963             GetDebugLocation(script, shared->start_position());
1964         debug::Location end = GetDebugLocation(script, shared->end_position());
1965         is_blackboxed = debug_delegate_->IsFunctionBlackboxed(
1966             ToApiHandle<debug::Script>(script), start, end);
1967       }
1968     }
1969     shared->set_debug_is_blackboxed(is_blackboxed);
1970     shared->set_computed_debug_is_blackboxed(true);
1971   }
1972   return shared->debug_is_blackboxed();
1973 }
1974 
OnAsyncTaskEvent(debug::PromiseDebugActionType type,int id,int parent_id)1975 void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id,
1976                              int parent_id) {
1977   if (in_debug_scope() || ignore_events()) return;
1978   if (!debug_delegate_) return;
1979   SuppressDebug while_processing(this);
1980   DebugScope debug_scope(isolate_->debug());
1981   if (debug_scope.failed()) return;
1982   HandleScope scope(isolate_);
1983   PostponeInterruptsScope no_interrupts(isolate_);
1984   DisableBreak no_recursive_break(this);
1985   debug_delegate_->PromiseEventOccurred(type, id, parent_id);
1986 }
1987 
ProcessCompileEvent(v8::DebugEvent event,Handle<Script> script)1988 void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
1989   if (ignore_events()) return;
1990   if (script->type() != i::Script::TYPE_NORMAL &&
1991       script->type() != i::Script::TYPE_WASM) {
1992     return;
1993   }
1994   if (!debug_delegate_) return;
1995   SuppressDebug while_processing(this);
1996   DebugScope debug_scope(this);
1997   if (debug_scope.failed()) return;
1998   HandleScope scope(isolate_);
1999   PostponeInterruptsScope postpone(isolate_);
2000   DisableBreak no_recursive_break(this);
2001   debug_delegate_->ScriptCompiled(ToApiHandle<debug::Script>(script),
2002                                   event != v8::AfterCompile);
2003 }
2004 
2005 
GetDebugContext()2006 Handle<Context> Debug::GetDebugContext() {
2007   if (!is_loaded()) return Handle<Context>();
2008   DebugScope debug_scope(this);
2009   if (debug_scope.failed()) return Handle<Context>();
2010   // The global handle may be destroyed soon after.  Return it reboxed.
2011   return handle(*debug_context(), isolate_);
2012 }
2013 
CurrentFrameCount()2014 int Debug::CurrentFrameCount() {
2015   StackTraceFrameIterator it(isolate_);
2016   if (break_frame_id() != StackFrame::NO_ID) {
2017     // Skip to break frame.
2018     DCHECK(in_debug_scope());
2019     while (!it.done() && it.frame()->id() != break_frame_id()) it.Advance();
2020   }
2021   int counter = 0;
2022   while (!it.done()) {
2023     if (it.frame()->is_optimized()) {
2024       List<SharedFunctionInfo*> infos;
2025       OptimizedFrame::cast(it.frame())->GetFunctions(&infos);
2026       counter += infos.length();
2027     } else {
2028       counter++;
2029     }
2030     it.Advance();
2031   }
2032   return counter;
2033 }
2034 
SetDebugDelegate(debug::DebugDelegate * delegate,bool pass_ownership)2035 void Debug::SetDebugDelegate(debug::DebugDelegate* delegate,
2036                              bool pass_ownership) {
2037   RemoveDebugDelegate();
2038   debug_delegate_ = delegate;
2039   owns_debug_delegate_ = pass_ownership;
2040   UpdateState();
2041 }
2042 
RemoveDebugDelegate()2043 void Debug::RemoveDebugDelegate() {
2044   if (debug_delegate_ == nullptr) return;
2045   if (owns_debug_delegate_) {
2046     owns_debug_delegate_ = false;
2047     delete debug_delegate_;
2048   }
2049   debug_delegate_ = nullptr;
2050 }
2051 
UpdateState()2052 void Debug::UpdateState() {
2053   bool is_active = debug_delegate_ != nullptr;
2054   if (is_active || in_debug_scope()) {
2055     // Note that the debug context could have already been loaded to
2056     // bootstrap test cases.
2057     isolate_->compilation_cache()->Disable();
2058     is_active = Load();
2059   } else if (is_loaded()) {
2060     isolate_->compilation_cache()->Enable();
2061     Unload();
2062   }
2063   is_active_ = is_active;
2064   isolate_->DebugStateUpdated();
2065 }
2066 
UpdateHookOnFunctionCall()2067 void Debug::UpdateHookOnFunctionCall() {
2068   STATIC_ASSERT(LastStepAction == StepIn);
2069   hook_on_function_call_ = thread_local_.last_step_action_ == StepIn ||
2070                            isolate_->needs_side_effect_check();
2071 }
2072 
Call(Handle<Object> fun,Handle<Object> data)2073 MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) {
2074   DebugScope debug_scope(this);
2075   if (debug_scope.failed()) return isolate_->factory()->undefined_value();
2076 
2077   // Create the execution state.
2078   Handle<Object> exec_state;
2079   if (!MakeExecutionState().ToHandle(&exec_state)) {
2080     return isolate_->factory()->undefined_value();
2081   }
2082 
2083   Handle<Object> argv[] = { exec_state, data };
2084   return Execution::Call(
2085       isolate_,
2086       fun,
2087       Handle<Object>(debug_context()->global_proxy(), isolate_),
2088       arraysize(argv),
2089       argv);
2090 }
2091 
2092 
HandleDebugBreak()2093 void Debug::HandleDebugBreak() {
2094   // Initialize LiveEdit.
2095   LiveEdit::InitializeThreadLocal(this);
2096   // Ignore debug break during bootstrapping.
2097   if (isolate_->bootstrapper()->IsActive()) return;
2098   // Just continue if breaks are disabled.
2099   if (break_disabled()) return;
2100   // Ignore debug break if debugger is not active.
2101   if (!is_active()) return;
2102 
2103   StackLimitCheck check(isolate_);
2104   if (check.HasOverflowed()) return;
2105 
2106   { JavaScriptFrameIterator it(isolate_);
2107     DCHECK(!it.done());
2108     Object* fun = it.frame()->function();
2109     if (fun && fun->IsJSFunction()) {
2110       HandleScope scope(isolate_);
2111       // Don't stop in builtin and blackboxed functions.
2112       Handle<SharedFunctionInfo> shared(JSFunction::cast(fun)->shared(),
2113                                         isolate_);
2114       if (!shared->IsSubjectToDebugging() || IsBlackboxed(shared)) {
2115         // Inspector uses pause on next statement for asynchronous breakpoints.
2116         // When breakpoint is fired we try to break on first not blackboxed
2117         // statement. To achieve this goal we need to deoptimize current
2118         // function and don't clear requested DebugBreak even if it's blackboxed
2119         // to be able to break on not blackboxed function call.
2120         // TODO(yangguo): introduce break_on_function_entry since current
2121         // implementation is slow.
2122         Deoptimizer::DeoptimizeFunction(JSFunction::cast(fun));
2123         return;
2124       }
2125       JSGlobalObject* global =
2126           JSFunction::cast(fun)->context()->global_object();
2127       // Don't stop in debugger functions.
2128       if (IsDebugGlobal(global)) return;
2129       // Don't stop if the break location is muted.
2130       if (IsMutedAtCurrentLocation(it.frame())) return;
2131     }
2132   }
2133 
2134   isolate_->stack_guard()->ClearDebugBreak();
2135 
2136   // Clear stepping to avoid duplicate breaks.
2137   ClearStepping();
2138 
2139   HandleScope scope(isolate_);
2140   DebugScope debug_scope(this);
2141   if (debug_scope.failed()) return;
2142 
2143   OnDebugBreak(isolate_->factory()->undefined_value());
2144 }
2145 
2146 #ifdef DEBUG
PrintBreakLocation()2147 void Debug::PrintBreakLocation() {
2148   if (!FLAG_print_break_location) return;
2149   HandleScope scope(isolate_);
2150   StackTraceFrameIterator iterator(isolate_);
2151   if (iterator.done()) return;
2152   StandardFrame* frame = iterator.frame();
2153   FrameSummary summary = FrameSummary::GetTop(frame);
2154   int source_position = summary.SourcePosition();
2155   Handle<Object> script_obj = summary.script();
2156   PrintF("[debug] break in function '");
2157   summary.FunctionName()->PrintOn(stdout);
2158   PrintF("'.\n");
2159   if (script_obj->IsScript()) {
2160     Handle<Script> script = Handle<Script>::cast(script_obj);
2161     Handle<String> source(String::cast(script->source()));
2162     Script::InitLineEnds(script);
2163     int line =
2164         Script::GetLineNumber(script, source_position) - script->line_offset();
2165     int column = Script::GetColumnNumber(script, source_position) -
2166                  (line == 0 ? script->column_offset() : 0);
2167     Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
2168     int line_start =
2169         line == 0 ? 0 : Smi::cast(line_ends->get(line - 1))->value() + 1;
2170     int line_end = Smi::cast(line_ends->get(line))->value();
2171     DisallowHeapAllocation no_gc;
2172     String::FlatContent content = source->GetFlatContent();
2173     if (content.IsOneByte()) {
2174       PrintF("[debug] %.*s\n", line_end - line_start,
2175              content.ToOneByteVector().start() + line_start);
2176       PrintF("[debug] ");
2177       for (int i = 0; i < column; i++) PrintF(" ");
2178       PrintF("^\n");
2179     } else {
2180       PrintF("[debug] at line %d column %d\n", line, column);
2181     }
2182   }
2183 }
2184 #endif  // DEBUG
2185 
DebugScope(Debug * debug)2186 DebugScope::DebugScope(Debug* debug)
2187     : debug_(debug),
2188       prev_(debug->debugger_entry()),
2189       save_(debug_->isolate_),
2190       no_termination_exceptons_(debug_->isolate_,
2191                                 StackGuard::TERMINATE_EXECUTION) {
2192   // Link recursive debugger entry.
2193   base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
2194                         reinterpret_cast<base::AtomicWord>(this));
2195 
2196   // Store the previous break id, frame id and return value.
2197   break_id_ = debug_->break_id();
2198   break_frame_id_ = debug_->break_frame_id();
2199 
2200   // Create the new break info. If there is no proper frames there is no break
2201   // frame id.
2202   StackTraceFrameIterator it(isolate());
2203   bool has_frames = !it.done();
2204   debug_->thread_local_.break_frame_id_ =
2205       has_frames ? it.frame()->id() : StackFrame::NO_ID;
2206   debug_->SetNextBreakId();
2207 
2208   debug_->UpdateState();
2209   // Make sure that debugger is loaded and enter the debugger context.
2210   // The previous context is kept in save_.
2211   failed_ = !debug_->is_loaded();
2212   if (!failed_) isolate()->set_context(*debug->debug_context());
2213 }
2214 
2215 
~DebugScope()2216 DebugScope::~DebugScope() {
2217   // Leaving this debugger entry.
2218   base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
2219                         reinterpret_cast<base::AtomicWord>(prev_));
2220 
2221   // Restore to the previous break state.
2222   debug_->thread_local_.break_frame_id_ = break_frame_id_;
2223   debug_->thread_local_.break_id_ = break_id_;
2224 
2225   debug_->UpdateState();
2226 }
2227 
ReturnValueScope(Debug * debug)2228 ReturnValueScope::ReturnValueScope(Debug* debug) : debug_(debug) {
2229   return_value_ = debug_->return_value_handle();
2230 }
2231 
~ReturnValueScope()2232 ReturnValueScope::~ReturnValueScope() {
2233   debug_->set_return_value(*return_value_);
2234 }
2235 
PerformSideEffectCheck(Handle<JSFunction> function)2236 bool Debug::PerformSideEffectCheck(Handle<JSFunction> function) {
2237   DCHECK(isolate_->needs_side_effect_check());
2238   DisallowJavascriptExecution no_js(isolate_);
2239   if (!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) return false;
2240   Deoptimizer::DeoptimizeFunction(*function);
2241   if (!function->shared()->HasNoSideEffect()) {
2242     if (FLAG_trace_side_effect_free_debug_evaluate) {
2243       PrintF("[debug-evaluate] Function %s failed side effect check.\n",
2244              function->shared()->DebugName()->ToCString().get());
2245     }
2246     side_effect_check_failed_ = true;
2247     // Throw an uncatchable termination exception.
2248     isolate_->TerminateExecution();
2249     return false;
2250   }
2251   return true;
2252 }
2253 
PerformSideEffectCheckForCallback(Address function)2254 bool Debug::PerformSideEffectCheckForCallback(Address function) {
2255   DCHECK(isolate_->needs_side_effect_check());
2256   if (DebugEvaluate::CallbackHasNoSideEffect(function)) return true;
2257   side_effect_check_failed_ = true;
2258   // Throw an uncatchable termination exception.
2259   isolate_->TerminateExecution();
2260   isolate_->OptionalRescheduleException(false);
2261   return false;
2262 }
2263 
PromiseEventOccurred(v8::debug::PromiseDebugActionType type,int id,int parent_id)2264 void LegacyDebugDelegate::PromiseEventOccurred(
2265     v8::debug::PromiseDebugActionType type, int id, int parent_id) {
2266   Handle<Object> event_data;
2267   if (isolate_->debug()->MakeAsyncTaskEvent(type, id).ToHandle(&event_data)) {
2268     ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data));
2269   }
2270 }
2271 
ScriptCompiled(v8::Local<v8::debug::Script> script,bool is_compile_error)2272 void LegacyDebugDelegate::ScriptCompiled(v8::Local<v8::debug::Script> script,
2273                                          bool is_compile_error) {
2274   Handle<Object> event_data;
2275   v8::DebugEvent event = is_compile_error ? v8::CompileError : v8::AfterCompile;
2276   if (isolate_->debug()
2277           ->MakeCompileEvent(v8::Utils::OpenHandle(*script), event)
2278           .ToHandle(&event_data)) {
2279     ProcessDebugEvent(event, Handle<JSObject>::cast(event_data));
2280   }
2281 }
2282 
BreakProgramRequested(v8::Local<v8::Context> paused_context,v8::Local<v8::Object> exec_state,v8::Local<v8::Value> break_points_hit)2283 void LegacyDebugDelegate::BreakProgramRequested(
2284     v8::Local<v8::Context> paused_context, v8::Local<v8::Object> exec_state,
2285     v8::Local<v8::Value> break_points_hit) {
2286   Handle<Object> event_data;
2287   if (isolate_->debug()
2288           ->MakeBreakEvent(v8::Utils::OpenHandle(*break_points_hit))
2289           .ToHandle(&event_data)) {
2290     ProcessDebugEvent(
2291         v8::Break, Handle<JSObject>::cast(event_data),
2292         Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state)));
2293   }
2294 }
2295 
ExceptionThrown(v8::Local<v8::Context> paused_context,v8::Local<v8::Object> exec_state,v8::Local<v8::Value> exception,v8::Local<v8::Value> promise,bool is_uncaught)2296 void LegacyDebugDelegate::ExceptionThrown(v8::Local<v8::Context> paused_context,
2297                                           v8::Local<v8::Object> exec_state,
2298                                           v8::Local<v8::Value> exception,
2299                                           v8::Local<v8::Value> promise,
2300                                           bool is_uncaught) {
2301   Handle<Object> event_data;
2302   if (isolate_->debug()
2303           ->MakeExceptionEvent(v8::Utils::OpenHandle(*exception), is_uncaught,
2304                                v8::Utils::OpenHandle(*promise))
2305           .ToHandle(&event_data)) {
2306     ProcessDebugEvent(
2307         v8::Exception, Handle<JSObject>::cast(event_data),
2308         Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state)));
2309   }
2310 }
2311 
ProcessDebugEvent(v8::DebugEvent event,Handle<JSObject> event_data)2312 void LegacyDebugDelegate::ProcessDebugEvent(v8::DebugEvent event,
2313                                             Handle<JSObject> event_data) {
2314   Handle<Object> exec_state;
2315   if (isolate_->debug()->MakeExecutionState().ToHandle(&exec_state)) {
2316     ProcessDebugEvent(event, event_data, Handle<JSObject>::cast(exec_state));
2317   }
2318 }
2319 
JavaScriptDebugDelegate(Isolate * isolate,Handle<JSFunction> listener,Handle<Object> data)2320 JavaScriptDebugDelegate::JavaScriptDebugDelegate(Isolate* isolate,
2321                                                  Handle<JSFunction> listener,
2322                                                  Handle<Object> data)
2323     : LegacyDebugDelegate(isolate) {
2324   GlobalHandles* global_handles = isolate->global_handles();
2325   listener_ = Handle<JSFunction>::cast(global_handles->Create(*listener));
2326   data_ = global_handles->Create(*data);
2327 }
2328 
~JavaScriptDebugDelegate()2329 JavaScriptDebugDelegate::~JavaScriptDebugDelegate() {
2330   GlobalHandles::Destroy(Handle<Object>::cast(listener_).location());
2331   GlobalHandles::Destroy(data_.location());
2332 }
2333 
ProcessDebugEvent(v8::DebugEvent event,Handle<JSObject> event_data,Handle<JSObject> exec_state)2334 void JavaScriptDebugDelegate::ProcessDebugEvent(v8::DebugEvent event,
2335                                                 Handle<JSObject> event_data,
2336                                                 Handle<JSObject> exec_state) {
2337   Handle<Object> argv[] = {Handle<Object>(Smi::FromInt(event), isolate_),
2338                            exec_state, event_data, data_};
2339   Handle<JSReceiver> global = isolate_->global_proxy();
2340   // Listener must not throw.
2341   Execution::Call(isolate_, listener_, global, arraysize(argv), argv)
2342       .ToHandleChecked();
2343 }
2344 
NativeDebugDelegate(Isolate * isolate,v8::Debug::EventCallback callback,Handle<Object> data)2345 NativeDebugDelegate::NativeDebugDelegate(Isolate* isolate,
2346                                          v8::Debug::EventCallback callback,
2347                                          Handle<Object> data)
2348     : LegacyDebugDelegate(isolate), callback_(callback) {
2349   data_ = isolate->global_handles()->Create(*data);
2350 }
2351 
~NativeDebugDelegate()2352 NativeDebugDelegate::~NativeDebugDelegate() {
2353   GlobalHandles::Destroy(data_.location());
2354 }
2355 
EventDetails(DebugEvent event,Handle<JSObject> exec_state,Handle<JSObject> event_data,Handle<Object> callback_data)2356 NativeDebugDelegate::EventDetails::EventDetails(DebugEvent event,
2357                                                 Handle<JSObject> exec_state,
2358                                                 Handle<JSObject> event_data,
2359                                                 Handle<Object> callback_data)
2360     : event_(event),
2361       exec_state_(exec_state),
2362       event_data_(event_data),
2363       callback_data_(callback_data) {}
2364 
GetEvent() const2365 DebugEvent NativeDebugDelegate::EventDetails::GetEvent() const {
2366   return event_;
2367 }
2368 
GetExecutionState() const2369 v8::Local<v8::Object> NativeDebugDelegate::EventDetails::GetExecutionState()
2370     const {
2371   return v8::Utils::ToLocal(exec_state_);
2372 }
2373 
GetEventData() const2374 v8::Local<v8::Object> NativeDebugDelegate::EventDetails::GetEventData() const {
2375   return v8::Utils::ToLocal(event_data_);
2376 }
2377 
GetEventContext() const2378 v8::Local<v8::Context> NativeDebugDelegate::EventDetails::GetEventContext()
2379     const {
2380   return GetDebugEventContext(exec_state_->GetIsolate());
2381 }
2382 
GetCallbackData() const2383 v8::Local<v8::Value> NativeDebugDelegate::EventDetails::GetCallbackData()
2384     const {
2385   return v8::Utils::ToLocal(callback_data_);
2386 }
2387 
GetIsolate() const2388 v8::Isolate* NativeDebugDelegate::EventDetails::GetIsolate() const {
2389   return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
2390 }
2391 
ProcessDebugEvent(v8::DebugEvent event,Handle<JSObject> event_data,Handle<JSObject> exec_state)2392 void NativeDebugDelegate::ProcessDebugEvent(v8::DebugEvent event,
2393                                             Handle<JSObject> event_data,
2394                                             Handle<JSObject> exec_state) {
2395   EventDetails event_details(event, exec_state, event_data, data_);
2396   Isolate* isolate = isolate_;
2397   callback_(event_details);
2398   CHECK(!isolate->has_scheduled_exception());
2399 }
2400 
~NoSideEffectScope()2401 NoSideEffectScope::~NoSideEffectScope() {
2402   if (isolate_->needs_side_effect_check() &&
2403       isolate_->debug()->side_effect_check_failed_) {
2404     DCHECK(isolate_->has_pending_exception());
2405     DCHECK_EQ(isolate_->heap()->termination_exception(),
2406               isolate_->pending_exception());
2407     // Convert the termination exception into a regular exception.
2408     isolate_->CancelTerminateExecution();
2409     isolate_->Throw(*isolate_->factory()->NewEvalError(
2410         MessageTemplate::kNoSideEffectDebugEvaluate));
2411   }
2412   isolate_->set_needs_side_effect_check(old_needs_side_effect_check_);
2413   isolate_->debug()->UpdateHookOnFunctionCall();
2414   isolate_->debug()->side_effect_check_failed_ = false;
2415 }
2416 
2417 }  // namespace internal
2418 }  // namespace v8
2419