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-scope-iterator.h"
6 :
7 : #include "src/api.h"
8 : #include "src/debug/debug.h"
9 : #include "src/debug/liveedit.h"
10 : #include "src/frames-inl.h"
11 : #include "src/isolate.h"
12 : #include "src/wasm/wasm-objects-inl.h"
13 :
14 : namespace v8 {
15 :
16 25 : std::unique_ptr<debug::ScopeIterator> debug::ScopeIterator::CreateForFunction(
17 : v8::Isolate* v8_isolate, v8::Local<v8::Function> v8_func) {
18 : internal::Handle<internal::JSFunction> func =
19 : internal::Handle<internal::JSFunction>::cast(Utils::OpenHandle(*v8_func));
20 : // Blink has function objects with callable map, JS_SPECIAL_API_OBJECT_TYPE
21 : // but without context on heap.
22 25 : if (!func->has_context()) return nullptr;
23 : return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator(
24 50 : reinterpret_cast<internal::Isolate*>(v8_isolate), func));
25 : }
26 :
27 : std::unique_ptr<debug::ScopeIterator>
28 35 : debug::ScopeIterator::CreateForGeneratorObject(
29 : v8::Isolate* v8_isolate, v8::Local<v8::Object> v8_generator) {
30 : internal::Handle<internal::Object> generator =
31 : Utils::OpenHandle(*v8_generator);
32 : DCHECK(generator->IsJSGeneratorObject());
33 : return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator(
34 : reinterpret_cast<internal::Isolate*>(v8_isolate),
35 70 : internal::Handle<internal::JSGeneratorObject>::cast(generator)));
36 : }
37 :
38 : namespace internal {
39 :
40 125102 : DebugScopeIterator::DebugScopeIterator(Isolate* isolate,
41 : FrameInspector* frame_inspector)
42 125102 : : iterator_(isolate, frame_inspector) {
43 125102 : if (!Done() && ShouldIgnore()) Advance();
44 125102 : }
45 :
46 25 : DebugScopeIterator::DebugScopeIterator(Isolate* isolate,
47 : Handle<JSFunction> function)
48 25 : : iterator_(isolate, function) {
49 25 : if (!Done() && ShouldIgnore()) Advance();
50 25 : }
51 :
52 35 : DebugScopeIterator::DebugScopeIterator(Isolate* isolate,
53 : Handle<JSGeneratorObject> generator)
54 35 : : iterator_(isolate, generator) {
55 35 : if (!Done() && ShouldIgnore()) Advance();
56 35 : }
57 :
58 902318 : bool DebugScopeIterator::Done() { return iterator_.Done(); }
59 :
60 333412 : void DebugScopeIterator::Advance() {
61 : DCHECK(!Done());
62 333412 : iterator_.Next();
63 674021 : while (!Done() && ShouldIgnore()) {
64 7197 : iterator_.Next();
65 : }
66 333412 : }
67 :
68 340894 : bool DebugScopeIterator::ShouldIgnore() {
69 : // Almost always Script scope will be empty, so just filter out that noise.
70 : // Also drop empty Block, Eval and Script scopes, should we get any.
71 : DCHECK(!Done());
72 : debug::ScopeIterator::ScopeType type = GetType();
73 340894 : if (type != debug::ScopeIterator::ScopeTypeBlock &&
74 : type != debug::ScopeIterator::ScopeTypeScript &&
75 340894 : type != debug::ScopeIterator::ScopeTypeEval &&
76 : type != debug::ScopeIterator::ScopeTypeModule) {
77 : return false;
78 : }
79 :
80 : // TODO(kozyatinskiy): make this function faster.
81 : Handle<JSObject> value;
82 263462 : if (!iterator_.ScopeObject().ToHandle(&value)) return false;
83 : Handle<FixedArray> keys =
84 : KeyAccumulator::GetKeys(value, KeyCollectionMode::kOwnOnly,
85 : ENUMERABLE_STRINGS,
86 131731 : GetKeysConversion::kConvertToString)
87 263462 : .ToHandleChecked();
88 131731 : return keys->length() == 0;
89 : }
90 :
91 325976 : v8::debug::ScopeIterator::ScopeType DebugScopeIterator::GetType() {
92 : DCHECK(!Done());
93 666870 : return static_cast<v8::debug::ScopeIterator::ScopeType>(iterator_.Type());
94 : }
95 :
96 326045 : v8::Local<v8::Object> DebugScopeIterator::GetObject() {
97 : DCHECK(!Done());
98 : Handle<JSObject> value;
99 652090 : if (iterator_.ScopeObject().ToHandle(&value)) {
100 : return Utils::ToLocal(value);
101 : }
102 0 : return v8::Local<v8::Object>();
103 : }
104 :
105 325976 : v8::Local<v8::Function> DebugScopeIterator::GetFunction() {
106 : DCHECK(!Done());
107 325976 : Handle<JSFunction> closure = iterator_.GetClosure();
108 325976 : if (closure.is_null()) return v8::Local<v8::Function>();
109 : return Utils::ToLocal(closure);
110 : }
111 :
112 88213 : debug::Location DebugScopeIterator::GetStartLocation() {
113 : DCHECK(!Done());
114 88213 : Handle<JSFunction> closure = iterator_.GetClosure();
115 88213 : if (closure.is_null()) return debug::Location();
116 : Object* obj = closure->shared()->script();
117 88213 : if (!obj->IsScript()) return debug::Location();
118 : return ToApiHandle<v8::debug::Script>(handle(Script::cast(obj)))
119 176426 : ->GetSourceLocation(iterator_.start_position());
120 : }
121 :
122 88213 : debug::Location DebugScopeIterator::GetEndLocation() {
123 : DCHECK(!Done());
124 88213 : Handle<JSFunction> closure = iterator_.GetClosure();
125 88213 : if (closure.is_null()) return debug::Location();
126 : Object* obj = closure->shared()->script();
127 88213 : if (!obj->IsScript()) return debug::Location();
128 : return ToApiHandle<v8::debug::Script>(handle(Script::cast(obj)))
129 176426 : ->GetSourceLocation(iterator_.end_position());
130 : }
131 :
132 216 : bool DebugScopeIterator::SetVariableValue(v8::Local<v8::String> name,
133 : v8::Local<v8::Value> value) {
134 : DCHECK(!Done());
135 : return iterator_.SetVariableValue(Utils::OpenHandle(*name),
136 216 : Utils::OpenHandle(*value));
137 : }
138 :
139 285 : DebugWasmScopeIterator::DebugWasmScopeIterator(Isolate* isolate,
140 : StandardFrame* frame,
141 : int inlined_frame_index)
142 : : isolate_(isolate),
143 : frame_(frame),
144 : inlined_frame_index_(inlined_frame_index),
145 285 : type_(debug::ScopeIterator::ScopeTypeGlobal) {}
146 :
147 855 : bool DebugWasmScopeIterator::Done() {
148 855 : return type_ != debug::ScopeIterator::ScopeTypeGlobal &&
149 855 : type_ != debug::ScopeIterator::ScopeTypeLocal;
150 : }
151 :
152 570 : void DebugWasmScopeIterator::Advance() {
153 : DCHECK(!Done());
154 570 : if (type_ == debug::ScopeIterator::ScopeTypeGlobal) {
155 285 : type_ = debug::ScopeIterator::ScopeTypeLocal;
156 : } else {
157 : // We use ScopeTypeWith type as marker for done.
158 285 : type_ = debug::ScopeIterator::ScopeTypeWith;
159 : }
160 570 : }
161 :
162 570 : v8::debug::ScopeIterator::ScopeType DebugWasmScopeIterator::GetType() {
163 : DCHECK(!Done());
164 570 : return type_;
165 : }
166 :
167 570 : v8::Local<v8::Object> DebugWasmScopeIterator::GetObject() {
168 : DCHECK(!Done());
169 : Handle<WasmDebugInfo> debug_info(
170 : WasmInterpreterEntryFrame::cast(frame_)->wasm_instance()->debug_info(),
171 570 : isolate_);
172 570 : switch (type_) {
173 : case debug::ScopeIterator::ScopeTypeGlobal:
174 : return Utils::ToLocal(WasmDebugInfo::GetGlobalScopeObject(
175 570 : debug_info, frame_->fp(), inlined_frame_index_));
176 : case debug::ScopeIterator::ScopeTypeLocal:
177 : return Utils::ToLocal(WasmDebugInfo::GetLocalScopeObject(
178 570 : debug_info, frame_->fp(), inlined_frame_index_));
179 : default:
180 0 : return v8::Local<v8::Object>();
181 : }
182 : return v8::Local<v8::Object>();
183 : }
184 :
185 570 : v8::Local<v8::Function> DebugWasmScopeIterator::GetFunction() {
186 : DCHECK(!Done());
187 570 : return v8::Local<v8::Function>();
188 : }
189 :
190 0 : debug::Location DebugWasmScopeIterator::GetStartLocation() {
191 : DCHECK(!Done());
192 0 : return debug::Location();
193 : }
194 :
195 0 : debug::Location DebugWasmScopeIterator::GetEndLocation() {
196 : DCHECK(!Done());
197 0 : return debug::Location();
198 : }
199 :
200 0 : bool DebugWasmScopeIterator::SetVariableValue(v8::Local<v8::String> name,
201 : v8::Local<v8::Value> value) {
202 : DCHECK(!Done());
203 0 : return false;
204 : }
205 : } // namespace internal
206 : } // namespace v8
|