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