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 
      9 namespace v8 {
     10 namespace internal {
     11 
     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 
     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 
     43 int FrameInspector::GetParametersCount() {
     44   return is_optimized_ ? deoptimized_frame_->parameters_count()
     45                        : frame_->ComputeParametersCount();
     46 }
     47 
     48 Handle<Object> FrameInspector::GetFunction() {
     49   return is_optimized_ ? deoptimized_frame_->GetFunction()
     50                        : handle(frame_->function(), isolate_);
     51 }
     52 
     53 Handle<Object> FrameInspector::GetParameter(int index) {
     54   return is_optimized_ ? deoptimized_frame_->GetParameter(index)
     55                        : handle(frame_->GetParameter(index), isolate_);
     56 }
     57 
     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 
     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 
     85 bool FrameInspector::IsConstructor() {
     86   return is_optimized_ && !is_bottommost_
     87              ? deoptimized_frame_->HasConstructStub()
     88              : frame_->IsConstructor();
     89 }
     90 
     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.
     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.
    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 
    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 
    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 
    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 
    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 
    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