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 16278 : TemporaryObjectsTracker() = default;
48 16278 : ~TemporaryObjectsTracker() override = default;
49 :
50 129258 : void AllocationEvent(Address addr, int) override { objects_.insert(addr); }
51 :
52 122133 : void MoveEvent(Address from, Address to, int) override {
53 122133 : if (from == to) return;
54 122135 : base::MutexGuard guard(&mutex_);
55 : auto it = objects_.find(from);
56 122217 : 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 9908 : if (obj->IsJSObject() &&
69 6589 : 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 61534 : 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 123068 : isolate_(isolate) {
97 61534 : ThreadInit();
98 61534 : }
99 :
100 123036 : Debug::~Debug() { DCHECK_NULL(debug_delegate_); }
101 :
102 306733 : BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
103 : JavaScriptFrame* frame) {
104 306733 : if (debug_info->CanBreakAtEntry()) {
105 : return BreakLocation(Debug::kBreakAtEntryPosition, DEBUG_BREAK_AT_ENTRY);
106 : }
107 306263 : auto summary = FrameSummary::GetTop(frame).AsJavaScript();
108 : int offset = summary.code_offset();
109 306263 : Handle<AbstractCode> abstract_code = summary.abstract_code();
110 306263 : BreakIterator it(debug_info);
111 306263 : it.SkipTo(BreakIndexFromCodeOffset(debug_info, abstract_code, offset));
112 306263 : 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 62196 : 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 : statement_position = it.statement_position();
128 : }
129 251659 : for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
130 189463 : if (it.statement_position() == statement_position) {
131 244332 : result_out->push_back(it.GetBreakLocation());
132 : }
133 : }
134 62196 : }
135 :
136 0 : 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 0 : return JSGeneratorObject::cast(generator_obj);
145 : }
146 :
147 368459 : 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 12216834 : for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
155 : // Check if this break point is closer that what was previously found.
156 12215963 : if (it.code_offset() <= offset && offset - it.code_offset() < distance) {
157 : closest_break = it.break_index();
158 12213581 : distance = offset - it.code_offset();
159 : // Check whether we can't get any closer.
160 12213581 : if (distance == 0) break;
161 : }
162 : }
163 368459 : return closest_break;
164 : }
165 :
166 186857 : 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 373714 : if (!debug_info->HasBreakPoint(isolate, position_)) return false;
170 4269 : 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 3799 : BreakIterator it(debug_info);
179 3799 : it.SkipToPosition(position_);
180 3799 : return it.code_offset() == code_offset_;
181 : }
182 : }
183 :
184 5000 : debug::BreakLocationType BreakLocation::type() const {
185 5000 : 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 2135437 : BreakIterator::BreakIterator(Handle<DebugInfo> debug_info)
201 : : debug_info_(debug_info),
202 : break_index_(-1),
203 : source_position_iterator_(
204 4270874 : debug_info->DebugBytecodeArray()->SourcePositionTable()) {
205 2135437 : position_ = debug_info->shared()->StartPosition();
206 2135437 : statement_position_ = position_;
207 : // There is at least one break location.
208 : DCHECK(!Done());
209 2135437 : Next();
210 2135437 : }
211 :
212 73390 : int BreakIterator::BreakIndexFromPosition(int source_position) {
213 : int distance = kMaxInt;
214 : int closest_break = break_index();
215 149926 : while (!Done()) {
216 : int next_position = position();
217 193812 : if (source_position <= next_position &&
218 83798 : 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 73864 : if (distance == 0) break;
223 : }
224 38268 : Next();
225 : }
226 73390 : return closest_break;
227 : }
228 :
229 40776403 : void BreakIterator::Next() {
230 : DisallowHeapAllocation no_gc;
231 : DCHECK(!Done());
232 40776403 : bool first = break_index_ == -1;
233 59979581 : while (!Done()) {
234 59979581 : if (!first) source_position_iterator_.Advance();
235 : first = false;
236 59979581 : if (Done()) return;
237 58725327 : position_ = source_position_iterator_.source_position().ScriptOffset();
238 58725327 : if (source_position_iterator_.is_statement()) {
239 37998415 : statement_position_ = position_;
240 : }
241 : DCHECK_LE(0, position_);
242 : DCHECK_LE(0, statement_position_);
243 :
244 58725327 : DebugBreakType type = GetDebugBreakType();
245 58725327 : if (type != NOT_DEBUG_BREAK) break;
246 : }
247 39522149 : break_index_++;
248 : }
249 :
250 73914397 : DebugBreakType BreakIterator::GetDebugBreakType() {
251 : 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 73914397 : if (interpreter::Bytecodes::IsPrefixScalingBytecode(bytecode)) {
257 : bytecode = interpreter::Bytecodes::FromByte(
258 19892036 : bytecode_array->get(code_offset() + 1));
259 : }
260 :
261 73914397 : if (bytecode == interpreter::Bytecode::kDebugger) {
262 : return DEBUGGER_STATEMENT;
263 72550558 : } else if (bytecode == interpreter::Bytecode::kReturn) {
264 : return DEBUG_BREAK_SLOT_AT_RETURN;
265 69953758 : } else if (bytecode == interpreter::Bytecode::kSuspendGenerator) {
266 : return DEBUG_BREAK_SLOT_AT_SUSPEND;
267 69878988 : } else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) {
268 : return DEBUG_BREAK_SLOT_AT_CALL;
269 67385370 : } else if (source_position_iterator_.is_statement()) {
270 : return DEBUG_BREAK_SLOT;
271 : } else {
272 19203178 : return NOT_DEBUG_BREAK;
273 : }
274 : }
275 :
276 73390 : void BreakIterator::SkipToPosition(int position) {
277 73390 : BreakIterator it(debug_info_);
278 73390 : SkipTo(it.BreakIndexFromPosition(position));
279 73390 : }
280 :
281 3814841 : void BreakIterator::SetDebugBreak() {
282 3814841 : DebugBreakType debug_break_type = GetDebugBreakType();
283 3834724 : if (debug_break_type == DEBUGGER_STATEMENT) return;
284 : HandleScope scope(isolate());
285 : DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
286 : Handle<BytecodeArray> bytecode_array(debug_info_->DebugBytecodeArray(),
287 : isolate());
288 : interpreter::BytecodeArrayAccessor(bytecode_array, code_offset())
289 3794958 : .ApplyDebugBreak();
290 : }
291 :
292 10938555 : void BreakIterator::ClearDebugBreak() {
293 10938555 : DebugBreakType debug_break_type = GetDebugBreakType();
294 10938555 : if (debug_break_type == DEBUGGER_STATEMENT) return;
295 : DCHECK(debug_break_type >= DEBUG_BREAK_SLOT);
296 : BytecodeArray bytecode_array = debug_info_->DebugBytecodeArray();
297 : BytecodeArray original = debug_info_->OriginalBytecodeArray();
298 : bytecode_array->set(code_offset(), original->get(code_offset()));
299 : }
300 :
301 435674 : BreakLocation BreakIterator::GetBreakLocation() {
302 : Handle<AbstractCode> code(
303 : AbstractCode::cast(debug_info_->DebugBytecodeArray()), isolate());
304 435674 : DebugBreakType type = GetDebugBreakType();
305 : int generator_object_reg_index = -1;
306 435674 : 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 : BytecodeArray bytecode_array = debug_info_->OriginalBytecodeArray();
313 : interpreter::BytecodeArrayAccessor accessor(
314 717 : 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 871348 : generator_object_reg_index);
323 : }
324 :
325 0 : Isolate* BreakIterator::isolate() { return debug_info_->GetIsolate(); }
326 :
327 1274 : void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) {
328 1274 : uint32_t mask = 1 << feature;
329 : // Only count one sample per feature and isolate.
330 69409 : if (bitfield_ & mask) return;
331 9546 : isolate_->counters()->debug_feature_usage()->AddSample(feature);
332 4773 : bitfield_ |= mask;
333 : }
334 :
335 :
336 : // Threading support.
337 73370 : void Debug::ThreadInit() {
338 73370 : thread_local_.break_frame_id_ = StackFrame::NO_ID;
339 73370 : thread_local_.last_step_action_ = StepNone;
340 73370 : thread_local_.last_statement_position_ = kNoSourcePosition;
341 73370 : thread_local_.last_frame_count_ = -1;
342 73370 : thread_local_.fast_forward_to_return_ = false;
343 73370 : thread_local_.ignore_step_into_function_ = Smi::kZero;
344 73370 : thread_local_.target_frame_count_ = -1;
345 73370 : thread_local_.return_value_ = Smi::kZero;
346 73370 : thread_local_.last_breakpoint_id_ = 0;
347 : clear_suspended_generator();
348 73370 : thread_local_.restart_fp_ = kNullAddress;
349 73370 : base::Relaxed_Store(&thread_local_.current_debug_scope_,
350 : static_cast<base::AtomicWord>(0));
351 73370 : thread_local_.break_on_next_function_call_ = false;
352 : UpdateHookOnFunctionCall();
353 73370 : }
354 :
355 :
356 32437 : char* Debug::ArchiveDebug(char* storage) {
357 32437 : MemCopy(storage, reinterpret_cast<char*>(&thread_local_),
358 : ArchiveSpacePerThread());
359 32437 : return storage + ArchiveSpacePerThread();
360 : }
361 :
362 32437 : char* Debug::RestoreDebug(char* storage) {
363 32437 : MemCopy(reinterpret_cast<char*>(&thread_local_), storage,
364 : ArchiveSpacePerThread());
365 :
366 : // Enter the debugger.
367 64874 : 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 32437 : ClearOneShot();
372 :
373 32437 : 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 64874 : return storage + ArchiveSpacePerThread();
379 : }
380 :
381 1133 : int Debug::ArchiveSpacePerThread() { return sizeof(ThreadLocal); }
382 :
383 276888 : void Debug::Iterate(RootVisitor* v) {
384 276888 : v->VisitRootPointer(Root::kDebug, nullptr,
385 553776 : FullObjectSlot(&thread_local_.return_value_));
386 276888 : v->VisitRootPointer(Root::kDebug, nullptr,
387 553776 : FullObjectSlot(&thread_local_.suspended_generator_));
388 276888 : v->VisitRootPointer(
389 : Root::kDebug, nullptr,
390 553776 : FullObjectSlot(&thread_local_.ignore_step_into_function_));
391 276888 : }
392 :
393 0 : DebugInfoListNode::DebugInfoListNode(Isolate* isolate, DebugInfo debug_info)
394 28634 : : next_(nullptr) {
395 : // Globalize the request debug info object and make it weak.
396 : GlobalHandles* global_handles = isolate->global_handles();
397 28634 : debug_info_ = global_handles->Create(debug_info).location();
398 0 : }
399 :
400 28634 : DebugInfoListNode::~DebugInfoListNode() {
401 28634 : if (debug_info_ == nullptr) return;
402 28634 : GlobalHandles::Destroy(debug_info_);
403 28634 : debug_info_ = nullptr;
404 0 : }
405 :
406 65437 : void Debug::Unload() {
407 65437 : ClearAllBreakPoints();
408 65436 : ClearStepping();
409 65436 : RemoveAllCoverageInfos();
410 65437 : ClearAllDebuggerHints();
411 65437 : debug_delegate_ = nullptr;
412 65437 : }
413 :
414 64822 : void Debug::Break(JavaScriptFrame* frame, Handle<JSFunction> break_target) {
415 : // Initialize LiveEdit.
416 64822 : LiveEdit::InitializeThreadLocal(this);
417 :
418 : // Just continue if breaks are disabled or debugger cannot be loaded.
419 71200 : if (break_disabled()) return;
420 :
421 : // Enter the debugger.
422 123248 : DebugScope debug_scope(this);
423 : DisableBreak no_recursive_break(this);
424 :
425 : // Return if we fail to retrieve debug info.
426 64804 : Handle<SharedFunctionInfo> shared(break_target->shared(), isolate_);
427 64804 : if (!EnsureBreakInfo(shared)) return;
428 64804 : PrepareFunctionForDebugExecution(shared);
429 :
430 64804 : Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_);
431 :
432 : // Find the break location where execution has stopped.
433 64804 : 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 64804 : CheckBreakPoints(debug_info, &location);
438 64804 : if (!break_points_hit.is_null() || break_on_next_function_call()) {
439 : // Clear all current stepping setup.
440 5161 : ClearStepping();
441 : // Notify the debug event listeners.
442 5161 : OnDebugBreak(!break_points_hit.is_null()
443 : ? break_points_hit.ToHandleChecked()
444 6716 : : isolate_->factory()->empty_fixed_array());
445 5161 : return;
446 : }
447 :
448 : // Debug break at function entry, do not worry about stepping.
449 59643 : 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 59608 : int current_frame_count = CurrentFrameCount();
459 59608 : int target_frame_count = thread_local_.target_frame_count_;
460 59608 : 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 59608 : 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 59175 : 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 116878 : 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 : 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 : }
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 186970 : MaybeHandle<FixedArray> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info,
522 : BreakLocation* location,
523 : bool* has_break_points) {
524 : bool has_break_points_to_check =
525 186970 : break_points_active_ && location->HasBreakPoint(isolate_, debug_info);
526 186970 : if (has_break_points) *has_break_points = has_break_points_to_check;
527 186970 : if (!has_break_points_to_check) return {};
528 :
529 4183 : return Debug::GetHitBreakPoints(debug_info, location->position());
530 : }
531 :
532 :
533 70539 : bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) {
534 70539 : 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 141078 : FrameSummary summary = FrameSummary::GetTop(frame);
541 : DCHECK(!summary.IsWasm());
542 : Handle<JSFunction> function = summary.AsJavaScript().function();
543 70539 : if (!function->shared()->HasBreakInfo()) return false;
544 62196 : 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 306390 : 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 4265 : bool Debug::CheckBreakPoint(Handle<BreakPoint> break_point,
562 : bool is_break_at_entry) {
563 4265 : HandleScope scope(isolate_);
564 :
565 4265 : if (!break_point->condition()->length()) return true;
566 908 : Handle<String> condition(break_point->condition(), isolate_);
567 : MaybeHandle<Object> maybe_result;
568 : Handle<Object> result;
569 :
570 908 : 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 823 : condition, throw_on_side_effect);
580 : }
581 :
582 908 : if (!maybe_result.ToHandle(&result)) {
583 36 : if (isolate_->has_pending_exception()) {
584 : isolate_->clear_pending_exception();
585 : }
586 : return false;
587 : }
588 1780 : 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 445 : Handle<SharedFunctionInfo> shared(function->shared(), isolate_);
598 445 : if (!EnsureBreakInfo(shared)) return false;
599 445 : PrepareFunctionForDebugExecution(shared);
600 :
601 445 : 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 : feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
615 : return true;
616 : }
617 :
618 2148 : bool Debug::SetBreakPointForScript(Handle<Script> script,
619 : Handle<String> condition,
620 : int* source_position, int* id) {
621 2148 : *id = ++thread_local_.last_breakpoint_id_;
622 : Handle<BreakPoint> break_point =
623 2148 : isolate_->factory()->NewBreakPoint(*id, condition);
624 2148 : 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 2068 : HandleScope scope(isolate_);
632 :
633 : // Obtain shared function info for the function.
634 : Handle<Object> result =
635 2068 : FindSharedFunctionInfoInScript(script, *source_position);
636 4136 : if (result->IsUndefined(isolate_)) return false;
637 :
638 : // Make sure the function has set up the debug info.
639 : Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result);
640 2038 : if (!EnsureBreakInfo(shared)) return false;
641 2038 : PrepareFunctionForDebugExecution(shared);
642 :
643 : // Find position within function. The script position might be before the
644 : // source position of the first function.
645 2038 : if (shared->StartPosition() > *source_position) {
646 14 : *source_position = shared->StartPosition();
647 : }
648 :
649 2038 : 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 2038 : int breakable_position = FindBreakablePosition(debug_info, *source_position);
655 2038 : if (breakable_position < *source_position) return false;
656 2038 : *source_position = breakable_position;
657 :
658 2038 : 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 2038 : ClearBreakPoints(debug_info);
663 2038 : ApplyBreakPoints(debug_info);
664 :
665 : feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
666 : return true;
667 : }
668 :
669 2483 : int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info,
670 : int source_position) {
671 2483 : if (debug_info->CanBreakAtEntry()) {
672 : return kBreakAtEntryPosition;
673 : } else {
674 : DCHECK(debug_info->HasInstrumentedBytecodeArray());
675 2333 : BreakIterator it(debug_info);
676 2333 : it.SkipToPosition(source_position);
677 : return it.position();
678 : }
679 : }
680 :
681 1363463 : void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) {
682 : DisallowHeapAllocation no_gc;
683 1363463 : if (debug_info->CanBreakAtEntry()) {
684 585 : debug_info->SetBreakAtEntry();
685 : } else {
686 1362878 : if (!debug_info->HasInstrumentedBytecodeArray()) return;
687 : FixedArray break_points = debug_info->break_points();
688 10019053 : for (int i = 0; i < break_points->length(); i++) {
689 13253570 : if (break_points->get(i)->IsUndefined(isolate_)) continue;
690 68019 : BreakPointInfo info = BreakPointInfo::cast(break_points->get(i));
691 68019 : if (info->GetBreakPointCount(isolate_) == 0) continue;
692 : DCHECK(debug_info->HasInstrumentedBytecodeArray());
693 67258 : BreakIterator it(debug_info);
694 67258 : it.SkipToPosition(info->source_position());
695 67258 : it.SetDebugBreak();
696 : }
697 : }
698 1139086 : debug_info->SetDebugExecutionMode(DebugInfo::kBreakpoints);
699 : }
700 :
701 1391430 : void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) {
702 1391430 : 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 3930116 : if (!debug_info->HasInstrumentedBytecodeArray() ||
708 2539421 : !debug_info->HasBreakInfo()) {
709 : return;
710 : }
711 :
712 : DisallowHeapAllocation no_gc;
713 12058413 : for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
714 10938555 : it.ClearDebugBreak();
715 : }
716 : }
717 : }
718 :
719 2378 : void Debug::ClearBreakPoint(Handle<BreakPoint> break_point) {
720 2378 : HandleScope scope(isolate_);
721 :
722 8337 : for (DebugInfoListNode* node = debug_info_list_; node != nullptr;
723 : node = node->next()) {
724 14211 : if (!node->debug_info()->HasBreakInfo()) continue;
725 : Handle<Object> result = DebugInfo::FindBreakPointInfo(
726 8010 : isolate_, node->debug_info(), break_point);
727 16020 : if (result->IsUndefined(isolate_)) continue;
728 : Handle<DebugInfo> debug_info = node->debug_info();
729 2293 : if (DebugInfo::ClearBreakPoint(isolate_, debug_info, break_point)) {
730 2293 : ClearBreakPoints(debug_info);
731 4586 : if (debug_info->GetBreakPointCount(isolate_) == 0) {
732 1800 : RemoveBreakInfoAndMaybeFree(debug_info);
733 : } else {
734 493 : ApplyBreakPoints(debug_info);
735 : }
736 2293 : return;
737 : }
738 : }
739 : }
740 :
741 170 : int Debug::GetFunctionDebuggingId(Handle<JSFunction> function) {
742 340 : Handle<SharedFunctionInfo> shared = handle(function->shared(), isolate_);
743 170 : Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
744 : 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 2203 : void Debug::RemoveBreakpoint(int id) {
762 : Handle<BreakPoint> breakpoint = isolate_->factory()->NewBreakPoint(
763 4406 : id, isolate_->factory()->empty_string());
764 2203 : ClearBreakPoint(breakpoint);
765 2203 : }
766 :
767 : // Clear out all the debug break code.
768 65437 : void Debug::ClearAllBreakPoints() {
769 91952 : ClearAllDebugInfos([=](Handle<DebugInfo> info) {
770 26516 : ClearBreakPoints(info);
771 53032 : info->ClearBreakInfo(isolate_);
772 91953 : });
773 65436 : }
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 68250 : Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_);
783 : // Flood the function with break points.
784 : DCHECK(debug_info->HasInstrumentedBytecodeArray());
785 3817210 : for (BreakIterator it(debug_info); !it.Done(); it.Next()) {
786 3751155 : if (returns_only && !it.GetBreakLocation().IsReturnOrSuspend()) continue;
787 3747583 : it.SetDebugBreak();
788 : }
789 : }
790 :
791 15016 : void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
792 15016 : if (type == BreakUncaughtException) {
793 7508 : break_on_uncaught_exception_ = enable;
794 : } else {
795 7508 : break_on_exception_ = enable;
796 : }
797 15016 : }
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 4183 : MaybeHandle<FixedArray> Debug::GetHitBreakPoints(Handle<DebugInfo> debug_info,
809 : int position) {
810 8366 : Handle<Object> break_points = debug_info->GetBreakPoints(isolate_, position);
811 4183 : bool is_break_at_entry = debug_info->BreakAtEntry();
812 : DCHECK(!break_points->IsUndefined(isolate_));
813 4183 : if (!break_points->IsFixedArray()) {
814 4135 : if (!CheckBreakPoint(Handle<BreakPoint>::cast(break_points),
815 : is_break_at_entry)) {
816 503 : return {};
817 : }
818 3632 : Handle<FixedArray> break_points_hit = isolate_->factory()->NewFixedArray(1);
819 3632 : break_points_hit->set(0, *break_points);
820 3632 : 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 308 : 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 : 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 528275 : void Debug::PrepareStepIn(Handle<JSFunction> function) {
857 528275 : 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 15321 : 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 14078 : FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_));
866 : }
867 :
868 262 : 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 262 : isolate_);
878 524 : FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_));
879 : clear_suspended_generator();
880 : }
881 :
882 3891 : void Debug::PrepareStepOnThrow() {
883 7782 : 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 752 : 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 94 : 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 10 : std::vector<FrameSummary> summaries;
916 532 : frame->Summarize(&summaries);
917 566 : 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 529 : 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 522 : summary.AsJavaScript().function()->shared(), isolate_);
945 522 : if (IsBlackboxed(info)) continue;
946 522 : FloodWithOneShot(info);
947 522 : return;
948 : }
949 : }
950 : }
951 : }
952 :
953 :
954 61693 : 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 : 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 61329 : Handle<SharedFunctionInfo> shared(function->shared(), isolate_);
991 61329 : if (!EnsureBreakInfo(shared)) return;
992 61329 : PrepareFunctionForDebugExecution(shared);
993 :
994 61329 : 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 21247 : 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 : 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 3726 : for (int i = 0; i < debug_info->break_points()->length(); ++i) {
1094 1656 : if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
1095 : BreakPointInfo break_point_info =
1096 801 : 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 1971 : for (int j = 0; j < break_points; ++j) {
1100 657 : locations->set(count++,
1101 : Smi::FromInt(break_point_info->source_position()));
1102 : }
1103 : }
1104 : }
1105 414 : return locations;
1106 : }
1107 :
1108 242668 : void Debug::ClearStepping() {
1109 : // Clear the various stepping setup.
1110 242668 : ClearOneShot();
1111 :
1112 242668 : thread_local_.last_step_action_ = StepNone;
1113 242668 : thread_local_.last_statement_position_ = kNoSourcePosition;
1114 242668 : thread_local_.ignore_step_into_function_ = Smi::kZero;
1115 242668 : thread_local_.fast_forward_to_return_ = false;
1116 242668 : thread_local_.last_frame_count_ = -1;
1117 242668 : thread_local_.target_frame_count_ = -1;
1118 242668 : thread_local_.break_on_next_function_call_ = false;
1119 : UpdateHookOnFunctionCall();
1120 242668 : }
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 275669 : 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 1629424 : for (DebugInfoListNode* node = debug_info_list_; node != nullptr;
1131 : node = node->next()) {
1132 1353755 : Handle<DebugInfo> debug_info = node->debug_info();
1133 1353755 : ClearBreakPoints(debug_info);
1134 1353755 : ApplyBreakPoints(debug_info);
1135 : }
1136 275669 : }
1137 :
1138 21184 : class RedirectActiveFunctions : public ThreadVisitor {
1139 : public:
1140 : explicit RedirectActiveFunctions(SharedFunctionInfo shared)
1141 10592 : : shared_(shared) {
1142 : DCHECK(shared->HasBytecodeArray());
1143 : }
1144 :
1145 10676 : void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
1146 41013 : for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1147 : JavaScriptFrame* frame = it.frame();
1148 30337 : JSFunction function = frame->function();
1149 89362 : if (!frame->is_interpreted()) continue;
1150 27617 : if (function->shared() != shared_) continue;
1151 : InterpretedFrame* interpreted_frame =
1152 : reinterpret_cast<InterpretedFrame*>(frame);
1153 1649 : BytecodeArray debug_copy = shared_->GetDebugInfo()->DebugBytecodeArray();
1154 1649 : interpreted_frame->PatchBytecodeArray(debug_copy);
1155 : }
1156 10676 : }
1157 :
1158 : private:
1159 : SharedFunctionInfo shared_;
1160 : DisallowHeapAllocation no_gc_;
1161 : };
1162 :
1163 12411 : void Debug::DeoptimizeFunction(Handle<SharedFunctionInfo> shared) {
1164 : // Deoptimize all code compiled from this shared function info including
1165 : // inlining.
1166 12411 : isolate_->AbortConcurrentOptimization(BlockingBehavior::kBlock);
1167 :
1168 : // TODO(mlippautz): Try to remove this call.
1169 12411 : isolate_->heap()->PreciseCollectAllGarbage(
1170 12411 : Heap::kNoGCFlags, GarbageCollectionReason::kDebugger);
1171 :
1172 : bool found_something = false;
1173 12411 : Code::OptimizedCodeIterator iterator(isolate_);
1174 17275 : do {
1175 29686 : Code code = iterator.Next();
1176 29686 : if (code.is_null()) break;
1177 17275 : if (code->Inlines(*shared)) {
1178 344 : code->set_marked_for_deoptimization(true);
1179 : found_something = true;
1180 : }
1181 : } while (true);
1182 :
1183 12411 : if (found_something) {
1184 : // Only go through with the deoptimization if something was found.
1185 340 : Deoptimizer::DeoptimizeMarkedCode(isolate_);
1186 : }
1187 12411 : }
1188 :
1189 200886 : 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 200886 : Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
1197 200886 : 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 10742 : isolate_->factory()->undefined_value();
1202 10742 : if (shared->HasBytecodeArray()) {
1203 : Handle<BytecodeArray> original_bytecode_array =
1204 31776 : handle(shared->GetBytecodeArray(), isolate_);
1205 : Handle<BytecodeArray> debug_bytecode_array =
1206 10592 : isolate_->factory()->CopyBytecodeArray(original_bytecode_array);
1207 21184 : debug_info->set_debug_bytecode_array(*debug_bytecode_array);
1208 10592 : shared->SetDebugBytecodeArray(*debug_bytecode_array);
1209 : maybe_original_bytecode_array = original_bytecode_array;
1210 : }
1211 10742 : debug_info->set_original_bytecode_array(*maybe_original_bytecode_array);
1212 :
1213 10742 : 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 10592 : DeoptimizeFunction(shared);
1219 : // Update PCs on the stack to point to recompiled code.
1220 : RedirectActiveFunctions redirect_visitor(*shared);
1221 21184 : redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top());
1222 10592 : isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor);
1223 : }
1224 10742 : debug_info->set_flags(debug_info->flags() |
1225 : DebugInfo::kPreparedForDebugExecution);
1226 : }
1227 :
1228 300 : 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 300 : 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 745 : 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 300 : if (!needs_to_use_trampoline) return;
1249 :
1250 310 : Handle<Code> trampoline = BUILTIN_CODE(isolate_, DebugBreakTrampoline);
1251 : std::vector<Handle<JSFunction>> needs_compile;
1252 : {
1253 465 : HeapIterator iterator(isolate_->heap());
1254 1144643 : for (HeapObject obj = iterator.next(); !obj.is_null();
1255 : obj = iterator.next()) {
1256 1439545 : if (needs_to_clear_ic && obj->IsFeedbackVector()) {
1257 230 : FeedbackVector::cast(obj)->ClearSlots(isolate_);
1258 230 : continue;
1259 1144258 : } else if (obj->IsJSFunction()) {
1260 105723 : JSFunction fun = JSFunction::cast(obj);
1261 105723 : SharedFunctionInfo shared = fun->shared();
1262 211286 : 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 : }
1271 : }
1272 : // By overwriting the function code with DebugBreakTrampoline, which tailcalls
1273 : // to shared code, we bypass CompileLazy. Perform CompileLazy here instead.
1274 155 : 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 1430 : void GetBreakablePositions(Iterator* it, int start_position, int end_position,
1285 : std::vector<BreakLocation>* locations) {
1286 11740 : while (!it->Done()) {
1287 5155 : if (it->position() >= start_position && it->position() < end_position) {
1288 10000 : locations->push_back(it->GetBreakLocation());
1289 : }
1290 5155 : 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 10 : if (result->IsUndefined(isolate_)) return false;
1310 :
1311 : // Make sure the function has set up the debug info.
1312 : Handle<SharedFunctionInfo> shared =
1313 : Handle<SharedFunctionInfo>::cast(result);
1314 5 : if (!EnsureBreakInfo(shared)) return false;
1315 5 : PrepareFunctionForDebugExecution(shared);
1316 :
1317 5 : 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 4504 : 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 4085 : 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 : &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 1630 : for (const auto& candidate : candidates) {
1359 1425 : CHECK(candidate->HasBreakInfo());
1360 1425 : 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 79273 : MaybeHandle<JSArray> Debug::GetPrivateFields(Handle<JSReceiver> receiver) {
1370 79273 : Factory* factory = isolate_->factory();
1371 :
1372 : Handle<FixedArray> internal_fields;
1373 158546 : ASSIGN_RETURN_ON_EXCEPTION(isolate_, internal_fields,
1374 : JSReceiver::GetPrivateEntries(isolate_, receiver),
1375 : JSArray);
1376 :
1377 : int nof_internal_fields = internal_fields->length();
1378 79273 : if (nof_internal_fields == 0) {
1379 79233 : return factory->NewJSArray(0);
1380 : }
1381 :
1382 40 : return factory->NewJSArrayWithElements(internal_fields);
1383 : }
1384 :
1385 : class SharedFunctionInfoFinder {
1386 : public:
1387 : explicit SharedFunctionInfoFinder(int target_position)
1388 : : current_start_position_(kNoSourcePosition),
1389 3303 : target_position_(target_position) {}
1390 :
1391 15094 : void NewCandidate(SharedFunctionInfo shared,
1392 : JSFunction closure = JSFunction()) {
1393 15094 : if (!shared->IsSubjectToDebugging()) return;
1394 : int start_position = shared->function_token_position();
1395 14930 : if (start_position == kNoSourcePosition) {
1396 0 : start_position = shared->StartPosition();
1397 : }
1398 :
1399 14930 : if (start_position > target_position_) return;
1400 11289 : if (target_position_ > shared->EndPosition()) return;
1401 :
1402 6729 : if (!current_candidate_.is_null()) {
1403 3937 : if (current_start_position_ == start_position &&
1404 481 : shared->EndPosition() == current_candidate_->EndPosition()) {
1405 : // If we already have a matching closure, do not throw it away.
1406 216 : if (!current_candidate_closure_.is_null() && closure.is_null()) return;
1407 : // If a top-level function contains only one function
1408 : // declaration the source for the top-level and the function
1409 : // is the same. In that case prefer the non top-level function.
1410 216 : if (!current_candidate_->is_toplevel() && shared->is_toplevel()) return;
1411 6480 : } else if (start_position < current_start_position_ ||
1412 3240 : current_candidate_->EndPosition() < shared->EndPosition()) {
1413 : return;
1414 : }
1415 : }
1416 :
1417 6729 : current_start_position_ = start_position;
1418 6729 : current_candidate_ = shared;
1419 6729 : current_candidate_closure_ = closure;
1420 : }
1421 :
1422 : SharedFunctionInfo Result() { return current_candidate_; }
1423 :
1424 : JSFunction ResultClosure() { return current_candidate_closure_; }
1425 :
1426 : private:
1427 : SharedFunctionInfo current_candidate_;
1428 : JSFunction current_candidate_closure_;
1429 : int current_start_position_;
1430 : int target_position_;
1431 : DisallowHeapAllocation no_gc_;
1432 : };
1433 :
1434 :
1435 : // We need to find a SFI for a literal that may not yet have been compiled yet,
1436 : // and there may not be a JSFunction referencing it. Find the SFI closest to
1437 : // the given position, compile it to reveal possible inner SFIs and repeat.
1438 : // While we are at this, also ensure code with debug break slots so that we do
1439 : // not have to compile a SFI without JSFunction, which is paifu for those that
1440 : // cannot be compiled without context (need to find outer compilable SFI etc.)
1441 2338 : Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
1442 : int position) {
1443 965 : for (int iteration = 0;; iteration++) {
1444 : // Go through all shared function infos associated with this script to
1445 : // find the inner most function containing this position.
1446 : // If there is no shared function info for this script at all, there is
1447 : // no point in looking for it by walking the heap.
1448 :
1449 3303 : SharedFunctionInfo shared;
1450 : IsCompiledScope is_compiled_scope;
1451 : {
1452 : SharedFunctionInfoFinder finder(position);
1453 3303 : SharedFunctionInfo::ScriptIterator iterator(isolate_, *script);
1454 36794 : for (SharedFunctionInfo info = iterator.Next(); !info.is_null();
1455 : info = iterator.Next()) {
1456 15094 : finder.NewCandidate(info);
1457 : }
1458 3303 : shared = finder.Result();
1459 3303 : if (shared.is_null()) break;
1460 : // We found it if it's already compiled.
1461 3273 : is_compiled_scope = shared->is_compiled_scope();
1462 3273 : if (is_compiled_scope.is_compiled()) {
1463 2308 : Handle<SharedFunctionInfo> shared_handle(shared, isolate_);
1464 : // If the iteration count is larger than 1, we had to compile the outer
1465 : // function in order to create this shared function info. So there can
1466 : // be no JSFunction referencing it. We can anticipate creating a debug
1467 : // info while bypassing PrepareFunctionForDebugExecution.
1468 2308 : if (iteration > 1) {
1469 : AllowHeapAllocation allow_before_return;
1470 54 : CreateBreakInfo(shared_handle);
1471 : }
1472 2308 : return shared_handle;
1473 : }
1474 : }
1475 : // If not, compile to reveal inner functions.
1476 965 : HandleScope scope(isolate_);
1477 : // Code that cannot be compiled lazily are internal and not debuggable.
1478 : DCHECK(shared->allows_lazy_compilation());
1479 1930 : if (!Compiler::Compile(handle(shared, isolate_), Compiler::CLEAR_EXCEPTION,
1480 : &is_compiled_scope)) {
1481 : break;
1482 : }
1483 : }
1484 60 : return isolate_->factory()->undefined_value();
1485 : }
1486 :
1487 :
1488 : // Ensures the debug information is present for shared.
1489 200510 : bool Debug::EnsureBreakInfo(Handle<SharedFunctionInfo> shared) {
1490 : // Return if we already have the break info for shared.
1491 200510 : if (shared->HasBreakInfo()) return true;
1492 10379 : if (!shared->IsSubjectToDebugging() && !CanBreakAtEntry(shared)) {
1493 : return false;
1494 : }
1495 10379 : IsCompiledScope is_compiled_scope = shared->is_compiled_scope();
1496 12035 : if (!is_compiled_scope.is_compiled() &&
1497 1656 : !Compiler::Compile(shared, Compiler::CLEAR_EXCEPTION,
1498 : &is_compiled_scope)) {
1499 : return false;
1500 : }
1501 10379 : CreateBreakInfo(shared);
1502 10379 : return true;
1503 : }
1504 :
1505 10433 : void Debug::CreateBreakInfo(Handle<SharedFunctionInfo> shared) {
1506 10433 : HandleScope scope(isolate_);
1507 10433 : Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
1508 :
1509 : // Initialize with break information.
1510 :
1511 : DCHECK(!debug_info->HasBreakInfo());
1512 :
1513 10433 : Factory* factory = isolate_->factory();
1514 : Handle<FixedArray> break_points(
1515 10433 : factory->NewFixedArray(DebugInfo::kEstimatedNofBreakPointsInFunction));
1516 :
1517 : int flags = debug_info->flags();
1518 10433 : flags |= DebugInfo::kHasBreakInfo;
1519 10433 : if (CanBreakAtEntry(shared)) flags |= DebugInfo::kCanBreakAtEntry;
1520 : debug_info->set_flags(flags);
1521 10433 : debug_info->set_break_points(*break_points);
1522 :
1523 10433 : SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate_, shared);
1524 10433 : }
1525 :
1526 396760 : Handle<DebugInfo> Debug::GetOrCreateDebugInfo(
1527 : Handle<SharedFunctionInfo> shared) {
1528 396760 : if (shared->HasDebugInfo()) return handle(shared->GetDebugInfo(), isolate_);
1529 :
1530 : // Create debug info and add it to the list.
1531 28634 : Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared);
1532 28634 : DebugInfoListNode* node = new DebugInfoListNode(isolate_, *debug_info);
1533 28634 : node->set_next(debug_info_list_);
1534 28634 : debug_info_list_ = node;
1535 :
1536 28634 : return debug_info;
1537 : }
1538 :
1539 880 : void Debug::InstallCoverageInfo(Handle<SharedFunctionInfo> shared,
1540 : Handle<CoverageInfo> coverage_info) {
1541 : DCHECK(!coverage_info.is_null());
1542 :
1543 880 : Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
1544 :
1545 : DCHECK(!debug_info->HasCoverageInfo());
1546 :
1547 880 : debug_info->set_flags(debug_info->flags() | DebugInfo::kHasCoverageInfo);
1548 1760 : debug_info->set_coverage_info(*coverage_info);
1549 880 : }
1550 :
1551 65678 : void Debug::RemoveAllCoverageInfos() {
1552 65679 : ClearAllDebugInfos(
1553 96990 : [=](Handle<DebugInfo> info) { info->ClearCoverageInfo(isolate_); });
1554 65679 : }
1555 :
1556 65437 : void Debug::ClearAllDebuggerHints() {
1557 65437 : ClearAllDebugInfos(
1558 65437 : [=](Handle<DebugInfo> info) { info->set_debugger_hints(0); });
1559 65437 : }
1560 :
1561 1426 : void Debug::FindDebugInfo(Handle<DebugInfo> debug_info,
1562 : DebugInfoListNode** prev, DebugInfoListNode** curr) {
1563 1426 : HandleScope scope(isolate_);
1564 1426 : *prev = nullptr;
1565 1426 : *curr = debug_info_list_;
1566 6390 : while (*curr != nullptr) {
1567 5334 : if ((*curr)->debug_info().is_identical_to(debug_info)) return;
1568 2482 : *prev = *curr;
1569 2482 : *curr = (*curr)->next();
1570 : }
1571 :
1572 0 : UNREACHABLE();
1573 : }
1574 :
1575 196551 : void Debug::ClearAllDebugInfos(const DebugInfoClearFunction& clear_function) {
1576 : DebugInfoListNode* prev = nullptr;
1577 196551 : DebugInfoListNode* current = debug_info_list_;
1578 253483 : while (current != nullptr) {
1579 : DebugInfoListNode* next = current->next();
1580 : Handle<DebugInfo> debug_info = current->debug_info();
1581 : clear_function(debug_info);
1582 56932 : if (debug_info->IsEmpty()) {
1583 27208 : FreeDebugInfoListNode(prev, current);
1584 : current = next;
1585 : } else {
1586 : prev = current;
1587 : current = next;
1588 : }
1589 : }
1590 196551 : }
1591 :
1592 1883 : void Debug::RemoveBreakInfoAndMaybeFree(Handle<DebugInfo> debug_info) {
1593 3766 : debug_info->ClearBreakInfo(isolate_);
1594 1883 : if (debug_info->IsEmpty()) {
1595 : DebugInfoListNode* prev;
1596 : DebugInfoListNode* node;
1597 1426 : FindDebugInfo(debug_info, &prev, &node);
1598 1426 : FreeDebugInfoListNode(prev, node);
1599 : }
1600 1883 : }
1601 :
1602 28634 : void Debug::FreeDebugInfoListNode(DebugInfoListNode* prev,
1603 : DebugInfoListNode* node) {
1604 : DCHECK(node->debug_info()->IsEmpty());
1605 :
1606 : // Unlink from list. If prev is nullptr we are looking at the first element.
1607 28634 : if (prev == nullptr) {
1608 26461 : debug_info_list_ = node->next();
1609 : } else {
1610 : prev->set_next(node->next());
1611 : }
1612 :
1613 : // Pack script back into the
1614 : // SFI::script_or_debug_info field.
1615 : Handle<DebugInfo> debug_info(node->debug_info());
1616 28634 : debug_info->shared()->set_script_or_debug_info(debug_info->script());
1617 :
1618 57268 : delete node;
1619 28634 : }
1620 :
1621 97497 : bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
1622 97497 : HandleScope scope(isolate_);
1623 :
1624 : // Get the executing function in which the debug break occurred.
1625 194994 : Handle<SharedFunctionInfo> shared(frame->function()->shared(), isolate_);
1626 :
1627 : // With no debug info there are no break points, so we can't be at a return.
1628 97497 : if (!shared->HasBreakInfo()) return false;
1629 :
1630 : DCHECK(!frame->is_optimized());
1631 89785 : Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_);
1632 89785 : BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
1633 89785 : return location.IsReturn();
1634 : }
1635 :
1636 324 : void Debug::ScheduleFrameRestart(StackFrame* frame) {
1637 : // Set a target FP for the FrameDropperTrampoline builtin to drop to once
1638 : // we return from the debugger.
1639 : DCHECK(frame->is_java_script());
1640 : // Only reschedule to a frame further below a frame we already scheduled for.
1641 633 : if (frame->fp() <= thread_local_.restart_fp_) return;
1642 : // If the frame is optimized, trigger a deopt and jump into the
1643 : // FrameDropperTrampoline in the deoptimizer.
1644 312 : thread_local_.restart_fp_ = frame->fp();
1645 :
1646 : // Reset break frame ID to the frame below the restarted frame.
1647 312 : StackTraceFrameIterator it(isolate_);
1648 312 : thread_local_.break_frame_id_ = StackFrame::NO_ID;
1649 3415 : for (StackTraceFrameIterator it(isolate_); !it.done(); it.Advance()) {
1650 3400 : if (it.frame()->fp() > thread_local_.restart_fp_) {
1651 594 : thread_local_.break_frame_id_ = it.frame()->id();
1652 : return;
1653 : }
1654 : }
1655 : }
1656 :
1657 118 : Handle<FixedArray> Debug::GetLoadedScripts() {
1658 118 : isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags,
1659 118 : GarbageCollectionReason::kDebugger);
1660 118 : Factory* factory = isolate_->factory();
1661 118 : if (!factory->script_list()->IsWeakArrayList()) {
1662 : return factory->empty_fixed_array();
1663 : }
1664 : Handle<WeakArrayList> array =
1665 : Handle<WeakArrayList>::cast(factory->script_list());
1666 118 : Handle<FixedArray> results = factory->NewFixedArray(array->length());
1667 : int length = 0;
1668 : {
1669 118 : Script::Iterator iterator(isolate_);
1670 1492 : for (Script script = iterator.Next(); !script.is_null();
1671 : script = iterator.Next()) {
1672 1256 : if (script->HasValidSource()) results->set(length++, script);
1673 : }
1674 : }
1675 118 : return FixedArray::ShrinkOrEmpty(isolate_, results, length);
1676 : }
1677 :
1678 1405489 : void Debug::OnThrow(Handle<Object> exception) {
1679 4205624 : if (in_debug_scope() || ignore_events()) return;
1680 : // Temporarily clear any scheduled_exception to allow evaluating
1681 : // JavaScript from the debug event handler.
1682 3891 : HandleScope scope(isolate_);
1683 : Handle<Object> scheduled_exception;
1684 7782 : if (isolate_->has_scheduled_exception()) {
1685 : scheduled_exception = handle(isolate_->scheduled_exception(), isolate_);
1686 0 : isolate_->clear_scheduled_exception();
1687 : }
1688 3891 : Handle<Object> maybe_promise = isolate_->GetPromiseOnStackOnThrow();
1689 3891 : OnException(exception, maybe_promise,
1690 : maybe_promise->IsJSPromise() ? v8::debug::kPromiseRejection
1691 3891 : : v8::debug::kException);
1692 3891 : if (!scheduled_exception.is_null()) {
1693 0 : isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception;
1694 : }
1695 3891 : PrepareStepOnThrow();
1696 : }
1697 :
1698 9136 : void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) {
1699 18272 : if (in_debug_scope() || ignore_events()) return;
1700 889 : HandleScope scope(isolate_);
1701 : // Check whether the promise has been marked as having triggered a message.
1702 889 : Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
1703 1649 : if (!promise->IsJSObject() ||
1704 760 : JSReceiver::GetDataProperty(Handle<JSObject>::cast(promise), key)
1705 760 : ->IsUndefined(isolate_)) {
1706 816 : OnException(value, promise, v8::debug::kPromiseRejection);
1707 : }
1708 : }
1709 :
1710 1934 : bool Debug::IsExceptionBlackboxed(bool uncaught) {
1711 : // Uncaught exception is blackboxed if all current frames are blackboxed,
1712 : // caught exception if top frame is blackboxed.
1713 1934 : StackTraceFrameIterator it(isolate_);
1714 3868 : while (!it.done() && it.is_wasm()) it.Advance();
1715 : bool is_top_frame_blackboxed =
1716 1934 : !it.done() ? IsFrameBlackboxed(it.javascript_frame()) : true;
1717 1934 : if (!uncaught || !is_top_frame_blackboxed) return is_top_frame_blackboxed;
1718 10 : return AllFramesOnStackAreBlackboxed();
1719 : }
1720 :
1721 62367 : bool Debug::IsFrameBlackboxed(JavaScriptFrame* frame) {
1722 62367 : HandleScope scope(isolate_);
1723 : std::vector<Handle<SharedFunctionInfo>> infos;
1724 62367 : frame->GetFunctions(&infos);
1725 62537 : for (const auto& info : infos) {
1726 62367 : if (!IsBlackboxed(info)) return false;
1727 : }
1728 : return true;
1729 : }
1730 :
1731 4707 : void Debug::OnException(Handle<Object> exception, Handle<Object> promise,
1732 : v8::debug::ExceptionType exception_type) {
1733 : // TODO(kozyatinskiy): regress-662674.js test fails on arm without this.
1734 7520 : if (!AllowJavascriptExecution::IsAllowed(isolate_)) return;
1735 :
1736 4685 : Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher();
1737 :
1738 : // Don't notify listener of exceptions that are internal to a desugaring.
1739 4685 : if (catch_type == Isolate::CAUGHT_BY_DESUGARING) return;
1740 :
1741 4685 : bool uncaught = catch_type == Isolate::NOT_CAUGHT;
1742 4685 : if (promise->IsJSObject()) {
1743 : Handle<JSObject> jspromise = Handle<JSObject>::cast(promise);
1744 : // Mark the promise as already having triggered a message.
1745 1943 : Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
1746 1943 : Object::SetProperty(isolate_, jspromise, key, key, StoreOrigin::kMaybeKeyed,
1747 1943 : Just(ShouldThrow::kThrowOnError))
1748 : .Assert();
1749 : // Check whether the promise reject is considered an uncaught exception.
1750 1943 : uncaught = !isolate_->PromiseHasUserDefinedRejectHandler(jspromise);
1751 : }
1752 :
1753 4685 : if (!debug_delegate_) return;
1754 :
1755 : // Bail out if exception breaks are not active
1756 4685 : if (uncaught) {
1757 : // Uncaught exceptions are reported by either flags.
1758 1299 : if (!(break_on_uncaught_exception_ || break_on_exception_)) return;
1759 : } else {
1760 : // Caught exceptions are reported is activated.
1761 3386 : if (!break_on_exception_) return;
1762 : }
1763 :
1764 : {
1765 2017 : JavaScriptFrameIterator it(isolate_);
1766 : // Check whether the top frame is blackboxed or the break location is muted.
1767 3951 : if (!it.done() && (IsMutedAtCurrentLocation(it.frame()) ||
1768 1934 : IsExceptionBlackboxed(uncaught))) {
1769 : return;
1770 : }
1771 1914 : if (it.done()) return; // Do not trigger an event with an empty stack.
1772 : }
1773 :
1774 3788 : DebugScope debug_scope(this);
1775 1894 : HandleScope scope(isolate_);
1776 : DisableBreak no_recursive_break(this);
1777 :
1778 1894 : Handle<Context> native_context(isolate_->native_context());
1779 3788 : debug_delegate_->ExceptionThrown(
1780 : v8::Utils::ToLocal(native_context), v8::Utils::ToLocal(exception),
1781 3788 : v8::Utils::ToLocal(promise), uncaught, exception_type);
1782 : }
1783 :
1784 127946 : void Debug::OnDebugBreak(Handle<FixedArray> break_points_hit) {
1785 : DCHECK(!break_points_hit.is_null());
1786 : // The caller provided for DebugScope.
1787 : AssertDebugContext();
1788 : // Bail out if there is no listener for this event
1789 127946 : if (ignore_events()) return;
1790 :
1791 : #ifdef DEBUG
1792 : PrintBreakLocation();
1793 : #endif // DEBUG
1794 :
1795 127946 : if (!debug_delegate_) return;
1796 : DCHECK(in_debug_scope());
1797 127946 : HandleScope scope(isolate_);
1798 : DisableBreak no_recursive_break(this);
1799 :
1800 : std::vector<int> inspector_break_points_hit;
1801 : int inspector_break_points_count = 0;
1802 : // This array contains breakpoints installed using JS debug API.
1803 135736 : for (int i = 0; i < break_points_hit->length(); ++i) {
1804 : BreakPoint break_point = BreakPoint::cast(break_points_hit->get(i));
1805 7790 : inspector_break_points_hit.push_back(break_point->id());
1806 : ++inspector_break_points_count;
1807 : }
1808 :
1809 127946 : Handle<Context> native_context(isolate_->native_context());
1810 127946 : debug_delegate_->BreakProgramRequested(v8::Utils::ToLocal(native_context),
1811 127946 : inspector_break_points_hit);
1812 : }
1813 :
1814 : namespace {
1815 24758 : debug::Location GetDebugLocation(Handle<Script> script, int source_position) {
1816 : Script::PositionInfo info;
1817 24758 : Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET);
1818 : // V8 provides ScriptCompiler::CompileFunctionInContext method which takes
1819 : // expression and compile it as anonymous function like (function() ..
1820 : // expression ..). To produce correct locations for stmts inside of this
1821 : // expression V8 compile this function with negative offset. Instead of stmt
1822 : // position blackboxing use function start position which is negative in
1823 : // described case.
1824 74274 : return debug::Location(std::max(info.line, 0), std::max(info.column, 0));
1825 : }
1826 : } // namespace
1827 :
1828 170621 : bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) {
1829 170621 : if (!debug_delegate_) return !shared->IsSubjectToDebugging();
1830 170621 : Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
1831 170621 : if (!debug_info->computed_debug_is_blackboxed()) {
1832 : bool is_blackboxed =
1833 37964 : !shared->IsSubjectToDebugging() || !shared->script()->IsScript();
1834 13206 : if (!is_blackboxed) {
1835 : SuppressDebug while_processing(this);
1836 12379 : HandleScope handle_scope(isolate_);
1837 12379 : PostponeInterruptsScope no_interrupts(isolate_);
1838 : DisableBreak no_recursive_break(this);
1839 : DCHECK(shared->script()->IsScript());
1840 37137 : Handle<Script> script(Script::cast(shared->script()), isolate_);
1841 : DCHECK(script->IsUserJavaScript());
1842 12379 : debug::Location start = GetDebugLocation(script, shared->StartPosition());
1843 12379 : debug::Location end = GetDebugLocation(script, shared->EndPosition());
1844 12379 : is_blackboxed = debug_delegate_->IsFunctionBlackboxed(
1845 12379 : ToApiHandle<debug::Script>(script), start, end);
1846 : }
1847 26412 : debug_info->set_debug_is_blackboxed(is_blackboxed);
1848 13206 : debug_info->set_computed_debug_is_blackboxed(true);
1849 : }
1850 : return debug_info->debug_is_blackboxed();
1851 : }
1852 :
1853 60588 : bool Debug::AllFramesOnStackAreBlackboxed() {
1854 60588 : HandleScope scope(isolate_);
1855 60713 : for (StackTraceFrameIterator it(isolate_); !it.done(); it.Advance()) {
1856 60433 : if (!it.is_javascript()) continue;
1857 60433 : if (!IsFrameBlackboxed(it.javascript_frame())) return false;
1858 : }
1859 280 : return true;
1860 : }
1861 :
1862 10583 : bool Debug::CanBreakAtEntry(Handle<SharedFunctionInfo> shared) {
1863 : // Allow break at entry for builtin functions.
1864 20946 : if (shared->native() || shared->IsApiFunction()) {
1865 : // Functions that are subject to debugging can have regular breakpoints.
1866 : DCHECK(!shared->IsSubjectToDebugging());
1867 : return true;
1868 : }
1869 10283 : return false;
1870 : }
1871 :
1872 50 : bool Debug::SetScriptSource(Handle<Script> script, Handle<String> source,
1873 : bool preview, debug::LiveEditResult* result) {
1874 100 : DebugScope debug_scope(this);
1875 50 : running_live_edit_ = true;
1876 50 : LiveEdit::PatchScript(isolate_, script, source, preview, result);
1877 50 : running_live_edit_ = false;
1878 100 : return result->status == debug::LiveEditResult::OK;
1879 : }
1880 :
1881 384223 : void Debug::OnCompileError(Handle<Script> script) {
1882 384223 : ProcessCompileEvent(true, script);
1883 384223 : }
1884 :
1885 3869047 : void Debug::OnAfterCompile(Handle<Script> script) {
1886 3869047 : ProcessCompileEvent(false, script);
1887 3869050 : }
1888 :
1889 4253275 : void Debug::ProcessCompileEvent(bool has_compile_error, Handle<Script> script) {
1890 : // TODO(kozyatinskiy): teach devtools to work with liveedit scripts better
1891 : // first and then remove this fast return.
1892 8480896 : if (running_live_edit_) return;
1893 : // Attach the correct debug id to the script. The debug id is used by the
1894 : // inspector to filter scripts by native context.
1895 12759794 : script->set_context_data(isolate_->native_context()->debug_context_id());
1896 4253264 : if (ignore_events()) return;
1897 26249 : if (!script->IsUserJavaScript() && script->type() != i::Script::TYPE_WASM) {
1898 : return;
1899 : }
1900 25651 : if (!debug_delegate_) return;
1901 : SuppressDebug while_processing(this);
1902 51302 : DebugScope debug_scope(this);
1903 25651 : HandleScope scope(isolate_);
1904 : DisableBreak no_recursive_break(this);
1905 51302 : AllowJavascriptExecution allow_script(isolate_);
1906 76953 : debug_delegate_->ScriptCompiled(ToApiHandle<debug::Script>(script),
1907 76953 : running_live_edit_, has_compile_error);
1908 : }
1909 :
1910 121501 : int Debug::CurrentFrameCount() {
1911 121501 : StackTraceFrameIterator it(isolate_);
1912 121501 : if (break_frame_id() != StackFrame::NO_ID) {
1913 : // Skip to break frame.
1914 : DCHECK(in_debug_scope());
1915 1043916 : while (!it.done() && it.frame()->id() != break_frame_id()) it.Advance();
1916 : }
1917 : int counter = 0;
1918 214648 : while (!it.done()) {
1919 429296 : if (it.frame()->is_optimized()) {
1920 : std::vector<SharedFunctionInfo> infos;
1921 6081 : OptimizedFrame::cast(it.frame())->GetFunctions(&infos);
1922 6081 : counter += infos.size();
1923 : } else {
1924 208567 : counter++;
1925 : }
1926 214648 : it.Advance();
1927 : }
1928 121501 : return counter;
1929 : }
1930 :
1931 7918 : void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) {
1932 7918 : debug_delegate_ = delegate;
1933 7918 : UpdateState();
1934 7918 : }
1935 :
1936 520368 : void Debug::UpdateState() {
1937 520368 : bool is_active = debug_delegate_ != nullptr;
1938 520368 : if (is_active == is_active_) return;
1939 7878 : if (is_active) {
1940 : // Note that the debug context could have already been loaded to
1941 : // bootstrap test cases.
1942 3959 : isolate_->compilation_cache()->Disable();
1943 : is_active = true;
1944 : feature_tracker()->Track(DebugFeatureTracker::kActive);
1945 : } else {
1946 3919 : isolate_->compilation_cache()->Enable();
1947 3919 : Unload();
1948 : }
1949 7878 : is_active_ = is_active;
1950 7878 : isolate_->PromiseHookStateUpdated();
1951 : }
1952 :
1953 0 : void Debug::UpdateHookOnFunctionCall() {
1954 : STATIC_ASSERT(LastStepAction == StepIn);
1955 : hook_on_function_call_ =
1956 492573 : thread_local_.last_step_action_ == StepIn ||
1957 411034 : isolate_->debug_execution_mode() == DebugInfo::kSideEffects ||
1958 417911 : thread_local_.break_on_next_function_call_;
1959 0 : }
1960 :
1961 68671 : void Debug::HandleDebugBreak(IgnoreBreakMode ignore_break_mode) {
1962 : // Initialize LiveEdit.
1963 68671 : LiveEdit::InitializeThreadLocal(this);
1964 : // Ignore debug break during bootstrapping.
1965 68818 : if (isolate_->bootstrapper()->IsActive()) return;
1966 : // Just continue if breaks are disabled.
1967 68671 : if (break_disabled()) return;
1968 : // Ignore debug break if debugger is not active.
1969 68662 : if (!is_active()) return;
1970 :
1971 : StackLimitCheck check(isolate_);
1972 68557 : if (check.HasOverflowed()) return;
1973 :
1974 68557 : { JavaScriptFrameIterator it(isolate_);
1975 : DCHECK(!it.done());
1976 68557 : Object fun = it.frame()->function();
1977 68557 : if (fun->IsJSFunction()) {
1978 68557 : HandleScope scope(isolate_);
1979 68557 : Handle<JSFunction> function(JSFunction::cast(fun), isolate_);
1980 : // Don't stop in builtin and blackboxed functions.
1981 68557 : Handle<SharedFunctionInfo> shared(function->shared(), isolate_);
1982 : bool ignore_break = ignore_break_mode == kIgnoreIfTopFrameBlackboxed
1983 : ? IsBlackboxed(shared)
1984 68557 : : AllFramesOnStackAreBlackboxed();
1985 68557 : if (ignore_break) return;
1986 : // Don't stop if the break location is muted.
1987 68542 : if (IsMutedAtCurrentLocation(it.frame())) return;
1988 : }
1989 : }
1990 :
1991 : // Clear stepping to avoid duplicate breaks.
1992 68524 : ClearStepping();
1993 :
1994 68524 : HandleScope scope(isolate_);
1995 137048 : DebugScope debug_scope(this);
1996 :
1997 137048 : OnDebugBreak(isolate_->factory()->empty_fixed_array());
1998 : }
1999 :
2000 : #ifdef DEBUG
2001 : void Debug::PrintBreakLocation() {
2002 : if (!FLAG_print_break_location) return;
2003 : HandleScope scope(isolate_);
2004 : StackTraceFrameIterator iterator(isolate_);
2005 : if (iterator.done()) return;
2006 : StandardFrame* frame = iterator.frame();
2007 : FrameSummary summary = FrameSummary::GetTop(frame);
2008 : int source_position = summary.SourcePosition();
2009 : Handle<Object> script_obj = summary.script();
2010 : PrintF("[debug] break in function '");
2011 : summary.FunctionName()->PrintOn(stdout);
2012 : PrintF("'.\n");
2013 : if (script_obj->IsScript()) {
2014 : Handle<Script> script = Handle<Script>::cast(script_obj);
2015 : Handle<String> source(String::cast(script->source()), isolate_);
2016 : Script::InitLineEnds(script);
2017 : int line =
2018 : Script::GetLineNumber(script, source_position) - script->line_offset();
2019 : int column = Script::GetColumnNumber(script, source_position) -
2020 : (line == 0 ? script->column_offset() : 0);
2021 : Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()),
2022 : isolate_);
2023 : int line_start = line == 0 ? 0 : Smi::ToInt(line_ends->get(line - 1)) + 1;
2024 : int line_end = Smi::ToInt(line_ends->get(line));
2025 : DisallowHeapAllocation no_gc;
2026 : String::FlatContent content = source->GetFlatContent(no_gc);
2027 : if (content.IsOneByte()) {
2028 : PrintF("[debug] %.*s\n", line_end - line_start,
2029 : content.ToOneByteVector().start() + line_start);
2030 : PrintF("[debug] ");
2031 : for (int i = 0; i < column; i++) PrintF(" ");
2032 : PrintF("^\n");
2033 : } else {
2034 : PrintF("[debug] at line %d column %d\n", line, column);
2035 : }
2036 : }
2037 : }
2038 : #endif // DEBUG
2039 :
2040 256225 : DebugScope::DebugScope(Debug* debug)
2041 : : debug_(debug),
2042 : prev_(reinterpret_cast<DebugScope*>(
2043 256225 : base::Relaxed_Load(&debug->thread_local_.current_debug_scope_))),
2044 512450 : no_interrupts_(debug_->isolate_) {
2045 : // Link recursive debugger entry.
2046 256225 : base::Relaxed_Store(&debug_->thread_local_.current_debug_scope_,
2047 : reinterpret_cast<base::AtomicWord>(this));
2048 :
2049 : // Store the previous frame id and return value.
2050 256225 : break_frame_id_ = debug_->break_frame_id();
2051 :
2052 : // Create the new break info. If there is no proper frames there is no break
2053 : // frame id.
2054 256225 : StackTraceFrameIterator it(isolate());
2055 : bool has_frames = !it.done();
2056 256225 : debug_->thread_local_.break_frame_id_ =
2057 512450 : has_frames ? it.frame()->id() : StackFrame::NO_ID;
2058 :
2059 256225 : debug_->UpdateState();
2060 256225 : }
2061 :
2062 :
2063 512450 : DebugScope::~DebugScope() {
2064 : // Leaving this debugger entry.
2065 256225 : base::Relaxed_Store(&debug_->thread_local_.current_debug_scope_,
2066 256225 : reinterpret_cast<base::AtomicWord>(prev_));
2067 :
2068 : // Restore to the previous break state.
2069 256225 : debug_->thread_local_.break_frame_id_ = break_frame_id_;
2070 :
2071 256225 : debug_->UpdateState();
2072 256225 : }
2073 :
2074 66685 : ReturnValueScope::ReturnValueScope(Debug* debug) : debug_(debug) {
2075 66685 : return_value_ = debug_->return_value_handle();
2076 66685 : }
2077 :
2078 133370 : ReturnValueScope::~ReturnValueScope() {
2079 66685 : debug_->set_return_value(*return_value_);
2080 66685 : }
2081 :
2082 16274 : void Debug::UpdateDebugInfosForExecutionMode() {
2083 : // Walk all debug infos and update their execution mode if it is different
2084 : // from the isolate execution mode.
2085 16274 : DebugInfoListNode* current = debug_info_list_;
2086 6632958 : while (current != nullptr) {
2087 : Handle<DebugInfo> debug_info = current->debug_info();
2088 6629799 : if (debug_info->HasInstrumentedBytecodeArray() &&
2089 3321457 : debug_info->DebugExecutionMode() != isolate_->debug_execution_mode()) {
2090 : DCHECK(debug_info->shared()->HasBytecodeArray());
2091 13115 : if (isolate_->debug_execution_mode() == DebugInfo::kBreakpoints) {
2092 6732 : ClearSideEffectChecks(debug_info);
2093 6732 : ApplyBreakPoints(debug_info);
2094 : } else {
2095 6383 : ClearBreakPoints(debug_info);
2096 6383 : ApplySideEffectChecks(debug_info);
2097 : }
2098 : }
2099 : current = current->next();
2100 : }
2101 16274 : }
2102 :
2103 8139 : void Debug::StartSideEffectCheckMode() {
2104 : DCHECK(isolate_->debug_execution_mode() != DebugInfo::kSideEffects);
2105 8139 : isolate_->set_debug_execution_mode(DebugInfo::kSideEffects);
2106 : UpdateHookOnFunctionCall();
2107 8139 : side_effect_check_failed_ = false;
2108 :
2109 : DCHECK(!temporary_objects_);
2110 8139 : temporary_objects_.reset(new TemporaryObjectsTracker());
2111 16278 : isolate_->heap()->AddHeapObjectAllocationTracker(temporary_objects_.get());
2112 24417 : Handle<FixedArray> array(isolate_->native_context()->regexp_last_match_info(),
2113 : isolate_);
2114 : regexp_match_info_ =
2115 8139 : Handle<RegExpMatchInfo>::cast(isolate_->factory()->CopyFixedArray(array));
2116 :
2117 : // Update debug infos to have correct execution mode.
2118 8139 : UpdateDebugInfosForExecutionMode();
2119 8139 : }
2120 :
2121 8135 : void Debug::StopSideEffectCheckMode() {
2122 : DCHECK(isolate_->debug_execution_mode() == DebugInfo::kSideEffects);
2123 8135 : if (side_effect_check_failed_) {
2124 : DCHECK(isolate_->has_pending_exception());
2125 : DCHECK_EQ(ReadOnlyRoots(isolate_).termination_exception(),
2126 : isolate_->pending_exception());
2127 : // Convert the termination exception into a regular exception.
2128 3029 : isolate_->CancelTerminateExecution();
2129 9087 : isolate_->Throw(*isolate_->factory()->NewEvalError(
2130 6058 : MessageTemplate::kNoSideEffectDebugEvaluate));
2131 : }
2132 8135 : isolate_->set_debug_execution_mode(DebugInfo::kBreakpoints);
2133 : UpdateHookOnFunctionCall();
2134 8135 : side_effect_check_failed_ = false;
2135 :
2136 : DCHECK(temporary_objects_);
2137 16270 : isolate_->heap()->RemoveHeapObjectAllocationTracker(temporary_objects_.get());
2138 : temporary_objects_.reset();
2139 16270 : isolate_->native_context()->set_regexp_last_match_info(*regexp_match_info_);
2140 8135 : regexp_match_info_ = Handle<RegExpMatchInfo>::null();
2141 :
2142 : // Update debug infos to have correct execution mode.
2143 8135 : UpdateDebugInfosForExecutionMode();
2144 8135 : }
2145 :
2146 6759 : void Debug::ApplySideEffectChecks(Handle<DebugInfo> debug_info) {
2147 : DCHECK(debug_info->HasInstrumentedBytecodeArray());
2148 : Handle<BytecodeArray> debug_bytecode(debug_info->DebugBytecodeArray(),
2149 6759 : isolate_);
2150 6759 : DebugEvaluate::ApplySideEffectChecks(debug_bytecode);
2151 6759 : debug_info->SetDebugExecutionMode(DebugInfo::kSideEffects);
2152 6759 : }
2153 :
2154 6732 : void Debug::ClearSideEffectChecks(Handle<DebugInfo> debug_info) {
2155 : DCHECK(debug_info->HasInstrumentedBytecodeArray());
2156 : Handle<BytecodeArray> debug_bytecode(debug_info->DebugBytecodeArray(),
2157 6732 : isolate_);
2158 6732 : Handle<BytecodeArray> original(debug_info->OriginalBytecodeArray(), isolate_);
2159 142537 : for (interpreter::BytecodeArrayIterator it(debug_bytecode); !it.done();
2160 135805 : it.Advance()) {
2161 : // Restore from original. This may copy only the scaling prefix, which is
2162 : // correct, since we patch scaling prefixes to debug breaks if exists.
2163 : debug_bytecode->set(it.current_offset(),
2164 : original->get(it.current_offset()));
2165 : }
2166 6732 : }
2167 :
2168 13770 : bool Debug::PerformSideEffectCheck(Handle<JSFunction> function,
2169 : Handle<Object> receiver) {
2170 : DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects);
2171 27540 : DisallowJavascriptExecution no_js(isolate_);
2172 13770 : IsCompiledScope is_compiled_scope(function->shared()->is_compiled_scope());
2173 14377 : if (!function->is_compiled() &&
2174 607 : !Compiler::Compile(function, Compiler::KEEP_EXCEPTION,
2175 : &is_compiled_scope)) {
2176 : return false;
2177 : }
2178 : DCHECK(is_compiled_scope.is_compiled());
2179 13770 : Handle<SharedFunctionInfo> shared(function->shared(), isolate_);
2180 13770 : Handle<DebugInfo> debug_info = GetOrCreateDebugInfo(shared);
2181 : DebugInfo::SideEffectState side_effect_state =
2182 27540 : debug_info->GetSideEffectState(isolate_);
2183 13770 : switch (side_effect_state) {
2184 : case DebugInfo::kHasSideEffects:
2185 2313 : if (FLAG_trace_side_effect_free_debug_evaluate) {
2186 : PrintF("[debug-evaluate] Function %s failed side effect check.\n",
2187 0 : function->shared()->DebugName()->ToCString().get());
2188 : }
2189 2313 : side_effect_check_failed_ = true;
2190 : // Throw an uncatchable termination exception.
2191 2313 : isolate_->TerminateExecution();
2192 2313 : return false;
2193 : case DebugInfo::kRequiresRuntimeChecks: {
2194 1253 : if (!shared->HasBytecodeArray()) {
2195 877 : return PerformSideEffectCheckForObject(receiver);
2196 : }
2197 : // If function has bytecode array then prepare function for debug
2198 : // execution to perform runtime side effect checks.
2199 : DCHECK(shared->is_compiled());
2200 376 : PrepareFunctionForDebugExecution(shared);
2201 376 : ApplySideEffectChecks(debug_info);
2202 376 : return true;
2203 : }
2204 : case DebugInfo::kHasNoSideEffect:
2205 : return true;
2206 : case DebugInfo::kNotComputed:
2207 0 : UNREACHABLE();
2208 : return false;
2209 : }
2210 0 : UNREACHABLE();
2211 : return false;
2212 : }
2213 :
2214 77117 : Handle<Object> Debug::return_value_handle() {
2215 154234 : return handle(thread_local_.return_value_, isolate_);
2216 : }
2217 :
2218 421 : bool Debug::PerformSideEffectCheckForCallback(
2219 : Handle<Object> callback_info, Handle<Object> receiver,
2220 : Debug::AccessorKind accessor_kind) {
2221 : DCHECK_EQ(!receiver.is_null(), callback_info->IsAccessorInfo());
2222 : DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects);
2223 1402 : if (!callback_info.is_null() && callback_info->IsCallHandlerInfo() &&
2224 560 : i::CallHandlerInfo::cast(*callback_info)->NextCallHasNoSideEffect()) {
2225 : return true;
2226 : }
2227 : // TODO(7515): always pass a valid callback info object.
2228 411 : if (!callback_info.is_null()) {
2229 411 : if (callback_info->IsAccessorInfo()) {
2230 : // List of whitelisted internal accessors can be found in accessors.h.
2231 : AccessorInfo info = AccessorInfo::cast(*callback_info);
2232 : DCHECK_NE(kNotAccessor, accessor_kind);
2233 492 : switch (accessor_kind == kSetter ? info->setter_side_effect_type()
2234 : : info->getter_side_effect_type()) {
2235 : case SideEffectType::kHasNoSideEffect:
2236 : // We do not support setter accessors with no side effects, since
2237 : // calling set accessors go through a store bytecode. Store bytecodes
2238 : // are considered to cause side effects (to non-temporary objects).
2239 : DCHECK_NE(kSetter, accessor_kind);
2240 : return true;
2241 : case SideEffectType::kHasSideEffectToReceiver:
2242 : DCHECK(!receiver.is_null());
2243 64 : if (PerformSideEffectCheckForObject(receiver)) return true;
2244 9 : isolate_->OptionalRescheduleException(false);
2245 9 : return false;
2246 : case SideEffectType::kHasSideEffect:
2247 : break;
2248 : }
2249 30 : if (FLAG_trace_side_effect_free_debug_evaluate) {
2250 0 : PrintF("[debug-evaluate] API Callback '");
2251 0 : info->name()->ShortPrint();
2252 0 : PrintF("' may cause side effect.\n");
2253 : }
2254 165 : } else if (callback_info->IsInterceptorInfo()) {
2255 : InterceptorInfo info = InterceptorInfo::cast(*callback_info);
2256 36 : if (info->has_no_side_effect()) return true;
2257 18 : if (FLAG_trace_side_effect_free_debug_evaluate) {
2258 0 : PrintF("[debug-evaluate] API Interceptor may cause side effect.\n");
2259 : }
2260 129 : } else if (callback_info->IsCallHandlerInfo()) {
2261 129 : CallHandlerInfo info = CallHandlerInfo::cast(*callback_info);
2262 129 : if (info->IsSideEffectFreeCallHandlerInfo()) return true;
2263 64 : if (FLAG_trace_side_effect_free_debug_evaluate) {
2264 0 : PrintF("[debug-evaluate] API CallHandlerInfo may cause side effect.\n");
2265 : }
2266 : }
2267 : }
2268 112 : side_effect_check_failed_ = true;
2269 : // Throw an uncatchable termination exception.
2270 112 : isolate_->TerminateExecution();
2271 112 : isolate_->OptionalRescheduleException(false);
2272 112 : return false;
2273 : }
2274 :
2275 2333 : bool Debug::PerformSideEffectCheckAtBytecode(InterpretedFrame* frame) {
2276 : using interpreter::Bytecode;
2277 :
2278 : DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects);
2279 4666 : SharedFunctionInfo shared = frame->function()->shared();
2280 2333 : BytecodeArray bytecode_array = shared->GetBytecodeArray();
2281 2333 : int offset = frame->GetBytecodeOffset();
2282 : interpreter::BytecodeArrayAccessor bytecode_accessor(
2283 4666 : handle(bytecode_array, isolate_), offset);
2284 :
2285 2333 : Bytecode bytecode = bytecode_accessor.current_bytecode();
2286 : interpreter::Register reg;
2287 2333 : switch (bytecode) {
2288 : case Bytecode::kStaCurrentContextSlot:
2289 49 : reg = interpreter::Register::current_context();
2290 49 : break;
2291 : default:
2292 2284 : reg = bytecode_accessor.GetRegisterOperand(0);
2293 2284 : break;
2294 : }
2295 : Handle<Object> object =
2296 4666 : handle(frame->ReadInterpreterRegister(reg.index()), isolate_);
2297 2333 : return PerformSideEffectCheckForObject(object);
2298 : }
2299 :
2300 3328 : bool Debug::PerformSideEffectCheckForObject(Handle<Object> object) {
2301 : DCHECK_EQ(isolate_->debug_execution_mode(), DebugInfo::kSideEffects);
2302 :
2303 : // We expect no side-effects for primitives.
2304 3328 : if (object->IsNumber()) return true;
2305 3328 : if (object->IsName()) return true;
2306 :
2307 3319 : if (temporary_objects_->HasObject(Handle<HeapObject>::cast(object))) {
2308 : return true;
2309 : }
2310 :
2311 604 : if (FLAG_trace_side_effect_free_debug_evaluate) {
2312 0 : PrintF("[debug-evaluate] failed runtime side effect check.\n");
2313 : }
2314 604 : side_effect_check_failed_ = true;
2315 : // Throw an uncatchable termination exception.
2316 604 : isolate_->TerminateExecution();
2317 604 : return false;
2318 : }
2319 : } // namespace internal
2320 120216 : } // namespace v8
|