// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/debug/debug-scope-iterator.h" #include "src/api-inl.h" #include "src/debug/debug.h" #include "src/debug/liveedit.h" #include "src/frames-inl.h" #include "src/isolate.h" #include "src/objects/js-generator-inl.h" #include "src/wasm/wasm-objects-inl.h" namespace v8 { std::unique_ptr<debug::ScopeIterator> debug::ScopeIterator::CreateForFunction( v8::Isolate* v8_isolate, v8::Local<v8::Function> v8_func) { internal::Handle<internal::JSReceiver> receiver = internal::Handle<internal::JSReceiver>::cast(Utils::OpenHandle(*v8_func)); // Besides JSFunction and JSBoundFunction, {v8_func} could be an // ObjectTemplate with a CallAsFunctionHandler. We only handle plain // JSFunctions. if (!receiver->IsJSFunction()) return nullptr; internal::Handle<internal::JSFunction> function = internal::Handle<internal::JSFunction>::cast(receiver); // Blink has function objects with callable map, JS_SPECIAL_API_OBJECT_TYPE // but without context on heap. if (!function->has_context()) return nullptr; return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator( reinterpret_cast<internal::Isolate*>(v8_isolate), function)); } std::unique_ptr<debug::ScopeIterator> debug::ScopeIterator::CreateForGeneratorObject( v8::Isolate* v8_isolate, v8::Local<v8::Object> v8_generator) { internal::Handle<internal::Object> generator = Utils::OpenHandle(*v8_generator); DCHECK(generator->IsJSGeneratorObject()); return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator( reinterpret_cast<internal::Isolate*>(v8_isolate), internal::Handle<internal::JSGeneratorObject>::cast(generator))); } namespace internal { DebugScopeIterator::DebugScopeIterator(Isolate* isolate, FrameInspector* frame_inspector) : iterator_(isolate, frame_inspector) { if (!Done() && ShouldIgnore()) Advance(); } DebugScopeIterator::DebugScopeIterator(Isolate* isolate, Handle<JSFunction> function) : iterator_(isolate, function) { if (!Done() && ShouldIgnore()) Advance(); } DebugScopeIterator::DebugScopeIterator(Isolate* isolate, Handle<JSGeneratorObject> generator) : iterator_(isolate, generator) { if (!Done() && ShouldIgnore()) Advance(); } bool DebugScopeIterator::Done() { return iterator_.Done(); } void DebugScopeIterator::Advance() { DCHECK(!Done()); iterator_.Next(); while (!Done() && ShouldIgnore()) { iterator_.Next(); } } bool DebugScopeIterator::ShouldIgnore() { if (GetType() == debug::ScopeIterator::ScopeTypeLocal) return false; return !iterator_.DeclaresLocals(i::ScopeIterator::Mode::ALL); } v8::debug::ScopeIterator::ScopeType DebugScopeIterator::GetType() { DCHECK(!Done()); return static_cast<v8::debug::ScopeIterator::ScopeType>(iterator_.Type()); } v8::Local<v8::Object> DebugScopeIterator::GetObject() { DCHECK(!Done()); Handle<JSObject> value = iterator_.ScopeObject(i::ScopeIterator::Mode::ALL); return Utils::ToLocal(value); } int DebugScopeIterator::GetScriptId() { DCHECK(!Done()); return iterator_.GetScript()->id(); } v8::Local<v8::Value> DebugScopeIterator::GetFunctionDebugName() { DCHECK(!Done()); Handle<Object> name = iterator_.GetFunctionDebugName(); return Utils::ToLocal(name); } bool DebugScopeIterator::HasLocationInfo() { return iterator_.HasPositionInfo(); } debug::Location DebugScopeIterator::GetStartLocation() { DCHECK(!Done()); return ToApiHandle<v8::debug::Script>(iterator_.GetScript()) ->GetSourceLocation(iterator_.start_position()); } debug::Location DebugScopeIterator::GetEndLocation() { DCHECK(!Done()); return ToApiHandle<v8::debug::Script>(iterator_.GetScript()) ->GetSourceLocation(iterator_.end_position()); } bool DebugScopeIterator::SetVariableValue(v8::Local<v8::String> name, v8::Local<v8::Value> value) { DCHECK(!Done()); return iterator_.SetVariableValue(Utils::OpenHandle(*name), Utils::OpenHandle(*value)); } DebugWasmScopeIterator::DebugWasmScopeIterator(Isolate* isolate, StandardFrame* frame, int inlined_frame_index) : isolate_(isolate), frame_(frame), inlined_frame_index_(inlined_frame_index), type_(debug::ScopeIterator::ScopeTypeGlobal) {} bool DebugWasmScopeIterator::Done() { return type_ != debug::ScopeIterator::ScopeTypeGlobal && type_ != debug::ScopeIterator::ScopeTypeLocal; } void DebugWasmScopeIterator::Advance() { DCHECK(!Done()); if (type_ == debug::ScopeIterator::ScopeTypeGlobal) { type_ = debug::ScopeIterator::ScopeTypeLocal; } else { // We use ScopeTypeWith type as marker for done. type_ = debug::ScopeIterator::ScopeTypeWith; } } v8::debug::ScopeIterator::ScopeType DebugWasmScopeIterator::GetType() { DCHECK(!Done()); return type_; } v8::Local<v8::Object> DebugWasmScopeIterator::GetObject() { DCHECK(!Done()); Handle<WasmDebugInfo> debug_info( WasmInterpreterEntryFrame::cast(frame_)->debug_info(), isolate_); switch (type_) { case debug::ScopeIterator::ScopeTypeGlobal: return Utils::ToLocal(WasmDebugInfo::GetGlobalScopeObject( debug_info, frame_->fp(), inlined_frame_index_)); case debug::ScopeIterator::ScopeTypeLocal: return Utils::ToLocal(WasmDebugInfo::GetLocalScopeObject( debug_info, frame_->fp(), inlined_frame_index_)); default: return v8::Local<v8::Object>(); } return v8::Local<v8::Object>(); } int DebugWasmScopeIterator::GetScriptId() { DCHECK(!Done()); return -1; } v8::Local<v8::Value> DebugWasmScopeIterator::GetFunctionDebugName() { DCHECK(!Done()); return Utils::ToLocal(isolate_->factory()->empty_string()); } bool DebugWasmScopeIterator::HasLocationInfo() { return false; } debug::Location DebugWasmScopeIterator::GetStartLocation() { DCHECK(!Done()); return debug::Location(); } debug::Location DebugWasmScopeIterator::GetEndLocation() { DCHECK(!Done()); return debug::Location(); } bool DebugWasmScopeIterator::SetVariableValue(v8::Local<v8::String> name, v8::Local<v8::Value> value) { DCHECK(!Done()); return false; } } // namespace internal } // namespace v8