Line data Source code
1 : // Copyright 2017 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-stack-trace-iterator.h"
6 :
7 : #include "src/api-inl.h"
8 : #include "src/debug/debug-evaluate.h"
9 : #include "src/debug/debug-scope-iterator.h"
10 : #include "src/debug/debug.h"
11 : #include "src/debug/liveedit.h"
12 : #include "src/frames-inl.h"
13 : #include "src/isolate.h"
14 :
15 : namespace v8 {
16 :
17 111695 : std::unique_ptr<debug::StackTraceIterator> debug::StackTraceIterator::Create(
18 : v8::Isolate* isolate, int index) {
19 : return std::unique_ptr<debug::StackTraceIterator>(
20 : new internal::DebugStackTraceIterator(
21 223390 : reinterpret_cast<internal::Isolate*>(isolate), index));
22 : }
23 :
24 : namespace internal {
25 :
26 111695 : DebugStackTraceIterator::DebugStackTraceIterator(Isolate* isolate, int index)
27 : : isolate_(isolate),
28 : iterator_(isolate, isolate->debug()->break_frame_id()),
29 223390 : is_top_frame_(true) {
30 111695 : if (iterator_.done()) return;
31 111695 : std::vector<FrameSummary> frames;
32 111695 : iterator_.frame()->Summarize(&frames);
33 111695 : inlined_frame_index_ = static_cast<int>(frames.size());
34 111695 : Advance();
35 120551 : for (; !Done() && index > 0; --index) Advance();
36 : }
37 :
38 : DebugStackTraceIterator::~DebugStackTraceIterator() = default;
39 :
40 517740 : bool DebugStackTraceIterator::Done() const { return iterator_.done(); }
41 :
42 312169 : void DebugStackTraceIterator::Advance() {
43 131407 : while (true) {
44 443576 : --inlined_frame_index_;
45 443632 : for (; inlined_frame_index_ >= 0; --inlined_frame_index_) {
46 : // Omit functions from native and extension scripts.
47 249695 : if (FrameSummary::Get(iterator_.frame(), inlined_frame_index_)
48 : .is_subject_to_debugging()) {
49 : break;
50 : }
51 28 : is_top_frame_ = false;
52 : }
53 443576 : if (inlined_frame_index_ >= 0) {
54 499334 : frame_inspector_.reset(new FrameInspector(
55 499334 : iterator_.frame(), inlined_frame_index_, isolate_));
56 249667 : break;
57 : }
58 193909 : is_top_frame_ = false;
59 193909 : frame_inspector_.reset();
60 193909 : iterator_.Advance();
61 193909 : if (iterator_.done()) break;
62 131407 : std::vector<FrameSummary> frames;
63 131407 : iterator_.frame()->Summarize(&frames);
64 131407 : inlined_frame_index_ = static_cast<int>(frames.size());
65 : }
66 312169 : }
67 :
68 147165 : int DebugStackTraceIterator::GetContextId() const {
69 : DCHECK(!Done());
70 147165 : Handle<Object> context = frame_inspector_->GetContext();
71 147165 : if (context->IsContext()) {
72 : Object value =
73 147070 : Context::cast(*context)->native_context()->debug_context_id();
74 294140 : if (value->IsSmi()) return Smi::ToInt(value);
75 : }
76 : return 0;
77 : }
78 :
79 147060 : v8::MaybeLocal<v8::Value> DebugStackTraceIterator::GetReceiver() const {
80 : DCHECK(!Done());
81 293656 : if (frame_inspector_->IsJavaScript() &&
82 : frame_inspector_->GetFunction()->shared()->kind() == kArrowFunction) {
83 : // FrameInspector is not able to get receiver for arrow function.
84 : // So let's try to fetch it using same logic as is used to retrieve 'this'
85 : // during DebugEvaluate::Local.
86 : Handle<JSFunction> function = frame_inspector_->GetFunction();
87 2450 : Handle<Context> context(function->context(), isolate_);
88 : // Arrow function defined in top level function without references to
89 : // variables may have NativeContext as context.
90 2450 : if (!context->IsFunctionContext()) return v8::MaybeLocal<v8::Value>();
91 439 : ScopeIterator scope_iterator(isolate_, frame_inspector_.get(),
92 878 : ScopeIterator::COLLECT_NON_LOCALS);
93 : // We lookup this variable in function context only when it is used in arrow
94 : // function otherwise V8 can optimize it out.
95 878 : if (!scope_iterator.GetNonLocals()->Has(isolate_,
96 439 : isolate_->factory()->this_string()))
97 362 : return v8::MaybeLocal<v8::Value>();
98 : DisallowHeapAllocation no_gc;
99 : VariableMode mode;
100 : InitializationFlag flag;
101 : MaybeAssignedFlag maybe_assigned_flag;
102 154 : int slot_index = ScopeInfo::ContextSlotIndex(
103 77 : context->scope_info(), ReadOnlyRoots(isolate_->heap()).this_string(),
104 77 : &mode, &flag, &maybe_assigned_flag);
105 77 : if (slot_index < 0) return v8::MaybeLocal<v8::Value>();
106 77 : Handle<Object> value = handle(context->get(slot_index), isolate_);
107 154 : if (value->IsTheHole(isolate_)) return v8::MaybeLocal<v8::Value>();
108 77 : return Utils::ToLocal(value);
109 : }
110 : Handle<Object> value = frame_inspector_->GetReceiver();
111 433821 : if (value.is_null() || (value->IsSmi() || !value->IsTheHole(isolate_))) {
112 144325 : return Utils::ToLocal(value);
113 : }
114 285 : return v8::MaybeLocal<v8::Value>();
115 : }
116 :
117 191613 : v8::Local<v8::Value> DebugStackTraceIterator::GetReturnValue() const {
118 : DCHECK(!Done());
119 191613 : if (frame_inspector_ && frame_inspector_->IsWasm()) {
120 792 : return v8::Local<v8::Value>();
121 : }
122 190821 : bool is_optimized = iterator_.frame()->is_optimized();
123 288337 : if (is_optimized || !is_top_frame_ ||
124 97516 : !isolate_->debug()->IsBreakAtReturn(iterator_.javascript_frame())) {
125 180389 : return v8::Local<v8::Value>();
126 : }
127 10432 : return Utils::ToLocal(isolate_->debug()->return_value_handle());
128 : }
129 :
130 147155 : v8::Local<v8::String> DebugStackTraceIterator::GetFunctionDebugName() const {
131 : DCHECK(!Done());
132 147155 : return Utils::ToLocal(frame_inspector_->GetFunctionName());
133 : }
134 :
135 294380 : v8::Local<v8::debug::Script> DebugStackTraceIterator::GetScript() const {
136 : DCHECK(!Done());
137 : Handle<Object> value = frame_inspector_->GetScript();
138 294380 : if (!value->IsScript()) return v8::Local<v8::debug::Script>();
139 : return ToApiHandle<debug::Script>(Handle<Script>::cast(value));
140 : }
141 :
142 147225 : debug::Location DebugStackTraceIterator::GetSourceLocation() const {
143 : DCHECK(!Done());
144 147225 : v8::Local<v8::debug::Script> script = GetScript();
145 147225 : if (script.IsEmpty()) return v8::debug::Location();
146 147225 : return script->GetSourceLocation(frame_inspector_->GetSourcePosition());
147 : }
148 :
149 147155 : v8::Local<v8::Function> DebugStackTraceIterator::GetFunction() const {
150 : DCHECK(!Done());
151 147155 : if (!frame_inspector_->IsJavaScript()) return v8::Local<v8::Function>();
152 : return Utils::ToLocal(frame_inspector_->GetFunction());
153 : }
154 :
155 : std::unique_ptr<v8::debug::ScopeIterator>
156 147411 : DebugStackTraceIterator::GetScopeIterator() const {
157 : DCHECK(!Done());
158 : StandardFrame* frame = iterator_.frame();
159 294822 : if (frame->is_wasm_interpreter_entry()) {
160 : return std::unique_ptr<v8::debug::ScopeIterator>(new DebugWasmScopeIterator(
161 464 : isolate_, iterator_.frame(), inlined_frame_index_));
162 : }
163 : return std::unique_ptr<v8::debug::ScopeIterator>(
164 146947 : new DebugScopeIterator(isolate_, frame_inspector_.get()));
165 : }
166 :
167 99 : bool DebugStackTraceIterator::Restart() {
168 : DCHECK(!Done());
169 99 : if (iterator_.is_wasm()) return false;
170 99 : return !LiveEdit::RestartFrame(iterator_.javascript_frame());
171 : }
172 :
173 11344 : v8::MaybeLocal<v8::Value> DebugStackTraceIterator::Evaluate(
174 : v8::Local<v8::String> source, bool throw_on_side_effect) {
175 : DCHECK(!Done());
176 : Handle<Object> value;
177 11344 : i::SafeForInterruptsScope safe_for_interrupt_scope(isolate_);
178 22688 : if (!DebugEvaluate::Local(isolate_, iterator_.frame()->id(),
179 : inlined_frame_index_, Utils::OpenHandle(*source),
180 34032 : throw_on_side_effect)
181 : .ToHandle(&value)) {
182 1164 : isolate_->OptionalRescheduleException(false);
183 1164 : return v8::MaybeLocal<v8::Value>();
184 : }
185 10180 : return Utils::ToLocal(value);
186 : }
187 : } // namespace internal
188 122036 : } // namespace v8
|