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 111595 : 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 223190 : reinterpret_cast<internal::Isolate*>(isolate), index));
22 : }
23 :
24 : namespace internal {
25 :
26 223190 : DebugStackTraceIterator::DebugStackTraceIterator(Isolate* isolate, int index)
27 : : isolate_(isolate),
28 : iterator_(isolate, isolate->debug()->break_frame_id()),
29 223190 : is_top_frame_(true) {
30 111595 : if (iterator_.done()) return;
31 : std::vector<FrameSummary> frames;
32 111595 : iterator_.frame()->Summarize(&frames);
33 223190 : inlined_frame_index_ = static_cast<int>(frames.size());
34 111595 : Advance();
35 232006 : for (; !Done() && index > 0; --index) Advance();
36 : }
37 :
38 : DebugStackTraceIterator::~DebugStackTraceIterator() = default;
39 :
40 517038 : bool DebugStackTraceIterator::Done() const { return iterator_.done(); }
41 :
42 311874 : void DebugStackTraceIterator::Advance() {
43 : while (true) {
44 442967 : --inlined_frame_index_;
45 442995 : for (; inlined_frame_index_ >= 0; --inlined_frame_index_) {
46 : // Omit functions from native and extension scripts.
47 498618 : if (FrameSummary::Get(iterator_.frame(), inlined_frame_index_)
48 498618 : .is_subject_to_debugging()) {
49 : break;
50 : }
51 28 : is_top_frame_ = false;
52 : }
53 442967 : if (inlined_frame_index_ >= 0) {
54 : frame_inspector_.reset(new FrameInspector(
55 249281 : iterator_.frame(), inlined_frame_index_, isolate_));
56 311874 : break;
57 : }
58 193686 : is_top_frame_ = false;
59 : frame_inspector_.reset();
60 193686 : iterator_.Advance();
61 193686 : if (iterator_.done()) break;
62 : std::vector<FrameSummary> frames;
63 131093 : iterator_.frame()->Summarize(&frames);
64 262186 : inlined_frame_index_ = static_cast<int>(frames.size());
65 131093 : }
66 311874 : }
67 :
68 146914 : int DebugStackTraceIterator::GetContextId() const {
69 : DCHECK(!Done());
70 146914 : Handle<Object> context = frame_inspector_->GetContext();
71 293828 : if (context->IsContext()) {
72 : Object value =
73 146805 : Context::cast(*context)->native_context()->debug_context_id();
74 146805 : if (value->IsSmi()) return Smi::ToInt(value);
75 : }
76 : return 0;
77 : }
78 :
79 146795 : v8::MaybeLocal<v8::Value> DebugStackTraceIterator::GetReceiver() const {
80 : DCHECK(!Done());
81 439810 : if (frame_inspector_->IsJavaScript() &&
82 293015 : 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 7410 : 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 2470 : if (!context->IsFunctionContext()) return v8::MaybeLocal<v8::Value>();
91 : ScopeIterator scope_iterator(isolate_, frame_inspector_.get(),
92 439 : 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 878 : isolate_->factory()->this_string()))
97 362 : return v8::MaybeLocal<v8::Value>();
98 :
99 231 : Handle<ScopeInfo> scope_info(context->scope_info(), isolate_);
100 : VariableMode mode;
101 : InitializationFlag flag;
102 : MaybeAssignedFlag maybe_assigned_flag;
103 : int slot_index = ScopeInfo::ContextSlotIndex(
104 : scope_info, isolate_->factory()->this_string(), &mode, &flag,
105 154 : &maybe_assigned_flag);
106 77 : if (slot_index < 0) return v8::MaybeLocal<v8::Value>();
107 231 : Handle<Object> value = handle(context->get(slot_index), isolate_);
108 231 : if (value->IsTheHole(isolate_)) return v8::MaybeLocal<v8::Value>();
109 77 : return Utils::ToLocal(value);
110 : }
111 : Handle<Object> value = frame_inspector_->GetReceiver();
112 721607 : if (value.is_null() || (value->IsSmi() || !value->IsTheHole(isolate_))) {
113 144040 : return Utils::ToLocal(value);
114 : }
115 285 : return v8::MaybeLocal<v8::Value>();
116 : }
117 :
118 191458 : v8::Local<v8::Value> DebugStackTraceIterator::GetReturnValue() const {
119 : DCHECK(!Done());
120 191458 : if (frame_inspector_ && frame_inspector_->IsWasm()) {
121 976 : return v8::Local<v8::Value>();
122 : }
123 190482 : bool is_optimized = iterator_.frame()->is_optimized();
124 288037 : if (is_optimized || !is_top_frame_ ||
125 107962 : !isolate_->debug()->IsBreakAtReturn(iterator_.javascript_frame())) {
126 180075 : return v8::Local<v8::Value>();
127 : }
128 20814 : return Utils::ToLocal(isolate_->debug()->return_value_handle());
129 : }
130 :
131 146904 : v8::Local<v8::String> DebugStackTraceIterator::GetFunctionDebugName() const {
132 : DCHECK(!Done());
133 146904 : return Utils::ToLocal(frame_inspector_->GetFunctionName());
134 : }
135 :
136 293878 : v8::Local<v8::debug::Script> DebugStackTraceIterator::GetScript() const {
137 : DCHECK(!Done());
138 : Handle<Object> value = frame_inspector_->GetScript();
139 587756 : if (!value->IsScript()) return v8::Local<v8::debug::Script>();
140 293878 : return ToApiHandle<debug::Script>(Handle<Script>::cast(value));
141 : }
142 :
143 146974 : debug::Location DebugStackTraceIterator::GetSourceLocation() const {
144 : DCHECK(!Done());
145 146974 : v8::Local<v8::debug::Script> script = GetScript();
146 146974 : if (script.IsEmpty()) return v8::debug::Location();
147 146974 : return script->GetSourceLocation(frame_inspector_->GetSourcePosition());
148 : }
149 :
150 146904 : v8::Local<v8::Function> DebugStackTraceIterator::GetFunction() const {
151 : DCHECK(!Done());
152 146904 : if (!frame_inspector_->IsJavaScript()) return v8::Local<v8::Function>();
153 : return Utils::ToLocal(frame_inspector_->GetFunction());
154 : }
155 :
156 : std::unique_ptr<v8::debug::ScopeIterator>
157 147120 : DebugStackTraceIterator::GetScopeIterator() const {
158 : DCHECK(!Done());
159 : StandardFrame* frame = iterator_.frame();
160 294240 : if (frame->is_wasm_interpreter_entry()) {
161 : return std::unique_ptr<v8::debug::ScopeIterator>(new DebugWasmScopeIterator(
162 575 : isolate_, iterator_.frame(), inlined_frame_index_));
163 : }
164 : return std::unique_ptr<v8::debug::ScopeIterator>(
165 146545 : new DebugScopeIterator(isolate_, frame_inspector_.get()));
166 : }
167 :
168 99 : bool DebugStackTraceIterator::Restart() {
169 : DCHECK(!Done());
170 99 : if (iterator_.is_wasm()) return false;
171 99 : return !LiveEdit::RestartFrame(iterator_.javascript_frame());
172 : }
173 :
174 11092 : v8::MaybeLocal<v8::Value> DebugStackTraceIterator::Evaluate(
175 : v8::Local<v8::String> source, bool throw_on_side_effect) {
176 : DCHECK(!Done());
177 : Handle<Object> value;
178 11092 : i::SafeForInterruptsScope safe_for_interrupt_scope(isolate_);
179 11092 : if (!DebugEvaluate::Local(isolate_, iterator_.frame()->id(),
180 : inlined_frame_index_, Utils::OpenHandle(*source),
181 44368 : throw_on_side_effect)
182 22184 : .ToHandle(&value)) {
183 1197 : isolate_->OptionalRescheduleException(false);
184 1197 : return v8::MaybeLocal<v8::Value>();
185 : }
186 9895 : return Utils::ToLocal(value);
187 : }
188 : } // namespace internal
189 183867 : } // namespace v8
|