| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 library simple_types_inferrer; | 5 library simple_types_inferrer; |
| 6 | 6 |
| 7 import 'dart:collection' show Queue, LinkedHashSet; | 7 import 'dart:collection' show Queue, LinkedHashSet; |
| 8 | 8 |
| 9 import '../closure.dart' show ClosureClassMap, ClosureScope; | 9 import '../closure.dart' show ClosureClassMap, ClosureScope; |
| 10 import '../dart_types.dart' show DartType, FunctionType, TypeKind; | 10 import '../dart_types.dart' show DartType, FunctionType, TypeKind; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 if (constructorsToVisitCount != 0) constructorsToVisitCount--; | 89 if (constructorsToVisitCount != 0) constructorsToVisitCount--; |
| 90 } | 90 } |
| 91 | 91 |
| 92 /** | 92 /** |
| 93 * Returns whether all generative constructors of the class have | 93 * Returns whether all generative constructors of the class have |
| 94 * been analyzed. | 94 * been analyzed. |
| 95 */ | 95 */ |
| 96 bool get isDone => constructorsToVisitCount == 0; | 96 bool get isDone => constructorsToVisitCount == 0; |
| 97 } | 97 } |
| 98 | 98 |
| 99 /** | |
| 100 * A sentinel type mask class used by the inferrer for the give up | |
| 101 * type, and the dynamic type. | |
| 102 */ | |
| 103 class SentinelTypeMask extends TypeMask { | |
| 104 final String name; | |
| 105 | |
| 106 SentinelTypeMask(this.name) : super(null, 0, false); | |
| 107 | |
| 108 bool operator==(other) { | |
| 109 return identical(this, other); | |
| 110 } | |
| 111 | |
| 112 TypeMask nullable() { | |
| 113 throw 'Unsupported operation'; | |
| 114 } | |
| 115 | |
| 116 bool get isNullable => true; | |
| 117 | |
| 118 String toString() => '$name sentinel type mask'; | |
| 119 } | |
| 120 | |
| 121 final OPTIMISTIC = 0; | 99 final OPTIMISTIC = 0; |
| 122 final RETRY = 1; | 100 final RETRY = 1; |
| 123 final PESSIMISTIC = 2; | 101 final PESSIMISTIC = 2; |
| 124 | 102 |
| 125 class SimpleTypesInferrer extends TypesInferrer { | 103 class SimpleTypesInferrer extends TypesInferrer { |
| 126 InternalSimpleTypesInferrer internal; | 104 InternalSimpleTypesInferrer internal; |
| 127 Compiler compiler; | 105 Compiler compiler; |
| 128 | 106 |
| 129 SimpleTypesInferrer(Compiler compiler) : | 107 SimpleTypesInferrer(Compiler compiler) : |
| 130 compiler = compiler, | 108 compiler = compiler, |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 * Heuristic for avoiding too many re-analysis of an element. | 232 * Heuristic for avoiding too many re-analysis of an element. |
| 255 */ | 233 */ |
| 256 final int MAX_ANALYSIS_COUNT_PER_ELEMENT = 5; | 234 final int MAX_ANALYSIS_COUNT_PER_ELEMENT = 5; |
| 257 | 235 |
| 258 int optimismState; | 236 int optimismState; |
| 259 | 237 |
| 260 /** | 238 /** |
| 261 * Sentinel used by the inferrer to notify that it does not know | 239 * Sentinel used by the inferrer to notify that it does not know |
| 262 * the type of a specific element. | 240 * the type of a specific element. |
| 263 */ | 241 */ |
| 264 final TypeMask dynamicType = new SentinelTypeMask('dynamic'); | 242 TypeMask dynamicType; |
| 265 bool isDynamicType(TypeMask type) => identical(type, dynamicType); | 243 bool isDynamicType(TypeMask type) => type == dynamicType; |
| 266 | 244 |
| 267 TypeMask nullType; | 245 TypeMask nullType; |
| 268 TypeMask intType; | 246 TypeMask intType; |
| 269 TypeMask doubleType; | 247 TypeMask doubleType; |
| 270 TypeMask numType; | 248 TypeMask numType; |
| 271 TypeMask boolType; | 249 TypeMask boolType; |
| 272 TypeMask functionType; | 250 TypeMask functionType; |
| 273 TypeMask listType; | 251 TypeMask listType; |
| 274 TypeMask constListType; | 252 TypeMask constListType; |
| 275 TypeMask fixedListType; | 253 TypeMask fixedListType; |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 rawTypeOf(backend.growableListImplementation)); | 514 rawTypeOf(backend.growableListImplementation)); |
| 537 | 515 |
| 538 mapType = new TypeMask.nonNullSubtype( | 516 mapType = new TypeMask.nonNullSubtype( |
| 539 rawTypeOf(backend.mapImplementation)); | 517 rawTypeOf(backend.mapImplementation)); |
| 540 constMapType = new TypeMask.nonNullSubtype( | 518 constMapType = new TypeMask.nonNullSubtype( |
| 541 rawTypeOf(backend.constMapImplementation)); | 519 rawTypeOf(backend.constMapImplementation)); |
| 542 functionType = new TypeMask.nonNullSubtype( | 520 functionType = new TypeMask.nonNullSubtype( |
| 543 rawTypeOf(backend.functionImplementation)); | 521 rawTypeOf(backend.functionImplementation)); |
| 544 typeType = new TypeMask.nonNullExact( | 522 typeType = new TypeMask.nonNullExact( |
| 545 rawTypeOf(backend.typeImplementation)); | 523 rawTypeOf(backend.typeImplementation)); |
| 524 |
| 525 dynamicType = new TypeMask.subclass( |
| 526 rawTypeOf(compiler.objectClass)); |
| 546 } | 527 } |
| 547 | 528 |
| 548 dump() { | 529 dump() { |
| 549 int interestingTypes = 0; | 530 int interestingTypes = 0; |
| 550 returnTypeOf.forEach((Element element, TypeMask type) { | 531 returnTypeOf.forEach((Element element, TypeMask type) { |
| 551 if (type != nullType && !isDynamicType(type)) { | 532 if (type != nullType && !isDynamicType(type)) { |
| 552 interestingTypes++; | 533 interestingTypes++; |
| 553 } | 534 } |
| 554 }); | 535 }); |
| 555 typeOf.forEach((Element element, TypeMask type) { | 536 typeOf.forEach((Element element, TypeMask type) { |
| (...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1180 enqueueCallersOf(field); | 1161 enqueueCallersOf(field); |
| 1181 } | 1162 } |
| 1182 }); | 1163 }); |
| 1183 } | 1164 } |
| 1184 | 1165 |
| 1185 /** | 1166 /** |
| 1186 * Returns the least upper bound between [firstType] and | 1167 * Returns the least upper bound between [firstType] and |
| 1187 * [secondType]. | 1168 * [secondType]. |
| 1188 */ | 1169 */ |
| 1189 TypeMask computeLUB(TypeMask firstType, TypeMask secondType) { | 1170 TypeMask computeLUB(TypeMask firstType, TypeMask secondType) { |
| 1190 assert(secondType != null); | |
| 1191 if (firstType == null) { | 1171 if (firstType == null) { |
| 1192 return secondType; | 1172 return secondType; |
| 1193 } else if (isDynamicType(secondType)) { | 1173 } else if (isDynamicType(secondType)) { |
| 1194 return secondType; | 1174 return secondType; |
| 1195 } else if (isDynamicType(firstType)) { | 1175 } else if (isDynamicType(firstType)) { |
| 1196 return firstType; | 1176 return firstType; |
| 1197 } else { | 1177 } else { |
| 1198 TypeMask union = firstType.union(secondType, compiler); | 1178 TypeMask union = firstType.union(secondType, compiler); |
| 1199 // TODO(kasperl): If the union isn't nullable it seems wasteful | 1179 // TODO(kasperl): If the union isn't nullable it seems wasteful |
| 1200 // to use dynamic. Fix that. | 1180 // to use dynamic. Fix that. |
| (...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1583 // same as [newType]. | 1563 // same as [newType]. |
| 1584 ClosureClassMap nestedClosureData = | 1564 ClosureClassMap nestedClosureData = |
| 1585 compiler.closureToClassMapper.getMappingForNestedFunction(node); | 1565 compiler.closureToClassMapper.getMappingForNestedFunction(node); |
| 1586 nestedClosureData.forEachNonBoxedCapturedVariable((Element variable) { | 1566 nestedClosureData.forEachNonBoxedCapturedVariable((Element variable) { |
| 1587 // The type may be null for instance contexts (this and type | 1567 // The type may be null for instance contexts (this and type |
| 1588 // parameters), as well as captured argument checks. | 1568 // parameters), as well as captured argument checks. |
| 1589 if (locals.locals[variable] == null) return; | 1569 if (locals.locals[variable] == null) return; |
| 1590 inferrer.recordType(variable, locals.locals[variable]); | 1570 inferrer.recordType(variable, locals.locals[variable]); |
| 1591 }); | 1571 }); |
| 1592 | 1572 |
| 1573 locals.update(elements[node], inferrer.functionType); |
| 1593 return inferrer.functionType; | 1574 return inferrer.functionType; |
| 1594 } | 1575 } |
| 1595 | 1576 |
| 1596 TypeMask visitFunctionDeclaration(FunctionDeclaration node) { | 1577 TypeMask visitFunctionDeclaration(FunctionDeclaration node) { |
| 1597 locals.update(elements[node], inferrer.functionType); | 1578 locals.update(elements[node], inferrer.functionType); |
| 1598 return visit(node.function); | 1579 return visit(node.function); |
| 1599 } | 1580 } |
| 1600 | 1581 |
| 1601 TypeMask visitLiteralString(LiteralString node) { | 1582 TypeMask visitLiteralString(LiteralString node) { |
| 1602 return inferrer.stringType; | 1583 return inferrer.stringType; |
| (...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2071 Selector selector, | 2052 Selector selector, |
| 2072 TypeMask receiver, | 2053 TypeMask receiver, |
| 2073 ArgumentsTypes arguments, | 2054 ArgumentsTypes arguments, |
| 2074 [Selector constraint]) { | 2055 [Selector constraint]) { |
| 2075 if (selector.mask != receiver) { | 2056 if (selector.mask != receiver) { |
| 2076 selector = inferrer.isDynamicType(receiver) | 2057 selector = inferrer.isDynamicType(receiver) |
| 2077 ? selector.asUntyped | 2058 ? selector.asUntyped |
| 2078 : new TypedSelector(receiver, selector); | 2059 : new TypedSelector(receiver, selector); |
| 2079 updateSelectorInTree(node, selector); | 2060 updateSelectorInTree(node, selector); |
| 2080 } | 2061 } |
| 2062 |
| 2063 // If the receiver of the call is a local, we may know more about |
| 2064 // its type by refining it with the potential targets of the |
| 2065 // calls. |
| 2066 if (node.asSend() != null |
| 2067 && node.asSend().receiver != null |
| 2068 && Elements.isLocal(elements[node.asSend().receiver])) { |
| 2069 Element element = elements[node.asSend().receiver]; |
| 2070 TypeMask refinedMask = new TypeMask.refineWith( |
| 2071 locals.use(element), selector, compiler); |
| 2072 locals.update(element, refinedMask); |
| 2073 } |
| 2074 |
| 2081 return inferrer.registerCalledSelector( | 2075 return inferrer.registerCalledSelector( |
| 2082 node, selector, receiver, outermostElement, arguments, | 2076 node, selector, receiver, outermostElement, arguments, |
| 2083 constraint, inLoop); | 2077 constraint, inLoop); |
| 2084 } | 2078 } |
| 2085 | 2079 |
| 2086 TypeMask visitDynamicSend(Send node) { | 2080 TypeMask visitDynamicSend(Send node) { |
| 2087 Element element = elements[node]; | 2081 Element element = elements[node]; |
| 2088 TypeMask receiverType; | 2082 TypeMask receiverType; |
| 2089 bool isCallOnThis = false; | 2083 bool isCallOnThis = false; |
| 2090 if (node.receiver == null) { | 2084 if (node.receiver == null) { |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2299 } | 2293 } |
| 2300 | 2294 |
| 2301 TypeMask visitParenthesizedExpression(ParenthesizedExpression node) { | 2295 TypeMask visitParenthesizedExpression(ParenthesizedExpression node) { |
| 2302 return visit(node.expression); | 2296 return visit(node.expression); |
| 2303 } | 2297 } |
| 2304 | 2298 |
| 2305 void internalError(String reason, {Node node}) { | 2299 void internalError(String reason, {Node node}) { |
| 2306 compiler.internalError(reason, node: node); | 2300 compiler.internalError(reason, node: node); |
| 2307 } | 2301 } |
| 2308 } | 2302 } |
| OLD | NEW |