Commit c5e9416b authored by Alexey Kozyatinskiy's avatar Alexey Kozyatinskiy Committed by Commit Bot

[inspector] move stack trace and scope inspection to native

This CL moves us much closer to the point where we can remove debugger-script.js and usage of debugger context from inspector.
There are three main parts left:
- managing breakpoints,
- inspecting stack and scopes (this CL),
- LiveEdit.

In this CL I moved all stack/scope inspection to native. As side effect running debugger and inspector tests are 10-20% faster (it's significant since not all of tests requesting break).

R=yangguo@chromium.org,jgruber@chromium.org

Bug: chromium:652939
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I409396a687e18e9c0554c0c9c35b6e1064627be8
Reviewed-on: https://chromium-review.googlesource.com/580645Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Commit-Queue: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46947}
parent b4f1e240
......@@ -1475,8 +1475,12 @@ v8_source_set("v8_base") {
"src/debug/debug-frames.cc",
"src/debug/debug-frames.h",
"src/debug/debug-interface.h",
"src/debug/debug-scope-iterator.cc",
"src/debug/debug-scope-iterator.h",
"src/debug/debug-scopes.cc",
"src/debug/debug-scopes.h",
"src/debug/debug-stack-trace-iterator.cc",
"src/debug/debug-stack-trace-iterator.h",
"src/debug/debug.cc",
"src/debug/debug.h",
"src/debug/interface-types.h",
......
......@@ -9646,10 +9646,6 @@ int debug::Script::GetSourceOffset(const debug::Location& location) const {
v8::debug::Location debug::Script::GetSourceLocation(int offset) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
if (script->type() == i::Script::TYPE_WASM) {
// TODO(clemensh): Return the proper thing for wasm.
return v8::debug::Location();
}
i::Script::PositionInfo info;
i::Script::GetPositionInfo(script, offset, &info, i::Script::WITH_OFFSET);
return debug::Location(info.line, info.column);
......@@ -9728,7 +9724,8 @@ int debug::Location::GetColumnNumber() const {
}
bool debug::Location::IsEmpty() const {
return line_number_ == -1 && column_number_ == -1;
return line_number_ == v8::Function::kLineOffsetNotFound &&
column_number_ == v8::Function::kLineOffsetNotFound;
}
void debug::GetLoadedScripts(v8::Isolate* v8_isolate,
......
......@@ -5,8 +5,6 @@
#ifndef V8_DEBUG_DEBUG_INTERFACE_H_
#define V8_DEBUG_DEBUG_INTERFACE_H_
#include <functional>
#include "include/v8-debug.h"
#include "include/v8-util.h"
#include "include/v8.h"
......@@ -319,6 +317,71 @@ class V8_EXPORT_PRIVATE Coverage {
explicit Coverage(i::Coverage* coverage) : coverage_(coverage) {}
i::Coverage* coverage_;
};
class ScopeIterator {
public:
static std::unique_ptr<ScopeIterator> CreateForFunction(
v8::Isolate* isolate, v8::Local<v8::Function> func);
static std::unique_ptr<ScopeIterator> CreateForGeneratorObject(
v8::Isolate* isolate, v8::Local<v8::Object> generator);
ScopeIterator() = default;
virtual ~ScopeIterator() = default;
enum ScopeType {
ScopeTypeGlobal = 0,
ScopeTypeLocal,
ScopeTypeWith,
ScopeTypeClosure,
ScopeTypeCatch,
ScopeTypeBlock,
ScopeTypeScript,
ScopeTypeEval,
ScopeTypeModule
};
virtual bool Done() = 0;
virtual void Advance() = 0;
virtual ScopeType GetType() = 0;
virtual v8::Local<v8::Object> GetObject() = 0;
virtual v8::Local<v8::Function> GetFunction() = 0;
virtual debug::Location GetStartLocation() = 0;
virtual debug::Location GetEndLocation() = 0;
virtual bool SetVariableValue(v8::Local<v8::String> name,
v8::Local<v8::Value> value) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(ScopeIterator);
};
class StackTraceIterator {
public:
static std::unique_ptr<StackTraceIterator> Create(Isolate* isolate,
int index = 0);
StackTraceIterator() = default;
virtual ~StackTraceIterator() = default;
virtual bool Done() const = 0;
virtual void Advance() = 0;
virtual int GetContextId() const = 0;
virtual v8::Local<v8::Value> GetReceiver() const = 0;
virtual v8::Local<v8::Value> GetReturnValue() const = 0;
virtual v8::Local<v8::String> GetFunctionName() const = 0;
virtual v8::Local<v8::debug::Script> GetScript() const = 0;
virtual debug::Location GetSourceLocation() const = 0;
virtual v8::Local<v8::Function> GetFunction() const = 0;
virtual std::unique_ptr<ScopeIterator> GetScopeIterator() const = 0;
virtual bool Restart() = 0;
virtual v8::MaybeLocal<v8::Value> Evaluate(v8::Local<v8::String> source,
bool throw_on_side_effect) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(StackTraceIterator);
};
} // namespace debug
} // namespace v8
......
// 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/debug/debug.h"
#include "src/debug/liveedit.h"
#include "src/frames-inl.h"
#include "src/isolate.h"
#include "src/wasm/wasm-objects.h"
namespace v8 {
std::unique_ptr<debug::ScopeIterator> debug::ScopeIterator::CreateForFunction(
v8::Isolate* v8_isolate, v8::Local<v8::Function> v8_func) {
return std::unique_ptr<debug::ScopeIterator>(new internal::DebugScopeIterator(
reinterpret_cast<internal::Isolate*>(v8_isolate),
internal::Handle<internal::JSFunction>::cast(
Utils::OpenHandle(*v8_func))));
}
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
// 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.
#ifndef V8_DEBUG_DEBUG_SCOPE_ITERATOR_H_
#define V8_DEBUG_DEBUG_SCOPE_ITERATOR_H_
#include "src/debug/debug-frames.h"
#include "src/debug/debug-interface.h"
#include "src/debug/debug-scopes.h"
#include "src/frames.h"
namespace v8 {
namespace internal {
class DebugScopeIterator final : public debug::ScopeIterator {
public:
DebugScopeIterator(Isolate* isolate, FrameInspector* frame_inspector);
DebugScopeIterator(Isolate* isolate, Handle<JSFunction> function);
DebugScopeIterator(Isolate* isolate, Handle<JSGeneratorObject> generator);
bool Done() override;
void Advance() override;
ScopeType GetType() override;
v8::Local<v8::Object> GetObject() override;
v8::Local<v8::Function> GetFunction() override;
debug::Location GetStartLocation() override;
debug::Location GetEndLocation() override;
bool SetVariableValue(v8::Local<v8::String> name,
v8::Local<v8::Value> value) override;
private:
bool ShouldIgnore();
v8::internal::ScopeIterator iterator_;
};
class DebugWasmScopeIterator final : public debug::ScopeIterator {
public:
DebugWasmScopeIterator(Isolate* isolate, StandardFrame* frame,
int inlined_frame_index);
bool Done() override;
void Advance() override;
ScopeType GetType() override;
v8::Local<v8::Object> GetObject() override;
v8::Local<v8::Function> GetFunction() override;
debug::Location GetStartLocation() override;
debug::Location GetEndLocation() override;
bool SetVariableValue(v8::Local<v8::String> name,
v8::Local<v8::Value> value) override;
private:
Isolate* isolate_;
StandardFrame* frame_;
int inlined_frame_index_;
ScopeType type_;
};
} // namespace internal
} // namespace v8
#endif // V8_DEBUG_DEBUG_SCOPE_ITERATOR_H_
......@@ -187,36 +187,49 @@ MUST_USE_RESULT MaybeHandle<JSObject> ScopeIterator::MaterializeScopeDetails() {
Handle<JSObject> scope_object;
ASSIGN_RETURN_ON_EXCEPTION(isolate_, scope_object, ScopeObject(), JSObject);
details->set(kScopeDetailsObjectIndex, *scope_object);
Handle<JSFunction> js_function = HasContext()
? handle(CurrentContext()->closure())
: Handle<JSFunction>::null();
if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript) {
return isolate_->factory()->NewJSArrayWithElements(details);
}
int start_position = 0;
int end_position = 0;
if (!nested_scope_chain_.is_empty()) {
js_function = GetFunction();
start_position = nested_scope_chain_.last().start_position;
end_position = nested_scope_chain_.last().end_position;
} else if (!js_function.is_null()) {
start_position = js_function->shared()->start_position();
end_position = js_function->shared()->end_position();
}
Handle<JSFunction> js_function = GetClosure();
if (!js_function.is_null()) {
Handle<String> closure_name = JSFunction::GetDebugName(js_function);
if (!closure_name.is_null() && closure_name->length() != 0) {
details->set(kScopeDetailsNameIndex, *closure_name);
}
details->set(kScopeDetailsStartPositionIndex, Smi::FromInt(start_position));
details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position));
details->set(kScopeDetailsStartPositionIndex,
Smi::FromInt(start_position()));
details->set(kScopeDetailsEndPositionIndex, Smi::FromInt(end_position()));
details->set(kScopeDetailsFunctionIndex, *js_function);
}
return isolate_->factory()->NewJSArrayWithElements(details);
}
Handle<JSFunction> ScopeIterator::GetClosure() {
if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript)
return Handle<JSFunction>::null();
if (HasNestedScopeChain()) return GetFunction();
return HasContext() ? handle(CurrentContext()->closure())
: Handle<JSFunction>::null();
}
int ScopeIterator::start_position() {
if (HasNestedScopeChain()) {
return LastNestedScopeChain().start_position;
}
if (!HasContext()) return 0;
Handle<JSFunction> js_function = handle(CurrentContext()->closure());
return js_function.is_null() ? 0 : js_function->shared()->start_position();
}
int ScopeIterator::end_position() {
if (HasNestedScopeChain()) {
return LastNestedScopeChain().end_position;
}
if (!HasContext()) return 0;
Handle<JSFunction> js_function = handle(CurrentContext()->closure());
return js_function.is_null() ? 0 : js_function->shared()->end_position();
}
void ScopeIterator::Next() {
DCHECK(!Done());
......@@ -230,25 +243,24 @@ void ScopeIterator::Next() {
if (context_->IsScriptContext()) {
context_ = Handle<Context>(context_->previous(), isolate_);
}
if (!nested_scope_chain_.is_empty()) {
DCHECK_EQ(nested_scope_chain_.last().scope_info->scope_type(),
SCRIPT_SCOPE);
if (HasNestedScopeChain()) {
DCHECK_EQ(LastNestedScopeChain().scope_info->scope_type(), SCRIPT_SCOPE);
nested_scope_chain_.RemoveLast();
DCHECK(nested_scope_chain_.is_empty());
DCHECK(!HasNestedScopeChain());
}
CHECK(context_->IsNativeContext());
} else if (nested_scope_chain_.is_empty()) {
} else if (!HasNestedScopeChain()) {
context_ = Handle<Context>(context_->previous(), isolate_);
} else {
do {
if (nested_scope_chain_.last().scope_info->HasContext()) {
if (LastNestedScopeChain().scope_info->HasContext()) {
DCHECK(context_->previous() != NULL);
context_ = Handle<Context>(context_->previous(), isolate_);
}
nested_scope_chain_.RemoveLast();
if (nested_scope_chain_.is_empty()) break;
if (!HasNestedScopeChain()) break;
// Repeat to skip hidden scopes.
} while (nested_scope_chain_.last().is_hidden());
} while (LastNestedScopeChain().is_hidden());
}
UnwrapEvaluationContext();
}
......@@ -257,8 +269,8 @@ void ScopeIterator::Next() {
// Return the type of the current scope.
ScopeIterator::ScopeType ScopeIterator::Type() {
DCHECK(!Done());
if (!nested_scope_chain_.is_empty()) {
Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
if (HasNestedScopeChain()) {
Handle<ScopeInfo> scope_info = LastNestedScopeChain().scope_info;
switch (scope_info->scope_type()) {
case FUNCTION_SCOPE:
DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
......@@ -342,8 +354,8 @@ bool ScopeIterator::HasContext() {
ScopeType type = Type();
if (type == ScopeTypeBlock || type == ScopeTypeLocal ||
type == ScopeTypeEval) {
if (!nested_scope_chain_.is_empty()) {
return nested_scope_chain_.last().scope_info->HasContext();
if (HasNestedScopeChain()) {
return LastNestedScopeChain().scope_info->HasContext();
}
}
return true;
......@@ -379,8 +391,8 @@ bool ScopeIterator::SetVariableValue(Handle<String> variable_name,
Handle<ScopeInfo> ScopeIterator::CurrentScopeInfo() {
DCHECK(!Done());
if (!nested_scope_chain_.is_empty()) {
return nested_scope_chain_.last().scope_info;
if (HasNestedScopeChain()) {
return LastNestedScopeChain().scope_info;
} else if (context_->IsBlockContext() || context_->IsFunctionContext() ||
context_->IsEvalContext()) {
return Handle<ScopeInfo>(context_->scope_info());
......@@ -392,9 +404,9 @@ Handle<ScopeInfo> ScopeIterator::CurrentScopeInfo() {
Handle<Context> ScopeIterator::CurrentContext() {
DCHECK(!Done());
if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
nested_scope_chain_.is_empty()) {
!HasNestedScopeChain()) {
return context_;
} else if (nested_scope_chain_.last().scope_info->HasContext()) {
} else if (LastNestedScopeChain().scope_info->HasContext()) {
return context_;
} else {
return Handle<Context>();
......@@ -638,8 +650,8 @@ Handle<JSObject> ScopeIterator::MaterializeInnerScope() {
isolate_->factory()->NewJSObjectWithNullProto();
Handle<Context> context = Handle<Context>::null();
if (!nested_scope_chain_.is_empty()) {
Handle<ScopeInfo> scope_info = nested_scope_chain_.last().scope_info;
if (HasNestedScopeChain()) {
Handle<ScopeInfo> scope_info = LastNestedScopeChain().scope_info;
MaterializeStackLocals(inner_scope, scope_info);
if (scope_info->HasContext()) context = CurrentContext();
} else {
......@@ -970,5 +982,14 @@ void ScopeIterator::GetNestedScopeChain(Isolate* isolate, Scope* scope,
}
}
bool ScopeIterator::HasNestedScopeChain() {
return !nested_scope_chain_.is_empty();
}
ScopeIterator::ExtendedScopeInfo& ScopeIterator::LastNestedScopeChain() {
DCHECK(HasNestedScopeChain());
return nested_scope_chain_.last();
}
} // namespace internal
} // namespace v8
......@@ -75,6 +75,11 @@ class ScopeIterator {
// Populate the set with collected non-local variable names.
Handle<StringSet> GetNonLocals();
// Return function which represents closure for current scope.
Handle<JSFunction> GetClosure();
int start_position();
int end_position();
#ifdef DEBUG
// Debug print of the content of the current scope.
void DebugPrint();
......@@ -169,6 +174,9 @@ class ScopeIterator {
void GetNestedScopeChain(Isolate* isolate, Scope* scope,
int statement_position);
bool HasNestedScopeChain();
ExtendedScopeInfo& LastNestedScopeChain();
DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
};
......
// 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-stack-trace-iterator.h"
#include "src/debug/debug-evaluate.h"
#include "src/debug/debug-scope-iterator.h"
#include "src/debug/debug.h"
#include "src/debug/liveedit.h"
#include "src/frames-inl.h"
#include "src/isolate.h"
namespace v8 {
std::unique_ptr<debug::StackTraceIterator> debug::StackTraceIterator::Create(
v8::Isolate* isolate, int index) {
return std::unique_ptr<debug::StackTraceIterator>(
new internal::DebugStackTraceIterator(
reinterpret_cast<internal::Isolate*>(isolate), index));
}
namespace internal {
DebugStackTraceIterator::DebugStackTraceIterator(Isolate* isolate, int index)
: isolate_(isolate),
iterator_(isolate, isolate->debug()->break_frame_id()),
is_top_frame_(true) {
if (iterator_.done()) return;
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
iterator_.frame()->Summarize(&frames);
inlined_frame_index_ = frames.length();
Advance();
for (; !Done() && index > 0; --index) Advance();
}
DebugStackTraceIterator::~DebugStackTraceIterator() {}
bool DebugStackTraceIterator::Done() const { return iterator_.done(); }
void DebugStackTraceIterator::Advance() {
while (true) {
--inlined_frame_index_;
for (; inlined_frame_index_ >= 0; --inlined_frame_index_) {
// Omit functions from native and extension scripts.
if (FrameSummary::Get(iterator_.frame(), inlined_frame_index_)
.is_subject_to_debugging()) {
break;
}
is_top_frame_ = false;
}
if (inlined_frame_index_ >= 0) {
frame_inspector_.reset(new FrameInspector(
iterator_.frame(), inlined_frame_index_, isolate_));
break;
}
is_top_frame_ = false;
frame_inspector_.reset();
iterator_.Advance();
if (iterator_.done()) break;
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
iterator_.frame()->Summarize(&frames);
inlined_frame_index_ = frames.length();
}
}
int DebugStackTraceIterator::GetContextId() const {
DCHECK(!Done());
Object* value =
frame_inspector_->summary().native_context()->debug_context_id();
return (value->IsSmi()) ? Smi::ToInt(value) : 0;
}
v8::Local<v8::Value> DebugStackTraceIterator::GetReceiver() const {
DCHECK(!Done());
Handle<Object> value = frame_inspector_->summary().receiver();
if (value.is_null() || (value->IsSmi() || !value->IsTheHole(isolate_))) {
return Utils::ToLocal(value);
}
return v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate_));
}
v8::Local<v8::Value> DebugStackTraceIterator::GetReturnValue() const {
DCHECK(!Done());
if (frame_inspector_->summary().IsWasm()) return v8::Local<v8::Value>();
bool is_optimized = iterator_.frame()->is_optimized();
if (is_optimized || !is_top_frame_ ||
!isolate_->debug()->IsBreakAtReturn(iterator_.javascript_frame())) {
return v8::Local<v8::Value>();
}
return Utils::ToLocal(isolate_->debug()->return_value_handle());
}
v8::Local<v8::String> DebugStackTraceIterator::GetFunctionName() const {
DCHECK(!Done());
return Utils::ToLocal(frame_inspector_->summary().FunctionName());
}
v8::Local<v8::debug::Script> DebugStackTraceIterator::GetScript() const {
DCHECK(!Done());
Handle<Object> value = frame_inspector_->summary().script();
if (!value->IsScript()) return v8::Local<v8::debug::Script>();
return ToApiHandle<debug::Script>(Handle<Script>::cast(value));
}
debug::Location DebugStackTraceIterator::GetSourceLocation() const {
DCHECK(!Done());
v8::Local<v8::debug::Script> script = GetScript();
if (script.IsEmpty()) return v8::debug::Location();
return script->GetSourceLocation(
frame_inspector_->summary().SourcePosition());
}
v8::Local<v8::Function> DebugStackTraceIterator::GetFunction() const {
DCHECK(!Done());
if (!frame_inspector_->summary().IsJavaScript())
return v8::Local<v8::Function>();
return Utils::ToLocal(frame_inspector_->summary().AsJavaScript().function());
}
std::unique_ptr<v8::debug::ScopeIterator>
DebugStackTraceIterator::GetScopeIterator() const {
DCHECK(!Done());
StandardFrame* frame = iterator_.frame();
if (frame->is_wasm_interpreter_entry()) {
return std::unique_ptr<v8::debug::ScopeIterator>(new DebugWasmScopeIterator(
isolate_, iterator_.frame(), inlined_frame_index_));
}
return std::unique_ptr<v8::debug::ScopeIterator>(
new DebugScopeIterator(isolate_, frame_inspector_.get()));
}
bool DebugStackTraceIterator::Restart() {
DCHECK(!Done());
if (iterator_.is_wasm()) return false;
return !LiveEdit::RestartFrame(iterator_.javascript_frame());
}
v8::MaybeLocal<v8::Value> DebugStackTraceIterator::Evaluate(
v8::Local<v8::String> source, bool throw_on_side_effect) {
DCHECK(!Done());
Handle<Object> value;
if (!DebugEvaluate::Local(isolate_, iterator_.frame()->id(),
inlined_frame_index_, Utils::OpenHandle(*source),
throw_on_side_effect)
.ToHandle(&value)) {
isolate_->OptionalRescheduleException(false);
return v8::MaybeLocal<v8::Value>();
}
return Utils::ToLocal(value);
}
} // namespace internal
} // namespace v8
// 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.
#ifndef V8_DEBUG_DEBUG_STACK_TRACE_ITERATOR_H_
#define V8_DEBUG_DEBUG_STACK_TRACE_ITERATOR_H_
#include "src/debug/debug-frames.h"
#include "src/debug/debug-interface.h"
#include "src/frames.h"
namespace v8 {
namespace internal {
class DebugStackTraceIterator final : public debug::StackTraceIterator {
public:
DebugStackTraceIterator(Isolate* isolate, int index);
~DebugStackTraceIterator() override;
bool Done() const override;
void Advance() override;
int GetContextId() const override;
v8::Local<v8::Value> GetReceiver() const override;
v8::Local<v8::Value> GetReturnValue() const override;
v8::Local<v8::String> GetFunctionName() const override;
v8::Local<v8::debug::Script> GetScript() const override;
debug::Location GetSourceLocation() const override;
v8::Local<v8::Function> GetFunction() const override;
std::unique_ptr<v8::debug::ScopeIterator> GetScopeIterator() const override;
bool Restart() override;
v8::MaybeLocal<v8::Value> Evaluate(v8::Local<v8::String> source,
bool throw_on_side_effect) override;
private:
Isolate* isolate_;
StackTraceFrameIterator iterator_;
std::unique_ptr<FrameInspector> frame_inspector_;
int inlined_frame_index_;
bool is_top_frame_;
};
} // namespace internal
} // namespace v8
#endif // V8_DEBUG_DEBUG_STACK_TRACE_ITERATOR_H_
......@@ -136,8 +136,6 @@ v8_source_set("inspector") {
"injected-script.h",
"inspected-context.cc",
"inspected-context.h",
"java-script-call-frame.cc",
"java-script-call-frame.h",
"remote-object-id.cc",
"remote-object-id.h",
"script-breakpoint.h",
......
This diff is collapsed.
......@@ -2,43 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/** @typedef {{
type: string,
object: !Object,
name: (string|undefined),
startLocation: (!RawLocation|undefined),
endLocation: (!RawLocation|undefined)
}} */
var Scope;
/** @typedef {{
scriptId: string,
lineNumber: number,
columnNumber: number
}} */
var RawLocation;
/** @typedef {{
functionName: string,
location: !RawLocation,
this: !Object,
scopeChain: !Array<!Scope>,
functionLocation: (RawLocation|undefined),
returnValue: (*|undefined)
}} */
var JavaScriptCallFrameDetails;
/** @typedef {{
contextId: function():number,
thisObject: !Object,
evaluate: function(string, boolean):*,
restart: function():undefined,
setVariableValue: function(number, string, *):undefined,
isAtReturn: boolean,
details: function():!JavaScriptCallFrameDetails
}} */
var JavaScriptCallFrame;
/**
* @const
*/
......@@ -58,6 +21,17 @@ Debug.scripts = function() {}
*/
Debug.setScriptBreakPointById = function(scriptId, line, column, condition, groupId) {}
/** @typedef {{
* script: number,
* position: number,
* line: number,
* column:number,
* start: number,
* end: number,
* }}
*/
var SourceLocation;
/**
* @param {number} breakId
* @return {!Array<!SourceLocation>}
......@@ -121,262 +95,8 @@ BreakPoint.prototype.number = function() {}
/** @interface */
function ExecutionState() {}
/**
* @param {string} source
*/
ExecutionState.prototype.evaluateGlobal = function(source) {}
/** @return {number} */
ExecutionState.prototype.frameCount = function() {}
/**
* @param {number} index
* @return {!FrameMirror}
*/
ExecutionState.prototype.frame = function(index) {}
/** @param {number} index */
ExecutionState.prototype.setSelectedFrame = function(index) {}
/** @return {number} */
ExecutionState.prototype.selectedFrame = function() {}
/** @enum */
var ScopeType = { Global: 0,
Local: 1,
With: 2,
Closure: 3,
Catch: 4,
Block: 5,
Script: 6,
Eval: 7,
Module: 8};
/** @typedef {{
* script: number,
* position: number,
* line: number,
* column:number,
* start: number,
* end: number,
* }}
*/
var SourceLocation;
/** @typedef{{
* id: number,
* context_data: (string|undefined),
* }}
*/
var Script;
/** @interface */
function ScopeDetails() {}
/** @return {!Object} */
ScopeDetails.prototype.object = function() {}
/** @return {string|undefined} */
ScopeDetails.prototype.name = function() {}
/** @return {number} */
ScopeDetails.prototype.type = function() {}
/** @interface */
function FrameDetails() {}
/** @return {!Object} */
FrameDetails.prototype.receiver = function() {}
/** @return {function()} */
FrameDetails.prototype.func = function() {}
/** @return {!Object} */
FrameDetails.prototype.script = function() {}
/** @return {boolean} */
FrameDetails.prototype.isAtReturn = function() {}
/** @return {number} */
FrameDetails.prototype.sourcePosition = function() {}
/** @return {*} */
FrameDetails.prototype.returnValue = function() {}
/** @return {number} */
FrameDetails.prototype.scopeCount = function() {}
/**
* @param {*} value
* @return {!Mirror}
*/
function MakeMirror(value) {}
/** @interface */
function Mirror() {}
/** @return {boolean} */
Mirror.prototype.isFunction = function() {}
/** @return {boolean} */
Mirror.prototype.isGenerator = function() {}
/**
* @interface
* @extends {Mirror}
*/
function ObjectMirror() {}
/** @return {!Array<!PropertyMirror>} */
ObjectMirror.prototype.properties = function() {}
/**
* @interface
* @extends {ObjectMirror}
*/
function FunctionMirror () {}
/** @return {number} */
FunctionMirror.prototype.scopeCount = function() {}
/**
* @param {number} index
* @return {!ScopeMirror|undefined}
*/
FunctionMirror.prototype.scope = function(index) {}
/** @return {boolean} */
FunctionMirror.prototype.resolved = function() {}
/** @return {function()} */
FunctionMirror.prototype.value = function() {}
/** @return {string} */
FunctionMirror.prototype.debugName = function() {}
/** @return {!ScriptMirror|undefined} */
FunctionMirror.prototype.script = function() {}
/** @return {!SourceLocation|undefined} */
FunctionMirror.prototype.sourceLocation = function() {}
/** @return {!ContextMirror|undefined} */
FunctionMirror.prototype.context = function() {}
/**
* @constructor
* @param {*} value
*/
function UnresolvedFunctionMirror(value) {}
/**
* @interface
* @extends {ObjectMirror}
*/
function GeneratorMirror () {}
/** @return {number} */
GeneratorMirror.prototype.scopeCount = function() {}
/**
* @param {number} index
* @return {!ScopeMirror|undefined}
*/
GeneratorMirror.prototype.scope = function(index) {}
/**
* @interface
* @extends {Mirror}
*/
function PropertyMirror() {}
/** @return {!Mirror} */
PropertyMirror.prototype.value = function() {}
/** @return {string} */
PropertyMirror.prototype.name = function() {}
/** @type {*} */
PropertyMirror.prototype.value_;
/**
* @interface
* @extends {Mirror}
*/
function FrameMirror() {}
/**
* @param {boolean=} ignoreNestedScopes
* @return {!Array<!ScopeMirror>}
*/
FrameMirror.prototype.allScopes = function(ignoreNestedScopes) {}
/** @return {!FrameDetails} */
FrameMirror.prototype.details = function() {}
/** @return {!ScriptMirror} */
FrameMirror.prototype.script = function() {}
/**
* @param {string} source
* @param {boolean} throwOnSideEffect
*/
FrameMirror.prototype.evaluate = function(source, throwOnSideEffect) {}
FrameMirror.prototype.restart = function() {}
/** @param {number} index */
FrameMirror.prototype.scope = function(index) {}
/**
* @interface
* @extends {Mirror}
*/
function ScriptMirror() {}
/** @return {!Script} */
ScriptMirror.prototype.value = function() {}
/** @return {number} */
ScriptMirror.prototype.id = function() {}
/** @return {ContextMirror} */
ScriptMirror.prototype.context = function() {}
/**
* @param {number} position
* @param {boolean=} includeResourceOffset
*/
ScriptMirror.prototype.locationFromPosition = function(position, includeResourceOffset) {}
/**
* @interface
* @extends {Mirror}
*/
function ScopeMirror() {}
/** @return {!ScopeDetails} */
ScopeMirror.prototype.details = function() {}
/**
* @param {string} name
* @param {*} newValue
*/
ScopeMirror.prototype.setVariableValue = function(name, newValue) {}
/**
* @interface
* @extends {Mirror}
*/
function ContextMirror() {}
/** @return {string|undefined} */
ContextMirror.prototype.data = function() {}
......@@ -40,8 +40,6 @@
'inspector/injected-script.h',
'inspector/inspected-context.cc',
'inspector/inspected-context.h',
'inspector/java-script-call-frame.cc',
'inspector/java-script-call-frame.h',
'inspector/remote-object-id.cc',
'inspector/remote-object-id.h',
'inspector/script-breakpoint.h',
......
/*
* Copyright (c) 2010, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "src/inspector/java-script-call-frame.h"
#include "src/debug/debug-interface.h"
#include "src/inspector/string-util.h"
namespace v8_inspector {
JavaScriptCallFrame::JavaScriptCallFrame(v8::Local<v8::Context> debuggerContext,
v8::Local<v8::Object> callFrame)
: m_isolate(debuggerContext->GetIsolate()),
m_debuggerContext(m_isolate, debuggerContext),
m_callFrame(m_isolate, callFrame) {}
JavaScriptCallFrame::~JavaScriptCallFrame() {}
int JavaScriptCallFrame::callV8FunctionReturnInt(const char* name) const {
v8::HandleScope handleScope(m_isolate);
v8::MicrotasksScope microtasks(m_isolate,
v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(m_isolate, m_debuggerContext);
v8::Local<v8::Object> callFrame =
v8::Local<v8::Object>::New(m_isolate, m_callFrame);
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(
callFrame->Get(context, toV8StringInternalized(m_isolate, name))
.ToLocalChecked());
v8::Local<v8::Value> result;
if (!func->Call(context, callFrame, 0, nullptr).ToLocal(&result) ||
!result->IsInt32())
return 0;
return result.As<v8::Int32>()->Value();
}
int JavaScriptCallFrame::contextId() const {
return callV8FunctionReturnInt("contextId");
}
bool JavaScriptCallFrame::isAtReturn() const {
v8::HandleScope handleScope(m_isolate);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(m_isolate, m_debuggerContext);
v8::Local<v8::Object> callFrame =
v8::Local<v8::Object>::New(m_isolate, m_callFrame);
v8::Local<v8::Value> result;
if (!callFrame->Get(context, toV8StringInternalized(m_isolate, "isAtReturn"))
.ToLocal(&result) ||
!result->IsBoolean())
return false;
return result.As<v8::Boolean>()->BooleanValue(context).FromMaybe(false);
}
v8::MaybeLocal<v8::Object> JavaScriptCallFrame::details() const {
v8::MicrotasksScope microtasks(m_isolate,
v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(m_isolate, m_debuggerContext);
v8::Local<v8::Object> callFrame =
v8::Local<v8::Object>::New(m_isolate, m_callFrame);
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(
callFrame->Get(context, toV8StringInternalized(m_isolate, "details"))
.ToLocalChecked());
v8::TryCatch try_catch(m_isolate);
v8::Local<v8::Value> details;
if (func->Call(context, callFrame, 0, nullptr).ToLocal(&details)) {
return v8::Local<v8::Object>::Cast(details);
}
return v8::MaybeLocal<v8::Object>();
}
v8::MaybeLocal<v8::Value> JavaScriptCallFrame::evaluate(
v8::Local<v8::Value> expression, bool throwOnSideEffect) {
v8::MicrotasksScope microtasks(m_isolate,
v8::MicrotasksScope::kRunMicrotasks);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(m_isolate, m_debuggerContext);
v8::Local<v8::Object> callFrame =
v8::Local<v8::Object>::New(m_isolate, m_callFrame);
v8::Local<v8::Function> evalFunction = v8::Local<v8::Function>::Cast(
callFrame->Get(context, toV8StringInternalized(m_isolate, "evaluate"))
.ToLocalChecked());
v8::Local<v8::Value> argv[] = {
expression, v8::Boolean::New(m_isolate, throwOnSideEffect)};
return evalFunction->Call(context, callFrame, arraysize(argv), argv);
}
v8::MaybeLocal<v8::Value> JavaScriptCallFrame::restart() {
v8::MicrotasksScope microtasks(m_isolate,
v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(m_isolate, m_debuggerContext);
v8::Local<v8::Object> callFrame =
v8::Local<v8::Object>::New(m_isolate, m_callFrame);
v8::Local<v8::Function> restartFunction = v8::Local<v8::Function>::Cast(
callFrame->Get(context, toV8StringInternalized(m_isolate, "restart"))
.ToLocalChecked());
v8::TryCatch try_catch(m_isolate);
v8::debug::SetLiveEditEnabled(m_isolate, true);
v8::MaybeLocal<v8::Value> result = restartFunction->Call(
m_debuggerContext.Get(m_isolate), callFrame, 0, nullptr);
v8::debug::SetLiveEditEnabled(m_isolate, false);
return result;
}
v8::MaybeLocal<v8::Value> JavaScriptCallFrame::setVariableValue(
int scopeNumber, v8::Local<v8::Value> variableName,
v8::Local<v8::Value> newValue) {
v8::MicrotasksScope microtasks(m_isolate,
v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(m_isolate, m_debuggerContext);
v8::Local<v8::Object> callFrame =
v8::Local<v8::Object>::New(m_isolate, m_callFrame);
v8::Local<v8::Function> setVariableValueFunction =
v8::Local<v8::Function>::Cast(
callFrame
->Get(context,
toV8StringInternalized(m_isolate, "setVariableValue"))
.ToLocalChecked());
v8::Local<v8::Value> argv[] = {
v8::Local<v8::Value>(v8::Integer::New(m_isolate, scopeNumber)),
variableName, newValue};
v8::TryCatch try_catch(m_isolate);
return setVariableValueFunction->Call(context, callFrame, arraysize(argv),
argv);
}
} // namespace v8_inspector
/*
* Copyright (c) 2010, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef V8_INSPECTOR_JAVASCRIPTCALLFRAME_H_
#define V8_INSPECTOR_JAVASCRIPTCALLFRAME_H_
#include <memory>
#include <vector>
#include "src/base/macros.h"
#include "include/v8.h"
namespace v8_inspector {
class JavaScriptCallFrame {
public:
static std::unique_ptr<JavaScriptCallFrame> create(
v8::Local<v8::Context> debuggerContext, v8::Local<v8::Object> callFrame) {
return std::unique_ptr<JavaScriptCallFrame>(
new JavaScriptCallFrame(debuggerContext, callFrame));
}
~JavaScriptCallFrame();
int contextId() const;
bool isAtReturn() const;
v8::MaybeLocal<v8::Object> details() const;
v8::MaybeLocal<v8::Value> evaluate(v8::Local<v8::Value> expression,
bool throwOnSideEffect);
v8::MaybeLocal<v8::Value> restart();
v8::MaybeLocal<v8::Value> setVariableValue(int scopeNumber,
v8::Local<v8::Value> variableName,
v8::Local<v8::Value> newValue);
private:
JavaScriptCallFrame(v8::Local<v8::Context> debuggerContext,
v8::Local<v8::Object> callFrame);
int callV8FunctionReturnInt(const char* name) const;
v8::Isolate* m_isolate;
v8::Global<v8::Context> m_debuggerContext;
v8::Global<v8::Object> m_callFrame;
DISALLOW_COPY_AND_ASSIGN(JavaScriptCallFrame);
};
using JavaScriptCallFrames = std::vector<std::unique_ptr<JavaScriptCallFrame>>;
} // namespace v8_inspector
#endif // V8_INSPECTOR_JAVASCRIPTCALLFRAME_H_
This diff is collapsed.
......@@ -9,7 +9,6 @@
#include "src/base/macros.h"
#include "src/debug/interface-types.h"
#include "src/inspector/java-script-call-frame.h"
#include "src/inspector/protocol/Debugger.h"
#include "src/inspector/protocol/Forward.h"
......@@ -179,7 +178,6 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
protocol::DictionaryValue* m_state;
protocol::Debugger::Frontend m_frontend;
v8::Isolate* m_isolate;
JavaScriptCallFrames m_pausedCallFrames;
ScriptsMap m_scripts;
BreakpointIdToDebuggerBreakpointIdsMap m_breakpointIdToDebuggerBreakpointIds;
DebugServerBreakpointToBreakpointIdAndSourceMap m_serverBreakpoints;
......
......@@ -134,6 +134,31 @@ void cleanupExpiredWeakPointers(Map& map) {
}
}
String16 scopeType(v8::debug::ScopeIterator::ScopeType type) {
switch (type) {
case v8::debug::ScopeIterator::ScopeTypeGlobal:
return protocol::Debugger::Scope::TypeEnum::Global;
case v8::debug::ScopeIterator::ScopeTypeLocal:
return protocol::Debugger::Scope::TypeEnum::Local;
case v8::debug::ScopeIterator::ScopeTypeWith:
return protocol::Debugger::Scope::TypeEnum::With;
case v8::debug::ScopeIterator::ScopeTypeClosure:
return protocol::Debugger::Scope::TypeEnum::Closure;
case v8::debug::ScopeIterator::ScopeTypeCatch:
return protocol::Debugger::Scope::TypeEnum::Catch;
case v8::debug::ScopeIterator::ScopeTypeBlock:
return protocol::Debugger::Scope::TypeEnum::Block;
case v8::debug::ScopeIterator::ScopeTypeScript:
return protocol::Debugger::Scope::TypeEnum::Script;
case v8::debug::ScopeIterator::ScopeTypeEval:
return protocol::Debugger::Scope::TypeEnum::Eval;
case v8::debug::ScopeIterator::ScopeTypeModule:
return protocol::Debugger::Scope::TypeEnum::Module;
}
UNREACHABLE();
return String16();
}
} // namespace
static bool inLiveEditScope = false;
......@@ -477,8 +502,7 @@ void V8Debugger::clearContinueToLocation() {
Response V8Debugger::setScriptSource(
const String16& sourceID, v8::Local<v8::String> newSource, bool dryRun,
Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails,
JavaScriptCallFrames* newCallFrames, Maybe<bool>* stackChanged,
bool* compileError) {
Maybe<bool>* stackChanged, bool* compileError) {
class EnableLiveEditScope {
public:
explicit EnableLiveEditScope(v8::Isolate* isolate) : m_isolate(isolate) {
......@@ -536,12 +560,6 @@ Response V8Debugger::setScriptSource(
.ToLocalChecked()
->BooleanValue(context)
.FromJust();
// Call stack may have changed after if the edited function was on the
// stack.
if (!dryRun && isPaused()) {
JavaScriptCallFrames frames = currentCallFrames();
newCallFrames->swap(frames);
}
return Response::OK();
}
// Compile error.
......@@ -571,30 +589,6 @@ Response V8Debugger::setScriptSource(
return Response::InternalError();
}
JavaScriptCallFrames V8Debugger::currentCallFrames(int limit) {
if (!isPaused()) return JavaScriptCallFrames();
v8::Local<v8::Value> currentCallFramesV8;
v8::Local<v8::Value> argv[] = {m_executionState,
v8::Integer::New(m_isolate, limit)};
if (!callDebuggerMethod("currentCallFrames", arraysize(argv), argv, true)
.ToLocal(&currentCallFramesV8)) {
return JavaScriptCallFrames();
}
if (!currentCallFramesV8->IsArray()) return JavaScriptCallFrames();
v8::Local<v8::Array> callFramesArray = currentCallFramesV8.As<v8::Array>();
JavaScriptCallFrames callFrames;
for (uint32_t i = 0; i < callFramesArray->Length(); ++i) {
v8::Local<v8::Value> callFrameValue;
if (!callFramesArray->Get(debuggerContext(), i).ToLocal(&callFrameValue))
return JavaScriptCallFrames();
if (!callFrameValue->IsObject()) return JavaScriptCallFrames();
v8::Local<v8::Object> callFrameObject = callFrameValue.As<v8::Object>();
callFrames.push_back(JavaScriptCallFrame::create(
debuggerContext(), v8::Local<v8::Object>::Cast(callFrameObject)));
}
return callFrames;
}
void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext,
v8::Local<v8::Object> executionState,
v8::Local<v8::Value> exception,
......@@ -843,34 +837,54 @@ v8::MaybeLocal<v8::Value> V8Debugger::getTargetScopes(
if (!enabled()) {
UNREACHABLE();
}
v8::Local<v8::Value> argv[] = {value};
v8::Local<v8::Value> scopesValue;
const char* debuggerMethod = nullptr;
std::unique_ptr<v8::debug::ScopeIterator> iterator;
switch (kind) {
case FUNCTION:
debuggerMethod = "getFunctionScopes";
iterator = v8::debug::ScopeIterator::CreateForFunction(
m_isolate, v8::Local<v8::Function>::Cast(value));
break;
case GENERATOR:
debuggerMethod = "getGeneratorScopes";
v8::Local<v8::debug::GeneratorObject> generatorObject =
v8::debug::GeneratorObject::Cast(value);
if (!generatorObject->IsSuspended()) return v8::MaybeLocal<v8::Value>();
iterator = v8::debug::ScopeIterator::CreateForGeneratorObject(
m_isolate, v8::Local<v8::Object>::Cast(value));
break;
}
if (!callDebuggerMethod(debuggerMethod, 1, argv, true).ToLocal(&scopesValue))
return v8::MaybeLocal<v8::Value>();
v8::Local<v8::Value> copied;
if (!copyValueFromDebuggerContext(m_isolate, debuggerContext(), context,
scopesValue)
.ToLocal(&copied) ||
!copied->IsArray())
v8::Local<v8::Array> result = v8::Array::New(m_isolate);
if (!result->SetPrototype(context, v8::Null(m_isolate)).FromMaybe(false)) {
return v8::MaybeLocal<v8::Value>();
if (!markAsInternal(context, v8::Local<v8::Array>::Cast(copied),
}
for (; !iterator->Done(); iterator->Advance()) {
v8::Local<v8::Object> scope = v8::Object::New(m_isolate);
if (!markAsInternal(context, scope, V8InternalValueType::kScope)) {
return v8::MaybeLocal<v8::Value>();
}
String16 type = scopeType(iterator->GetType());
String16 name;
v8::Local<v8::Function> closure = iterator->GetFunction();
if (!closure.IsEmpty()) {
name = toProtocolStringWithTypeCheck(closure->GetDebugName());
}
v8::Local<v8::Object> object = iterator->GetObject();
createDataProperty(context, scope,
toV8StringInternalized(m_isolate, "type"),
toV8String(m_isolate, type));
createDataProperty(context, scope,
toV8StringInternalized(m_isolate, "name"),
toV8String(m_isolate, name));
createDataProperty(context, scope,
toV8StringInternalized(m_isolate, "object"), object);
createDataProperty(context, result, result->Length(), scope);
}
if (!markAsInternal(context, v8::Local<v8::Array>::Cast(result),
V8InternalValueType::kScopeList))
return v8::MaybeLocal<v8::Value>();
if (!markArrayEntriesAsInternal(context, v8::Local<v8::Array>::Cast(copied),
V8InternalValueType::kScope))
return v8::MaybeLocal<v8::Value>();
return copied;
return result;
}
v8::MaybeLocal<v8::Value> V8Debugger::functionScopes(
......
......@@ -10,7 +10,6 @@
#include "src/base/macros.h"
#include "src/debug/debug-interface.h"
#include "src/inspector/java-script-call-frame.h"
#include "src/inspector/protocol/Debugger.h"
#include "src/inspector/protocol/Forward.h"
#include "src/inspector/protocol/Runtime.h"
......@@ -68,9 +67,7 @@ class V8Debugger : public v8::debug::DebugDelegate {
Response setScriptSource(
const String16& sourceID, v8::Local<v8::String> newSource, bool dryRun,
protocol::Maybe<protocol::Runtime::ExceptionDetails>*,
JavaScriptCallFrames* newCallFrames, protocol::Maybe<bool>* stackChanged,
bool* compileError);
JavaScriptCallFrames currentCallFrames(int limit = 0);
protocol::Maybe<bool>* stackChanged, bool* compileError);
// Each script inherits debug data from v8::Context where it has been
// compiled.
......
......@@ -919,8 +919,12 @@
'debug/debug-interface.h',
'debug/debug-frames.cc',
'debug/debug-frames.h',
'debug/debug-scope-iterator.cc',
'debug/debug-scope-iterator.h',
'debug/debug-scopes.cc',
'debug/debug-scopes.h',
'debug/debug-stack-trace-iterator.cc',
'debug/debug-stack-trace-iterator.h',
'debug/debug.cc',
'debug/debug.h',
'debug/interface-types.h',
......
......@@ -439,23 +439,14 @@ class InterpreterHandle {
interpreter()->UpdateMemory(mem_start, mem_size);
}
Handle<JSArray> GetScopeDetails(Address frame_pointer, int frame_index,
Handle<WasmDebugInfo> debug_info) {
auto frame = GetInterpretedFrame(frame_pointer, frame_index);
Handle<JSObject> GetGlobalScopeObject(wasm::InterpretedFrame* frame,
Handle<WasmDebugInfo> debug_info) {
Isolate* isolate = debug_info->GetIsolate();
Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
Handle<FixedArray> global_scope =
isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
global_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
Smi::FromInt(ScopeIterator::ScopeTypeGlobal));
// TODO(clemensh): Add globals to the global scope.
Handle<JSObject> global_scope_object =
isolate_->factory()->NewJSObjectWithNullProto();
global_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
*global_scope_object);
// TODO(clemensh): Add globals to the global scope.
if (instance->has_memory_buffer()) {
Handle<String> name = isolate_->factory()->InternalizeOneByteString(
STATIC_CHAR_VECTOR("memory"));
......@@ -468,16 +459,16 @@ class InterpreterHandle {
uint8_array, NONE)
.Assert();
}
return global_scope_object;
}
Handle<JSObject> GetLocalScopeObject(wasm::InterpretedFrame* frame,
Handle<WasmDebugInfo> debug_info) {
Isolate* isolate = debug_info->GetIsolate();
Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
Handle<FixedArray> local_scope =
isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
local_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
Smi::FromInt(ScopeIterator::ScopeTypeLocal));
Handle<JSObject> local_scope_object =
isolate_->factory()->NewJSObjectWithNullProto();
local_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
*local_scope_object);
// Fill parameters and locals.
int num_params = frame->GetParameterCount();
int num_locals = frame->GetLocalCount();
......@@ -527,6 +518,32 @@ class InterpreterHandle {
stack_obj, static_cast<uint32_t>(i), value_obj, NONE)
.Assert();
}
return local_scope_object;
}
Handle<JSArray> GetScopeDetails(Address frame_pointer, int frame_index,
Handle<WasmDebugInfo> debug_info) {
auto frame = GetInterpretedFrame(frame_pointer, frame_index);
Isolate* isolate = debug_info->GetIsolate();
Handle<WasmInstanceObject> instance(debug_info->wasm_instance(), isolate);
Handle<FixedArray> global_scope =
isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
global_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
Smi::FromInt(ScopeIterator::ScopeTypeGlobal));
Handle<JSObject> global_scope_object =
GetGlobalScopeObject(frame.get(), debug_info);
global_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
*global_scope_object);
Handle<FixedArray> local_scope =
isolate_->factory()->NewFixedArray(ScopeIterator::kScopeDetailsSize);
local_scope->set(ScopeIterator::kScopeDetailsTypeIndex,
Smi::FromInt(ScopeIterator::ScopeTypeLocal));
Handle<JSObject> local_scope_object =
GetLocalScopeObject(frame.get(), debug_info);
local_scope->set(ScopeIterator::kScopeDetailsObjectIndex,
*local_scope_object);
Handle<JSArray> global_jsarr =
isolate_->factory()->NewJSArrayWithElements(global_scope);
......@@ -738,9 +755,24 @@ void WasmDebugInfo::UpdateMemory(JSArrayBuffer* new_memory) {
}
// static
Handle<JSArray> WasmDebugInfo::GetScopeDetails(Handle<WasmDebugInfo> debug_info,
Address frame_pointer,
int frame_index) {
Handle<JSObject> WasmDebugInfo::GetScopeDetails(
Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
InterpreterHandle* interp_handle = GetInterpreterHandle(*debug_info);
return interp_handle->GetScopeDetails(frame_pointer, frame_index, debug_info);
}
// static
Handle<JSObject> WasmDebugInfo::GetGlobalScopeObject(
Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
InterpreterHandle* interp_handle = GetInterpreterHandle(*debug_info);
auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
return interp_handle->GetGlobalScopeObject(frame.get(), debug_info);
}
// static
Handle<JSObject> WasmDebugInfo::GetLocalScopeObject(
Handle<WasmDebugInfo> debug_info, Address frame_pointer, int frame_index) {
InterpreterHandle* interp_handle = GetInterpreterHandle(*debug_info);
auto frame = interp_handle->GetInterpretedFrame(frame_pointer, frame_index);
return interp_handle->GetLocalScopeObject(frame.get(), debug_info);
}
......@@ -655,9 +655,15 @@ class WasmDebugInfo : public FixedArray {
// The global scope contains information about globals and the memory.
// The local scope contains information about parameters, locals, and stack
// values.
static Handle<JSArray> GetScopeDetails(Handle<WasmDebugInfo>,
Address frame_pointer,
int frame_index);
static Handle<JSObject> GetScopeDetails(Handle<WasmDebugInfo>,
Address frame_pointer,
int frame_index);
static Handle<JSObject> GetGlobalScopeObject(Handle<WasmDebugInfo>,
Address frame_pointer,
int frame_index);
static Handle<JSObject> GetLocalScopeObject(Handle<WasmDebugInfo>,
Address frame_pointer,
int frame_index);
};
// TODO(titzer): these should be moved to wasm-objects-inl.h
......
Locations in script with negative offset.
[
[0] : {
columnNumber : 16
lineNumber : 0
scriptId : <scriptId>
type : debuggerStatement
}
[1] : {
columnNumber : 26
lineNumber : 0
scriptId : <scriptId>
type : return
}
]
foo (:-1:16)
(anonymous) (:0:0)
boo (:0:16)
(anonymous) (:0:0)
// 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.
let {session, contextGroup, Protocol} =
InspectorTest.start('Locations in script with negative offset.');
(async function test() {
contextGroup.addScript(`function foo() { debugger; }
function boo(){ debugger; }
`, -1, -1);
session.setupScriptMap();
Protocol.Debugger.enable();
let {params:{scriptId}} = await Protocol.Debugger.onceScriptParsed();
let {result:{locations}} = await Protocol.Debugger.getPossibleBreakpoints({
start: {scriptId, lineNumber: 0, columnNumber: 0}
});
InspectorTest.logMessage(locations);
Protocol.Runtime.evaluate({expression: 'foo()'});
var {params:{callFrames}} = await Protocol.Debugger.oncePaused();
session.logCallFrames(callFrames);
await Protocol.Debugger.resume();
Protocol.Runtime.evaluate({expression: 'boo()'});
var {params:{callFrames}} = await Protocol.Debugger.oncePaused();
session.logCallFrames(callFrames);
await Protocol.Debugger.resume();
InspectorTest.completeTest();
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment