Revision: 15727
Author: [email protected]
Date: Wed Jul 17 08:29:00 2013
Log: Do not materialize context-allocated values for debug-evaluate.
BUG=259300
[email protected], [email protected]
Review URL: https://codereview.chromium.org/19569003
http://code.google.com/p/v8/source/detail?r=15727
Added:
/branches/bleeding_edge/test/mjsunit/debug-evaluate-closure.js
/branches/bleeding_edge/test/mjsunit/regress/regress-crbug-259300.js
Modified:
/branches/bleeding_edge/src/mirror-debugger.js
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/scopes.cc
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/debug-evaluate-closure.js Wed Jul
17 08:29:00 2013
@@ -0,0 +1,91 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug --allow-natives-syntax
+
+Debug = debug.Debug;
+var listened = false;
+
+function listener(event, exec_state, event_data, data) {
+ if (event != Debug.DebugEvent.Break) return;
+ try {
+ assertEquals("goo", exec_state.frame(0).evaluate("goo").value());
+ exec_state.frame(0).evaluate("goo = 'goo foo'");
+ assertEquals("bar return",
exec_state.frame(0).evaluate("bar()").value());
+ assertEquals("inner bar",
exec_state.frame(0).evaluate("inner").value());
+ assertEquals("outer bar",
exec_state.frame(0).evaluate("outer").value());
+ assertEquals("baz inner", exec_state.frame(0).evaluate("baz").value());
+ assertEquals("baz outer", exec_state.frame(1).evaluate("baz").value());
+ exec_state.frame(0).evaluate("w = 'w foo'");
+ exec_state.frame(0).evaluate("inner = 'inner foo'");
+ exec_state.frame(0).evaluate("outer = 'outer foo'");
+ exec_state.frame(0).evaluate("baz = 'baz inner foo'");
+ exec_state.frame(1).evaluate("baz = 'baz outer foo'");
+ listened = true;
+ } catch (e) {
+ print(e);
+ print(e.stack);
+ }
+}
+
+Debug.setListener(listener);
+
+var outer = "outer";
+var baz = "baz outer";
+
+function foo() {
+ var inner = "inner";
+ var baz = "baz inner";
+ var goo = "goo";
+ var withw = { w: "w" };
+ var withv = { v: "v" };
+
+ with (withv) {
+ var bar = function bar() {
+ assertEquals("goo foo", goo);
+ inner = "inner bar";
+ outer = "outer bar";
+ v = "v bar";
+ return "bar return";
+ };
+ }
+
+ with (withw) {
+ debugger;
+ }
+
+ assertEquals("inner foo", inner);
+ assertEquals("baz inner foo", baz);
+ assertEquals("w foo", withw.w);
+ assertEquals("v bar", withv.v);
+}
+
+foo();
+assertEquals("outer foo", outer);
+assertEquals("baz outer foo", baz);
+assertTrue(listened);
+Debug.setListener(null);
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/regress/regress-crbug-259300.js
Wed Jul 17 08:29:00 2013
@@ -0,0 +1,49 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+
+Debug = debug.Debug;
+var listened = false;
+var recursion_depth = 0;
+
+function listener(event, exec_state, event_data, data) {
+ if (event == Debug.DebugEvent.Break) {
+ recursion_depth++;
+ var disable_break = (recursion_depth > 2);
+ for (var i = 0; i < exec_state.frameCount(); i++) {
+ exec_state.frame(i).evaluate("debugger", disable_break);
+ }
+ }
+ listened = true;
+}
+
+Debug.setListener(listener);
+eval("debugger");
+Debug.setListener(null);
+assertTrue(listened);
+
=======================================
--- /branches/bleeding_edge/src/mirror-debugger.js Wed Jun 26 09:18:00 2013
+++ /branches/bleeding_edge/src/mirror-debugger.js Wed Jul 17 08:29:00 2013
@@ -1699,30 +1699,12 @@
FrameMirror.prototype.evaluate = function(source, disable_break,
opt_context_object) {
- var result_array = %DebugEvaluate(this.break_id_,
- this.details_.frameId(),
- this.details_.inlinedFrameIndex(),
- source,
- Boolean(disable_break),
- opt_context_object);
- // Silently ignore local variables changes if the frame is optimized.
- if (!this.isOptimizedFrame()) {
- var local_scope_on_stack = result_array[1];
- var local_scope_modifed = result_array[2];
- for (var n in local_scope_modifed) {
- var value_on_stack = local_scope_on_stack[n];
- var value_modifed = local_scope_modifed[n];
- if (value_on_stack !== value_modifed) {
- %SetScopeVariableValue(this.break_id_,
- this.details_.frameId(),
- this.details_.inlinedFrameIndex(),
- 0,
- n,
- value_modifed);
- }
- }
- }
- return MakeMirror(result_array[0]);
+ return MakeMirror(%DebugEvaluate(this.break_id_,
+ this.details_.frameId(),
+ this.details_.inlinedFrameIndex(),
+ source,
+ Boolean(disable_break),
+ opt_context_object));
};
=======================================
--- /branches/bleeding_edge/src/runtime.cc Mon Jul 15 11:47:40 2013
+++ /branches/bleeding_edge/src/runtime.cc Wed Jul 17 08:29:00 2013
@@ -11180,19 +11180,14 @@
// Create a plain JSObject which materializes the local scope for the
specified
// frame.
-static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
+static Handle<JSObject> MaterializeStackLocalsWithFrameInspector(
Isolate* isolate,
- JavaScriptFrame* frame,
+ Handle<JSObject> target,
+ Handle<JSFunction> function,
FrameInspector* frame_inspector) {
- Handle<JSFunction>
function(JSFunction::cast(frame_inspector->GetFunction()));
Handle<SharedFunctionInfo> shared(function->shared());
Handle<ScopeInfo> scope_info(shared->scope_info());
- // Allocate and initialize a JSObject with all the arguments, stack
locals
- // heap locals and extension properties of the debugged function.
- Handle<JSObject> local_scope =
- isolate->factory()->NewJSObject(isolate->object_function());
-
// First fill all parameters.
for (int i = 0; i < scope_info->ParameterCount(); ++i) {
Handle<Object> value(i < frame_inspector->GetParametersCount()
@@ -11203,7 +11198,7 @@
RETURN_IF_EMPTY_HANDLE_VALUE(
isolate,
SetProperty(isolate,
- local_scope,
+ target,
Handle<String>(scope_info->ParameterName(i)),
value,
NONE,
@@ -11216,7 +11211,7 @@
RETURN_IF_EMPTY_HANDLE_VALUE(
isolate,
SetProperty(isolate,
- local_scope,
+ target,
Handle<String>(scope_info->StackLocalName(i)),
Handle<Object>(frame_inspector->GetExpression(i),
isolate),
NONE,
@@ -11224,45 +11219,90 @@
Handle<JSObject>());
}
- if (scope_info->HasContext()) {
- // Third fill all context locals.
- Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context(frame_context->declaration_context());
- if (!scope_info->CopyContextLocalsToScopeObject(
- isolate, function_context, local_scope)) {
- return Handle<JSObject>();
- }
+ return target;
+}
+
+
+static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate,
+ Handle<JSObject>
target,
+ Handle<JSFunction>
function,
+ 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;
+ }
+
+ Handle<SharedFunctionInfo> shared(function->shared());
+ Handle<ScopeInfo> scope_info(shared->scope_info());
+
+ // Parameters.
+ for (int i = 0; i < scope_info->ParameterCount(); ++i) {
+ HandleScope scope(isolate);
+ Handle<Object> value = GetProperty(
+ isolate, target, Handle<String>(scope_info->ParameterName(i)));
+ frame->SetParameterValue(i, *value);
+ }
+
+ // Stack locals.
+ for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
+ HandleScope scope(isolate);
+ Handle<Object> value = GetProperty(
+ isolate, target, Handle<String>(scope_info->StackLocalName(i)));
+ frame->SetExpression(i, *value);
+ }
+}
+
- // 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()));
- bool threw = false;
- Handle<FixedArray> keys =
- GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
- if (threw) return Handle<JSObject>();
+static Handle<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());
- for (int i = 0; i < keys->length(); i++) {
- // Names of variables introduced by eval are strings.
- ASSERT(keys->get(i)->IsString());
- Handle<String> key(String::cast(keys->get(i)));
- RETURN_IF_EMPTY_HANDLE_VALUE(
- isolate,
- SetProperty(isolate,
- local_scope,
- key,
- GetProperty(isolate, ext, key),
- NONE,
- kNonStrictMode),
- Handle<JSObject>());
- }
+ 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());
+ if (!scope_info->CopyContextLocalsToScopeObject(
+ isolate, function_context, target)) {
+ return Handle<JSObject>();
+ }
+
+ // 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()));
+ bool threw = false;
+ Handle<FixedArray> keys =
+ GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
+ if (threw) return Handle<JSObject>();
+
+ for (int i = 0; i < keys->length(); i++) {
+ // Names of variables introduced by eval are strings.
+ ASSERT(keys->get(i)->IsString());
+ Handle<String> key(String::cast(keys->get(i)));
+ RETURN_IF_EMPTY_HANDLE_VALUE(
+ isolate,
+ SetProperty(isolate,
+ target,
+ key,
+ GetProperty(isolate, ext, key),
+ NONE,
+ kNonStrictMode),
+ Handle<JSObject>());
}
}
}
- return local_scope;
+ return target;
}
@@ -11271,9 +11311,15 @@
JavaScriptFrame* frame,
int inlined_jsframe_index) {
FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
- return MaterializeLocalScopeWithFrameInspector(isolate,
- frame,
- &frame_inspector);
+ Handle<JSFunction>
function(JSFunction::cast(frame_inspector.GetFunction()));
+
+ Handle<JSObject> local_scope =
+ isolate->factory()->NewJSObject(isolate->object_function());
+ local_scope = MaterializeStackLocalsWithFrameInspector(
+ isolate, local_scope, function, &frame_inspector);
+ RETURN_IF_EMPTY_HANDLE_VALUE(isolate, local_scope, Handle<JSObject>());
+
+ return MaterializeLocalContext(isolate, local_scope, function, frame);
}
@@ -12424,113 +12470,33 @@
isolate->debug()->ClearStepping();
return isolate->heap()->undefined_value();
}
-
-
-static bool IsBlockOrCatchOrWithScope(ScopeIterator::ScopeType type) {
- return type == ScopeIterator::ScopeTypeBlock ||
- type == ScopeIterator::ScopeTypeCatch ||
- type == ScopeIterator::ScopeTypeWith;
-}
-
-
-// Creates a copy of the with context chain. The copy of the context chain
is
-// is linked to the function context supplied.
-static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
- Handle<JSFunction>
function,
- Handle<Context> base,
- JavaScriptFrame* frame,
- int
inlined_jsframe_index) {
- HandleScope scope(isolate);
- List<Handle<ScopeInfo> > scope_chain;
- List<Handle<Context> > context_chain;
-
- ScopeIterator it(isolate, frame, inlined_jsframe_index);
- if (it.Failed()) return Handle<Context>::null();
-
- for ( ; IsBlockOrCatchOrWithScope(it.Type()); it.Next()) {
- ASSERT(!it.Done());
- scope_chain.Add(it.CurrentScopeInfo());
- context_chain.Add(it.CurrentContext());
- }
-
- // At the end of the chain. Return the base context to link to.
- Handle<Context> context = base;
-
- // Iteratively copy and or materialize the nested contexts.
- while (!scope_chain.is_empty()) {
- Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
- Handle<Context> current = context_chain.RemoveLast();
- ASSERT(!(scope_info->HasContext() & current.is_null()));
-
- if (scope_info->scope_type() == CATCH_SCOPE) {
- ASSERT(current->IsCatchContext());
- Handle<String> name(String::cast(current->extension()));
- Handle<Object>
thrown_object(current->get(Context::THROWN_OBJECT_INDEX),
- isolate);
- context =
- isolate->factory()->NewCatchContext(function,
- context,
- name,
- thrown_object);
- } else if (scope_info->scope_type() == BLOCK_SCOPE) {
- // Materialize the contents of the block scope into a JSObject.
- ASSERT(current->IsBlockContext());
- Handle<JSObject> block_scope_object =
- MaterializeBlockScope(isolate, current);
- CHECK(!block_scope_object.is_null());
- // Allocate a new function context for the debug evaluation and set
the
- // extension object.
- Handle<Context> new_context =
-
isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
- function);
- new_context->set_extension(*block_scope_object);
- new_context->set_previous(*context);
- context = new_context;
- } else {
- ASSERT(scope_info->scope_type() == WITH_SCOPE);
- ASSERT(current->IsWithContext());
- Handle<JSObject> extension(JSObject::cast(current->extension()));
- context =
- isolate->factory()->NewWithContext(function, context, extension);
- }
- }
-
- return scope.CloseAndEscape(context);
-}
// Helper function to find or create the arguments object for
// Runtime_DebugEvaluate.
-static Handle<Object> GetArgumentsObject(Isolate* isolate,
- JavaScriptFrame* frame,
- FrameInspector* frame_inspector,
- Handle<ScopeInfo> scope_info,
- Handle<Context> function_context)
{
- // Try to find the value of 'arguments' to pass as parameter. If it is
not
- // found (that is the debugged function does not reference 'arguments'
and
- // does not support eval) then create an 'arguments' object.
- int index;
- if (scope_info->StackLocalCount() > 0) {
- index =
scope_info->StackSlotIndex(isolate->heap()->arguments_string());
- if (index != -1) {
- return Handle<Object>(frame->GetExpression(index), isolate);
- }
- }
-
- if (scope_info->HasHeapAllocatedLocals()) {
- VariableMode mode;
- InitializationFlag init_flag;
- index = scope_info->ContextSlotIndex(
- isolate->heap()->arguments_string(), &mode, &init_flag);
- if (index != -1) {
- return Handle<Object>(function_context->get(index), isolate);
- }
+static Handle<JSObject> MaterializeArgumentsObject(
+ Isolate* isolate,
+ Handle<JSObject> target,
+ Handle<JSFunction> function,
+ FrameInspector* frame_inspector) {
+ // Do not materialize the arguments object for eval or top-level code.
+ // Skip if "arguments" is already taken.
+ if (!function->shared()->is_function() ||
+ target->HasLocalProperty(isolate->heap()->arguments_string())) {
+ return target;
}
// FunctionGetArguments can't return a non-Object.
- return Handle<JSObject>(JSObject::cast(
+ Handle<JSObject> arguments(JSObject::cast(
Accessors::FunctionGetArguments(frame_inspector->GetFunction(),
NULL)->ToObjectUnchecked()),
isolate);
+ SetProperty(isolate,
+ target,
+ isolate->factory()->arguments_string(),
+ arguments,
+ ::NONE,
+ kNonStrictMode);
+ return target;
}
@@ -12577,24 +12543,10 @@
// Evaluate a piece of JavaScript in the context of a stack frame for
-// debugging. This is done by creating a new context which in its
extension
-// part has all the parameters and locals of the function on the stack
frame
-// as well as a materialized arguments object. As this context replaces
-// the context of the function on the stack frame a new (empty) function
-// is created as well to be used as the closure for the context.
-// This closure as replacements for the one on the stack frame presenting
-// the same view of the values of parameters and local variables as if the
-// piece of JavaScript was evaluated at the point where the function on the
-// stack frame is currently stopped when we compile and run the (direct)
eval.
-// Returns array of
-// #0: evaluate result
-// #1: local variables materizalized again as object after evaluation,
contain
-// original variable values as they remained on stack
-// #2: local variables materizalized as object before evaluation (and
possibly
-// modified by expression having been executed)
-// Since user expression only reaches (and modifies) copies of local
variables,
-// those copies are returned to the caller to allow tracking the changes
and
-// manually updating the actual variables.
+// 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(MaybeObject*, Runtime_DebugEvaluate) {
HandleScope scope(isolate);
@@ -12629,69 +12581,24 @@
SaveContext savex(isolate);
isolate->set_context(*(save->context()));
- // Create the (empty) function replacing the function on the stack frame
for
- // the purpose of evaluating in the context created below. It is
important
- // that this function does not describe any parameters and local
variables
- // in the context. If it does then this will cause problems with the
lookup
- // in Context::Lookup, where context slots for parameters and local
variables
- // are looked at before the extension object.
- Handle<JSFunction> go_between =
- isolate->factory()->NewFunction(isolate->factory()->empty_string(),
-
isolate->factory()->undefined_value());
- go_between->set_context(function->context());
-#ifdef DEBUG
- Handle<ScopeInfo>
go_between_scope_info(go_between->shared()->scope_info());
- ASSERT(go_between_scope_info->ParameterCount() == 0);
- ASSERT(go_between_scope_info->ContextLocalCount() == 0);
-#endif
+ // Evaluate on the context of the frame.
+ Handle<Context> context(Context::cast(frame->context()));
+ ASSERT(!context.is_null());
- // Materialize the content of the local scope including the arguments
object.
- Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
- isolate, frame, &frame_inspector);
- RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
+ // Materialize stack locals and the arguments object.
+ Handle<JSObject> materialized =
+ isolate->factory()->NewJSObject(isolate->object_function());
- // Do not materialize the arguments object for eval or top-level code.
- if (function->shared()->is_function()) {
- Handle<Context> frame_context(Context::cast(frame->context()));
- Handle<Context> function_context;
- Handle<ScopeInfo> scope_info(function->shared()->scope_info());
- if (scope_info->HasContext()) {
- function_context =
Handle<Context>(frame_context->declaration_context());
- }
- Handle<Object> arguments = GetArgumentsObject(isolate,
- frame,
- &frame_inspector,
- scope_info,
- function_context);
- SetProperty(isolate,
- local_scope,
- isolate->factory()->arguments_string(),
- arguments,
- ::NONE,
- kNonStrictMode);
- }
+ materialized = MaterializeStackLocalsWithFrameInspector(
+ isolate, materialized, function, &frame_inspector);
+ RETURN_IF_EMPTY_HANDLE(isolate, materialized);
- // Allocate a new context for the debug evaluation and set the extension
- // object build.
- Handle<Context> context = isolate->factory()->NewFunctionContext(
- Context::MIN_CONTEXT_SLOTS, go_between);
+ materialized = MaterializeArgumentsObject(
+ isolate, materialized, function, &frame_inspector);
+ RETURN_IF_EMPTY_HANDLE(isolate, materialized);
- // Use the materialized local scope in a with context.
- context =
- isolate->factory()->NewWithContext(go_between, context, local_scope);
-
- // Copy any with contexts present and chain them in front of this
context.
- context = CopyNestedScopeContextChain(isolate,
- go_between,
- context,
- frame,
- inlined_jsframe_index);
- if (context.is_null()) {
- ASSERT(isolate->has_pending_exception());
- MaybeObject* exception = isolate->pending_exception();
- isolate->clear_pending_exception();
- return exception;
- }
+ // Add the materialized object in a with-scope to shadow the stack
locals.
+ context = isolate->factory()->NewWithContext(function, context,
materialized);
Handle<Object> receiver(frame->receiver(), isolate);
Object* evaluate_result_object;
@@ -12699,18 +12606,12 @@
DebugEvaluate(isolate, context, context_extension, receiver, source);
if (!maybe_result->ToObject(&evaluate_result_object)) return
maybe_result;
}
- Handle<Object> evaluate_result(evaluate_result_object, isolate);
- Handle<JSObject> local_scope_control_copy =
- MaterializeLocalScopeWithFrameInspector(isolate, frame,
- &frame_inspector);
+ // Write back potential changes to materialized stack locals to the
stack.
+ UpdateStackLocalsFromMaterializedObject(
+ isolate, materialized, function, frame, inlined_jsframe_index);
- Handle<FixedArray> resultArray = isolate->factory()->NewFixedArray(3);
- resultArray->set(0, *evaluate_result);
- resultArray->set(1, *local_scope_control_copy);
- resultArray->set(2, *local_scope);
-
- return *(isolate->factory()->NewJSArrayWithElements(resultArray));
+ return evaluate_result_object;
}
=======================================
--- /branches/bleeding_edge/src/scopes.cc Thu Jun 6 06:28:22 2013
+++ /branches/bleeding_edge/src/scopes.cc Wed Jul 17 08:29:00 2013
@@ -970,6 +970,13 @@
BindingKind* binding_kind,
AstNodeFactory<AstNullVisitor>* factory) {
ASSERT(binding_kind != NULL);
+ if (already_resolved() && is_with_scope()) {
+ // Short-cut: if the scope is deserialized from a scope info, variable
+ // allocation is already fixed. We can simply return with dynamic
lookup.
+ *binding_kind = DYNAMIC_LOOKUP;
+ return NULL;
+ }
+
// Try to find the variable in this scope.
Variable* var = LocalLookup(name);
@@ -998,6 +1005,7 @@
}
if (is_with_scope()) {
+ ASSERT(!already_resolved());
// The current scope is a with scope, so the variable binding can not
be
// statically resolved. However, note that it was necessary to do a
lookup
// in the outer scope anyway, because if a binding exists in an outer
scope,
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.