Line data Source code
1 : // Copyright 2015 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-frames.h"
6 :
7 : #include "src/accessors.h"
8 : #include "src/frames-inl.h"
9 : #include "src/wasm/wasm-interpreter.h"
10 : #include "src/wasm/wasm-objects-inl.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 194044 : FrameInspector::FrameInspector(StandardFrame* frame, int inlined_frame_index,
16 : Isolate* isolate)
17 : : frame_(frame),
18 388088 : isolate_(isolate) {
19 : // Extract the relevant information from the frame summary and discard it.
20 194044 : FrameSummary summary = FrameSummary::Get(frame, inlined_frame_index);
21 :
22 194044 : is_constructor_ = summary.is_constructor();
23 194044 : source_position_ = summary.SourcePosition();
24 194044 : function_name_ = summary.FunctionName();
25 194044 : script_ = Handle<Script>::cast(summary.script());
26 194044 : receiver_ = summary.receiver();
27 :
28 194044 : if (summary.IsJavaScript()) {
29 193648 : function_ = summary.AsJavaScript().function();
30 : }
31 :
32 : JavaScriptFrame* js_frame =
33 194044 : frame->is_java_script() ? javascript_frame() : nullptr;
34 : DCHECK(js_frame || frame->is_wasm());
35 387692 : has_adapted_arguments_ = js_frame && js_frame->has_adapted_arguments();
36 388373 : is_optimized_ = frame_->is_optimized();
37 388088 : is_interpreted_ = frame_->is_interpreted();
38 :
39 : // Calculate the deoptimized frame.
40 194044 : if (is_optimized_) {
41 : DCHECK_NOT_NULL(js_frame);
42 : // TODO(turbofan): Deoptimization from AstGraphBuilder is not supported.
43 104565 : if (js_frame->LookupCode()->is_turbofanned() &&
44 69710 : !js_frame->function()->shared()->HasBytecodeArray()) {
45 0 : is_optimized_ = false;
46 194044 : return;
47 : }
48 :
49 : deoptimized_frame_.reset(Deoptimizer::DebuggerInspectableFrame(
50 34855 : js_frame, inlined_frame_index, isolate));
51 318378 : } else if (frame_->is_wasm_interpreter_entry()) {
52 855 : wasm_interpreted_frame_ =
53 : summary.AsWasm().wasm_instance()->debug_info()->GetInterpretedFrame(
54 : frame_->fp(), inlined_frame_index);
55 : DCHECK(wasm_interpreted_frame_);
56 194044 : }
57 : }
58 :
59 194044 : FrameInspector::~FrameInspector() {
60 : // Destructor needs to be defined in the .cc file, because it instantiates
61 : // std::unique_ptr destructors but the types are not known in the header.
62 194044 : }
63 :
64 64429 : int FrameInspector::GetParametersCount() {
65 86926 : if (is_optimized_) return deoptimized_frame_->parameters_count();
66 41932 : if (wasm_interpreted_frame_)
67 0 : return wasm_interpreted_frame_->GetParameterCount();
68 41932 : return frame_->ComputeParametersCount();
69 : }
70 :
71 33132 : Handle<Object> FrameInspector::GetParameter(int index) {
72 33132 : if (is_optimized_) return deoptimized_frame_->GetParameter(index);
73 : // TODO(clemensh): Handle wasm_interpreted_frame_.
74 21903 : return handle(frame_->GetParameter(index), isolate_);
75 : }
76 :
77 3339307 : Handle<Object> FrameInspector::GetExpression(int index) {
78 : // TODO(turbofan): Deoptimization from AstGraphBuilder is not supported.
79 10017921 : if (frame_->is_java_script() &&
80 6696055 : javascript_frame()->LookupCode()->is_turbofanned() &&
81 34882 : !javascript_frame()->function()->shared()->HasBytecodeArray()) {
82 0 : return isolate_->factory()->undefined_value();
83 : }
84 : return is_optimized_ ? deoptimized_frame_->GetExpression(index)
85 6661173 : : handle(frame_->GetExpression(index), isolate_);
86 : }
87 :
88 497392 : Handle<Object> FrameInspector::GetContext() {
89 : return deoptimized_frame_ ? deoptimized_frame_->GetContext()
90 994784 : : handle(frame_->context(), isolate_);
91 : }
92 :
93 310594 : bool FrameInspector::IsWasm() { return frame_->is_wasm(); }
94 :
95 125078 : bool FrameInspector::IsJavaScript() { return frame_->is_java_script(); }
96 :
97 : // To inspect all the provided arguments the frame might need to be
98 : // replaced with the arguments frame.
99 180 : void FrameInspector::SetArgumentsFrame(StandardFrame* frame) {
100 : DCHECK(has_adapted_arguments_);
101 : DCHECK(frame->is_arguments_adaptor());
102 180 : frame_ = frame;
103 360 : is_optimized_ = frame_->is_optimized();
104 360 : is_interpreted_ = frame_->is_interpreted();
105 : DCHECK(!is_optimized_);
106 180 : }
107 :
108 :
109 : // Create a plain JSObject which materializes the local scope for the specified
110 : // frame.
111 89913 : void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
112 : Handle<ScopeInfo> scope_info,
113 : bool materialize_arguments_object) {
114 89913 : HandleScope scope(isolate_);
115 : // First fill all parameters.
116 237914 : for (int i = 0; i < scope_info->ParameterCount(); ++i) {
117 : // Do not materialize the parameter if it is shadowed by a context local.
118 : // TODO(yangguo): check whether this is necessary, now that we materialize
119 : // context locals as well.
120 29044 : Handle<String> name(scope_info->ParameterName(i));
121 35693 : if (ScopeInfo::VariableIsSynthetic(*name)) continue;
122 28223 : if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
123 :
124 : Handle<Object> value =
125 22395 : i < GetParametersCount()
126 : ? GetParameter(i)
127 23263 : : Handle<Object>::cast(isolate_->factory()->undefined_value());
128 : DCHECK(!value->IsTheHole(isolate_));
129 :
130 44790 : JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
131 : }
132 :
133 : // Second fill all stack locals.
134 6847385 : for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
135 3378736 : Handle<String> name(scope_info->StackLocalName(i));
136 3378736 : if (ScopeInfo::VariableIsSynthetic(*name)) continue;
137 3297497 : Handle<Object> value = GetExpression(scope_info->StackLocalIndex(i));
138 : // TODO(yangguo): We convert optimized out values to {undefined} when they
139 : // are passed to the debugger. Eventually we should handle them somehow.
140 6594994 : if (value->IsTheHole(isolate_)) {
141 72 : value = isolate_->factory()->undefined_value();
142 : }
143 6594994 : if (value->IsOptimizedOut(isolate_)) {
144 768 : if (materialize_arguments_object) {
145 78 : Handle<String> arguments_str = isolate_->factory()->arguments_string();
146 39 : if (String::Equals(name, arguments_str)) continue;
147 : }
148 766 : value = isolate_->factory()->undefined_value();
149 : }
150 6594990 : JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
151 : }
152 89913 : }
153 :
154 10148 : void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
155 : Handle<JSFunction> function,
156 : bool materialize_arguments_object) {
157 : // Do not materialize the arguments object for eval or top-level code.
158 10148 : if (function->shared()->is_toplevel()) materialize_arguments_object = false;
159 :
160 : Handle<SharedFunctionInfo> shared(function->shared());
161 : Handle<ScopeInfo> scope_info(shared->scope_info());
162 10148 : MaterializeStackLocals(target, scope_info, materialize_arguments_object);
163 :
164 : // Third materialize the arguments object.
165 10148 : if (materialize_arguments_object) {
166 : // Skip if "arguments" is already taken and wasn't optimized out (which
167 : // causes {MaterializeStackLocals} above to skip the local variable).
168 10148 : Handle<String> arguments_str = isolate_->factory()->arguments_string();
169 10148 : Maybe<bool> maybe = JSReceiver::HasOwnProperty(target, arguments_str);
170 : DCHECK(maybe.IsJust());
171 10182 : if (maybe.FromJust()) return;
172 :
173 : // FunctionGetArguments can't throw an exception.
174 10114 : Handle<JSObject> arguments = Accessors::FunctionGetArguments(function);
175 : JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
176 10114 : NONE)
177 20228 : .Check();
178 : }
179 : }
180 :
181 :
182 9542 : void FrameInspector::UpdateStackLocalsFromMaterializedObject(
183 : Handle<JSObject> target, Handle<ScopeInfo> scope_info) {
184 : // Optimized frames and wasm frames are not supported. Simply give up.
185 24876 : if (is_optimized_ || frame_->is_wasm()) return;
186 :
187 5792 : HandleScope scope(isolate_);
188 :
189 : // Parameters.
190 16672 : for (int i = 0; i < scope_info->ParameterCount(); ++i) {
191 : // Shadowed parameters were not materialized.
192 2544 : Handle<String> name(scope_info->ParameterName(i));
193 2544 : if (ScopeInfo::VariableIsSynthetic(*name)) continue;
194 2352 : if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
195 :
196 : DCHECK(!javascript_frame()->GetParameter(i)->IsTheHole(isolate_));
197 : Handle<Object> value =
198 4112 : Object::GetPropertyOrElement(target, name).ToHandleChecked();
199 2056 : javascript_frame()->SetParameterValue(i, *value);
200 : }
201 :
202 : // Stack locals.
203 84902 : for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
204 39555 : Handle<String> name(scope_info->StackLocalName(i));
205 39555 : if (ScopeInfo::VariableIsSynthetic(*name)) continue;
206 39174 : int index = scope_info->StackLocalIndex(i);
207 78348 : if (frame_->GetExpression(index)->IsTheHole(isolate_)) continue;
208 : Handle<Object> value =
209 78348 : Object::GetPropertyOrElement(target, name).ToHandleChecked();
210 39174 : frame_->SetExpression(index, *value);
211 : }
212 : }
213 :
214 :
215 0 : bool FrameInspector::ParameterIsShadowedByContextLocal(
216 : Handle<ScopeInfo> info, Handle<String> parameter_name) {
217 : VariableMode mode;
218 : InitializationFlag init_flag;
219 : MaybeAssignedFlag maybe_assigned_flag;
220 : return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag,
221 30575 : &maybe_assigned_flag) != -1;
222 : }
223 :
224 40710 : SaveContext* DebugFrameHelper::FindSavedContextForFrame(Isolate* isolate,
225 : StandardFrame* frame) {
226 80112 : SaveContext* save = isolate->save_context();
227 161532 : while (save != nullptr && !save->IsBelowFrame(frame)) {
228 : save = save->prev();
229 : }
230 : DCHECK(save != nullptr);
231 40710 : return save;
232 : }
233 :
234 30219 : int DebugFrameHelper::FindIndexedNonNativeFrame(StackTraceFrameIterator* it,
235 : int index) {
236 : int count = -1;
237 60518 : for (; !it->done(); it->Advance()) {
238 : std::vector<FrameSummary> frames;
239 30259 : frames.reserve(FLAG_max_inlining_levels + 1);
240 30259 : it->frame()->Summarize(&frames);
241 90832 : for (size_t i = frames.size(); i != 0; i--) {
242 : // Omit functions from native and extension scripts.
243 60548 : if (!frames[i - 1].is_subject_to_debugging()) continue;
244 30274 : if (++count == index) return static_cast<int>(i) - 1;
245 : }
246 40 : }
247 : return -1;
248 : }
249 :
250 :
251 : } // namespace internal
252 : } // namespace v8
|