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