summaryrefslogtreecommitdiff
path: root/deps/v8/src/runtime/runtime-debug.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/runtime/runtime-debug.cc')
-rw-r--r--deps/v8/src/runtime/runtime-debug.cc1722
1 files changed, 111 insertions, 1611 deletions
diff --git a/deps/v8/src/runtime/runtime-debug.cc b/deps/v8/src/runtime/runtime-debug.cc
index e7aaed1f6f..1cd524f17c 100644
--- a/deps/v8/src/runtime/runtime-debug.cc
+++ b/deps/v8/src/runtime/runtime-debug.cc
@@ -2,16 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/v8.h"
+#include "src/runtime/runtime-utils.h"
-#include "src/accessors.h"
#include "src/arguments.h"
-#include "src/compiler.h"
-#include "src/debug.h"
-#include "src/deoptimizer.h"
-#include "src/parser.h"
+#include "src/debug/debug.h"
+#include "src/debug/debug-evaluate.h"
+#include "src/debug/debug-frames.h"
+#include "src/debug/debug-scopes.h"
+#include "src/frames-inl.h"
#include "src/runtime/runtime.h"
-#include "src/runtime/runtime-utils.h"
namespace v8 {
namespace internal {
@@ -19,20 +18,19 @@ namespace internal {
RUNTIME_FUNCTION(Runtime_DebugBreak) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 0);
- isolate->debug()->HandleDebugBreak();
+ // Get the top-most JavaScript frame.
+ JavaScriptFrameIterator it(isolate);
+ isolate->debug()->Break(args, it.frame());
+ isolate->debug()->SetAfterBreakTarget(it.frame());
return isolate->heap()->undefined_value();
}
-// 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);
+RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) {
+ SealHandleScope shs(isolate);
+ DCHECK(args.length() == 0);
+ isolate->debug()->HandleDebugBreak();
+ return isolate->heap()->undefined_value();
}
@@ -311,9 +309,8 @@ RUNTIME_FUNCTION(Runtime_DebugGetPropertyDetails) {
if (name->AsArrayIndex(&index)) {
Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
Handle<Object> element_or_char;
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, element_or_char,
- Runtime::GetElementOrCharAt(isolate, obj, index));
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element_or_char,
+ Object::GetElement(isolate, obj, index));
details->set(0, *element_or_char);
details->set(1, PropertyDetails::Empty().AsSmi());
return *isolate->factory()->NewJSArrayWithElements(details);
@@ -465,93 +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();
- }
-
- // 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;
@@ -564,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
@@ -627,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);
@@ -635,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();
@@ -855,932 +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.
- // TODO(yangguo): make sure all code deoptimized when debugger is active
- // and assert that this cannot happen.
- 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,
- JavaScriptFrame* frame) {
- 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> frame_context(Context::cast(frame->context()));
- 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, JavaScriptFrame* frame, int inlined_jsframe_index) {
- FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
- 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);
-
- return MaterializeLocalContext(isolate, local_scope, function, frame);
-}
-
-
-// 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,
- int inlined_jsframe_index,
- Handle<String> variable_name,
- Handle<Object> new_value) {
- if (inlined_jsframe_index != 0 || frame->is_optimized()) {
- // Optimized frames are not supported.
- 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,
- JavaScriptFrame* frame,
- int inlined_jsframe_index) {
- Handle<JSObject> block_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
-
- if (frame != nullptr) {
- FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
- 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, JavaScriptFrame* frame,
- int inlined_jsframe_index, bool ignore_nested_scopes = false)
- : isolate_(isolate),
- frame_(frame),
- inlined_jsframe_index_(inlined_jsframe_index),
- function_(frame->function()),
- context_(Context::cast(frame->context())),
- nested_scope_chain_(4),
- seen_script_scope_(false),
- failed_(false) {
- // 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;
- }
-
- // Get the debug info (create it if it does not exist).
- if (!isolate->debug()->EnsureDebugInfo(shared_info, function_)) {
- // Return if ensuring debug info failed.
- 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) {
- Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
-
- // 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);
-
- // Within the return sequence at the moment it is not possible to
- // get a source position which is consistent with the current scope chain.
- // Thus all nested with, catch and block contexts are skipped and we only
- // provide the function scope.
- ignore_nested_scopes = location.IsExit();
- }
-
- 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, 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_(NULL),
- inlined_jsframe_index_(0),
- function_(function),
- 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_, inlined_jsframe_index_);
- 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_,
- inlined_jsframe_index_);
- } else {
- return MaterializeBlockScope(isolate_, Handle<ScopeInfo>::null(),
- CurrentContext(), nullptr, 0);
- }
- }
- 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_, inlined_jsframe_index_,
- 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_;
- JavaScriptFrame* frame_;
- int inlined_jsframe_index_;
- Handle<JSFunction> function_;
- Handle<Context> context_;
- List<Handle<ScopeInfo> > nested_scope_chain_;
- bool seen_script_scope_;
- bool failed_;
-
- void RetrieveScopeChain(Scope* scope,
- Handle<SharedFunctionInfo> shared_info) {
- if (scope != NULL) {
- int source_position = shared_info->code()->SourcePosition(frame_->pc());
- 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);
@@ -1790,13 +749,14 @@ 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);
// Count the visible scopes.
int n = 0;
- for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
+ for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) {
n++;
}
@@ -1816,85 +776,18 @@ 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());
- List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
- frame_it.frame()->Summarize(&frames);
- FrameSummary summary = frames.first();
-
- Handle<JSFunction> fun = Handle<JSFunction>(summary.function());
- Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared());
-
- if (!isolate->debug()->EnsureDebugInfo(shared, fun)) {
- return isolate->heap()->undefined_value();
- }
-
- Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared);
-
- // Find range of break points starting from the break point where execution
- // has stopped.
- Address call_pc = summary.pc() - 1;
- List<BreakLocation> locations;
- BreakLocation::FromAddressSameStatement(debug_info, ALL_BREAK_LOCATIONS,
- call_pc, &locations);
-
- Handle<JSArray> array = isolate->factory()->NewJSArray(locations.length());
-
- int index = 0;
- for (BreakLocation location : locations) {
- bool accept;
- if (location.pc() > summary.pc()) {
- accept = true;
- } else {
- StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
- // The break point is near our pc. Could be a step-in possibility,
- // that is currently taken by active debugger call.
- if (break_frame_id == StackFrame::NO_ID) {
- // We are not stepping.
- accept = false;
- } else {
- JavaScriptFrameIterator additional_frame_it(isolate, break_frame_id);
- // If our frame is a top frame and we are stepping, we can do step-in
- // at this place.
- accept = additional_frame_it.frame()->id() == id;
- }
- }
- if (accept) {
- if (location.IsStepInLocation()) {
- Smi* position_value = Smi::FromInt(location.position());
- RETURN_FAILURE_ON_EXCEPTION(
- isolate,
- JSObject::SetElement(array, index, handle(position_value, isolate),
- SLOPPY));
- index++;
- }
- }
+ List<int> positions;
+ isolate->debug()->GetStepinPositions(frame_it.frame(), id, &positions);
+ Factory* factory = isolate->factory();
+ Handle<FixedArray> array = factory->NewFixedArray(positions.length());
+ for (int i = 0; i < positions.length(); ++i) {
+ array->set(i, Smi::FromInt(positions[i]));
}
- return *array;
-}
-
-
-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 *factory->NewJSArrayWithElements(array, FAST_SMI_ELEMENTS);
}
@@ -1918,13 +811,14 @@ 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);
// Find the requested scope.
int n = 0;
- ScopeIterator it(isolate, frame, inlined_jsframe_index);
+ ScopeIterator it(isolate, &frame_inspector);
for (; !it.Done() && n < index; it.Next()) {
n++;
}
@@ -1933,7 +827,7 @@ RUNTIME_FUNCTION(Runtime_GetScopeDetails) {
}
Handle<JSObject> details;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
- MaterializeScopeDetails(isolate, &it));
+ it.MaterializeScopeDetails());
return *details;
}
@@ -1963,16 +857,17 @@ 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);
List<Handle<JSObject> > result(4);
- ScopeIterator it(isolate, frame, inlined_jsframe_index, ignore_nested_scopes);
+ ScopeIterator it(isolate, &frame_inspector, ignore_nested_scopes);
for (; !it.Done(); it.Next()) {
Handle<JSObject> details;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
- MaterializeScopeDetails(isolate, &it));
+ it.MaterializeScopeDetails());
result.Add(details);
}
@@ -2021,7 +916,7 @@ RUNTIME_FUNCTION(Runtime_GetFunctionScopeDetails) {
Handle<JSObject> details;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, details,
- MaterializeScopeDetails(isolate, &it));
+ it.MaterializeScopeDetails());
return *details;
}
@@ -2066,11 +961,12 @@ 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);
- ScopeIterator it(isolate, frame, inlined_jsframe_index);
+ ScopeIterator it(isolate, &frame_inspector);
res = SetScopeVariableValue(&it, index, variable_name, new_value);
} else {
CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
@@ -2090,7 +986,9 @@ RUNTIME_FUNCTION(Runtime_DebugPrintScopes) {
// Print the scopes for the top frame.
StackFrameLocator locator(isolate);
JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
- for (ScopeIterator it(isolate, frame, 0); !it.Done(); it.Next()) {
+ FrameInspector frame_inspector(frame, 0, isolate);
+
+ for (ScopeIterator it(isolate, &frame_inspector); !it.Done(); it.Next()) {
it.DebugPrint();
}
#endif
@@ -2336,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.
@@ -2378,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, inlined_jsframe_index);
- !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);
@@ -2641,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);
@@ -2698,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;
}
@@ -2760,71 +1359,6 @@ RUNTIME_FUNCTION(Runtime_DebugGetLoadedScripts) {
}
-// Helper function used by Runtime_DebugReferencedBy below.
-static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
- Object* instance_filter, int max_references,
- FixedArray* instances, int instances_size,
- JSFunction* arguments_function) {
- Isolate* isolate = target->GetIsolate();
- SealHandleScope shs(isolate);
- DisallowHeapAllocation no_allocation;
-
- // Iterate the heap.
- int count = 0;
- JSObject* last = NULL;
- HeapObject* heap_obj = NULL;
- while (((heap_obj = iterator->next()) != NULL) &&
- (max_references == 0 || count < max_references)) {
- // Only look at all JSObjects.
- if (heap_obj->IsJSObject()) {
- // Skip context extension objects and argument arrays as these are
- // checked in the context of functions using them.
- JSObject* obj = JSObject::cast(heap_obj);
- if (obj->IsJSContextExtensionObject() ||
- obj->map()->GetConstructor() == arguments_function) {
- continue;
- }
-
- // Check if the JS object has a reference to the object looked for.
- if (obj->ReferencesObject(target)) {
- // Check instance filter if supplied. This is normally used to avoid
- // references from mirror objects (see Runtime_IsInPrototypeChain).
- if (!instance_filter->IsUndefined()) {
- for (PrototypeIterator iter(isolate, obj); !iter.IsAtEnd();
- iter.Advance()) {
- if (iter.GetCurrent() == instance_filter) {
- obj = NULL; // Don't add this object.
- break;
- }
- }
- }
-
- if (obj != NULL) {
- // Valid reference found add to instance array if supplied an update
- // count.
- if (instances != NULL && count < instances_size) {
- instances->set(count, obj);
- }
- last = obj;
- count++;
- }
- }
- }
- }
-
- // Check for circular reference only. This can happen when the object is only
- // referenced from mirrors and has a circular reference in which case the
- // object is not really alive and would have been garbage collected if not
- // referenced from the mirror.
- if (count == 1 && last == target) {
- count = 0;
- }
-
- // Return the number of referencing objects found.
- return count;
-}
-
-
// Scan the heap for objects with direct references to an object
// args[0]: the object to find references to
// args[1]: constructor function for instances to exclude (Mirror)
@@ -2832,79 +1366,54 @@ static int DebugReferencedBy(HeapIterator* iterator, JSObject* target,
RUNTIME_FUNCTION(Runtime_DebugReferencedBy) {
HandleScope scope(isolate);
DCHECK(args.length() == 3);
-
- // Check parameters.
CONVERT_ARG_HANDLE_CHECKED(JSObject, target, 0);
- CONVERT_ARG_HANDLE_CHECKED(Object, instance_filter, 1);
- RUNTIME_ASSERT(instance_filter->IsUndefined() ||
- instance_filter->IsJSObject());
+ CONVERT_ARG_HANDLE_CHECKED(Object, filter, 1);
+ RUNTIME_ASSERT(filter->IsUndefined() || filter->IsJSObject());
CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
RUNTIME_ASSERT(max_references >= 0);
-
- // Get the constructor function for context extension and arguments array.
- Handle<JSFunction> arguments_function(
- JSFunction::cast(isolate->sloppy_arguments_map()->GetConstructor()));
-
- // Get the number of referencing objects.
- int count;
- // First perform a full GC in order to avoid dead objects and to make the heap
- // iterable.
+ List<Handle<JSObject> > instances;
Heap* heap = isolate->heap();
- heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
- {
- HeapIterator heap_iterator(heap);
- count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
- max_references, NULL, 0, *arguments_function);
- }
-
- // Allocate an array to hold the result.
- Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
-
- // Fill the referencing objects.
{
- HeapIterator heap_iterator(heap);
- count = DebugReferencedBy(&heap_iterator, *target, *instance_filter,
- max_references, *instances, count,
- *arguments_function);
- }
-
- // Return result as JS array.
- Handle<JSFunction> constructor = isolate->array_function();
-
- Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
- JSArray::SetContent(Handle<JSArray>::cast(result), instances);
- return *result;
-}
-
-
-// Helper function used by Runtime_DebugConstructedBy below.
-static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
- int max_references, FixedArray* instances,
- int instances_size) {
- DisallowHeapAllocation no_allocation;
-
- // Iterate the heap.
- int count = 0;
- HeapObject* heap_obj = NULL;
- while (((heap_obj = iterator->next()) != NULL) &&
- (max_references == 0 || count < max_references)) {
- // Only look at all JSObjects.
- if (heap_obj->IsJSObject()) {
+ HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
+ // Get the constructor function for context extension and arguments array.
+ Object* arguments_fun = isolate->sloppy_arguments_map()->GetConstructor();
+ HeapObject* heap_obj;
+ while ((heap_obj = iterator.next())) {
+ if (!heap_obj->IsJSObject()) continue;
JSObject* obj = JSObject::cast(heap_obj);
- if (obj->map()->GetConstructor() == constructor) {
- // Valid reference found add to instance array if supplied an update
- // count.
- if (instances != NULL && count < instances_size) {
- instances->set(count, obj);
- }
- count++;
+ if (obj->IsJSContextExtensionObject()) continue;
+ if (obj->map()->GetConstructor() == arguments_fun) continue;
+ if (!obj->ReferencesObject(*target)) continue;
+ // Check filter if supplied. This is normally used to avoid
+ // references from mirror objects.
+ if (!filter->IsUndefined() &&
+ obj->HasInPrototypeChain(isolate, *filter)) {
+ continue;
+ }
+ if (obj->IsJSGlobalObject()) {
+ obj = JSGlobalObject::cast(obj)->global_proxy();
}
+ instances.Add(Handle<JSObject>(obj));
+ if (instances.length() == max_references) break;
+ }
+ // Iterate the rest of the heap to satisfy HeapIterator constraints.
+ while (iterator.next()) {
}
}
- // Return the number of referencing objects found.
- return count;
+ Handle<FixedArray> result;
+ if (instances.length() == 1 && instances.last().is_identical_to(target)) {
+ // Check for circular reference only. This can happen when the object is
+ // only referenced from mirrors and has a circular reference in which case
+ // the object is not really alive and would have been garbage collected if
+ // not referenced from the mirror.
+ result = isolate->factory()->empty_fixed_array();
+ } else {
+ result = isolate->factory()->NewFixedArray(instances.length());
+ for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]);
+ }
+ return *isolate->factory()->NewJSArrayWithElements(result);
}
@@ -2914,40 +1423,31 @@ static int DebugConstructedBy(HeapIterator* iterator, JSFunction* constructor,
RUNTIME_FUNCTION(Runtime_DebugConstructedBy) {
HandleScope scope(isolate);
DCHECK(args.length() == 2);
-
-
- // Check parameters.
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
RUNTIME_ASSERT(max_references >= 0);
- // Get the number of referencing objects.
- int count;
- // First perform a full GC in order to avoid dead objects and to make the heap
- // iterable.
+ List<Handle<JSObject> > instances;
Heap* heap = isolate->heap();
- heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "%DebugConstructedBy");
- {
- HeapIterator heap_iterator(heap);
- count = DebugConstructedBy(&heap_iterator, *constructor, max_references,
- NULL, 0);
- }
-
- // Allocate an array to hold the result.
- Handle<FixedArray> instances = isolate->factory()->NewFixedArray(count);
-
- // Fill the referencing objects.
{
- HeapIterator heap_iterator2(heap);
- count = DebugConstructedBy(&heap_iterator2, *constructor, max_references,
- *instances, count);
+ HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
+ HeapObject* heap_obj;
+ while ((heap_obj = iterator.next())) {
+ if (!heap_obj->IsJSObject()) continue;
+ JSObject* obj = JSObject::cast(heap_obj);
+ if (obj->map()->GetConstructor() != *constructor) continue;
+ instances.Add(Handle<JSObject>(obj));
+ if (instances.length() == max_references) break;
+ }
+ // Iterate the rest of the heap to satisfy HeapIterator constraints.
+ while (iterator.next()) {
+ }
}
- // Return result as JS array.
- Handle<JSFunction> array_function = isolate->array_function();
- Handle<JSObject> result = isolate->factory()->NewJSObject(array_function);
- JSArray::SetContent(Handle<JSArray>::cast(result), instances);
- return *result;
+ Handle<FixedArray> result =
+ isolate->factory()->NewFixedArray(instances.length());
+ for (int i = 0; i < instances.length(); ++i) result->set(i, *instances[i]);
+ return *isolate->factory()->NewJSArrayWithElements(result);
}