OLD | NEW |
---|---|
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'optimizers.dart'; | 5 import 'optimizers.dart'; |
6 | 6 |
7 import '../common/names.dart' show | 7 import '../common/names.dart' show |
8 Selectors; | 8 Selectors; |
9 import '../compiler.dart' as dart2js show | 9 import '../compiler.dart' as dart2js show |
10 Compiler; | 10 Compiler; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
67 new TypeMask.nonNullSubtype(classWorld.numClass, classWorld); | 67 new TypeMask.nonNullSubtype(classWorld.numClass, classWorld); |
68 TypeMask anyString = | 68 TypeMask anyString = |
69 new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld); | 69 new TypeMask.nonNullSubtype(classWorld.stringClass, classWorld); |
70 TypeMask anyBool = | 70 TypeMask anyBool = |
71 new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld); | 71 new TypeMask.nonNullSubtype(classWorld.boolClass, classWorld); |
72 numStringBoolType = | 72 numStringBoolType = |
73 new TypeMask.unionOf(<TypeMask>[anyNum, anyString, anyBool], | 73 new TypeMask.unionOf(<TypeMask>[anyNum, anyString, anyBool], |
74 classWorld); | 74 classWorld); |
75 } | 75 } |
76 | 76 |
77 bool methodUsesReceiverArgument(FunctionElement function) { | |
78 assert(backend.isInterceptedMethod(function)); | |
79 ClassElement clazz = function.enclosingClass.declaration; | |
80 return clazz.isSubclassOf(backend.jsInterceptorClass) || | |
81 classWorld.isUsedAsMixin(clazz); | |
82 } | |
83 | |
77 Element locateSingleElement(TypeMask mask, Selector selector) { | 84 Element locateSingleElement(TypeMask mask, Selector selector) { |
78 return mask.locateSingleElement(selector, mask, classWorld.compiler); | 85 return mask.locateSingleElement(selector, mask, classWorld.compiler); |
79 } | 86 } |
80 | 87 |
81 ClassElement singleClass(TypeMask mask) { | 88 ClassElement singleClass(TypeMask mask) { |
82 return mask.singleClass(classWorld); | 89 return mask.singleClass(classWorld); |
83 } | 90 } |
84 | 91 |
85 bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) { | 92 bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) { |
86 return mask.needsNoSuchMethodHandling(selector, classWorld); | 93 return mask.needsNoSuchMethodHandling(selector, classWorld); |
87 } | 94 } |
88 | 95 |
89 TypeMask getReceiverType(MethodElement method) { | 96 TypeMask getReceiverType(MethodElement method) { |
90 assert(method.isInstanceMember); | 97 assert(method.isInstanceMember); |
91 return nonNullSubclass(method.enclosingClass); | 98 if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) { |
99 // If used as a mixin, the receiver could be any of the classes that mix | |
100 // in the class, and these are not considered subclasses. | |
101 // TODO(asgerf): Exclude the subtypes that only `implement` the class. | |
102 return nonNullSubtype(method.enclosingClass); | |
103 } else { | |
104 return nonNullSubclass(method.enclosingClass); | |
105 } | |
92 } | 106 } |
93 | 107 |
94 TypeMask getParameterType(ParameterElement parameter) { | 108 TypeMask getParameterType(ParameterElement parameter) { |
95 return inferrer.getGuaranteedTypeOfElement(parameter); | 109 return inferrer.getGuaranteedTypeOfElement(parameter); |
96 } | 110 } |
97 | 111 |
98 TypeMask getReturnType(FunctionElement function) { | 112 TypeMask getReturnType(FunctionElement function) { |
99 return inferrer.getGuaranteedReturnTypeOfElement(function); | 113 return inferrer.getGuaranteedReturnTypeOfElement(function); |
100 } | 114 } |
101 | 115 |
(...skipping 19 matching lines...) Expand all Loading... | |
121 // TODO(asgerf): Maybe closure conversion should create a new ClassWorld? | 135 // TODO(asgerf): Maybe closure conversion should create a new ClassWorld? |
122 if (element.isClosure) return functionType; | 136 if (element.isClosure) return functionType; |
123 return new TypeMask.nonNullExact(element.declaration, classWorld); | 137 return new TypeMask.nonNullExact(element.declaration, classWorld); |
124 } | 138 } |
125 | 139 |
126 TypeMask nonNullSubclass(ClassElement element) { | 140 TypeMask nonNullSubclass(ClassElement element) { |
127 if (element.isClosure) return functionType; | 141 if (element.isClosure) return functionType; |
128 return new TypeMask.nonNullSubclass(element.declaration, classWorld); | 142 return new TypeMask.nonNullSubclass(element.declaration, classWorld); |
129 } | 143 } |
130 | 144 |
145 TypeMask nonNullSubtype(ClassElement element) { | |
146 if (element.isClosure) return functionType; | |
147 return new TypeMask.nonNullSubtype(element.declaration, classWorld); | |
148 } | |
149 | |
131 bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) { | 150 bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) { |
132 if (!allowNull && t.isNullable) return false; | 151 if (!allowNull && t.isNullable) return false; |
133 return t.nonNullable().containsOnlyBool(classWorld); | 152 return t.nonNullable().containsOnlyBool(classWorld); |
134 } | 153 } |
135 | 154 |
136 bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) { | 155 bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) { |
137 if (!allowNull && t.isNullable) return false; | 156 if (!allowNull && t.isNullable) return false; |
138 return t.nonNullable().containsOnlyNum(classWorld); | 157 return t.nonNullable().containsOnlyNum(classWorld); |
139 } | 158 } |
140 | 159 |
(...skipping 1433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1574 void visitInvokeMethod(InvokeMethod node) { | 1593 void visitInvokeMethod(InvokeMethod node) { |
1575 if (constifyExpression(node)) return; | 1594 if (constifyExpression(node)) return; |
1576 if (specializeOperatorCall(node)) return; | 1595 if (specializeOperatorCall(node)) return; |
1577 if (specializeFieldAccess(node)) return; | 1596 if (specializeFieldAccess(node)) return; |
1578 if (specializeIndexableAccess(node)) return; | 1597 if (specializeIndexableAccess(node)) return; |
1579 if (specializeArrayAccess(node)) return; | 1598 if (specializeArrayAccess(node)) return; |
1580 if (specializeClosureCall(node)) return; | 1599 if (specializeClosureCall(node)) return; |
1581 | 1600 |
1582 AbstractValue receiver = getValue(node.receiver.definition); | 1601 AbstractValue receiver = getValue(node.receiver.definition); |
1583 node.receiverIsNotNull = receiver.isDefinitelyNotNull; | 1602 node.receiverIsNotNull = receiver.isDefinitelyNotNull; |
1603 | |
1604 if (isInterceptedSelector(node.selector) && | |
1605 node.receiver.definition == node.arguments[0].definition) { | |
1606 // The receiver and first argument are the same; that means we already | |
1607 // determined in visitInterceptor that we are targeting a non-interceptor. | |
1608 | |
1609 // Check if any of the possible targets depend on the extra receiver | |
1610 // argument. Mixins do this, and tear-offs always needs the extra receiver | |
1611 // argument because BoundClosure uses it for equality and hash code. | |
sra1
2015/08/26 15:04:43
SSA backend has this TODO.
// TODO(1593
| |
1612 bool needsReceiver(Element target) { | |
1613 if (target is! FunctionElement) return false; | |
1614 FunctionElement function = target; | |
1615 return typeSystem.methodUsesReceiverArgument(function) || | |
1616 node.selector.isGetter && !function.isGetter; | |
1617 } | |
1618 if (!getAllTargets(receiver.type, node.selector).any(needsReceiver)) { | |
1619 // Replace the extra receiver argument with a dummy value if the | |
1620 // target definitely does not use it. | |
1621 Constant dummy = makeConstantPrimitive(new IntConstantValue(0)); | |
sra1
2015/08/26 15:04:43
There is a special constant for this purpose.
In c
| |
1622 insertLetPrim(node, dummy); | |
1623 node.arguments[0].unlink(); | |
1624 node.arguments[0] = new Reference<Primitive>(dummy); | |
1625 } | |
1626 } | |
1584 } | 1627 } |
1585 | 1628 |
1586 void visitTypeCast(TypeCast node) { | 1629 void visitTypeCast(TypeCast node) { |
1587 Continuation cont = node.continuation.definition; | 1630 Continuation cont = node.continuation.definition; |
1588 | 1631 |
1589 AbstractValue value = getValue(node.value.definition); | 1632 AbstractValue value = getValue(node.value.definition); |
1590 switch (lattice.isSubtypeOf(value, node.type, allowNull: true)) { | 1633 switch (lattice.isSubtypeOf(value, node.type, allowNull: true)) { |
1591 case AbstractBool.Maybe: | 1634 case AbstractBool.Maybe: |
1592 case AbstractBool.Nothing: | 1635 case AbstractBool.Nothing: |
1593 break; | 1636 break; |
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2065 values[node] = newValue; | 2108 values[node] = newValue; |
2066 defWorklist.add(node); | 2109 defWorklist.add(node); |
2067 } | 2110 } |
2068 | 2111 |
2069 // -------------------------- Visitor overrides ------------------------------ | 2112 // -------------------------- Visitor overrides ------------------------------ |
2070 void visit(Node node) { node.accept(this); } | 2113 void visit(Node node) { node.accept(this); } |
2071 | 2114 |
2072 void visitFunctionDefinition(FunctionDefinition node) { | 2115 void visitFunctionDefinition(FunctionDefinition node) { |
2073 int firstActualParameter = 0; | 2116 int firstActualParameter = 0; |
2074 if (backend.isInterceptedMethod(node.element)) { | 2117 if (backend.isInterceptedMethod(node.element)) { |
2075 setValue(node.thisParameter, nonConstant(typeSystem.nonNullType)); | 2118 if (typeSystem.methodUsesReceiverArgument(node.element)) { |
2076 setValue(node.parameters[0], | 2119 setValue(node.thisParameter, nonConstant(typeSystem.nonNullType)); |
2077 nonConstant(typeSystem.getReceiverType(node.element))); | 2120 setValue(node.parameters[0], |
2121 nonConstant(typeSystem.getReceiverType(node.element))); | |
2122 } else { | |
2123 setValue(node.thisParameter, | |
2124 nonConstant(typeSystem.getReceiverType(node.element))); | |
2125 setValue(node.parameters[0], nonConstant()); | |
2126 } | |
2078 firstActualParameter = 1; | 2127 firstActualParameter = 1; |
2079 } else if (node.thisParameter != null) { | 2128 } else if (node.thisParameter != null) { |
2080 setValue(node.thisParameter, | 2129 setValue(node.thisParameter, |
2081 nonConstant(typeSystem.getReceiverType(node.element))); | 2130 nonConstant(typeSystem.getReceiverType(node.element))); |
2082 } | 2131 } |
2083 for (Parameter param in node.parameters.skip(firstActualParameter)) { | 2132 for (Parameter param in node.parameters.skip(firstActualParameter)) { |
2084 // TODO(karlklose): remove reference to the element model. | 2133 // TODO(karlklose): remove reference to the element model. |
2085 TypeMask type = param.hint is ParameterElement | 2134 TypeMask type = param.hint is ParameterElement |
2086 ? typeSystem.getParameterType(param.hint) | 2135 ? typeSystem.getParameterType(param.hint) |
2087 : typeSystem.dynamicType; | 2136 : typeSystem.dynamicType; |
(...skipping 584 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2672 } | 2721 } |
2673 | 2722 |
2674 processLetPrim(LetPrim node) { | 2723 processLetPrim(LetPrim node) { |
2675 values.remove(node.primitive); | 2724 values.remove(node.primitive); |
2676 } | 2725 } |
2677 | 2726 |
2678 processLetMutable(LetMutable node) { | 2727 processLetMutable(LetMutable node) { |
2679 values.remove(node.variable); | 2728 values.remove(node.variable); |
2680 } | 2729 } |
2681 } | 2730 } |
OLD | NEW |