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-scope-iterator.h"
6
7 #include "src/api/api-inl.h"
8 #include "src/debug/debug.h"
9 #include "src/debug/liveedit.h"
10 #include "src/execution/frames-inl.h"
11 #include "src/execution/isolate.h"
12 #include "src/objects/js-generator-inl.h"
13 #include "src/wasm/wasm-debug.h"
14 #include "src/wasm/wasm-objects-inl.h"
15
16 namespace v8 {
17
CreateForFunction(v8::Isolate * v8_isolate,v8::Local<v8::Function> v8_func)18 std::unique_ptr<debug::ScopeIterator> debug::ScopeIterator::CreateForFunction(
19 v8::Isolate* v8_isolate, v8::Local<v8::Function> v8_func) {
20 internal::Handle<internal::JSReceiver> receiver =
21 internal::Handle<internal::JSReceiver>::cast(Utils::OpenHandle(*v8_func));
22
23 // Besides JSFunction and JSBoundFunction, {v8_func} could be an
24 // ObjectTemplate with a CallAsFunctionHandler. We only handle plain
25 // JSFunctions.
26 if (!receiver->IsJSFunction()) return nullptr;
27
28 internal::Handle<internal::JSFunction> function =
29 internal::Handle<internal::JSFunction>::cast(receiver);
30
31 // Blink has function objects with callable map, JS_SPECIAL_API_OBJECT_TYPE
32 // but without context on heap.
33 if (!function->has_context()) return nullptr;
34 return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator(
35 reinterpret_cast<internal::Isolate*>(v8_isolate), function));
36 }
37
38 std::unique_ptr<debug::ScopeIterator>
CreateForGeneratorObject(v8::Isolate * v8_isolate,v8::Local<v8::Object> v8_generator)39 debug::ScopeIterator::CreateForGeneratorObject(
40 v8::Isolate* v8_isolate, v8::Local<v8::Object> v8_generator) {
41 internal::Handle<internal::Object> generator =
42 Utils::OpenHandle(*v8_generator);
43 DCHECK(generator->IsJSGeneratorObject());
44 return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator(
45 reinterpret_cast<internal::Isolate*>(v8_isolate),
46 internal::Handle<internal::JSGeneratorObject>::cast(generator)));
47 }
48
49 namespace internal {
50
DebugScopeIterator(Isolate * isolate,FrameInspector * frame_inspector)51 DebugScopeIterator::DebugScopeIterator(Isolate* isolate,
52 FrameInspector* frame_inspector)
53 : iterator_(
54 isolate, frame_inspector,
55 ::v8::internal::ScopeIterator::ReparseStrategy::kFunctionLiteral) {
56 if (!Done() && ShouldIgnore()) Advance();
57 }
58
DebugScopeIterator(Isolate * isolate,Handle<JSFunction> function)59 DebugScopeIterator::DebugScopeIterator(Isolate* isolate,
60 Handle<JSFunction> function)
61 : iterator_(isolate, function) {
62 if (!Done() && ShouldIgnore()) Advance();
63 }
64
DebugScopeIterator(Isolate * isolate,Handle<JSGeneratorObject> generator)65 DebugScopeIterator::DebugScopeIterator(Isolate* isolate,
66 Handle<JSGeneratorObject> generator)
67 : iterator_(isolate, generator) {
68 if (!Done() && ShouldIgnore()) Advance();
69 }
70
Done()71 bool DebugScopeIterator::Done() { return iterator_.Done(); }
72
Advance()73 void DebugScopeIterator::Advance() {
74 DCHECK(!Done());
75 iterator_.Next();
76 while (!Done() && ShouldIgnore()) {
77 iterator_.Next();
78 }
79 }
80
ShouldIgnore()81 bool DebugScopeIterator::ShouldIgnore() {
82 if (GetType() == debug::ScopeIterator::ScopeTypeLocal) return false;
83 return !iterator_.DeclaresLocals(i::ScopeIterator::Mode::ALL);
84 }
85
GetType()86 v8::debug::ScopeIterator::ScopeType DebugScopeIterator::GetType() {
87 DCHECK(!Done());
88 return static_cast<v8::debug::ScopeIterator::ScopeType>(iterator_.Type());
89 }
90
GetObject()91 v8::Local<v8::Object> DebugScopeIterator::GetObject() {
92 DCHECK(!Done());
93 Handle<JSObject> value = iterator_.ScopeObject(i::ScopeIterator::Mode::ALL);
94 return Utils::ToLocal(value);
95 }
96
GetScriptId()97 int DebugScopeIterator::GetScriptId() {
98 DCHECK(!Done());
99 return iterator_.GetScript()->id();
100 }
101
GetFunctionDebugName()102 v8::Local<v8::Value> DebugScopeIterator::GetFunctionDebugName() {
103 DCHECK(!Done());
104 Handle<Object> name = iterator_.GetFunctionDebugName();
105 return Utils::ToLocal(name);
106 }
107
HasLocationInfo()108 bool DebugScopeIterator::HasLocationInfo() {
109 return iterator_.HasPositionInfo();
110 }
111
GetStartLocation()112 debug::Location DebugScopeIterator::GetStartLocation() {
113 DCHECK(!Done());
114 return ToApiHandle<v8::debug::Script>(iterator_.GetScript())
115 ->GetSourceLocation(iterator_.start_position());
116 }
117
GetEndLocation()118 debug::Location DebugScopeIterator::GetEndLocation() {
119 DCHECK(!Done());
120 return ToApiHandle<v8::debug::Script>(iterator_.GetScript())
121 ->GetSourceLocation(iterator_.end_position());
122 }
123
SetVariableValue(v8::Local<v8::String> name,v8::Local<v8::Value> value)124 bool DebugScopeIterator::SetVariableValue(v8::Local<v8::String> name,
125 v8::Local<v8::Value> value) {
126 DCHECK(!Done());
127 return iterator_.SetVariableValue(Utils::OpenHandle(*name),
128 Utils::OpenHandle(*value));
129 }
130
DebugWasmScopeIterator(Isolate * isolate,WasmFrame * frame)131 DebugWasmScopeIterator::DebugWasmScopeIterator(Isolate* isolate,
132 WasmFrame* frame)
133 : isolate_(isolate),
134 frame_(frame),
135 type_(debug::ScopeIterator::ScopeTypeModule) {}
136
Done()137 bool DebugWasmScopeIterator::Done() {
138 return type_ == debug::ScopeIterator::ScopeTypeWith;
139 }
140
Advance()141 void DebugWasmScopeIterator::Advance() {
142 DCHECK(!Done());
143 switch (type_) {
144 case ScopeTypeModule:
145 // Skip local scope and expression stack scope if the frame is not
146 // inspectable.
147 type_ = frame_->is_inspectable() ? debug::ScopeIterator::ScopeTypeLocal
148 : debug::ScopeIterator::ScopeTypeWith;
149 break;
150 case ScopeTypeLocal:
151 type_ = debug::ScopeIterator::ScopeTypeWasmExpressionStack;
152 break;
153 case ScopeTypeWasmExpressionStack:
154 // We use ScopeTypeWith type as marker for done.
155 type_ = debug::ScopeIterator::ScopeTypeWith;
156 break;
157 default:
158 UNREACHABLE();
159 }
160 }
161
GetType()162 v8::debug::ScopeIterator::ScopeType DebugWasmScopeIterator::GetType() {
163 DCHECK(!Done());
164 return type_;
165 }
166
GetObject()167 v8::Local<v8::Object> DebugWasmScopeIterator::GetObject() {
168 DCHECK(!Done());
169 switch (type_) {
170 case debug::ScopeIterator::ScopeTypeModule: {
171 Handle<WasmInstanceObject> instance =
172 FrameSummary::GetTop(frame_).AsWasm().wasm_instance();
173 return Utils::ToLocal(wasm::GetModuleScopeObject(instance));
174 }
175 case debug::ScopeIterator::ScopeTypeLocal: {
176 DCHECK(frame_->is_wasm());
177 wasm::DebugInfo* debug_info = frame_->native_module()->GetDebugInfo();
178 return Utils::ToLocal(debug_info->GetLocalScopeObject(
179 isolate_, frame_->pc(), frame_->fp(), frame_->callee_fp()));
180 }
181 case debug::ScopeIterator::ScopeTypeWasmExpressionStack: {
182 DCHECK(frame_->is_wasm());
183 wasm::DebugInfo* debug_info = frame_->native_module()->GetDebugInfo();
184 return Utils::ToLocal(debug_info->GetStackScopeObject(
185 isolate_, frame_->pc(), frame_->fp(), frame_->callee_fp()));
186 }
187 default:
188 return {};
189 }
190 }
191
GetScriptId()192 int DebugWasmScopeIterator::GetScriptId() {
193 DCHECK(!Done());
194 return -1;
195 }
196
GetFunctionDebugName()197 v8::Local<v8::Value> DebugWasmScopeIterator::GetFunctionDebugName() {
198 DCHECK(!Done());
199 return Utils::ToLocal(isolate_->factory()->empty_string());
200 }
201
HasLocationInfo()202 bool DebugWasmScopeIterator::HasLocationInfo() { return false; }
203
GetStartLocation()204 debug::Location DebugWasmScopeIterator::GetStartLocation() {
205 DCHECK(!Done());
206 return debug::Location();
207 }
208
GetEndLocation()209 debug::Location DebugWasmScopeIterator::GetEndLocation() {
210 DCHECK(!Done());
211 return debug::Location();
212 }
213
SetVariableValue(v8::Local<v8::String> name,v8::Local<v8::Value> value)214 bool DebugWasmScopeIterator::SetVariableValue(v8::Local<v8::String> name,
215 v8::Local<v8::Value> value) {
216 DCHECK(!Done());
217 return false;
218 }
219 } // namespace internal
220 } // namespace v8
221