blob: 2e06dccab6818526dc5580a59c0a9bae579daa74 [file] [log] [blame]
// 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.h"
#include "src/debug/debug.h"
#include "src/debug/liveedit.h"
#include "src/frames-inl.h"
#include "src/isolate.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() {
// Almost always Script scope will be empty, so just filter out that noise.
// Also drop empty Block, Eval and Script scopes, should we get any.
DCHECK(!Done());
debug::ScopeIterator::ScopeType type = GetType();
if (type != debug::ScopeIterator::ScopeTypeBlock &&
type != debug::ScopeIterator::ScopeTypeScript &&
type != debug::ScopeIterator::ScopeTypeEval &&
type != debug::ScopeIterator::ScopeTypeModule) {
return false;
}
// TODO(kozyatinskiy): make this function faster.
Handle<JSObject> value;
if (!iterator_.ScopeObject().ToHandle(&value)) return false;
Handle<FixedArray> keys =
KeyAccumulator::GetKeys(value, KeyCollectionMode::kOwnOnly,
ENUMERABLE_STRINGS,
GetKeysConversion::kConvertToString)
.ToHandleChecked();
return keys->length() == 0;
}
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;
if (iterator_.ScopeObject().ToHandle(&value)) {
return Utils::ToLocal(value);
}
return v8::Local<v8::Object>();
}
v8::Local<v8::Function> DebugScopeIterator::GetFunction() {
DCHECK(!Done());
Handle<JSFunction> closure = iterator_.GetClosure();
if (closure.is_null()) return v8::Local<v8::Function>();
return Utils::ToLocal(closure);
}
debug::Location DebugScopeIterator::GetStartLocation() {
DCHECK(!Done());
Handle<JSFunction> closure = iterator_.GetClosure();
if (closure.is_null()) return debug::Location();
Object* obj = closure->shared()->script();
if (!obj->IsScript()) return debug::Location();
return ToApiHandle<v8::debug::Script>(handle(Script::cast(obj)))
->GetSourceLocation(iterator_.start_position());
}
debug::Location DebugScopeIterator::GetEndLocation() {
DCHECK(!Done());
Handle<JSFunction> closure = iterator_.GetClosure();
if (closure.is_null()) return debug::Location();
Object* obj = closure->shared()->script();
if (!obj->IsScript()) return debug::Location();
return ToApiHandle<v8::debug::Script>(handle(Script::cast(obj)))
->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_)->wasm_instance()->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>();
}
v8::Local<v8::Function> DebugWasmScopeIterator::GetFunction() {
DCHECK(!Done());
return v8::Local<v8::Function>();
}
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