| 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;
|
| }
|
|
|
|
|