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

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

Issue 1264993002: Debugger: refactor ScopeIterator, FrameInspector and DebugEvaluate. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: readd include Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/debug/debug-evaluate.cc
diff --git a/src/debug/debug-evaluate.cc b/src/debug/debug-evaluate.cc
new file mode 100644
index 0000000000000000000000000000000000000000..509d97a3903511ec4e269fb7d4605ac7b23d0dc8
--- /dev/null
+++ b/src/debug/debug-evaluate.cc
@@ -0,0 +1,319 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/debug/debug-evaluate.h"
+
+#include "src/accessors.h"
+#include "src/contexts.h"
+#include "src/debug/debug.h"
+#include "src/debug/debug-frames.h"
+#include "src/debug/debug-scopes.h"
+#include "src/isolate.h"
+
+namespace v8 {
+namespace internal {
+
+
+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();
+}
+
+
+MaybeHandle<Object> DebugEvaluate::Global(Isolate* isolate,
+ Handle<String> source,
+ bool disable_break,
+ Handle<Object> context_extension) {
+ // 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);
+ return Evaluate(isolate, outer_info, context, context_extension, receiver,
+ source);
+}
+
+
+MaybeHandle<Object> DebugEvaluate::Local(Isolate* isolate,
+ StackFrame::Id frame_id,
+ int inlined_jsframe_index,
+ Handle<String> source,
+ bool disable_break,
+ Handle<Object> context_extension) {
+ // Handle the processing of break.
+ DisableBreak disable_break_scope(isolate->debug(), disable_break);
+
+ // Get the frame where the debugging is performed.
+ JavaScriptFrameIterator it(isolate, frame_id);
+ JavaScriptFrame* frame = it.frame();
+
+ // Traverse the saved contexts chain to find the active context for the
+ // selected frame.
+ SaveContext* save =
+ DebugFrameHelper::FindSavedContextForFrame(isolate, frame);
+ SaveContext savex(isolate);
+ isolate->set_context(*(save->context()));
+
+ // Materialize stack locals and the arguments object.
+ ContextBuilder context_builder(isolate, frame, inlined_jsframe_index);
+ if (isolate->has_pending_exception()) return MaybeHandle<Object>();
+
+ Handle<Object> receiver(frame->receiver(), isolate);
+ MaybeHandle<Object> maybe_result = Evaluate(
+ isolate, context_builder.outer_info(),
+ context_builder.innermost_context(), context_extension, receiver, source);
+ if (!maybe_result.is_null()) context_builder.UpdateValues();
+ return maybe_result;
+}
+
+
+// Compile and evaluate source for the given context.
+MaybeHandle<Object> DebugEvaluate::Evaluate(
+ 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;
+}
+
+
+DebugEvaluate::ContextBuilder::ContextBuilder(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(parent_context, function);
+
+ Handle<JSObject> materialized_function = NewJSObjectWithNullProto();
+
+ frame_inspector.MaterializeStackLocals(materialized_function, function);
+
+ MaterializeArgumentsObject(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();
+ frame_inspector.MaterializeStackLocals(materialized_object,
+ it.CurrentScopeInfo());
+ 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 DebugEvaluate::ContextBuilder::UpdateValues() {
+ 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.
+ FrameInspector(frame_, inlined_jsframe_index_, isolate_)
+ .UpdateStackLocalsFromMaterializedObject(element.materialized_object,
+ element.scope_info);
+ }
+ }
+}
+
+
+Handle<JSObject> DebugEvaluate::ContextBuilder::NewJSObjectWithNullProto() {
+ 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;
+}
+
+
+void DebugEvaluate::ContextBuilder::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;
+}
+
+
+void DebugEvaluate::ContextBuilder::MaterializeArgumentsObject(
+ 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();
+}
+
+
+Handle<Context> DebugEvaluate::ContextBuilder::MaterializeReceiver(
+ Handle<Context> target, Handle<JSFunction> function) {
+ 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);
+}
+
+} // namespace internal
+} // namespace v8
« no previous file with comments | « src/debug/debug-evaluate.h ('k') | src/debug/debug-frames.h » ('j') | src/debug/debug-scopes.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698