Index: pkg/compiler/lib/src/cps_ir/type_propagation.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
index 7ae47a5c134e79a5ad369d2a07259bf3dd9c03d7..099e2a699026603bc570f58f041ddf4ac34bbd45 100644 |
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart |
@@ -12,12 +12,12 @@ import '../dart_types.dart' as types; |
import '../dart2jslib.dart' as dart2js; |
import '../tree/tree.dart' show LiteralDartString; |
import 'cps_ir_nodes.dart'; |
-import '../types/types.dart' show TypeMask, TypesTask; |
+import '../types/types.dart'; |
import '../types/constants.dart' show computeTypeMask; |
-import '../elements/elements.dart' show ClassElement, Element, Entity, |
- FieldElement, FunctionElement, ParameterElement; |
-import '../dart2jslib.dart' show ClassWorld; |
+import '../elements/elements.dart'; |
+import '../dart2jslib.dart' show ClassWorld, World; |
import '../universe/universe.dart'; |
+import '../js_backend/js_backend.dart' show JavaScriptBackend; |
enum AbstractBool { |
True, False, Maybe, Nothing |
@@ -25,7 +25,7 @@ enum AbstractBool { |
class TypeMaskSystem { |
final TypesTask inferrer; |
- final ClassWorld classWorld; |
+ final World classWorld; |
TypeMask get dynamicType => inferrer.dynamicType; |
TypeMask get typeType => inferrer.typeType; |
@@ -50,6 +50,10 @@ class TypeMaskSystem { |
classWorld); |
} |
+ Element locateSingleElement(TypeMask mask, Selector selector) { |
+ return mask.locateSingleElement(selector, classWorld.compiler); |
+ } |
+ |
TypeMask getParameterType(ParameterElement parameter) { |
return inferrer.getGuaranteedTypeOfElement(parameter); |
} |
@@ -355,6 +359,7 @@ class ConstantPropagationLattice { |
class TypePropagator extends Pass { |
String get passName => 'Sparse constant propagation'; |
+ final dart2js.Compiler _compiler; |
// The constant system is used for evaluation of expressions with constant |
// arguments. |
final ConstantPropagationLattice _lattice; |
@@ -362,7 +367,8 @@ class TypePropagator extends Pass { |
final Map<Definition, AbstractValue> _values = <Definition, AbstractValue>{}; |
TypePropagator(dart2js.Compiler compiler) |
- : _internalError = compiler.internalError, |
+ : _compiler = compiler, |
+ _internalError = compiler.internalError, |
_lattice = new ConstantPropagationLattice( |
new TypeMaskSystem(compiler), |
compiler.backend.constantSystem, |
@@ -389,6 +395,7 @@ class TypePropagator extends Pass { |
// replace branches with fixed targets and side-effect-free expressions |
// with constant results or existing values that are in scope. |
TransformingVisitor transformer = new TransformingVisitor( |
+ _compiler, |
_lattice, |
analyzer.reachableNodes, |
analyzer.values, |
@@ -423,13 +430,16 @@ class TransformingVisitor extends RecursiveVisitor { |
final Map<Node, AbstractValue> values; |
final Map<Expression, ConstantValue> replacements; |
final ConstantPropagationLattice lattice; |
+ final dart2js.Compiler compiler; |
+ JavaScriptBackend get backend => compiler.backend; |
TypeMaskSystem get typeSystem => lattice.typeSystem; |
types.DartTypes get dartTypes => lattice.dartTypes; |
final dart2js.InternalErrorFunction internalError; |
- TransformingVisitor(this.lattice, |
+ TransformingVisitor(this.compiler, |
+ this.lattice, |
this.reachable, |
this.values, |
this.replacements, |
@@ -635,10 +645,64 @@ class TransformingVisitor extends RecursiveVisitor { |
return false; |
} |
+ bool isInterceptedSelector(Selector selector) { |
+ return backend.isInterceptedSelector(selector); |
+ } |
+ |
+ Primitive getDartReceiver(InvokeMethod node) { |
+ if (isInterceptedSelector(node.selector)) { |
+ return node.arguments[0].definition; |
+ } else { |
+ return node.receiver.definition; |
+ } |
+ } |
+ |
+ Primitive getDartArgument(InvokeMethod node, int n) { |
+ if (isInterceptedSelector(node.selector)) { |
+ return node.arguments[n+1].definition; |
+ } else { |
+ return node.arguments[n].definition; |
+ } |
+ } |
+ |
+ /// If [node] is a getter or setter invocation, tries to replace the |
+ /// invocation with a direct access to a field. |
+ /// |
+ /// Returns `true` if the node was replaced. |
+ bool inlineFieldAccess(InvokeMethod node) { |
+ if (!node.selector.isGetter && !node.selector.isSetter) return false; |
+ AbstractValue receiver = getValue(getDartReceiver(node)); |
+ if (receiver.isNothing) return false; |
+ Element target = |
+ typeSystem.locateSingleElement(receiver.type, node.selector); |
+ if (target is! FieldElement) return false; |
+ Continuation cont = node.continuation.definition; |
+ if (node.selector.isGetter) { |
+ GetField get = new GetField(getDartReceiver(node), target); |
+ get.objectIsNotNull = receiver.isDefinitelyNotNull; |
+ LetPrim let = makeLetPrimInvoke(get, cont); |
+ replaceSubtree(node, let); |
+ visitLetPrim(let); |
+ return true; |
+ } else { |
+ if (target.isFinal) return false; |
+ assert(cont.parameters.single.hasNoUses); |
+ cont.parameters.clear(); |
+ SetField set = new SetField(getDartReceiver(node), |
sra1
2015/06/19 18:21:00
This is not valid in checked mode unless we can pr
asgerf
2015/06/22 09:31:58
Nicely spotted, although we are not at all trying
|
+ target, |
+ getDartArgument(node, 0)); |
+ set.body = new InvokeContinuation(cont, <Primitive>[]); |
+ replaceSubtree(node, set); |
+ visitSetField(set); |
+ return true; |
+ } |
+ } |
+ |
void visitInvokeMethod(InvokeMethod node) { |
Continuation cont = node.continuation.definition; |
if (constifyExpression(node, cont)) return; |
if (specializeInvoke(node)) return; |
+ if (inlineFieldAccess(node)) return; |
AbstractValue receiver = getValue(node.receiver.definition); |
node.receiverIsNotNull = receiver.isDefinitelyNotNull; |
@@ -721,6 +785,10 @@ class TransformingVisitor extends RecursiveVisitor { |
return null; |
} |
+ void visitGetField(GetField node) { |
+ node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull; |
+ } |
+ |
void visitLetPrim(LetPrim node) { |
AbstractValue value = getValue(node.primitive); |
if (node.primitive is! Constant && value.isConstant) { |