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