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