Revision: 9157
Author:   [email protected]
Date:     Tue Sep  6 14:48:32 2011
Log:      Simplfy handling of exits from scoped blocks.

BUG=
TEST=mjsunit/harmony/block-leave.js

Review URL: http://codereview.chromium.org/7792100
http://code.google.com/p/v8/source/detail?r=9157

Added:
 /branches/bleeding_edge/test/mjsunit/harmony/block-leave.js
Modified:
 /branches/bleeding_edge/src/full-codegen.cc
 /branches/bleeding_edge/src/full-codegen.h
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/test/mjsunit/harmony/debug-blockscopes.js

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/harmony/block-leave.js Tue Sep 6 14:48:32 2011
@@ -0,0 +1,225 @@
+// Copyright 2011 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: --harmony-block-scoping
+
+// We want to test the context chain shape.  In each of the tests cases
+// below, the outer with is to force a runtime lookup of the identifier 'x'
+// to actually verify that the inner context has been discarded.  A static
+// lookup of 'x' might accidentally succeed.
+
+{
+  let x = 2;
+  L: {
+    let x = 3;
+    assertEquals(3, x);
+    break L;
+    assertTrue(false);
+  }
+  assertEquals(2, x);
+}
+
+do {
+  let x = 4;
+  assertEquals(4,x);
+  {
+    let x = 5;
+    assertEquals(5, x);
+    continue;
+    assertTrue(false);
+  }
+} while (false);
+
+var caught = false;
+try {
+  {
+    let xx = 18;
+    throw 25;
+    assertTrue(false);
+  }
+} catch (e) {
+  caught = true;
+  assertEquals(25, e);
+  with ({y:19}) {
+    assertEquals(19, y);
+    try {
+      // NOTE: This checks that the block scope containing xx has been
+      // removed from the context chain.
+      xx;
+      assertTrue(false);  // should not reach here
+    } catch (e2) {
+      assertTrue(e2 instanceof ReferenceError);
+    }
+  }
+}
+assertTrue(caught);
+
+
+with ({x: 'outer'}) {
+  label: {
+    let x = 'inner';
+    break label;
+  }
+  assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+  label: {
+    let x = 'middle';
+    {
+      let x = 'inner';
+      break label;
+    }
+  }
+  assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+  for (var i = 0; i < 10; ++i) {
+    let x = 'inner' + i;
+    continue;
+  }
+  assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+  label: for (var i = 0; i < 10; ++i) {
+    let x = 'middle' + i;
+    for (var j = 0; j < 10; ++j) {
+      let x = 'inner' + j;
+      continue label;
+    }
+  }
+  assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+  try {
+    let x = 'inner';
+    throw 0;
+  } catch (e) {
+    assertEquals('outer', x);
+  }
+}
+
+
+with ({x: 'outer'}) {
+  try {
+    let x = 'middle';
+    {
+      let x = 'inner';
+      throw 0;
+    }
+  } catch (e) {
+    assertEquals('outer', x);
+  }
+}
+
+
+try {
+  with ({x: 'outer'}) {
+    try {
+      let x = 'inner';
+      throw 0;
+    } finally {
+      assertEquals('outer', x);
+    }
+  }
+} catch (e) {
+  if (e instanceof MjsUnitAssertionError) throw e;
+}
+
+
+try {
+  with ({x: 'outer'}) {
+    try {
+      let x = 'middle';
+      {
+        let x = 'inner';
+        throw 0;
+      }
+    } finally {
+      assertEquals('outer', x);
+    }
+  }
+} catch (e) {
+  if (e instanceof MjsUnitAssertionError) throw e;
+}
+
+
+// Verify that the context is correctly set in the stack frame after exiting
+// from with.
+function f() {}
+
+with ({x: 'outer'}) {
+  label: {
+    let x = 'inner';
+    break label;
+  }
+  f();  // The context could be restored from the stack after the call.
+  assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+  for (var i = 0; i < 10; ++i) {
+    let x = 'inner';
+    continue;
+  }
+  f();
+  assertEquals('outer', x);
+}
+
+
+with ({x: 'outer'}) {
+  try {
+    let x = 'inner';
+    throw 0;
+  } catch (e) {
+    f();
+    assertEquals('outer', x);
+  }
+}
+
+
+try {
+  with ({x: 'outer'}) {
+    try {
+      let x = 'inner';
+      throw 0;
+    } finally {
+      f();
+      assertEquals('outer', x);
+    }
+  }
+} catch (e) {
+  if (e instanceof MjsUnitAssertionError) throw e;
+}
=======================================
--- /branches/bleeding_edge/src/full-codegen.cc Thu Sep  1 04:57:02 2011
+++ /branches/bleeding_edge/src/full-codegen.cc Tue Sep  6 14:48:32 2011
@@ -851,7 +851,7 @@

 void FullCodeGenerator::VisitBlock(Block* stmt) {
   Comment cmnt(masm_, "[ Block");
-  Breakable nested_statement(this, stmt);
+  NestedBlock nested_block(this, stmt);
   SetStatementPosition(stmt);

   Scope* saved_scope = scope();
@@ -871,7 +871,7 @@
   PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
   VisitStatements(stmt->statements());
   scope_ = saved_scope;
-  __ bind(nested_statement.break_label());
+  __ bind(nested_block.break_label());
   PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
 }

