Commit 4e036f30 authored by yangguo's avatar yangguo Committed by Commit bot

Debugger: refactor ScopeIterator, FrameInspector and DebugEvaluate.

This is a pure refactor and does not change functionality.

R=ulan@chromium.org

Review URL: https://codereview.chromium.org/1264993002

Cr-Commit-Position: refs/heads/master@{#29995}
parent 0cf86bd2
......@@ -834,6 +834,12 @@ source_set("v8_base") {
"src/dateparser-inl.h",
"src/dateparser.cc",
"src/dateparser.h",
"src/debug/debug-evaluate.cc",
"src/debug/debug-evaluate.h",
"src/debug/debug-frames.cc",
"src/debug/debug-frames.h",
"src/debug/debug-scopes.cc",
"src/debug/debug-scopes.h",
"src/debug/debug.cc",
"src/debug/debug.h",
"src/debug/liveedit.cc",
......
This diff is collapsed.
// Copyright 2015 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_EVALUATE_H_
#define V8_DEBUG_DEBUG_EVALUATE_H_
#include "src/frames.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
class DebugEvaluate : public AllStatic {
public:
static MaybeHandle<Object> Global(Isolate* isolate, Handle<String> source,
bool disable_break,
Handle<Object> context_extension);
// Evaluate a piece of JavaScript in the context of a stack frame for
// debugging. Things that need special attention are:
// - Parameters and stack-allocated locals need to be materialized. Altered
// values need to be written back to the stack afterwards.
// - The arguments object needs to materialized.
static MaybeHandle<Object> Local(Isolate* isolate, StackFrame::Id frame_id,
int inlined_jsframe_index,
Handle<String> source, bool disable_break,
Handle<Object> context_extension);
private:
// This class builds a context chain for evaluation of expressions
// in debugger.
// The scope chain leading up to a breakpoint where evaluation occurs
// looks like:
// - [a mix of with, catch and block scopes]
// - [function stack + context]
// - [outer context]
// The builder materializes all stack variables into properties of objects;
// the expression is then evaluated as if it is inside a series of 'with'
// statements using those objects. To this end, the builder builds a new
// context chain, based on a scope chain:
// - every With and Catch scope begets a cloned context
// - Block scope begets one or two contexts:
// - if a block has context-allocated varaibles, its context is cloned
// - stack locals are materizalized as a With context
// - Local scope begets a With context for materizalized locals, chained to
// original function context. Original function context is the end of
// the chain.
class ContextBuilder {
public:
ContextBuilder(Isolate* isolate, JavaScriptFrame* frame,
int inlined_jsframe_index);
void UpdateValues();
Handle<Context> innermost_context() const { return innermost_context_; }
Handle<SharedFunctionInfo> outer_info() const { return outer_info_; }
private:
struct ContextChainElement {
Handle<Context> original_context;
Handle<Context> cloned_context;
Handle<JSObject> materialized_object;
Handle<ScopeInfo> scope_info;
};
void RecordContextsInChain(Handle<Context>* inner_context,
Handle<Context> first, Handle<Context> last);
Handle<JSObject> NewJSObjectWithNullProto();
// Helper function to find or create the arguments object for
// Runtime_DebugEvaluate.
void MaterializeArgumentsObject(Handle<JSObject> target,
Handle<JSFunction> function);
Handle<Context> MaterializeReceiver(Handle<Context> target,
Handle<JSFunction> function);
Handle<SharedFunctionInfo> outer_info_;
Handle<Context> innermost_context_;
List<ContextChainElement> context_chain_;
Isolate* isolate_;
JavaScriptFrame* frame_;
int inlined_jsframe_index_;
};
static MaybeHandle<Object> Evaluate(Isolate* isolate,
Handle<SharedFunctionInfo> outer_info,
Handle<Context> context,
Handle<Object> context_extension,
Handle<Object> receiver,
Handle<String> source);
};
} // namespace internal
} // namespace v8
#endif // V8_DEBUG_DEBUG_EVALUATE_H_
// Copyright 2015 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-frames.h"
namespace v8 {
namespace internal {
FrameInspector::FrameInspector(JavaScriptFrame* frame,
int inlined_jsframe_index, Isolate* isolate)
: frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
has_adapted_arguments_ = frame_->has_adapted_arguments();
is_bottommost_ = inlined_jsframe_index == 0;
is_optimized_ = frame_->is_optimized();
// Calculate the deoptimized frame.
if (frame->is_optimized()) {
// TODO(turbofan): Revisit once we support deoptimization.
if (frame->LookupCode()->is_turbofanned() &&
frame->function()->shared()->asm_function() &&
!FLAG_turbo_asm_deoptimization) {
is_optimized_ = false;
return;
}
deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
frame, inlined_jsframe_index, isolate);
}
}
FrameInspector::~FrameInspector() {
// Get rid of the calculated deoptimized frame if any.
if (deoptimized_frame_ != NULL) {
Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_);
}
}
int FrameInspector::GetParametersCount() {
return is_optimized_ ? deoptimized_frame_->parameters_count()
: frame_->ComputeParametersCount();
}
int FrameInspector::expression_count() {
return deoptimized_frame_->expression_count();
}
Object* FrameInspector::GetFunction() {
return is_optimized_ ? deoptimized_frame_->GetFunction() : frame_->function();
}
Object* FrameInspector::GetParameter(int index) {
return is_optimized_ ? deoptimized_frame_->GetParameter(index)
: frame_->GetParameter(index);
}
Object* FrameInspector::GetExpression(int index) {
// TODO(turbofan): Revisit once we support deoptimization.
if (frame_->LookupCode()->is_turbofanned() &&
frame_->function()->shared()->asm_function() &&
!FLAG_turbo_asm_deoptimization) {
return isolate_->heap()->undefined_value();
}
return is_optimized_ ? deoptimized_frame_->GetExpression(index)
: frame_->GetExpression(index);
}
int FrameInspector::GetSourcePosition() {
return is_optimized_ ? deoptimized_frame_->GetSourcePosition()
: frame_->LookupCode()->SourcePosition(frame_->pc());
}
bool FrameInspector::IsConstructor() {
return is_optimized_ && !is_bottommost_
? deoptimized_frame_->HasConstructStub()
: frame_->IsConstructor();
}
Object* FrameInspector::GetContext() {
return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context();
}
// To inspect all the provided arguments the frame might need to be
// replaced with the arguments frame.
void FrameInspector::SetArgumentsFrame(JavaScriptFrame* frame) {
DCHECK(has_adapted_arguments_);
frame_ = frame;
is_optimized_ = frame_->is_optimized();
DCHECK(!is_optimized_);
}
// Create a plain JSObject which materializes the local scope for the specified
// frame.
void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
Handle<ScopeInfo> scope_info) {
HandleScope scope(isolate_);
// First fill all parameters.
for (int i = 0; i < scope_info->ParameterCount(); ++i) {
// Do not materialize the parameter if it is shadowed by a context local.
Handle<String> name(scope_info->ParameterName(i));
if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
Handle<Object> value(i < GetParametersCount()
? GetParameter(i)
: isolate_->heap()->undefined_value(),
isolate_);
DCHECK(!value->IsTheHole());
JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
}
// Second fill all stack locals.
for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
if (scope_info->LocalIsSynthetic(i)) continue;
Handle<String> name(scope_info->StackLocalName(i));
Handle<Object> value(GetExpression(scope_info->StackLocalIndex(i)),
isolate_);
if (value->IsTheHole()) value = isolate_->factory()->undefined_value();
JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
}
}
void FrameInspector::MaterializeStackLocals(Handle<JSObject> target,
Handle<JSFunction> function) {
Handle<SharedFunctionInfo> shared(function->shared());
Handle<ScopeInfo> scope_info(shared->scope_info());
MaterializeStackLocals(target, scope_info);
}
void FrameInspector::UpdateStackLocalsFromMaterializedObject(
Handle<JSObject> target, Handle<ScopeInfo> scope_info) {
if (is_optimized_) {
// Optimized frames are not supported. Simply give up.
return;
}
HandleScope scope(isolate_);
// Parameters.
for (int i = 0; i < scope_info->ParameterCount(); ++i) {
// Shadowed parameters were not materialized.
Handle<String> name(scope_info->ParameterName(i));
if (ParameterIsShadowedByContextLocal(scope_info, name)) continue;
DCHECK(!frame_->GetParameter(i)->IsTheHole());
Handle<Object> value =
Object::GetPropertyOrElement(target, name).ToHandleChecked();
frame_->SetParameterValue(i, *value);
}
// Stack locals.
for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
if (scope_info->LocalIsSynthetic(i)) continue;
int index = scope_info->StackLocalIndex(i);
if (frame_->GetExpression(index)->IsTheHole()) continue;
Handle<Object> value =
Object::GetPropertyOrElement(
target, handle(scope_info->StackLocalName(i), isolate_))
.ToHandleChecked();
frame_->SetExpression(index, *value);
}
}
bool FrameInspector::ParameterIsShadowedByContextLocal(
Handle<ScopeInfo> info, Handle<String> parameter_name) {
VariableMode mode;
VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &location,
&init_flag, &maybe_assigned_flag) != -1;
}
SaveContext* DebugFrameHelper::FindSavedContextForFrame(
Isolate* isolate, JavaScriptFrame* frame) {
SaveContext* save = isolate->save_context();
while (save != NULL && !save->IsBelowFrame(frame)) {
save = save->prev();
}
DCHECK(save != NULL);
return save;
}
int DebugFrameHelper::FindIndexedNonNativeFrame(JavaScriptFrameIterator* it,
int index) {
int count = -1;
for (; !it->done(); it->Advance()) {
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
it->frame()->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0; i--) {
// Omit functions from native and extension scripts.
if (!frames[i].function()->IsSubjectToDebugging()) continue;
if (++count == index) return i;
}
}
return -1;
}
} // namespace internal
} // namespace v8
// Copyright 2015 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_FRAMES_H_
#define V8_DEBUG_DEBUG_FRAMES_H_
#include "src/deoptimizer.h"
#include "src/frames.h"
#include "src/isolate.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
class FrameInspector {
public:
FrameInspector(JavaScriptFrame* frame, int inlined_jsframe_index,
Isolate* isolate);
~FrameInspector();
int GetParametersCount();
int expression_count();
Object* GetFunction();
Object* GetParameter(int index);
Object* GetExpression(int index);
int GetSourcePosition();
bool IsConstructor();
Object* GetContext();
JavaScriptFrame* GetArgumentsFrame() { return frame_; }
void SetArgumentsFrame(JavaScriptFrame* frame);
void MaterializeStackLocals(Handle<JSObject> target,
Handle<ScopeInfo> scope_info);
void MaterializeStackLocals(Handle<JSObject> target,
Handle<JSFunction> function);
void UpdateStackLocalsFromMaterializedObject(Handle<JSObject> object,
Handle<ScopeInfo> scope_info);
private:
bool ParameterIsShadowedByContextLocal(Handle<ScopeInfo> info,
Handle<String> parameter_name);
JavaScriptFrame* frame_;
DeoptimizedFrameInfo* deoptimized_frame_;
Isolate* isolate_;
bool is_optimized_;
bool is_bottommost_;
bool has_adapted_arguments_;
DISALLOW_COPY_AND_ASSIGN(FrameInspector);
};
class DebugFrameHelper : public AllStatic {
public:
static SaveContext* FindSavedContextForFrame(Isolate* isolate,
JavaScriptFrame* frame);
// Advances the iterator to the frame that matches the index and returns the
// inlined frame index, or -1 if not found. Skips native JS functions.
static int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index);
// Helper functions for wrapping and unwrapping stack frame ids.
static Smi* WrapFrameId(StackFrame::Id id) {
DCHECK(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
return Smi::FromInt(id >> 2);
}
static StackFrame::Id UnwrapFrameId(int wrapped) {
return static_cast<StackFrame::Id>(wrapped << 2);
}
};
} // namespace internal
} // namespace v8
#endif // V8_DEBUG_DEBUG_FRAMES_H_
This diff is collapsed.
// Copyright 2015 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_SCOPES_H_
#define V8_DEBUG_DEBUG_SCOPES_H_
#include "src/debug/debug-frames.h"
#include "src/frames.h"
namespace v8 {
namespace internal {
// Iterate over the actual scopes visible from a stack frame or from a closure.
// The iteration proceeds from the innermost visible nested scope outwards.
// All scopes are backed by an actual context except the local scope,
// which is inserted "artificially" in the context chain.
class ScopeIterator {
public:
enum ScopeType {
ScopeTypeGlobal = 0,
ScopeTypeLocal,
ScopeTypeWith,
ScopeTypeClosure,
ScopeTypeCatch,
ScopeTypeBlock,
ScopeTypeScript,
ScopeTypeModule
};
static const int kScopeDetailsTypeIndex = 0;
static const int kScopeDetailsObjectIndex = 1;
static const int kScopeDetailsSize = 2;
ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
bool ignore_nested_scopes = false);
ScopeIterator(Isolate* isolate, Handle<JSFunction> function);
MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScopeDetails();
// More scopes?
bool Done() {
DCHECK(!failed_);
return context_.is_null();
}
bool Failed() { return failed_; }
// Move to the next scope.
void Next();
// Return the type of the current scope.
ScopeType Type();
// Return the JavaScript object with the content of the current scope.
MaybeHandle<JSObject> ScopeObject();
bool HasContext();
// Set variable value and return true on success.
bool SetVariableValue(Handle<String> variable_name, Handle<Object> new_value);
Handle<ScopeInfo> CurrentScopeInfo();
// Return the context for this scope. For the local context there might not
// be an actual context.
Handle<Context> CurrentContext();
#ifdef DEBUG
// Debug print of the content of the current scope.
void DebugPrint();
#endif
private:
Isolate* isolate_;
FrameInspector* const frame_inspector_;
Handle<Context> context_;
List<Handle<ScopeInfo> > nested_scope_chain_;
bool seen_script_scope_;
bool failed_;
inline JavaScriptFrame* GetFrame() {
return frame_inspector_->GetArgumentsFrame();
}
inline Handle<JSFunction> GetFunction() {
return Handle<JSFunction>(
JSFunction::cast(frame_inspector_->GetFunction()));
}
void RetrieveScopeChain(Scope* scope, Handle<SharedFunctionInfo> shared_info);
MUST_USE_RESULT MaybeHandle<JSObject> MaterializeScriptScope();
MUST_USE_RESULT MaybeHandle<JSObject> MaterializeLocalScope();
MUST_USE_RESULT MaybeHandle<JSObject> MaterializeModuleScope();
Handle<JSObject> MaterializeClosure();
Handle<JSObject> MaterializeCatchScope();
Handle<JSObject> MaterializeBlockScope();
bool SetLocalVariableValue(Handle<String> variable_name,
Handle<Object> new_value);
bool SetBlockVariableValue(Handle<String> variable_name,
Handle<Object> new_value);
bool SetClosureVariableValue(Handle<String> variable_name,
Handle<Object> new_value);
bool SetScriptVariableValue(Handle<String> variable_name,
Handle<Object> new_value);
bool SetCatchVariableValue(Handle<String> variable_name,
Handle<Object> new_value);
bool SetContextLocalValue(Handle<ScopeInfo> scope_info,
Handle<Context> context,
Handle<String> variable_name,
Handle<Object> new_value);
void CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
Handle<Context> context,
Handle<JSObject> scope_object);
DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
};
} // namespace internal
} // namespace v8
#endif // V8_DEBUG_DEBUG_SCOPES_H_
......@@ -423,7 +423,6 @@ class CodeGenerator;
class CodeStub;
class Context;
class Debug;
class Debugger;
class DebugInfo;
class Descriptor;
class DescriptorArray;
......
......@@ -83,7 +83,6 @@ typedef void* ExternalReferenceRedirectorPointer();
class Debug;
class Debugger;
class PromiseOnStack;
class Redirection;
class Simulator;
......
......@@ -3965,12 +3965,6 @@ class ScopeInfo : public FixedArray {
FunctionKind function_kind();
// Copies all the context locals into an object used to materialize a scope.
static void CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
Handle<Context> context,
Handle<JSObject> scope_object);
static Handle<ScopeInfo> Create(Isolate* isolate, Zone* zone, Scope* scope);
static Handle<ScopeInfo> CreateGlobalThisBinding(Isolate* isolate);
......@@ -4106,6 +4100,8 @@ class ScopeInfo : public FixedArray {
class ContextLocalInitFlag: public BitField<InitializationFlag, 3, 1> {};
class ContextLocalMaybeAssignedFlag
: public BitField<MaybeAssignedFlag, 4, 1> {};
friend class ScopeIterator;
};
......
This diff is collapsed.
......@@ -6,6 +6,7 @@
#include "src/arguments.h"
#include "src/debug/debug.h"
#include "src/debug/debug-frames.h"
#include "src/debug/liveedit.h"
#include "src/runtime/runtime.h"
#include "src/runtime/runtime-utils.h"
......@@ -280,7 +281,8 @@ RUNTIME_FUNCTION(Runtime_LiveEditRestartFrame) {
}
JavaScriptFrameIterator it(isolate, id);
int inlined_jsframe_index = Runtime::FindIndexedNonNativeFrame(&it, index);
int inlined_jsframe_index =
DebugFrameHelper::FindIndexedNonNativeFrame(&it, index);
if (inlined_jsframe_index == -1) return heap->undefined_value();
// We don't really care what the inlined frame index is, since we are
// throwing away the entire frame anyways.
......
......@@ -929,8 +929,6 @@ class Runtime : public AllStatic {
static void NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer);
static int FindIndexedNonNativeFrame(JavaScriptFrameIterator* it, int index);
enum TypedArrayId {
// arrayIds below should be synchromized with typedarray.js natives.
ARRAY_ID_UINT8 = 1,
......
......@@ -626,30 +626,6 @@ FunctionKind ScopeInfo::function_kind() {
}
void ScopeInfo::CopyContextLocalsToScopeObject(Handle<ScopeInfo> scope_info,
Handle<Context> context,
Handle<JSObject> scope_object) {
Isolate* isolate = scope_info->GetIsolate();
int local_count = scope_info->ContextLocalCount();
if (local_count == 0) return;
// Fill all context locals to the context extension.
int first_context_var = scope_info->StackLocalCount();
int start = scope_info->ContextLocalNameEntriesIndex();
for (int i = 0; i < local_count; ++i) {
if (scope_info->LocalIsSynthetic(first_context_var + i)) continue;
int context_index = Context::MIN_CONTEXT_SLOTS + i;
Handle<Object> value = Handle<Object>(context->get(context_index), isolate);
// Reflect variables under TDZ as undefined in scope object.
if (value->IsTheHole()) continue;
// This should always succeed.
// TODO(verwaest): Use AddDataProperty instead.
JSObject::SetOwnPropertyIgnoreAttributes(
scope_object, handle(String::cast(scope_info->get(i + start))), value,
::NONE).Check();
}
}
int ScopeInfo::ParameterEntriesIndex() {
DCHECK(length() > 0);
return kVariablePartIndex;
......
......@@ -52,7 +52,6 @@ using ::v8::internal::Heap;
using ::v8::internal::JSGlobalProxy;
using ::v8::internal::Code;
using ::v8::internal::Debug;
using ::v8::internal::Debugger;
using ::v8::internal::CommandMessage;
using ::v8::internal::CommandMessageQueue;
using ::v8::internal::StackFrame;
......
......@@ -627,6 +627,12 @@
'../../src/dateparser-inl.h',
'../../src/dateparser.cc',
'../../src/dateparser.h',
'../../src/debug/debug-evaluate.cc',
'../../src/debug/debug-evaluate.h',
'../../src/debug/debug-frames.cc',
'../../src/debug/debug-frames.h',
'../../src/debug/debug-scopes.cc',
'../../src/debug/debug-scopes.h',
'../../src/debug/debug.cc',
'../../src/debug/debug.h',
'../../src/debug/liveedit.cc',
......
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