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