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