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