=======================================
--- /branches/bleeding_edge/src/full-codegen.h  Thu Sep  1 09:33:57 2011
+++ /branches/bleeding_edge/src/full-codegen.h  Tue Sep  6 14:48:32 2011
@@ -191,6 +191,22 @@
     Label continue_label_;
   };

+  // A nested block statement.
+  class NestedBlock : public Breakable {
+   public:
+    NestedBlock(FullCodeGenerator* codegen, Block* block)
+        : Breakable(codegen, block) {
+    }
+    virtual ~NestedBlock() {}
+
+    virtual NestedStatement* Exit(int* stack_depth, int* context_length) {
+      if (statement()->AsBlock()->block_scope() != NULL) {
+        ++(*context_length);
+      }
+      return previous_;
+    };
+  };
+
   // The try block of a try/catch statement.
   class TryCatch : public NestedStatement {
    public:
=======================================
--- /branches/bleeding_edge/src/parser.cc       Tue Sep  6 14:22:35 2011
+++ /branches/bleeding_edge/src/parser.cc       Tue Sep  6 14:48:32 2011
@@ -1588,19 +1588,11 @@
   body->set_block_scope(block_scope);

   if (block_scope != NULL) {
-    // Create exit block.
-    Block* exit = new(zone()) Block(isolate(), NULL, 1, false);
+    // Rewrite the block { B } to a block: { { B } ExitContext; }
+    Block* exit = new(zone()) Block(isolate(), NULL, 2, false);
+    exit->AddStatement(body);
     exit->AddStatement(new(zone()) ExitContextStatement());
-
-    // Create a try-finally statement.
-    TryFinallyStatement* try_finally =
-        new(zone()) TryFinallyStatement(body, exit);
-    try_finally->set_escaping_targets(collector.targets());
-
-    // Create a result block.
-    Block* result = new(zone()) Block(isolate(), NULL, 1, false);
-    result->AddStatement(try_finally);
-    return result;
+    return exit;
   } else {
     return body;
   }
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/debug-blockscopes.js Tue Sep 6 14:22:35 2011 +++ /branches/bleeding_edge/test/mjsunit/harmony/debug-blockscopes.js Tue Sep 6 14:48:32 2011
@@ -418,6 +418,28 @@
 // With block and a block local variable.
 BeginTest("With block 5");

+function with_block_5() {
+  with({a:1}) {
+    let a = 2;
+    debugger;
+  }
+}
+
+listener_delegate = function(exec_state) {
+  CheckScopeChain([debug.ScopeType.Block,
+                   debug.ScopeType.With,
+                   debug.ScopeType.Local,
+                   debug.ScopeType.Global], exec_state);
+  CheckScopeContent({a:2}, 0, exec_state);
+  CheckScopeContent({a:1}, 1, exec_state);
+};
+with_block_5();
+EndTest();
+
+
+// With block and a block local variable.
+BeginTest("With block 5");
+
 function with_block_5() {
   with({a:1}) {
     let a = 2;

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to