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