1// Copyright 2017 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-stack-trace-iterator.h" 6 7#include "src/api/api-inl.h" 8#include "src/debug/debug-evaluate.h" 9#include "src/debug/debug-scope-iterator.h" 10#include "src/debug/debug.h" 11#include "src/debug/liveedit.h" 12#include "src/execution/frames-inl.h" 13#include "src/execution/isolate.h" 14 15#if V8_ENABLE_WEBASSEMBLY 16#include "src/debug/debug-wasm-objects.h" 17#endif // V8_ENABLE_WEBASSEMBLY 18 19namespace v8 { 20 21std::unique_ptr<debug::StackTraceIterator> debug::StackTraceIterator::Create( 22 v8::Isolate* isolate, int index) { 23 return std::unique_ptr<debug::StackTraceIterator>( 24 new internal::DebugStackTraceIterator( 25 reinterpret_cast<internal::Isolate*>(isolate), index)); 26} 27 28namespace internal { 29 30DebugStackTraceIterator::DebugStackTraceIterator(Isolate* isolate, int index) 31 : isolate_(isolate), 32 iterator_(isolate, isolate->debug()->break_frame_id()), 33 is_top_frame_(true) { 34 if (iterator_.done()) return; 35 std::vector<FrameSummary> frames; 36 iterator_.frame()->Summarize(&frames); 37 inlined_frame_index_ = static_cast<int>(frames.size()); 38 Advance(); 39 for (; !Done() && index > 0; --index) Advance(); 40} 41 42DebugStackTraceIterator::~DebugStackTraceIterator() = default; 43 44bool DebugStackTraceIterator::Done() const { return iterator_.done(); } 45 46void DebugStackTraceIterator::Advance() { 47 while (true) { 48 --inlined_frame_index_; 49 for (; inlined_frame_index_ >= 0; --inlined_frame_index_) { 50 // Omit functions from native and extension scripts. 51 if (FrameSummary::Get(iterator_.frame(), inlined_frame_index_) 52 .is_subject_to_debugging()) { 53 break; 54 } 55 is_top_frame_ = false; 56 } 57 if (inlined_frame_index_ >= 0) { 58 frame_inspector_.reset(new FrameInspector( 59 iterator_.frame(), inlined_frame_index_, isolate_)); 60 break; 61 } 62 is_top_frame_ = false; 63 frame_inspector_.reset(); 64 iterator_.Advance(); 65 if (iterator_.done()) break; 66 std::vector<FrameSummary> frames; 67 iterator_.frame()->Summarize(&frames); 68 inlined_frame_index_ = static_cast<int>(frames.size()); 69 } 70} 71 72int DebugStackTraceIterator::GetContextId() const { 73 DCHECK(!Done()); 74 Handle<Object> context = frame_inspector_->GetContext(); 75 if (context->IsContext()) { 76 Object value = Context::cast(*context).native_context().debug_context_id(); 77 if (value.IsSmi()) return Smi::ToInt(value); 78 } 79 return 0; 80} 81 82v8::MaybeLocal<v8::Value> DebugStackTraceIterator::GetReceiver() const { 83 DCHECK(!Done()); 84 if (frame_inspector_->IsJavaScript() && 85 frame_inspector_->GetFunction()->shared().kind() == 86 FunctionKind::kArrowFunction) { 87 // FrameInspector is not able to get receiver for arrow function. 88 // So let's try to fetch it using same logic as is used to retrieve 'this' 89 // during DebugEvaluate::Local. 90 Handle<JSFunction> function = frame_inspector_->GetFunction(); 91 Handle<Context> context(function->context(), isolate_); 92 // Arrow function defined in top level function without references to 93 // variables may have NativeContext as context. 94 if (!context->IsFunctionContext()) return v8::MaybeLocal<v8::Value>(); 95 ScopeIterator scope_iterator( 96 isolate_, frame_inspector_.get(), 97 ScopeIterator::ReparseStrategy::kFunctionLiteral); 98 // We lookup this variable in function context only when it is used in arrow 99 // function otherwise V8 can optimize it out. 100 if (!scope_iterator.ClosureScopeHasThisReference()) { 101 return v8::MaybeLocal<v8::Value>(); 102 } 103 DisallowGarbageCollection no_gc; 104 int slot_index = context->scope_info().ContextSlotIndex( 105 ReadOnlyRoots(isolate_).this_string_handle()); 106 if (slot_index < 0) return v8::MaybeLocal<v8::Value>(); 107 Handle<Object> value = handle(context->get(slot_index), isolate_); 108 if (value->IsTheHole(isolate_)) return v8::MaybeLocal<v8::Value>(); 109 return Utils::ToLocal(value); 110 } 111 112 Handle<Object> value = frame_inspector_->GetReceiver(); 113 if (value.is_null() || (value->IsSmi() || !value->IsTheHole(isolate_))) { 114 return Utils::ToLocal(value); 115 } 116 return v8::MaybeLocal<v8::Value>(); 117} 118 119v8::Local<v8::Value> DebugStackTraceIterator::GetReturnValue() const { 120 CHECK(!Done()); 121#if V8_ENABLE_WEBASSEMBLY 122 if (frame_inspector_ && frame_inspector_->IsWasm()) { 123 return v8::Local<v8::Value>(); 124 } 125#endif // V8_ENABLE_WEBASSEMBLY 126 CHECK_NOT_NULL(iterator_.frame()); 127 bool is_optimized = iterator_.frame()->is_optimized(); 128 if (is_optimized || !is_top_frame_ || 129 !isolate_->debug()->IsBreakAtReturn(iterator_.javascript_frame())) { 130 return v8::Local<v8::Value>(); 131 } 132 return Utils::ToLocal(isolate_->debug()->return_value_handle()); 133} 134 135v8::Local<v8::String> DebugStackTraceIterator::GetFunctionDebugName() const { 136 DCHECK(!Done()); 137 return Utils::ToLocal(frame_inspector_->GetFunctionName()); 138} 139 140v8::Local<v8::debug::Script> DebugStackTraceIterator::GetScript() const { 141 DCHECK(!Done()); 142 Handle<Object> value = frame_inspector_->GetScript(); 143 if (!value->IsScript()) return v8::Local<v8::debug::Script>(); 144 return ToApiHandle<debug::Script>(Handle<Script>::cast(value)); 145} 146 147debug::Location DebugStackTraceIterator::GetSourceLocation() const { 148 DCHECK(!Done()); 149 v8::Local<v8::debug::Script> script = GetScript(); 150 if (script.IsEmpty()) return v8::debug::Location(); 151 return script->GetSourceLocation(frame_inspector_->GetSourcePosition()); 152} 153 154v8::Local<v8::Function> DebugStackTraceIterator::GetFunction() const { 155 DCHECK(!Done()); 156 if (!frame_inspector_->IsJavaScript()) return v8::Local<v8::Function>(); 157 return Utils::ToLocal(frame_inspector_->GetFunction()); 158} 159 160std::unique_ptr<v8::debug::ScopeIterator> 161DebugStackTraceIterator::GetScopeIterator() const { 162 DCHECK(!Done()); 163#if V8_ENABLE_WEBASSEMBLY 164 if (iterator_.frame()->is_wasm()) { 165 return GetWasmScopeIterator(WasmFrame::cast(iterator_.frame())); 166 } 167#endif // V8_ENABLE_WEBASSEMBLY 168 return std::make_unique<DebugScopeIterator>(isolate_, frame_inspector_.get()); 169} 170 171v8::MaybeLocal<v8::Value> DebugStackTraceIterator::Evaluate( 172 v8::Local<v8::String> source, bool throw_on_side_effect) { 173 DCHECK(!Done()); 174 Handle<Object> value; 175 176 i::SafeForInterruptsScope safe_for_interrupt_scope(isolate_); 177 if (!DebugEvaluate::Local(isolate_, iterator_.frame()->id(), 178 inlined_frame_index_, Utils::OpenHandle(*source), 179 throw_on_side_effect) 180 .ToHandle(&value)) { 181 isolate_->OptionalRescheduleException(false); 182 return v8::MaybeLocal<v8::Value>(); 183 } 184 return Utils::ToLocal(value); 185} 186 187} // namespace internal 188} // namespace v8 189