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/frames-inl.h"
8
9 namespace v8 {
10 namespace internal {
11
FrameInspector(JavaScriptFrame * frame,int inlined_jsframe_index,Isolate * isolate)12 FrameInspector::FrameInspector(JavaScriptFrame* frame,
13 int inlined_jsframe_index, Isolate* isolate)
14 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
15 has_adapted_arguments_ = frame_->has_adapted_arguments();
16 is_bottommost_ = inlined_jsframe_index == 0;
17 is_optimized_ = frame_->is_optimized();
18 is_interpreted_ = frame_->is_interpreted();
19 // Calculate the deoptimized frame.
20 if (frame->is_optimized()) {
21 // TODO(turbofan): Revisit once we support deoptimization.
22 if (frame->LookupCode()->is_turbofanned() &&
23 frame->function()->shared()->asm_function() &&
24 !FLAG_turbo_asm_deoptimization) {
25 is_optimized_ = false;
26 return;
27 }
28
29 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
30 frame, inlined_jsframe_index, isolate);
31 }
32 }
33
34
~FrameInspector()35 FrameInspector::~FrameInspector() {
36 // Get rid of the calculated deoptimized frame if any.
37 if (deoptimized_frame_ != NULL) {
38 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_);
39 }
40 }
41
42
GetParametersCount()43 int FrameInspector::GetParametersCount() {
44 return is_optimized_ ? deoptimized_frame_->parameters_count()
45 : frame_->ComputeParametersCount();
46 }
47
GetFunction()48 Handle<Object> FrameInspector::GetFunction() {
49 return is_optimized_ ? deoptimized_frame_->GetFunction()
50 : handle(frame_->function(), isolate_);
51 }
52
GetParameter(int index)53 Handle<Object> FrameInspector::GetParameter(int index) {
54 return is_optimized_ ? deoptimized_frame_->GetParameter(index)
55 : handle(frame_->GetParameter(index), isolate_);
56 }
57
GetExpression(int index)58 Handle<Object> FrameInspector::GetExpression(int index) {
59 // TODO(turbofan): Revisit once we support deoptimization.
60 if (frame_->LookupCode()->is_turbofanned() &&
61 frame_->function()->shared()->asm_function() &&
62 !FLAG_turbo_asm_deoptimization) {
63 return isolate_->factory()->undefined_value();
64 }
65 return is_optimized_ ? deoptimized_frame_->GetExpression(index)
66 : handle(frame_->GetExpression(index), isolate_);
67 }
68
69
GetSourcePosition()70 int FrameInspector::GetSourcePosition() {
71 if (is_optimized_) {
72 return deoptimized_frame_->GetSourcePosition();
73 } else if (is_interpreted_) {
74 InterpretedFrame* frame = reinterpret_cast<InterpretedFrame*>(frame_);
75 BytecodeArray* bytecode_array = frame->GetBytecodeArray();
76 return bytecode_array->SourcePosition(frame->GetBytecodeOffset());
77 } else {
78 Code* code = frame_->LookupCode();
79 int offset = static_cast<int>(frame_->pc() - code->instruction_start());
80 return code->SourcePosition(offset);
81 }
82 }
83
84
IsConstructor()85 bool FrameInspector::IsConstructor() {
86 return is_optimized_ && !is_bottommost_
87 ? deoptimized_frame_->HasConstructStub()
88 : frame_->IsConstructor();
89 }
90
GetContext()91 Handle<Object> FrameInspector::GetContext() {
92 return is_optimized_ ? deoptimized_frame_->GetContext()
93 : handle(frame_->context(), isolate_);
94 }
95
96
97 // To inspect all the provided arguments the frame might need to be
98 // replaced with the arguments frame.
SetArgumentsFrame(JavaScriptFrame * frame)99 void FrameInspector::SetArgumentsFrame(JavaScriptFrame* frame) {
100 DCHECK(has_adapted_arguments_);
101 frame_ = frame;
102 is_optimized_ = frame_->is_optimized();
103 is_interpreted_ = frame_->is_interpreted();
104 DCHECK(!is_optimized_);
105 }
106
107
108 // Create a plain JSObject which materializes the local scope for the specified
109 // frame.
MaterializeStackLocals(Handle<JSObject> target,Handle<ScopeInfo> scope_info)110 void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
111 Handle<ScopeInfo> scope_info) {
112 HandleScope scope(isolate_);
113 // First fill all parameters.
114 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
115 // Do not materialize the parameter if it is shadowed by a context local.
116 // TODO(yangguo): check whether this is necessary, now that we materialize
117 // context locals as well.
118 Handle<String> name(scope_info->ParameterName(i));
119 if (ScopeInfo::VariableIsSynthetic(*name)) continue;
120 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
121
122 Handle<Object> value =
123 i < GetParametersCount()
124 ? GetParameter(i)
125 : Handle<Object>::cast(isolate_->factory()->undefined_value());
126 DCHECK(!value->IsTheHole(isolate_));
127
128 JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
129 }
130
131 // Second fill all stack locals.
132 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
133 Handle<String> name(scope_info->StackLocalName(i));
134 if (ScopeInfo::VariableIsSynthetic(*name)) continue;
135 Handle<Object> value = GetExpression(scope_info->StackLocalIndex(i));
136 // TODO(yangguo): We convert optimized out values to {undefined} when they
137 // are passed to the debugger. Eventually we should handle them somehow.
138 if (value->IsTheHole(isolate_)) {
139 value = isolate_->factory()->undefined_value();
140 }
141 if (value->IsOptimizedOut(isolate_)) {
142 value = isolate_->factory()->undefined_value();
143 }
144 JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
145 }
146 }
147
148
MaterializeStackLocals(Handle<JSObject> target,Handle<JSFunction> function)149 void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
150 Handle<JSFunction> function) {
151 Handle<SharedFunctionInfo> shared(function->shared());
152 Handle<ScopeInfo> scope_info(shared->scope_info());
153 MaterializeStackLocals(target, scope_info);
154 }
155
156
UpdateStackLocalsFromMaterializedObject(Handle<JSObject> target,Handle<ScopeInfo> scope_info)157 void FrameInspector::UpdateStackLocalsFromMaterializedObject(
158 Handle<JSObject> target, Handle<ScopeInfo> scope_info) {
159 if (is_optimized_) {
160 // Optimized frames are not supported. Simply give up.
161 return;
162 }
163
164 HandleScope scope(isolate_);
165
166 // Parameters.
167 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
168 // Shadowed parameters were not materialized.
169 Handle<String> name(scope_info->ParameterName(i));
170 if (ScopeInfo::VariableIsSynthetic(*name)) continue;
171 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
172
173 DCHECK(!frame_->GetParameter(i)->IsTheHole(isolate_));
174 Handle<Object> value =
175 Object::GetPropertyOrElement(target, name).ToHandleChecked();
176 frame_->SetParameterValue(i, *value);
177 }
178
179 // Stack locals.
180 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
181 Handle<String> name(scope_info->StackLocalName(i));
182 if (ScopeInfo::VariableIsSynthetic(*name)) continue;
183 int index = scope_info->StackLocalIndex(i);
184 if (frame_->GetExpression(index)->IsTheHole(isolate_)) continue;
185 Handle<Object> value =
186 Object::GetPropertyOrElement(target, name).ToHandleChecked();
187 frame_->SetExpression(index, *value);
188 }
189 }
190
191
ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,Handle<String> parameter_name)192 bool FrameInspector::ParameterIsShadowedByContextLocal(
193 Handle<ScopeInfo> info, Handle<String> parameter_name) {
194 VariableMode mode;
195 InitializationFlag init_flag;
196 MaybeAssignedFlag maybe_assigned_flag;
197 return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag,
198 &maybe_assigned_flag) != -1;
199 }
200
201
FindSavedContextForFrame(Isolate * isolate,JavaScriptFrame * frame)202 SaveContext* DebugFrameHelper::FindSavedContextForFrame(
203 Isolate* isolate, JavaScriptFrame* frame) {
204 SaveContext* save = isolate->save_context();
205 while (save != NULL && !save->IsBelowFrame(frame)) {
206 save = save->prev();
207 }
208 DCHECK(save != NULL);
209 return save;
210 }
211
212
FindIndexedNonNativeFrame(JavaScriptFrameIterator * it,int index)213 int DebugFrameHelper::FindIndexedNonNativeFrame(JavaScriptFrameIterator* it,
214 int index) {
215 int count = -1;
216 for (; !it->done(); it->Advance()) {
217 List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
218 it->frame()->Summarize(&frames);
219 for (int i = frames.length() - 1; i >= 0; i--) {
220 // Omit functions from native and extension scripts.
221 if (!frames[i].function()->shared()->IsSubjectToDebugging()) continue;
222 if (++count == index) return i;
223 }
224 }
225 return -1;
226 }
227
228
229 } // namespace internal
230 } // namespace v8
231