Version 1.2.1 (stable channel)
svn merge -c 33118 https://dart.googlecode.com/svn/branches/bleeding_edge 1.2
svn merge -c 33152 https://dart.googlecode.com/svn/branches/bleeding_edge 1.2
git-svn-id: http://dart.googlecode.com/svn/branches/1.2@33265 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index ce258c0..d312b0a 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -5478,7 +5478,6 @@
result->id());
}
}
-
phi_moves->CreateOutgoingMove(block->PredecessorAt(j),
result->id(),
place->id());
@@ -5636,8 +5635,6 @@
// Loads that are locally redundant will be replaced as we go through
// instructions.
void ComputeInitialSets() {
- BitVector* forwarded_loads = new BitVector(aliased_set_->max_place_id());
-
for (BlockIterator block_it = graph_->reverse_postorder_iterator();
!block_it.Done();
block_it.Advance()) {
@@ -5797,12 +5794,6 @@
(*out_values)[place_id] = defn;
}
- PhiPlaceMoves::MovesList phi_moves =
- aliased_set_->phi_moves()->GetOutgoingMoves(block);
- if (phi_moves != NULL) {
- PerformPhiMoves(phi_moves, gen, forwarded_loads);
- }
-
exposed_values_[preorder_number] = exposed_values;
out_values_[preorder_number] = out_values;
}
@@ -5839,6 +5830,7 @@
void ComputeOutSets() {
BitVector* temp = new BitVector(aliased_set_->max_place_id());
BitVector* forwarded_loads = new BitVector(aliased_set_->max_place_id());
+ BitVector* temp_out = new BitVector(aliased_set_->max_place_id());
bool changed = true;
while (changed) {
@@ -5866,9 +5858,17 @@
for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
BlockEntryInstr* pred = block->PredecessorAt(i);
BitVector* pred_out = out_[pred->preorder_number()];
- if (pred_out != NULL) {
- temp->Intersect(pred_out);
+ if (pred_out == NULL) continue;
+ PhiPlaceMoves::MovesList phi_moves =
+ aliased_set_->phi_moves()->GetOutgoingMoves(pred);
+ if (phi_moves != NULL) {
+ // If there are phi moves, perform intersection with
+ // a copy of pred_out where the phi moves are applied.
+ temp_out->CopyFrom(pred_out);
+ PerformPhiMoves(phi_moves, temp_out, forwarded_loads);
+ pred_out = temp_out;
}
+ temp->Intersect(pred_out);
}
}
@@ -5879,12 +5879,6 @@
temp->RemoveAll(block_kill);
temp->AddAll(block_gen);
- PhiPlaceMoves::MovesList phi_moves =
- aliased_set_->phi_moves()->GetOutgoingMoves(block);
- if (phi_moves != NULL) {
- PerformPhiMoves(phi_moves, temp, forwarded_loads);
- }
-
if ((block_out == NULL) || !block_out->Equals(*temp)) {
if (block_out == NULL) {
block_out = out_[preorder_number] =
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
index c9646c3..3207932 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
@@ -812,14 +812,19 @@
} else if ("&&" == op.source) {
conditionIsSimple = false;
bool oldAccumulateIsChecks = accumulateIsChecks;
- accumulateIsChecks = true;
- if (isChecks == null) isChecks = <Send>[];
+ List<Send> oldIsChecks = isChecks;
+ if (!accumulateIsChecks) {
+ accumulateIsChecks = true;
+ isChecks = <Send>[];
+ }
visit(node.receiver);
- accumulateIsChecks = oldAccumulateIsChecks;
- if (!accumulateIsChecks) isChecks = null;
LocalsHandler<T> saved = locals;
locals = new LocalsHandler<T>.from(locals, node);
updateIsChecks(isChecks, usePositive: true);
+ if (!oldAccumulateIsChecks) {
+ accumulateIsChecks = false;
+ isChecks = oldIsChecks;
+ }
visit(node.arguments.head);
saved.mergeDiamondFlow(locals, null);
locals = saved;
@@ -827,10 +832,10 @@
} else if ("||" == op.source) {
conditionIsSimple = false;
List<Send> tests = <Send>[];
- handleCondition(node.receiver, tests);
+ bool isSimple = handleCondition(node.receiver, tests);
LocalsHandler<T> saved = locals;
locals = new LocalsHandler<T>.from(locals, node);
- updateIsChecks(tests, usePositive: false);
+ if (isSimple) updateIsChecks(tests, usePositive: false);
bool oldAccumulateIsChecks = accumulateIsChecks;
accumulateIsChecks = false;
visit(node.arguments.head);
diff --git a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
index 19926f0..67004a3 100644
--- a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
@@ -44,6 +44,39 @@
return a;
}
+returnDyn7b(x) => x;
+
+returnDyn7() {
+ var a = "foo";
+ if (a.length == 3) a = 52;
+ if ((a is int) || (a is String && true)) returnDyn7b(a);
+ return a;
+}
+
+returnDyn8(x) => x;
+
+test8() {
+ var a = "foo";
+ if (a.length == 3) a = 52;
+ if ((false && a is! String) || returnDyn8(a)) return a;
+}
+
+returnDyn9(x) => x;
+
+test9() {
+ var a = "foo";
+ if (a.length == 3) a = 52;
+ if (!(a is bool && a is bool)) returnDyn9(a);
+}
+
+returnString(x) => x;
+
+test10() {
+ var a = "foo";
+ if (a.length == 3) a = 52;
+ if (!(a is num) && a is String) returnString(a);
+}
+
main() {
returnDyn1();
returnDyn2();
@@ -51,6 +84,10 @@
returnDyn4();
returnDyn5();
returnDyn6();
+ returnDyn7();
+ test8();
+ test9();
+ test10();
}
""";
@@ -76,5 +113,10 @@
checkReturn('returnDyn4', compiler.typesTask.dynamicType.nonNullable());
checkReturn('returnDyn5', compiler.typesTask.dynamicType.nonNullable());
checkReturn('returnDyn6', compiler.typesTask.dynamicType.nonNullable());
+ checkReturn('returnDyn7', subclassOfInterceptor);
+ checkReturn('returnDyn7b', subclassOfInterceptor);
+ checkReturn('returnDyn8', subclassOfInterceptor);
+ checkReturn('returnDyn9', subclassOfInterceptor);
+ checkReturn('returnString', compiler.typesTask.stringType);
}));
}
diff --git a/tests/language/logical_expression2_test.dart b/tests/language/logical_expression2_test.dart
new file mode 100644
index 0000000..7d6ddd5
--- /dev/null
+++ b/tests/language/logical_expression2_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Regression test for issue 17149.
+
+int globalCounter = 0;
+
+void nonInlinedUse(Object object) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) nonInlinedUse(object);
+ if (object is! String) globalCounter++;
+}
+
+int confuse(x) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) return confuse(x - 1);
+ return x;
+}
+
+main() {
+ var o = [ "foo", 499 ][confuse(1)];
+
+ // The `o is String` check in the rhs of the logical or must not be
+ // propagated to the `if` body.
+ if ((o is num) ||
+ (o is String && true)) {
+ nonInlinedUse(o);
+ }
+ Expect.equals(1, globalCounter);
+}
diff --git a/tests/language/logical_expression3_test.dart b/tests/language/logical_expression3_test.dart
new file mode 100644
index 0000000..2a90d70
--- /dev/null
+++ b/tests/language/logical_expression3_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+bool nonInlinedNumTypeCheck(Object object) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) {
+ return nonInlinedNumTypeCheck(object);
+ }
+ return object is num;
+}
+
+int confuse(x) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) return confuse(x - 1);
+ return x;
+}
+
+main() {
+ var o = [ "foo", 499 ][confuse(0)];
+
+ // When the lhs of a logical or fails, it must not assume that all negative is
+ // checks in it, have failed.
+ // Here, the `o is! num` check succeeds, but the length test failed.
+ if ((o is! num && o.length == 4) ||
+ (nonInlinedNumTypeCheck(o))) {
+ Expect.fail("Type-check failed");
+ }
+}
diff --git a/tests/language/logical_expression4_test.dart b/tests/language/logical_expression4_test.dart
new file mode 100644
index 0000000..4799a88
--- /dev/null
+++ b/tests/language/logical_expression4_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+bool nonInlinedNumTypeCheck(Object object) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) {
+ return nonInlinedNumTypeCheck(object);
+ }
+ return object is num;
+}
+
+int confuse(x) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) return confuse(x - 1);
+ return x;
+}
+
+main() {
+ var o = [ "foo", 499 ][confuse(0)];
+
+ // The is-checks in the '!' must not be propagated to the if-body.
+ // This was a bug in dart2js.
+ if (!(o is num && o is num)) {
+ Expect.isFalse((nonInlinedNumTypeCheck(o)));
+ }
+}
diff --git a/tests/language/logical_expression5_test.dart b/tests/language/logical_expression5_test.dart
new file mode 100644
index 0000000..5d983e0
--- /dev/null
+++ b/tests/language/logical_expression5_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+bool nonInlinedNumTypeCheck(Object object) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) {
+ return nonInlinedNumTypeCheck(object);
+ }
+ return object is num;
+}
+
+bool nonInlinedStringTypeCheck(Object object) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) {
+ return nonInlinedStringTypeCheck(object);
+ }
+ return object is String;
+}
+
+int confuse(x) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) return confuse(x - 1);
+ return x;
+}
+
+main() {
+ var o = [ "foo", 499 ][confuse(0)];
+
+ // The is-checks in the '!' must not be propagated to the if-body, but
+ // the second is-check should.
+ if (!(o is num) && o is String) {
+ Expect.isFalse((nonInlinedNumTypeCheck(o)));
+ Expect.isTrue((nonInlinedStringTypeCheck(o)));
+ }
+}
diff --git a/tests/language/vm/load_to_load_forwarding_vm_test.dart b/tests/language/vm/load_to_load_forwarding_vm_test.dart
index 4a0faed..18cd44c 100644
--- a/tests/language/vm/load_to_load_forwarding_vm_test.dart
+++ b/tests/language/vm/load_to_load_forwarding_vm_test.dart
@@ -169,6 +169,27 @@
0.1, 0.0, -0.1], result);
}
+
+class C {
+ C(this.box, this.parent);
+ final box;
+ final C parent;
+}
+
+testPhiForwarding5(C c) {
+ var s = 0;
+ var tmp = c;
+ var a = c.parent;
+ if (a.box + tmp.box != 1) throw "failed";
+ do {
+ s += tmp.box + a.box;
+ tmp = a;
+ a = a.parent;
+ } while (a != null);
+ return s;
+}
+
+
class U {
var x, y;
U() : x = 0, y = 0;
@@ -260,6 +281,8 @@
final obj = new X(new X(new X(null)));
+ final cs = new C(0, new C(1, new C(2, null)));
+
for (var i = 0; i < 20; i++) {
Expect.listEquals([0x02010000, 0x03020100], foo(new A(0, 0)));
Expect.listEquals([0x02010000, 0x03020100], bar(new A(0, 0), false));
@@ -270,6 +293,7 @@
testPhiForwarding2(obj);
testPhiForwarding3();
testPhiForwarding4();
+ Expect.equals(4, testPhiForwarding5(cs));
testEqualPhisElimination();
}
diff --git a/tools/VERSION b/tools/VERSION
index 0fc6d04..abd8144 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -26,6 +26,6 @@
CHANNEL stable
MAJOR 1
MINOR 2
-PATCH 0
+PATCH 1
PRERELEASE 0
PRERELEASE_PATCH 0