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.


Reply via email to