Version 1.3.0-dev.5.2
svn merge -c 34213 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@34229 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index ba34bb2..fdedd2a 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -816,6 +816,8 @@
void setUseGvn() { _useGvn = true; }
void clearUseGvn() { _useGvn = false; }
+ bool get isMovable => useGvn();
+
/**
* A pure instruction is an instruction that does not have any side
* effect, nor any dependency. They can be moved anywhere in the
@@ -2464,16 +2466,27 @@
bool dataEquals(HTypeConversion other) {
return kind == other.kind
&& typeExpression == other.typeExpression
- && checkedType == other.checkedType;
+ && checkedType == other.checkedType
+ && receiverTypeCheckSelector == other.receiverTypeCheckSelector;
}
}
/// The [HTypeKnown] instruction marks a value with a refined type.
class HTypeKnown extends HCheck {
TypeMask knownType;
- HTypeKnown(TypeMask knownType, HInstruction input)
+ bool _isMovable;
+
+ HTypeKnown.pinned(TypeMask knownType, HInstruction input)
: this.knownType = knownType,
+ this._isMovable = false,
super(<HInstruction>[input], knownType);
+
+ HTypeKnown.witnessed(TypeMask knownType, HInstruction input,
+ HInstruction witness)
+ : this.knownType = knownType,
+ this._isMovable = true,
+ super(<HInstruction>[input, witness], knownType);
+
toString() => 'TypeKnown $knownType';
accept(HVisitor visitor) => visitor.visitTypeKnown(this);
@@ -2484,6 +2497,7 @@
int typeCode() => HInstruction.TYPE_KNOWN_TYPECODE;
bool typeEquals(HInstruction other) => other is HTypeKnown;
bool isCodeMotionInvariant() => true;
+ bool get isMovable => _isMovable && useGvn();
bool dataEquals(HTypeKnown other) {
return knownType == other.knownType
@@ -2496,6 +2510,9 @@
: super(<HInstruction>[input], type) {
sourceElement = input.sourceElement;
}
+
+ bool get isMovable => false;
+
accept(HVisitor visitor) => visitor.visitRangeConversion(this);
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index b575772..3ea9d98 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -1243,7 +1243,7 @@
&& loopHeader.successors[0] == block);
while (instruction != null) {
HInstruction next = instruction.next;
- if (instruction.useGvn()
+ if (instruction.useGvn() && instruction.isMovable
&& (!instruction.canThrow() || firstInstructionInLoop)
&& !instruction.sideEffects.dependsOn(dependsFlags)) {
bool loopInvariantInputs = true;
@@ -1465,11 +1465,11 @@
HInstruction current = instruction;
instruction = instruction.next;
-
- // TODO(ngeoffray): this check is needed because we currently do
- // not have flags to express 'Gvn'able', but not movable.
- if (current is HCheck) continue;
- if (!current.useGvn()) continue;
+ if (!current.useGvn() || !current.isMovable) continue;
+ // TODO(sra): We could move throwing instructions provided we keep the
+ // exceptions in the same order. This requires they are in the same order
+ // in all successors, which is not tracked by the ValueSet.
+ if (current.canThrow()) continue;
if (current.sideEffects.dependsOn(dependsFlags)) continue;
bool canBeMoved = true;
@@ -1504,14 +1504,16 @@
}
// Update users of [input] that are dominated by [:dominator.first:]
- // to use [newInput] instead.
- void changeUsesDominatedBy(HBasicBlock dominator,
- HInstruction input,
- TypeMask convertedType) {
+ // to use [TypeKnown] of [input] instead. As the type information depends
+ // on the control flow, we mark the inserted [HTypeKnown] nodes as
+ // non-movable.
+ void insertTypePropagationForDominatedUsers(HBasicBlock dominator,
+ HInstruction input,
+ TypeMask convertedType) {
Setlet<HInstruction> dominatedUsers = input.dominatedUsers(dominator.first);
if (dominatedUsers.isEmpty) return;
- HTypeKnown newInput = new HTypeKnown(convertedType, input);
+ HTypeKnown newInput = new HTypeKnown.pinned(convertedType, input);
dominator.addBefore(dominator.first, newInput);
dominatedUsers.forEach((HInstruction user) {
user.changeUse(input, newInput);
@@ -1538,12 +1540,14 @@
HInstruction input = instruction.expression;
for (HIf ifUser in ifUsers) {
- changeUsesDominatedBy(ifUser.thenBlock, input, convertedType);
+ insertTypePropagationForDominatedUsers(ifUser.thenBlock, input,
+ convertedType);
// TODO(ngeoffray): Also change uses for the else block on a type
// that knows it is not of a specific type.
}
for (HIf ifUser in notIfUsers) {
- changeUsesDominatedBy(ifUser.elseBlock, input, convertedType);
+ insertTypePropagationForDominatedUsers(ifUser.elseBlock, input,
+ convertedType);
// TODO(ngeoffray): Also change uses for the then block on a type
// that knows it is not of a specific type.
}
@@ -1575,11 +1579,13 @@
TypeMask nonNullType = input.instructionType.nonNullable();
for (HIf ifUser in ifUsers) {
- changeUsesDominatedBy(ifUser.elseBlock, input, nonNullType);
+ insertTypePropagationForDominatedUsers(ifUser.elseBlock, input,
+ nonNullType);
// Uses in thenBlock are `null`, but probably not common.
}
for (HIf ifUser in notIfUsers) {
- changeUsesDominatedBy(ifUser.thenBlock, input, nonNullType);
+ insertTypePropagationForDominatedUsers(ifUser.thenBlock, input,
+ nonNullType);
// Uses in elseBlock are `null`, but probably not common.
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index 705f219..9c871fc 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -342,7 +342,8 @@
// Insert a refinement node after the call and update all
// users dominated by the call to use that node instead of
// [receiver].
- HTypeKnown converted = new HTypeKnown(newType, receiver);
+ HTypeKnown converted =
+ new HTypeKnown.witnessed(newType, receiver, instruction);
instruction.block.addBefore(instruction.next, converted);
receiver.replaceAllUsersDominatedBy(converted.next, converted);
addDependentInstructionsToWorkList(converted);
diff --git a/tests/compiler/dart2js_extra/17645_test.dart b/tests/compiler/dart2js_extra/17645_test.dart
new file mode 100644
index 0000000..67d8de8
--- /dev/null
+++ b/tests/compiler/dart2js_extra/17645_test.dart
@@ -0,0 +1,74 @@
+// 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 17645.
+get never => new DateTime.now().millisecondsSinceEpoch == 0;
+
+class A {
+ var foo;
+ A(this.foo);
+}
+
+var log = [];
+
+test1(a, xs) { // Called with a = [null|exact=A]
+ log.clear();
+ for (var x in xs) {
+ if (a != null) {
+ log.add('${a.foo}.$x'); // a.foo must not be hoisted
+ }
+ }
+ return '$log';
+}
+
+test2(a, xs) { // Called with a = [exact=A]
+ log.clear();
+ for (var x in xs) {
+ if (a != null) {
+ log.add('${a.foo}.$x'); // a.foo may be hoisted
+ }
+ }
+ return '$log';
+}
+
+test3(a, xs) { // Called with a = [null|exact=A]
+ log.clear();
+ for (var x in xs) {
+ if (a is A) {
+ log.add('${a.foo}.$x'); // a.foo must not be hoisted
+ }
+ }
+ return '$log';
+}
+
+test4(a, xs) { // Called with a = [exact=A]
+ log.clear();
+ for (var x in xs) {
+ if (a is A) {
+ log.add('${a.foo}.$x'); // a.foo may be hoisted
+ }
+ }
+ return '$log';
+}
+
+
+main() {
+ var a1 = new A('a1');
+ var a2 = new A('a2');
+
+ Expect.equals('[a1.11]', test1(a1, [11]));
+ Expect.equals('[]', test1(null, [11]));
+
+ Expect.equals('[a1.22]', test2(a1, [22]));
+ Expect.equals('[a2.22]', test2(a2, [22]));
+
+
+ Expect.equals('[a1.33]', test3(a1, [33]));
+ Expect.equals('[]', test3(null, [2]));
+
+ Expect.equals('[a1.44]', test4(a1, [44]));
+ Expect.equals('[a2.44]', test4(a2, [44]));
+}
diff --git a/tools/VERSION b/tools/VERSION
index d607301..b4a3d44 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 3
PATCH 0
PRERELEASE 5
-PRERELEASE_PATCH 1
+PRERELEASE_PATCH 2