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