V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
debug-stack-trace-iterator.cc
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 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 
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 
38 DebugStackTraceIterator::~DebugStackTraceIterator() = default;
39 
40 bool DebugStackTraceIterator::Done() const { return iterator_.done(); }
41 
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 
68 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 
79 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()))
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 
118 v8::Local<v8::Value> DebugStackTraceIterator::GetReturnValue() const {
119  DCHECK(!Done());
120  if (frame_inspector_ && frame_inspector_->IsWasm()) {
121  return v8::Local<v8::Value>();
122  }
123  bool is_optimized = iterator_.frame()->is_optimized();
124  if (is_optimized || !is_top_frame_ ||
125  !isolate_->debug()->IsBreakAtReturn(iterator_.javascript_frame())) {
126  return v8::Local<v8::Value>();
127  }
128  return Utils::ToLocal(isolate_->debug()->return_value_handle());
129 }
130 
131 v8::Local<v8::String> DebugStackTraceIterator::GetFunctionDebugName() const {
132  DCHECK(!Done());
133  return Utils::ToLocal(frame_inspector_->GetFunctionName());
134 }
135 
136 v8::Local<v8::debug::Script> DebugStackTraceIterator::GetScript() const {
137  DCHECK(!Done());
138  Handle<Object> value = frame_inspector_->GetScript();
139  if (!value->IsScript()) return v8::Local<v8::debug::Script>();
140  return ToApiHandle<debug::Script>(Handle<Script>::cast(value));
141 }
142 
143 debug::Location DebugStackTraceIterator::GetSourceLocation() const {
144  DCHECK(!Done());
145  v8::Local<v8::debug::Script> script = GetScript();
146  if (script.IsEmpty()) return v8::debug::Location();
147  return script->GetSourceLocation(frame_inspector_->GetSourcePosition());
148 }
149 
150 v8::Local<v8::Function> DebugStackTraceIterator::GetFunction() const {
151  DCHECK(!Done());
152  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 DebugStackTraceIterator::GetScopeIterator() const {
158  DCHECK(!Done());
159  StandardFrame* frame = iterator_.frame();
160  if (frame->is_wasm_interpreter_entry()) {
161  return std::unique_ptr<v8::debug::ScopeIterator>(new DebugWasmScopeIterator(
162  isolate_, iterator_.frame(), inlined_frame_index_));
163  }
164  return std::unique_ptr<v8::debug::ScopeIterator>(
165  new DebugScopeIterator(isolate_, frame_inspector_.get()));
166 }
167 
168 bool DebugStackTraceIterator::Restart() {
169  DCHECK(!Done());
170  if (iterator_.is_wasm()) return false;
171  return !LiveEdit::RestartFrame(iterator_.javascript_frame());
172 }
173 
174 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  i::SafeForInterruptsScope safe_for_interrupt_scope(isolate_);
179  if (!DebugEvaluate::Local(isolate_, iterator_.frame()->id(),
180  inlined_frame_index_, Utils::OpenHandle(*source),
181  throw_on_side_effect)
182  .ToHandle(&value)) {
183  isolate_->OptionalRescheduleException(false);
184  return v8::MaybeLocal<v8::Value>();
185  }
186  return Utils::ToLocal(value);
187 }
188 } // namespace internal
189 } // namespace v8
V8_INLINE bool IsEmpty() const
Definition: v8.h:195
Definition: libplatform.h:13