• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Create(v8::Isolate * isolate,int index)17 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           reinterpret_cast<internal::Isolate*>(isolate), index));
22 }
23 
24 namespace internal {
25 
DebugStackTraceIterator(Isolate * isolate,int index)26 DebugStackTraceIterator::DebugStackTraceIterator(Isolate* isolate, int index)
27     : isolate_(isolate),
28       iterator_(isolate, isolate->debug()->break_frame_id()),
29       is_top_frame_(true) {
30   if (iterator_.done()) return;
31   std::vector<FrameSummary> frames;
32   iterator_.frame()->Summarize(&frames);
33   inlined_frame_index_ = static_cast<int>(frames.size());
34   Advance();
35   for (; !Done() && index > 0; --index) Advance();
36 }
37 
~DebugStackTraceIterator()38 DebugStackTraceIterator::~DebugStackTraceIterator() {}
39 
Done() const40 bool DebugStackTraceIterator::Done() const { return iterator_.done(); }
41 
Advance()42 void DebugStackTraceIterator::Advance() {
43   while (true) {
44     --inlined_frame_index_;
45     for (; inlined_frame_index_ >= 0; --inlined_frame_index_) {
46       // Omit functions from native and extension scripts.
47       if (FrameSummary::Get(iterator_.frame(), inlined_frame_index_)
48               .is_subject_to_debugging()) {
49         break;
50       }
51       is_top_frame_ = false;
52     }
53     if (inlined_frame_index_ >= 0) {
54       frame_inspector_.reset(new FrameInspector(
55           iterator_.frame(), inlined_frame_index_, isolate_));
56       break;
57     }
58     is_top_frame_ = false;
59     frame_inspector_.reset();
60     iterator_.Advance();
61     if (iterator_.done()) break;
62     std::vector<FrameSummary> frames;
63     iterator_.frame()->Summarize(&frames);
64     inlined_frame_index_ = static_cast<int>(frames.size());
65   }
66 }
67 
GetContextId() const68 int DebugStackTraceIterator::GetContextId() const {
69   DCHECK(!Done());
70   Handle<Object> context = frame_inspector_->GetContext();
71   if (context->IsContext()) {
72     Object* value =
73         Context::cast(*context)->native_context()->debug_context_id();
74     if (value->IsSmi()) return Smi::ToInt(value);
75   }
76   return 0;
77 }
78 
GetReceiver() const79 v8::MaybeLocal<v8::Value> DebugStackTraceIterator::GetReceiver() const {
80   DCHECK(!Done());
81   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     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     if (!context->IsFunctionContext()) return v8::MaybeLocal<v8::Value>();
91     ScopeIterator scope_iterator(isolate_, frame_inspector_.get(),
92                                  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     if (!scope_iterator.GetNonLocals()->Has(isolate_,
96                                             isolate_->factory()->this_string()))
97       return v8::MaybeLocal<v8::Value>();
98 
99     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         &maybe_assigned_flag);
106     if (slot_index < 0) return v8::MaybeLocal<v8::Value>();
107     Handle<Object> value = handle(context->get(slot_index), isolate_);
108     if (value->IsTheHole(isolate_)) return v8::MaybeLocal<v8::Value>();
109     return Utils::ToLocal(value);
110   }
111   Handle<Object> value = frame_inspector_->GetReceiver();
112   if (value.is_null() || (value->IsSmi() || !value->IsTheHole(isolate_))) {
113     return Utils::ToLocal(value);
114   }
115   return v8::MaybeLocal<v8::Value>();
116 }
117 
GetReturnValue() const118 v8::Local<v8::Value> DebugStackTraceIterator::GetReturnValue() const {
119   DCHECK(!Done());
120   if (frame_inspector_->IsWasm()) return v8::Local<v8::Value>();
121   bool is_optimized = iterator_.frame()->is_optimized();
122   if (is_optimized || !is_top_frame_ ||
123       !isolate_->debug()->IsBreakAtReturn(iterator_.javascript_frame())) {
124     return v8::Local<v8::Value>();
125   }
126   return Utils::ToLocal(isolate_->debug()->return_value_handle());
127 }
128 
GetFunctionDebugName() const129 v8::Local<v8::String> DebugStackTraceIterator::GetFunctionDebugName() const {
130   DCHECK(!Done());
131   return Utils::ToLocal(frame_inspector_->GetFunctionName());
132 }
133 
GetScript() const134 v8::Local<v8::debug::Script> DebugStackTraceIterator::GetScript() const {
135   DCHECK(!Done());
136   Handle<Object> value = frame_inspector_->GetScript();
137   if (!value->IsScript()) return v8::Local<v8::debug::Script>();
138   return ToApiHandle<debug::Script>(Handle<Script>::cast(value));
139 }
140 
GetSourceLocation() const141 debug::Location DebugStackTraceIterator::GetSourceLocation() const {
142   DCHECK(!Done());
143   v8::Local<v8::debug::Script> script = GetScript();
144   if (script.IsEmpty()) return v8::debug::Location();
145   return script->GetSourceLocation(frame_inspector_->GetSourcePosition());
146 }
147 
GetFunction() const148 v8::Local<v8::Function> DebugStackTraceIterator::GetFunction() const {
149   DCHECK(!Done());
150   if (!frame_inspector_->IsJavaScript()) return v8::Local<v8::Function>();
151   return Utils::ToLocal(frame_inspector_->GetFunction());
152 }
153 
154 std::unique_ptr<v8::debug::ScopeIterator>
GetScopeIterator() const155 DebugStackTraceIterator::GetScopeIterator() const {
156   DCHECK(!Done());
157   StandardFrame* frame = iterator_.frame();
158   if (frame->is_wasm_interpreter_entry()) {
159     return std::unique_ptr<v8::debug::ScopeIterator>(new DebugWasmScopeIterator(
160         isolate_, iterator_.frame(), inlined_frame_index_));
161   }
162   return std::unique_ptr<v8::debug::ScopeIterator>(
163       new DebugScopeIterator(isolate_, frame_inspector_.get()));
164 }
165 
Restart()166 bool DebugStackTraceIterator::Restart() {
167   DCHECK(!Done());
168   if (iterator_.is_wasm()) return false;
169   return !LiveEdit::RestartFrame(iterator_.javascript_frame());
170 }
171 
Evaluate(v8::Local<v8::String> source,bool throw_on_side_effect)172 v8::MaybeLocal<v8::Value> DebugStackTraceIterator::Evaluate(
173     v8::Local<v8::String> source, bool throw_on_side_effect) {
174   DCHECK(!Done());
175   Handle<Object> value;
176   i::SafeForInterruptsScope safe_for_interrupt_scope(isolate_);
177   if (!DebugEvaluate::Local(isolate_, iterator_.frame()->id(),
178                             inlined_frame_index_, Utils::OpenHandle(*source),
179                             throw_on_side_effect)
180            .ToHandle(&value)) {
181     isolate_->OptionalRescheduleException(false);
182     return v8::MaybeLocal<v8::Value>();
183   }
184   return Utils::ToLocal(value);
185 }
186 }  // namespace internal
187 }  // namespace v8
188