• 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/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/execution/frames-inl.h"
13 #include "src/execution/isolate.h"
14 
15 #if V8_ENABLE_WEBASSEMBLY
16 #include "src/debug/debug-wasm-objects.h"
17 #endif  // V8_ENABLE_WEBASSEMBLY
18 
19 namespace v8 {
20 
Create(v8::Isolate * isolate,int index)21 std::unique_ptr<debug::StackTraceIterator> debug::StackTraceIterator::Create(
22     v8::Isolate* isolate, int index) {
23   return std::unique_ptr<debug::StackTraceIterator>(
24       new internal::DebugStackTraceIterator(
25           reinterpret_cast<internal::Isolate*>(isolate), index));
26 }
27 
28 namespace internal {
29 
DebugStackTraceIterator(Isolate * isolate,int index)30 DebugStackTraceIterator::DebugStackTraceIterator(Isolate* isolate, int index)
31     : isolate_(isolate),
32       iterator_(isolate, isolate->debug()->break_frame_id()),
33       is_top_frame_(true) {
34   if (iterator_.done()) return;
35   std::vector<FrameSummary> frames;
36   iterator_.frame()->Summarize(&frames);
37   inlined_frame_index_ = static_cast<int>(frames.size());
38   Advance();
39   for (; !Done() && index > 0; --index) Advance();
40 }
41 
42 DebugStackTraceIterator::~DebugStackTraceIterator() = default;
43 
Done() const44 bool DebugStackTraceIterator::Done() const { return iterator_.done(); }
45 
Advance()46 void DebugStackTraceIterator::Advance() {
47   while (true) {
48     --inlined_frame_index_;
49     for (; inlined_frame_index_ >= 0; --inlined_frame_index_) {
50       // Omit functions from native and extension scripts.
51       if (FrameSummary::Get(iterator_.frame(), inlined_frame_index_)
52               .is_subject_to_debugging()) {
53         break;
54       }
55       is_top_frame_ = false;
56     }
57     if (inlined_frame_index_ >= 0) {
58       frame_inspector_.reset(new FrameInspector(
59           iterator_.frame(), inlined_frame_index_, isolate_));
60       break;
61     }
62     is_top_frame_ = false;
63     frame_inspector_.reset();
64     iterator_.Advance();
65     if (iterator_.done()) break;
66     std::vector<FrameSummary> frames;
67     iterator_.frame()->Summarize(&frames);
68     inlined_frame_index_ = static_cast<int>(frames.size());
69   }
70 }
71 
GetContextId() const72 int DebugStackTraceIterator::GetContextId() const {
73   DCHECK(!Done());
74   Handle<Object> context = frame_inspector_->GetContext();
75   if (context->IsContext()) {
76     Object value = Context::cast(*context).native_context().debug_context_id();
77     if (value.IsSmi()) return Smi::ToInt(value);
78   }
79   return 0;
80 }
81 
GetReceiver() const82 v8::MaybeLocal<v8::Value> DebugStackTraceIterator::GetReceiver() const {
83   DCHECK(!Done());
84   if (frame_inspector_->IsJavaScript() &&
85       frame_inspector_->GetFunction()->shared().kind() ==
86           FunctionKind::kArrowFunction) {
87     // FrameInspector is not able to get receiver for arrow function.
88     // So let's try to fetch it using same logic as is used to retrieve 'this'
89     // during DebugEvaluate::Local.
90     Handle<JSFunction> function = frame_inspector_->GetFunction();
91     Handle<Context> context(function->context(), isolate_);
92     // Arrow function defined in top level function without references to
93     // variables may have NativeContext as context.
94     if (!context->IsFunctionContext()) return v8::MaybeLocal<v8::Value>();
95     ScopeIterator scope_iterator(
96         isolate_, frame_inspector_.get(),
97         ScopeIterator::ReparseStrategy::kFunctionLiteral);
98     // We lookup this variable in function context only when it is used in arrow
99     // function otherwise V8 can optimize it out.
100     if (!scope_iterator.ClosureScopeHasThisReference()) {
101       return v8::MaybeLocal<v8::Value>();
102     }
103     DisallowGarbageCollection no_gc;
104     int slot_index = context->scope_info().ContextSlotIndex(
105         ReadOnlyRoots(isolate_).this_string_handle());
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 
112   Handle<Object> value = frame_inspector_->GetReceiver();
113   if (value.is_null() || (value->IsSmi() || !value->IsTheHole(isolate_))) {
114     return Utils::ToLocal(value);
115   }
116   return v8::MaybeLocal<v8::Value>();
117 }
118 
GetReturnValue() const119 v8::Local<v8::Value> DebugStackTraceIterator::GetReturnValue() const {
120   CHECK(!Done());
121 #if V8_ENABLE_WEBASSEMBLY
122   if (frame_inspector_ && frame_inspector_->IsWasm()) {
123     return v8::Local<v8::Value>();
124   }
125 #endif  // V8_ENABLE_WEBASSEMBLY
126   CHECK_NOT_NULL(iterator_.frame());
127   bool is_optimized = iterator_.frame()->is_optimized();
128   if (is_optimized || !is_top_frame_ ||
129       !isolate_->debug()->IsBreakAtReturn(iterator_.javascript_frame())) {
130     return v8::Local<v8::Value>();
131   }
132   return Utils::ToLocal(isolate_->debug()->return_value_handle());
133 }
134 
GetFunctionDebugName() const135 v8::Local<v8::String> DebugStackTraceIterator::GetFunctionDebugName() const {
136   DCHECK(!Done());
137   return Utils::ToLocal(frame_inspector_->GetFunctionName());
138 }
139 
GetScript() const140 v8::Local<v8::debug::Script> DebugStackTraceIterator::GetScript() const {
141   DCHECK(!Done());
142   Handle<Object> value = frame_inspector_->GetScript();
143   if (!value->IsScript()) return v8::Local<v8::debug::Script>();
144   return ToApiHandle<debug::Script>(Handle<Script>::cast(value));
145 }
146 
GetSourceLocation() const147 debug::Location DebugStackTraceIterator::GetSourceLocation() const {
148   DCHECK(!Done());
149   v8::Local<v8::debug::Script> script = GetScript();
150   if (script.IsEmpty()) return v8::debug::Location();
151   return script->GetSourceLocation(frame_inspector_->GetSourcePosition());
152 }
153 
GetFunction() const154 v8::Local<v8::Function> DebugStackTraceIterator::GetFunction() const {
155   DCHECK(!Done());
156   if (!frame_inspector_->IsJavaScript()) return v8::Local<v8::Function>();
157   return Utils::ToLocal(frame_inspector_->GetFunction());
158 }
159 
160 std::unique_ptr<v8::debug::ScopeIterator>
GetScopeIterator() const161 DebugStackTraceIterator::GetScopeIterator() const {
162   DCHECK(!Done());
163 #if V8_ENABLE_WEBASSEMBLY
164   if (iterator_.frame()->is_wasm()) {
165     return GetWasmScopeIterator(WasmFrame::cast(iterator_.frame()));
166   }
167 #endif  // V8_ENABLE_WEBASSEMBLY
168   return std::make_unique<DebugScopeIterator>(isolate_, frame_inspector_.get());
169 }
170 
Evaluate(v8::Local<v8::String> source,bool throw_on_side_effect)171 v8::MaybeLocal<v8::Value> DebugStackTraceIterator::Evaluate(
172     v8::Local<v8::String> source, bool throw_on_side_effect) {
173   DCHECK(!Done());
174   Handle<Object> value;
175 
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 
187 }  // namespace internal
188 }  // namespace v8
189