Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Unified Diff: src/runtime/runtime-debug.cc

Issue 1264993002: Debugger: refactor ScopeIterator, FrameInspector and DebugEvaluate. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: readd include Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/runtime/runtime-debug.cc
diff --git a/src/runtime/runtime-debug.cc b/src/runtime/runtime-debug.cc
index c3862f08d927e8dbf6d51bb5b0141b60b09bd8fa..f747f35184eb71dfba3f032fc9167f0c6a556ea4 100644
--- a/src/runtime/runtime-debug.cc
+++ b/src/runtime/runtime-debug.cc
@@ -4,12 +4,11 @@
#include "src/v8.h"
-#include "src/accessors.h"
#include "src/arguments.h"
-#include "src/compiler.h"
#include "src/debug/debug.h"
-#include "src/deoptimizer.h"
-#include "src/parser.h"
+#include "src/debug/debug-evaluate.h"
+#include "src/debug/debug-frames.h"
+#include "src/debug/debug-scopes.h"
#include "src/runtime/runtime.h"
#include "src/runtime/runtime-utils.h"
@@ -35,18 +34,6 @@ RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) {
}
-// 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);
-}
-
-
// Adds a JavaScript function as a debug event listener.
// args[0]: debug event listener function to set or null or undefined for
// clearing the event listener function
@@ -475,94 +462,6 @@ RUNTIME_FUNCTION(Runtime_GetFrameCount) {
}
-class FrameInspector {
- public:
- 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() {
- // Get rid of the calculated deoptimized frame if any.
- if (deoptimized_frame_ != NULL) {
- Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_, isolate_);
- }
- }
-
- int GetParametersCount() {
- return is_optimized_ ? deoptimized_frame_->parameters_count()
- : frame_->ComputeParametersCount();
- }
- int expression_count() { return deoptimized_frame_->expression_count(); }
- Object* GetFunction() {
- return is_optimized_ ? deoptimized_frame_->GetFunction()
- : frame_->function();
- }
- Object* GetParameter(int index) {
- return is_optimized_ ? deoptimized_frame_->GetParameter(index)
- : frame_->GetParameter(index);
- }
- Object* 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 GetSourcePosition() {
- return is_optimized_ ? deoptimized_frame_->GetSourcePosition()
- : frame_->LookupCode()->SourcePosition(frame_->pc());
- }
- bool IsConstructor() {
- return is_optimized_ && !is_bottommost_
- ? deoptimized_frame_->HasConstructStub()
- : frame_->IsConstructor();
- }
- Object* GetContext() {
- return is_optimized_ ? deoptimized_frame_->GetContext() : frame_->context();
- }
- JavaScriptFrame* GetArgumentsFrame() { return frame_; }
-
- // To inspect all the provided arguments the frame might need to be
- // replaced with the arguments frame.
- void SetArgumentsFrame(JavaScriptFrame* frame) {
- DCHECK(has_adapted_arguments_);
- frame_ = frame;
- is_optimized_ = frame_->is_optimized();
- DCHECK(!is_optimized_);
- }
-
- private:
- JavaScriptFrame* frame_;
- DeoptimizedFrameInfo* deoptimized_frame_;
- Isolate* isolate_;
- bool is_optimized_;
- bool is_bottommost_;
- bool has_adapted_arguments_;
-
- DISALLOW_COPY_AND_ASSIGN(FrameInspector);
-};
-
-
static const int kFrameDetailsFrameIdIndex = 0;
static const int kFrameDetailsReceiverIndex = 1;
static const int kFrameDetailsFunctionIndex = 2;
@@ -575,34 +474,6 @@ static const int kFrameDetailsFlagsIndex = 8;
static const int kFrameDetailsFirstDynamicIndex = 9;
-static SaveContext* FindSavedContextForFrame(Isolate* isolate,
- JavaScriptFrame* frame) {
- SaveContext* save = isolate->save_context();
- while (save != NULL && !save->IsBelowFrame(frame)) {
- save = save->prev();
- }
- DCHECK(save != NULL);
- return save;
-}
-
-
-// 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.
-int Runtime::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;
-}
-
-
// Return an array with frame details
// args[0]: number: break id
// args[1]: number: frame index
@@ -638,7 +509,8 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
JavaScriptFrameIterator it(isolate, id);
// Inlined frame index in optimized frame, starting from outer function.
- 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();
FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
@@ -646,10 +518,12 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
// Traverse the saved contexts chain to find the active context for the
// selected frame.
- SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
+ SaveContext* save =
+ DebugFrameHelper::FindSavedContextForFrame(isolate, it.frame());
// Get the frame id.
- Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
+ Handle<Object> frame_id(DebugFrameHelper::WrapFrameId(it.frame()->id()),
+ isolate);
// Find source position in unoptimized code.
int position = frame_inspector.GetSourcePosition();
@@ -866,929 +740,6 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
}
-static bool 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;
-}
-
-
-static Handle<Context> MaterializeReceiver(Isolate* isolate,
- Handle<Context> target,
- Handle<JSFunction> function,
- JavaScriptFrame* frame) {
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
- Handle<Object> receiver;
- switch (scope_info->scope_type()) {
- case FUNCTION_SCOPE: {
- VariableMode mode;
- VariableLocation location;
- InitializationFlag init_flag;
- MaybeAssignedFlag maybe_assigned_flag;
-
- // Don't bother creating a fake context node if "this" is in the context
- // already.
- if (ScopeInfo::ContextSlotIndex(
- scope_info, isolate->factory()->this_string(), &mode, &location,
- &init_flag, &maybe_assigned_flag) >= 0) {
- return target;
- }
- receiver = handle(frame->receiver(), isolate);
- break;
- }
- case MODULE_SCOPE:
- receiver = isolate->factory()->undefined_value();
- break;
- case SCRIPT_SCOPE:
- receiver = handle(function->global_proxy(), isolate);
- break;
- default:
- // For eval code, arrow functions, and the like, there's no "this" binding
- // to materialize.
- return target;
- }
-
- return isolate->factory()->NewCatchContext(
- function, target, isolate->factory()->this_string(), receiver);
-}
-
-
-// Create a plain JSObject which materializes the local scope for the specified
-// frame.
-static void MaterializeStackLocalsWithFrameInspector(
- Isolate* isolate, Handle<JSObject> target, Handle<ScopeInfo> scope_info,
- FrameInspector* frame_inspector) {
- // 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;
-
- DCHECK_NOT_NULL(frame_inspector);
-
- HandleScope scope(isolate);
- Handle<Object> value(i < frame_inspector->GetParametersCount()
- ? frame_inspector->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(
- frame_inspector->GetExpression(scope_info->StackLocalIndex(i)),
- isolate);
- if (value->IsTheHole()) {
- value = isolate->factory()->undefined_value();
- }
-
- JSObject::SetOwnPropertyIgnoreAttributes(target, name, value, NONE).Check();
- }
-}
-
-static void MaterializeStackLocalsWithFrameInspector(
- Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
- FrameInspector* frame_inspector) {
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- MaterializeStackLocalsWithFrameInspector(isolate, target, scope_info,
- frame_inspector);
-}
-
-
-static void UpdateStackLocalsFromMaterializedObject(
- Isolate* isolate, Handle<JSObject> target, Handle<ScopeInfo> scope_info,
- JavaScriptFrame* frame, int inlined_jsframe_index) {
- if (inlined_jsframe_index != 0 || frame->is_optimized()) {
- // Optimized frames are not supported. Simply give up.
- return;
- }
-
- // 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());
- HandleScope scope(isolate);
- 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;
- HandleScope scope(isolate);
- Handle<Object> value = Object::GetPropertyOrElement(
- target, handle(scope_info->StackLocalName(i),
- isolate)).ToHandleChecked();
- frame->SetExpression(index, *value);
- }
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext(
- Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function,
- Handle<Context> frame_context) {
- HandleScope scope(isolate);
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- if (!scope_info->HasContext()) return target;
-
- // Third fill all context locals.
- Handle<Context> function_context(frame_context->declaration_context());
- ScopeInfo::CopyContextLocalsToScopeObject(scope_info, function_context,
- target);
-
- // Finally copy any properties from the function context extension.
- // These will be variables introduced by eval.
- if (function_context->closure() == *function) {
- if (function_context->has_extension() &&
- !function_context->IsNativeContext()) {
- Handle<JSObject> ext(JSObject::cast(function_context->extension()));
- Handle<FixedArray> keys;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, keys, JSReceiver::GetKeys(ext, JSReceiver::INCLUDE_PROTOS),
- JSObject);
-
- for (int i = 0; i < keys->length(); i++) {
- // Names of variables introduced by eval are strings.
- DCHECK(keys->get(i)->IsString());
- Handle<String> key(String::cast(keys->get(i)));
- Handle<Object> value;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, value, Object::GetPropertyOrElement(ext, key), JSObject);
- RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty(
- isolate, target, key, value, SLOPPY),
- JSObject);
- }
- }
- }
-
- return target;
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScriptScope(
- Handle<GlobalObject> global) {
- Isolate* isolate = global->GetIsolate();
- Handle<ScriptContextTable> script_contexts(
- global->native_context()->script_context_table());
-
- Handle<JSObject> script_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
-
- for (int context_index = 0; context_index < script_contexts->used();
- context_index++) {
- Handle<Context> context =
- ScriptContextTable::GetContext(script_contexts, context_index);
- Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
- ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context,
- script_scope);
- }
- return script_scope;
-}
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalScope(
- Isolate* isolate, FrameInspector* frame_inspector) {
- Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
-
- Handle<JSObject> local_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
- MaterializeStackLocalsWithFrameInspector(isolate, local_scope, function,
- frame_inspector);
-
- Handle<Context> frame_context(Context::cast(frame_inspector->GetContext()));
-
- return MaterializeLocalContext(isolate, local_scope, function, frame_context);
-}
-
-
-// Set the context local variable value.
-static bool SetContextLocalValue(Isolate* isolate, Handle<ScopeInfo> scope_info,
- Handle<Context> context,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
- Handle<String> next_name(scope_info->ContextLocalName(i));
- if (String::Equals(variable_name, next_name)) {
- VariableMode mode;
- VariableLocation location;
- InitializationFlag init_flag;
- MaybeAssignedFlag maybe_assigned_flag;
- int context_index =
- ScopeInfo::ContextSlotIndex(scope_info, next_name, &mode, &location,
- &init_flag, &maybe_assigned_flag);
- context->set(context_index, *new_value);
- return true;
- }
- }
-
- return false;
-}
-
-
-static bool SetLocalVariableValue(Isolate* isolate, JavaScriptFrame* frame,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- // Optimized frames are not supported.
- if (frame->is_optimized()) return false;
-
- Handle<JSFunction> function(frame->function());
- Handle<SharedFunctionInfo> shared(function->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- bool default_result = false;
-
- // Parameters.
- for (int i = 0; i < scope_info->ParameterCount(); ++i) {
- HandleScope scope(isolate);
- if (String::Equals(handle(scope_info->ParameterName(i)), variable_name)) {
- frame->SetParameterValue(i, *new_value);
- // Argument might be shadowed in heap context, don't stop here.
- default_result = true;
- }
- }
-
- // Stack locals.
- for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
- HandleScope scope(isolate);
- if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) {
- frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
- return true;
- }
- }
-
- if (scope_info->HasContext()) {
- // Context locals.
- Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->declaration_context());
- if (SetContextLocalValue(isolate, scope_info, function_context,
- variable_name, new_value)) {
- return true;
- }
-
- // Function context extension. These are variables introduced by eval.
- if (function_context->closure() == *function) {
- if (function_context->has_extension() &&
- !function_context->IsNativeContext()) {
- Handle<JSObject> ext(JSObject::cast(function_context->extension()));
-
- Maybe<bool> maybe = JSReceiver::HasProperty(ext, variable_name);
- DCHECK(maybe.IsJust());
- if (maybe.FromJust()) {
- // We don't expect this to do anything except replacing
- // property value.
- Runtime::SetObjectProperty(isolate, ext, variable_name, new_value,
- SLOPPY).Assert();
- return true;
- }
- }
- }
- }
-
- return default_result;
-}
-
-
-static bool SetBlockVariableValue(Isolate* isolate,
- Handle<Context> block_context,
- Handle<ScopeInfo> scope_info,
- JavaScriptFrame* frame,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- if (frame != nullptr) {
- for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
- HandleScope scope(isolate);
- if (String::Equals(handle(scope_info->StackLocalName(i)),
- variable_name)) {
- frame->SetExpression(scope_info->StackLocalIndex(i), *new_value);
- return true;
- }
- }
- }
- if (!block_context.is_null()) {
- return SetContextLocalValue(block_context->GetIsolate(), scope_info,
- block_context, variable_name, new_value);
- }
- return false;
-}
-
-
-// Create a plain JSObject which materializes the closure content for the
-// context.
-static Handle<JSObject> MaterializeClosure(Isolate* isolate,
- Handle<Context> context) {
- DCHECK(context->IsFunctionContext());
-
- Handle<SharedFunctionInfo> shared(context->closure()->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- // Allocate and initialize a JSObject with all the content of this function
- // closure.
- Handle<JSObject> closure_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
-
- // Fill all context locals to the context extension.
- ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, closure_scope);
-
- // Finally copy any properties from the function context extension. This will
- // be variables introduced by eval.
- if (context->has_extension()) {
- Handle<JSObject> ext(JSObject::cast(context->extension()));
- DCHECK(ext->IsJSContextExtensionObject());
- Handle<FixedArray> keys =
- JSReceiver::GetKeys(ext, JSReceiver::OWN_ONLY).ToHandleChecked();
-
- for (int i = 0; i < keys->length(); i++) {
- HandleScope scope(isolate);
- // Names of variables introduced by eval are strings.
- DCHECK(keys->get(i)->IsString());
- Handle<String> key(String::cast(keys->get(i)));
- Handle<Object> value = Object::GetProperty(ext, key).ToHandleChecked();
- JSObject::SetOwnPropertyIgnoreAttributes(closure_scope, key, value, NONE)
- .Check();
- }
- }
-
- return closure_scope;
-}
-
-
-// This method copies structure of MaterializeClosure method above.
-static bool SetClosureVariableValue(Isolate* isolate, Handle<Context> context,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- DCHECK(context->IsFunctionContext());
-
- Handle<SharedFunctionInfo> shared(context->closure()->shared());
- Handle<ScopeInfo> scope_info(shared->scope_info());
-
- // Context locals to the context extension.
- if (SetContextLocalValue(isolate, scope_info, context, variable_name,
- new_value)) {
- return true;
- }
-
- // Properties from the function context extension. This will
- // be variables introduced by eval.
- if (context->has_extension()) {
- Handle<JSObject> ext(JSObject::cast(context->extension()));
- DCHECK(ext->IsJSContextExtensionObject());
- Maybe<bool> maybe = JSReceiver::HasOwnProperty(ext, variable_name);
- DCHECK(maybe.IsJust());
- if (maybe.FromJust()) {
- // We don't expect this to do anything except replacing property value.
- JSObject::SetOwnPropertyIgnoreAttributes(ext, variable_name, new_value,
- NONE).Check();
- return true;
- }
- }
-
- return false;
-}
-
-
-static bool SetScriptVariableValue(Handle<Context> context,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- Handle<ScriptContextTable> script_contexts(
- context->global_object()->native_context()->script_context_table());
- ScriptContextTable::LookupResult lookup_result;
- if (ScriptContextTable::Lookup(script_contexts, variable_name,
- &lookup_result)) {
- Handle<Context> script_context = ScriptContextTable::GetContext(
- script_contexts, lookup_result.context_index);
- script_context->set(lookup_result.slot_index, *new_value);
- return true;
- }
-
- return false;
-}
-
-
-// Create a plain JSObject which materializes the scope for the specified
-// catch context.
-static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
- Handle<Context> context) {
- DCHECK(context->IsCatchContext());
- Handle<String> name(String::cast(context->extension()));
- Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX),
- isolate);
- Handle<JSObject> catch_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
- JSObject::SetOwnPropertyIgnoreAttributes(catch_scope, name, thrown_object,
- NONE).Check();
- return catch_scope;
-}
-
-
-static bool SetCatchVariableValue(Isolate* isolate, Handle<Context> context,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- DCHECK(context->IsCatchContext());
- Handle<String> name(String::cast(context->extension()));
- if (!String::Equals(name, variable_name)) {
- return false;
- }
- context->set(Context::THROWN_OBJECT_INDEX, *new_value);
- return true;
-}
-
-
-// Create a plain JSObject which materializes the block scope for the specified
-// block context.
-static Handle<JSObject> MaterializeBlockScope(Isolate* isolate,
- Handle<ScopeInfo> scope_info,
- Handle<Context> context,
- FrameInspector* frame_inspector) {
- Handle<JSObject> block_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
-
- if (frame_inspector != nullptr) {
- MaterializeStackLocalsWithFrameInspector(isolate, block_scope, scope_info,
- frame_inspector);
- }
-
- if (!context.is_null()) {
- Handle<ScopeInfo> scope_info_from_context(
- ScopeInfo::cast(context->extension()));
- // Fill all context locals.
- ScopeInfo::CopyContextLocalsToScopeObject(scope_info_from_context, context,
- block_scope);
- }
-
- return block_scope;
-}
-
-
-// Create a plain JSObject which materializes the module scope for the specified
-// module context.
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope(
- Isolate* isolate, Handle<Context> context) {
- DCHECK(context->IsModuleContext());
- Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
-
- // Allocate and initialize a JSObject with all the members of the debugged
- // module.
- Handle<JSObject> module_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
-
- // Fill all context locals.
- ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, module_scope);
-
- return module_scope;
-}
-
-
-// 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
- };
-
- ScopeIterator(Isolate* isolate, FrameInspector* frame_inspector,
- bool ignore_nested_scopes = false)
- : isolate_(isolate),
- frame_inspector_(frame_inspector),
- nested_scope_chain_(4),
- seen_script_scope_(false),
- failed_(false) {
- if (!frame_inspector->GetContext()->IsContext() ||
- !frame_inspector->GetFunction()->IsJSFunction()) {
- // Optimized frame, context or function cannot be materialized. Give up.
- return;
- }
-
- context_ = Handle<Context>(Context::cast(frame_inspector->GetContext()));
-
- // Catch the case when the debugger stops in an internal function.
- Handle<SharedFunctionInfo> shared_info(function()->shared());
- Handle<ScopeInfo> scope_info(shared_info->scope_info());
- if (shared_info->script() == isolate->heap()->undefined_value()) {
- while (context_->closure() == function()) {
- context_ = Handle<Context>(context_->previous(), isolate_);
- }
- return;
- }
-
- // Currently it takes too much time to find nested scopes due to script
- // parsing. Sometimes we want to run the ScopeIterator as fast as possible
- // (for example, while collecting async call stacks on every
- // addEventListener call), even if we drop some nested scopes.
- // Later we may optimize getting the nested scopes (cache the result?)
- // and include nested scopes into the "fast" iteration case as well.
-
- if (!ignore_nested_scopes && shared_info->HasDebugInfo()) {
- // The source position at return is always the end of the function,
- // which is not consistent with the current scope chain. Therefore all
- // nested with, catch and block contexts are skipped, and we can only
- // inspect the function scope.
- // This can only happen if we set a break point inside right before the
- // return, which requires a debug info to be available.
- Handle<DebugInfo> debug_info(shared_info->GetDebugInfo());
-
- // PC points to the instruction after the current one, possibly a break
- // location as well. So the "- 1" to exclude it from the search.
- Address call_pc = frame()->pc() - 1;
-
- // Find the break point where execution has stopped.
- BreakLocation location =
- BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
-
- ignore_nested_scopes = location.IsReturn();
- }
-
- if (ignore_nested_scopes) {
- if (scope_info->HasContext()) {
- context_ = Handle<Context>(context_->declaration_context(), isolate_);
- } else {
- while (context_->closure() == function()) {
- context_ = Handle<Context>(context_->previous(), isolate_);
- }
- }
- if (scope_info->scope_type() == FUNCTION_SCOPE ||
- scope_info->scope_type() == ARROW_SCOPE) {
- nested_scope_chain_.Add(scope_info);
- }
- } else {
- // Reparse the code and analyze the scopes.
- Handle<Script> script(Script::cast(shared_info->script()));
- Scope* scope = NULL;
-
- // Check whether we are in global, eval or function code.
- Handle<ScopeInfo> scope_info(shared_info->scope_info());
- Zone zone;
- if (scope_info->scope_type() != FUNCTION_SCOPE &&
- scope_info->scope_type() != ARROW_SCOPE) {
- // Global or eval code.
- ParseInfo info(&zone, script);
- if (scope_info->scope_type() == SCRIPT_SCOPE) {
- info.set_global();
- } else {
- DCHECK(scope_info->scope_type() == EVAL_SCOPE);
- info.set_eval();
- info.set_context(Handle<Context>(function()->context()));
- }
- if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
- scope = info.function()->scope();
- }
- RetrieveScopeChain(scope, shared_info);
- } else {
- // Function code
- ParseInfo info(&zone, Handle<JSFunction>(function()));
- if (Parser::ParseStatic(&info) && Scope::Analyze(&info)) {
- scope = info.function()->scope();
- }
- RetrieveScopeChain(scope, shared_info);
- }
- }
- }
-
- ScopeIterator(Isolate* isolate, Handle<JSFunction> function)
- : isolate_(isolate),
- frame_inspector_(NULL),
- context_(function->context()),
- seen_script_scope_(false),
- failed_(false) {
- if (function->IsBuiltin()) context_ = Handle<Context>();
- }
-
- // More scopes?
- bool Done() {
- DCHECK(!failed_);
- return context_.is_null();
- }
-
- bool Failed() { return failed_; }
-
- // Move to the next scope.
- void Next() {
- DCHECK(!failed_);
- ScopeType scope_type = Type();
- if (scope_type == ScopeTypeGlobal) {
- // The global scope is always the last in the chain.
- DCHECK(context_->IsNativeContext());
- context_ = Handle<Context>();
- return;
- }
- if (scope_type == ScopeTypeScript) {
- seen_script_scope_ = true;
- if (context_->IsScriptContext()) {
- context_ = Handle<Context>(context_->previous(), isolate_);
- }
- if (!nested_scope_chain_.is_empty()) {
- DCHECK_EQ(nested_scope_chain_.last()->scope_type(), SCRIPT_SCOPE);
- nested_scope_chain_.RemoveLast();
- DCHECK(nested_scope_chain_.is_empty());
- }
- CHECK(context_->IsNativeContext());
- return;
- }
- if (nested_scope_chain_.is_empty()) {
- context_ = Handle<Context>(context_->previous(), isolate_);
- } else {
- if (nested_scope_chain_.last()->HasContext()) {
- DCHECK(context_->previous() != NULL);
- context_ = Handle<Context>(context_->previous(), isolate_);
- }
- nested_scope_chain_.RemoveLast();
- }
- }
-
- // Return the type of the current scope.
- ScopeType Type() {
- DCHECK(!failed_);
- if (!nested_scope_chain_.is_empty()) {
- Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
- switch (scope_info->scope_type()) {
- case FUNCTION_SCOPE:
- case ARROW_SCOPE:
- DCHECK(context_->IsFunctionContext() || !scope_info->HasContext());
- return ScopeTypeLocal;
- case MODULE_SCOPE:
- DCHECK(context_->IsModuleContext());
- return ScopeTypeModule;
- case SCRIPT_SCOPE:
- DCHECK(context_->IsScriptContext() || context_->IsNativeContext());
- return ScopeTypeScript;
- case WITH_SCOPE:
- DCHECK(context_->IsWithContext());
- return ScopeTypeWith;
- case CATCH_SCOPE:
- DCHECK(context_->IsCatchContext());
- return ScopeTypeCatch;
- case BLOCK_SCOPE:
- DCHECK(!scope_info->HasContext() || context_->IsBlockContext());
- return ScopeTypeBlock;
- case EVAL_SCOPE:
- UNREACHABLE();
- }
- }
- if (context_->IsNativeContext()) {
- DCHECK(context_->global_object()->IsGlobalObject());
- // If we are at the native context and have not yet seen script scope,
- // fake it.
- return seen_script_scope_ ? ScopeTypeGlobal : ScopeTypeScript;
- }
- if (context_->IsFunctionContext()) {
- return ScopeTypeClosure;
- }
- if (context_->IsCatchContext()) {
- return ScopeTypeCatch;
- }
- if (context_->IsBlockContext()) {
- return ScopeTypeBlock;
- }
- if (context_->IsModuleContext()) {
- return ScopeTypeModule;
- }
- if (context_->IsScriptContext()) {
- return ScopeTypeScript;
- }
- DCHECK(context_->IsWithContext());
- return ScopeTypeWith;
- }
-
- // Return the JavaScript object with the content of the current scope.
- MaybeHandle<JSObject> ScopeObject() {
- DCHECK(!failed_);
- switch (Type()) {
- case ScopeIterator::ScopeTypeGlobal:
- return Handle<JSObject>(CurrentContext()->global_object());
- case ScopeIterator::ScopeTypeScript:
- return MaterializeScriptScope(
- Handle<GlobalObject>(CurrentContext()->global_object()));
- case ScopeIterator::ScopeTypeLocal:
- // Materialize the content of the local scope into a JSObject.
- DCHECK(nested_scope_chain_.length() == 1);
- return MaterializeLocalScope(isolate_, frame_inspector_);
- case ScopeIterator::ScopeTypeWith:
- // Return the with object.
- return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
- case ScopeIterator::ScopeTypeCatch:
- return MaterializeCatchScope(isolate_, CurrentContext());
- case ScopeIterator::ScopeTypeClosure:
- // Materialize the content of the closure scope into a JSObject.
- return MaterializeClosure(isolate_, CurrentContext());
- case ScopeIterator::ScopeTypeBlock: {
- if (!nested_scope_chain_.is_empty()) {
- // this is a block scope on the stack.
- Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
- Handle<Context> context = scope_info->HasContext()
- ? CurrentContext()
- : Handle<Context>::null();
- return MaterializeBlockScope(isolate_, scope_info, context,
- frame_inspector_);
- } else {
- return MaterializeBlockScope(isolate_, Handle<ScopeInfo>::null(),
- CurrentContext(), nullptr);
- }
- }
- case ScopeIterator::ScopeTypeModule:
- return MaterializeModuleScope(isolate_, CurrentContext());
- }
- UNREACHABLE();
- return Handle<JSObject>();
- }
-
- bool HasContext() {
- ScopeType type = Type();
- if (type == ScopeTypeBlock || type == ScopeTypeLocal) {
- if (!nested_scope_chain_.is_empty()) {
- return nested_scope_chain_.last()->HasContext();
- }
- }
- return true;
- }
-
- bool SetVariableValue(Handle<String> variable_name,
- Handle<Object> new_value) {
- DCHECK(!failed_);
- switch (Type()) {
- case ScopeIterator::ScopeTypeGlobal:
- break;
- case ScopeIterator::ScopeTypeLocal:
- return SetLocalVariableValue(isolate_, frame(), variable_name,
- new_value);
- case ScopeIterator::ScopeTypeWith:
- break;
- case ScopeIterator::ScopeTypeCatch:
- return SetCatchVariableValue(isolate_, CurrentContext(), variable_name,
- new_value);
- case ScopeIterator::ScopeTypeClosure:
- return SetClosureVariableValue(isolate_, CurrentContext(),
- variable_name, new_value);
- case ScopeIterator::ScopeTypeScript:
- return SetScriptVariableValue(CurrentContext(), variable_name,
- new_value);
- case ScopeIterator::ScopeTypeBlock:
- return SetBlockVariableValue(
- isolate_, HasContext() ? CurrentContext() : Handle<Context>::null(),
- CurrentScopeInfo(), frame(), variable_name, new_value);
- case ScopeIterator::ScopeTypeModule:
- // TODO(2399): should we implement it?
- break;
- }
- return false;
- }
-
- Handle<ScopeInfo> CurrentScopeInfo() {
- DCHECK(!failed_);
- if (!nested_scope_chain_.is_empty()) {
- return nested_scope_chain_.last();
- } else if (context_->IsBlockContext()) {
- return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
- } else if (context_->IsFunctionContext()) {
- return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
- }
- return Handle<ScopeInfo>::null();
- }
-
- // Return the context for this scope. For the local context there might not
- // be an actual context.
- Handle<Context> CurrentContext() {
- DCHECK(!failed_);
- if (Type() == ScopeTypeGlobal || Type() == ScopeTypeScript ||
- nested_scope_chain_.is_empty()) {
- return context_;
- } else if (nested_scope_chain_.last()->HasContext()) {
- return context_;
- } else {
- return Handle<Context>();
- }
- }
-
-#ifdef DEBUG
- // Debug print of the content of the current scope.
- void DebugPrint() {
- OFStream os(stdout);
- DCHECK(!failed_);
- switch (Type()) {
- case ScopeIterator::ScopeTypeGlobal:
- os << "Global:\n";
- CurrentContext()->Print(os);
- break;
-
- case ScopeIterator::ScopeTypeLocal: {
- os << "Local:\n";
- function()->shared()->scope_info()->Print();
- if (!CurrentContext().is_null()) {
- CurrentContext()->Print(os);
- if (CurrentContext()->has_extension()) {
- Handle<Object> extension(CurrentContext()->extension(), isolate_);
- if (extension->IsJSContextExtensionObject()) {
- extension->Print(os);
- }
- }
- }
- break;
- }
-
- case ScopeIterator::ScopeTypeWith:
- os << "With:\n";
- CurrentContext()->extension()->Print(os);
- break;
-
- case ScopeIterator::ScopeTypeCatch:
- os << "Catch:\n";
- CurrentContext()->extension()->Print(os);
- CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print(os);
- break;
-
- case ScopeIterator::ScopeTypeClosure:
- os << "Closure:\n";
- CurrentContext()->Print(os);
- if (CurrentContext()->has_extension()) {
- Handle<Object> extension(CurrentContext()->extension(), isolate_);
- if (extension->IsJSContextExtensionObject()) {
- extension->Print(os);
- }
- }
- break;
-
- case ScopeIterator::ScopeTypeScript:
- os << "Script:\n";
- CurrentContext()
- ->global_object()
- ->native_context()
- ->script_context_table()
- ->Print(os);
- break;
-
- default:
- UNREACHABLE();
- }
- PrintF("\n");
- }
-#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* frame() {
- return frame_inspector_->GetArgumentsFrame();
- }
-
- inline JSFunction* function() {
- return JSFunction::cast(frame_inspector_->GetFunction());
- }
-
- void RetrieveScopeChain(Scope* scope,
- Handle<SharedFunctionInfo> shared_info) {
- if (scope != NULL) {
- int source_position = frame_inspector_->GetSourcePosition();
- scope->GetNestedScopeChain(isolate_, &nested_scope_chain_,
- source_position);
- } else {
- // A failed reparse indicates that the preparser has diverged from the
- // parser or that the preparse data given to the initial parse has been
- // faulty. We fail in debug mode but in release mode we only provide the
- // information we get from the context chain but nothing about
- // completely stack allocated scopes or stack allocated locals.
- // Or it could be due to stack overflow.
- DCHECK(isolate_->has_pending_exception());
- failed_ = true;
- }
- }
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
-};
-
-
RUNTIME_FUNCTION(Runtime_GetScopeCount) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
@@ -1798,7 +749,7 @@ RUNTIME_FUNCTION(Runtime_GetScopeCount) {
CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
// Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
+ StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
JavaScriptFrameIterator it(isolate, id);
JavaScriptFrame* frame = it.frame();
FrameInspector frame_inspector(frame, 0, isolate);
@@ -1825,7 +776,7 @@ RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
CONVERT_SMI_ARG_CHECKED(wrapped_id, 1);
// Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
+ StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
JavaScriptFrameIterator frame_it(isolate, id);
RUNTIME_ASSERT(!frame_it.done());
@@ -1840,28 +791,6 @@ RUNTIME_FUNCTION(Runtime_GetStepInPositions) {
}
-static const int kScopeDetailsTypeIndex = 0;
-static const int kScopeDetailsObjectIndex = 1;
-static const int kScopeDetailsSize = 2;
-
-
-MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeScopeDetails(
- Isolate* isolate, ScopeIterator* it) {
- // Calculate the size of the result.
- int details_size = kScopeDetailsSize;
- Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
-
- // Fill in scope details.
- details->set(kScopeDetailsTypeIndex, Smi::FromInt(it->Type()));
- Handle<JSObject> scope_object;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, scope_object, it->ScopeObject(),
- JSObject);
- details->set(kScopeDetailsObjectIndex, *scope_object);
-
- return isolate->factory()->NewJSArrayWithElements(details);
-}
-
-
// Return an array with scope details
// args[0]: number: break id
// args[1]: number: frame index
@@ -1882,7 +811,7 @@ RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
// Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
+ StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
JavaScriptFrameIterator frame_it(isolate, id);
JavaScriptFrame* frame = frame_it.frame();
FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
@@ -1898,7 +827,7 @@ RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
}
Handle<JSObject> details;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
- MaterializeScopeDetails(isolate, &it));
+ it.MaterializeScopeDetails());
return *details;
}
@@ -1928,7 +857,7 @@ RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
}
// Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
+ StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
JavaScriptFrameIterator frame_it(isolate, id);
JavaScriptFrame* frame = frame_it.frame();
FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
@@ -1938,7 +867,7 @@ RUNTIME_FUNCTION(Runtime_GetAllScopesDetails) {
for (; !it.Done(); it.Next()) {
Handle<JSObject> details;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
- MaterializeScopeDetails(isolate, &it));
+ it.MaterializeScopeDetails());
result.Add(details);
}
@@ -1987,7 +916,7 @@ RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
Handle<JSObject> details;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
- MaterializeScopeDetails(isolate, &it));
+ it.MaterializeScopeDetails());
return *details;
}
@@ -2032,7 +961,7 @@ RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
// Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
+ StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
JavaScriptFrameIterator frame_it(isolate, id);
JavaScriptFrame* frame = frame_it.frame();
FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
@@ -2305,7 +1234,7 @@ RUNTIME_FUNCTION(Runtime_PrepareStep) {
if (wrapped_frame_id == 0) {
frame_id = StackFrame::NO_ID;
} else {
- frame_id = UnwrapFrameId(wrapped_frame_id);
+ frame_id = DebugFrameHelper::UnwrapFrameId(wrapped_frame_id);
}
// Get the step action and check validity.
@@ -2347,254 +1276,6 @@ RUNTIME_FUNCTION(Runtime_ClearStepping) {
}
-// Helper function to find or create the arguments object for
-// Runtime_DebugEvaluate.
-static void MaterializeArgumentsObject(Isolate* isolate,
- Handle<JSObject> target,
- Handle<JSFunction> function) {
- // Do not materialize the arguments object for eval or top-level code.
- // Skip if "arguments" is already taken.
- if (!function->shared()->is_function()) return;
- Maybe<bool> maybe = JSReceiver::HasOwnProperty(
- target, isolate->factory()->arguments_string());
- DCHECK(maybe.IsJust());
- if (maybe.FromJust()) return;
-
- // FunctionGetArguments can't throw an exception.
- Handle<JSObject> arguments =
- Handle<JSObject>::cast(Accessors::FunctionGetArguments(function));
- Handle<String> arguments_str = isolate->factory()->arguments_string();
- JSObject::SetOwnPropertyIgnoreAttributes(target, arguments_str, arguments,
- NONE).Check();
-}
-
-
-// Compile and evaluate source for the given context.
-static MaybeHandle<Object> DebugEvaluate(Isolate* isolate,
- Handle<SharedFunctionInfo> outer_info,
- Handle<Context> context,
- Handle<Object> context_extension,
- Handle<Object> receiver,
- Handle<String> source) {
- if (context_extension->IsJSObject()) {
- Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
- Handle<JSFunction> closure(context->closure(), isolate);
- context = isolate->factory()->NewWithContext(closure, context, extension);
- }
-
- Handle<JSFunction> eval_fun;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, eval_fun,
- Compiler::GetFunctionFromEval(
- source, outer_info, context, SLOPPY,
- NO_PARSE_RESTRICTION, RelocInfo::kNoPosition),
- Object);
-
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, result, Execution::Call(isolate, eval_fun, receiver, 0, NULL),
- Object);
-
- // Skip the global proxy as it has no properties and always delegates to the
- // real global object.
- if (result->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate, result);
- // TODO(verwaest): This will crash when the global proxy is detached.
- result = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
- }
-
- return result;
-}
-
-
-static Handle<JSObject> NewJSObjectWithNullProto(Isolate* isolate) {
- Handle<JSObject> result =
- isolate->factory()->NewJSObject(isolate->object_function());
- Handle<Map> new_map =
- Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto");
- Map::SetPrototype(new_map, isolate->factory()->null_value());
- JSObject::MigrateToMap(result, new_map);
- return result;
-}
-
-
-namespace {
-
-// 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 EvaluationContextBuilder {
- public:
- EvaluationContextBuilder(Isolate* isolate, JavaScriptFrame* frame,
- int inlined_jsframe_index)
- : isolate_(isolate),
- frame_(frame),
- inlined_jsframe_index_(inlined_jsframe_index) {
- FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
- Handle<JSFunction> function =
- handle(JSFunction::cast(frame_inspector.GetFunction()));
- Handle<Context> outer_context = handle(function->context(), isolate);
- outer_info_ = handle(function->shared());
- Handle<Context> inner_context;
-
- bool stop = false;
- for (ScopeIterator it(isolate, &frame_inspector);
- !it.Failed() && !it.Done() && !stop; it.Next()) {
- ScopeIterator::ScopeType scope_type = it.Type();
-
- if (scope_type == ScopeIterator::ScopeTypeLocal) {
- Handle<Context> parent_context =
- it.HasContext() ? it.CurrentContext() : outer_context;
-
- // The "this" binding, if any, can't be bound via "with". If we need
- // to, add another node onto the outer context to bind "this".
- parent_context =
- MaterializeReceiver(isolate, parent_context, function, frame);
-
- Handle<JSObject> materialized_function =
- NewJSObjectWithNullProto(isolate);
-
- MaterializeStackLocalsWithFrameInspector(isolate, materialized_function,
- function, &frame_inspector);
-
- MaterializeArgumentsObject(isolate, materialized_function, function);
-
- Handle<Context> with_context = isolate->factory()->NewWithContext(
- function, parent_context, materialized_function);
-
- ContextChainElement context_chain_element;
- context_chain_element.original_context = it.CurrentContext();
- context_chain_element.materialized_object = materialized_function;
- context_chain_element.scope_info = it.CurrentScopeInfo();
- context_chain_.Add(context_chain_element);
-
- stop = true;
- RecordContextsInChain(&inner_context, with_context, with_context);
- } else if (scope_type == ScopeIterator::ScopeTypeCatch ||
- scope_type == ScopeIterator::ScopeTypeWith) {
- Handle<Context> cloned_context =
- Handle<Context>::cast(FixedArray::CopySize(
- it.CurrentContext(), it.CurrentContext()->length()));
-
- ContextChainElement context_chain_element;
- context_chain_element.original_context = it.CurrentContext();
- context_chain_element.cloned_context = cloned_context;
- context_chain_.Add(context_chain_element);
-
- RecordContextsInChain(&inner_context, cloned_context, cloned_context);
- } else if (scope_type == ScopeIterator::ScopeTypeBlock) {
- Handle<JSObject> materialized_object =
- NewJSObjectWithNullProto(isolate);
- MaterializeStackLocalsWithFrameInspector(isolate, materialized_object,
- it.CurrentScopeInfo(),
- &frame_inspector);
- if (it.HasContext()) {
- Handle<Context> cloned_context =
- Handle<Context>::cast(FixedArray::CopySize(
- it.CurrentContext(), it.CurrentContext()->length()));
- Handle<Context> with_context = isolate->factory()->NewWithContext(
- function, cloned_context, materialized_object);
-
- ContextChainElement context_chain_element;
- context_chain_element.original_context = it.CurrentContext();
- context_chain_element.cloned_context = cloned_context;
- context_chain_element.materialized_object = materialized_object;
- context_chain_element.scope_info = it.CurrentScopeInfo();
- context_chain_.Add(context_chain_element);
-
- RecordContextsInChain(&inner_context, cloned_context, with_context);
- } else {
- Handle<Context> with_context = isolate->factory()->NewWithContext(
- function, outer_context, materialized_object);
-
- ContextChainElement context_chain_element;
- context_chain_element.materialized_object = materialized_object;
- context_chain_element.scope_info = it.CurrentScopeInfo();
- context_chain_.Add(context_chain_element);
-
- RecordContextsInChain(&inner_context, with_context, with_context);
- }
- } else {
- stop = true;
- }
- }
- if (innermost_context_.is_null()) {
- innermost_context_ = outer_context;
- }
- DCHECK(!innermost_context_.is_null());
- }
-
- void UpdateVariables() {
- for (int i = 0; i < context_chain_.length(); i++) {
- ContextChainElement element = context_chain_[i];
- if (!element.original_context.is_null() &&
- !element.cloned_context.is_null()) {
- Handle<Context> cloned_context = element.cloned_context;
- cloned_context->CopyTo(
- Context::MIN_CONTEXT_SLOTS, *element.original_context,
- Context::MIN_CONTEXT_SLOTS,
- cloned_context->length() - Context::MIN_CONTEXT_SLOTS);
- }
- if (!element.materialized_object.is_null()) {
- // Write back potential changes to materialized stack locals to the
- // stack.
- UpdateStackLocalsFromMaterializedObject(
- isolate_, element.materialized_object, element.scope_info, frame_,
- inlined_jsframe_index_);
- }
- }
- }
-
- 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) {
- if (!inner_context->is_null()) {
- (*inner_context)->set_previous(*last);
- } else {
- innermost_context_ = last;
- }
- *inner_context = first;
- }
-
- Handle<SharedFunctionInfo> outer_info_;
- Handle<Context> innermost_context_;
- List<ContextChainElement> context_chain_;
- Isolate* isolate_;
- JavaScriptFrame* frame_;
- int inlined_jsframe_index_;
-};
-}
-
-
-// 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.
RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
HandleScope scope(isolate);
@@ -2610,50 +1291,17 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluate) {
CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 4);
CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 5);
- // Handle the processing of break.
- DisableBreak disable_break_scope(isolate->debug(), disable_break);
-
- // Get the frame where the debugging is performed.
- StackFrame::Id id = UnwrapFrameId(wrapped_id);
- JavaScriptFrameIterator it(isolate, id);
- JavaScriptFrame* frame = it.frame();
-
- // Traverse the saved contexts chain to find the active context for the
- // selected frame.
- SaveContext* save = FindSavedContextForFrame(isolate, frame);
-
- SaveContext savex(isolate);
- isolate->set_context(*(save->context()));
-
- // Materialize stack locals and the arguments object.
-
- EvaluationContextBuilder context_builder(isolate, frame,
- inlined_jsframe_index);
- if (isolate->has_pending_exception()) {
- return isolate->heap()->exception();
- }
-
-
- Handle<Object> receiver(frame->receiver(), isolate);
- MaybeHandle<Object> maybe_result = DebugEvaluate(
- isolate, context_builder.outer_info(),
- context_builder.innermost_context(), context_extension, receiver, source);
+ StackFrame::Id id = DebugFrameHelper::UnwrapFrameId(wrapped_id);
Handle<Object> result;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result);
- context_builder.UpdateVariables();
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ DebugEvaluate::Local(isolate, id, inlined_jsframe_index, source,
+ disable_break, context_extension));
return *result;
}
-static inline bool IsDebugContext(Isolate* isolate, Context* context) {
- // Try to unwrap script context if it exist.
- if (context->IsScriptContext()) context = context->previous();
- DCHECK_NOT_NULL(context);
- return context == *isolate->debug()->debug_context();
-}
-
-
RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
HandleScope scope(isolate);
@@ -2667,28 +1315,10 @@ RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) {
CONVERT_BOOLEAN_ARG_CHECKED(disable_break, 2);
CONVERT_ARG_HANDLE_CHECKED(Object, context_extension, 3);
- // Handle the processing of break.
- DisableBreak disable_break_scope(isolate->debug(), disable_break);
-
- // Enter the top context from before the debugger was invoked.
- SaveContext save(isolate);
- SaveContext* top = &save;
- while (top != NULL && IsDebugContext(isolate, *top->context())) {
- top = top->prev();
- }
- if (top != NULL) {
- isolate->set_context(*top->context());
- }
-
- // Get the native context now set to the top context from before the
- // debugger was invoked.
- Handle<Context> context = isolate->native_context();
- Handle<JSObject> receiver(context->global_proxy());
- Handle<SharedFunctionInfo> outer_info(context->closure()->shared(), isolate);
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, result, DebugEvaluate(isolate, outer_info, context,
- context_extension, receiver, source));
+ isolate, result,
+ DebugEvaluate::Global(isolate, source, disable_break, context_extension));
return *result;
}

Powered by Google App Engine
This is Rietveld 408576698