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