| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, 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 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../common/names.dart'; | 8 import '../common/names.dart'; |
| 9 import '../compiler.dart'; | 9 import '../compiler.dart'; |
| 10 import '../constants/expressions.dart'; | |
| 11 import '../constants/values.dart'; | |
| 12 import '../common_elements.dart'; | 10 import '../common_elements.dart'; |
| 13 import '../elements/elements.dart'; | 11 import '../elements/elements.dart' |
| 12 show |
| 13 ClassElement, |
| 14 ConstructorElement, |
| 15 Elements, |
| 16 MemberElement, |
| 17 ParameterElement; |
| 14 import '../elements/entities.dart'; | 18 import '../elements/entities.dart'; |
| 15 import '../elements/names.dart'; | 19 import '../elements/names.dart'; |
| 16 import '../js_backend/annotations.dart'; | 20 import '../js_backend/annotations.dart'; |
| 17 import '../js_backend/js_backend.dart'; | 21 import '../js_backend/js_backend.dart'; |
| 18 import '../native/behavior.dart' as native; | 22 import '../native/behavior.dart' as native; |
| 19 import '../resolution/tree_elements.dart'; | |
| 20 import '../tree/nodes.dart' as ast; | |
| 21 import '../types/constants.dart'; | |
| 22 import '../types/types.dart'; | 23 import '../types/types.dart'; |
| 23 import '../universe/call_structure.dart'; | 24 import '../universe/call_structure.dart'; |
| 24 import '../universe/selector.dart'; | 25 import '../universe/selector.dart'; |
| 25 import '../universe/side_effects.dart'; | 26 import '../universe/side_effects.dart'; |
| 26 import '../util/util.dart'; | |
| 27 import '../world.dart'; | 27 import '../world.dart'; |
| 28 import 'closure_tracer.dart'; | |
| 29 import 'debug.dart' as debug; | 28 import 'debug.dart' as debug; |
| 30 import 'locals_handler.dart'; | 29 import 'locals_handler.dart'; |
| 31 import 'list_tracer.dart'; | 30 import 'list_tracer.dart'; |
| 32 import 'map_tracer.dart'; | 31 import 'map_tracer.dart'; |
| 33 import 'builder.dart'; | 32 import 'builder.dart'; |
| 34 import 'builder_kernel.dart'; | |
| 35 import 'type_graph_dump.dart'; | |
| 36 import 'type_graph_inferrer.dart'; | 33 import 'type_graph_inferrer.dart'; |
| 37 import 'type_graph_nodes.dart'; | 34 import 'type_graph_nodes.dart'; |
| 38 import 'type_system.dart'; | 35 import 'type_system.dart'; |
| 39 | 36 |
| 40 /// An inferencing engine that computes a call graph of [TypeInformation] nodes | 37 /// An inferencing engine that computes a call graph of [TypeInformation] nodes |
| 41 /// by visiting the AST of the application, and then does the inferencing on the | 38 /// by visiting the AST of the application, and then does the inferencing on the |
| 42 /// graph. | 39 /// graph. |
| 43 abstract class InferrerEngine { | 40 abstract class InferrerEngine<T> { |
| 44 /// A set of selector names that [List] implements, that we know return their | 41 /// A set of selector names that [List] implements, that we know return their |
| 45 /// element type. | 42 /// element type. |
| 46 final Set<Selector> returnsListElementTypeSet = | 43 final Set<Selector> returnsListElementTypeSet = |
| 47 new Set<Selector>.from(<Selector>[ | 44 new Set<Selector>.from(<Selector>[ |
| 48 new Selector.getter(const PublicName('first')), | 45 new Selector.getter(const PublicName('first')), |
| 49 new Selector.getter(const PublicName('last')), | 46 new Selector.getter(const PublicName('last')), |
| 50 new Selector.getter(const PublicName('single')), | 47 new Selector.getter(const PublicName('single')), |
| 51 new Selector.call(const PublicName('singleWhere'), CallStructure.ONE_ARG), | 48 new Selector.call(const PublicName('singleWhere'), CallStructure.ONE_ARG), |
| 52 new Selector.call(const PublicName('elementAt'), CallStructure.ONE_ARG), | 49 new Selector.call(const PublicName('elementAt'), CallStructure.ONE_ARG), |
| 53 new Selector.index(), | 50 new Selector.index(), |
| 54 new Selector.call(const PublicName('removeAt'), CallStructure.ONE_ARG), | 51 new Selector.call(const PublicName('removeAt'), CallStructure.ONE_ARG), |
| 55 new Selector.call(const PublicName('removeLast'), CallStructure.NO_ARGS) | 52 new Selector.call(const PublicName('removeLast'), CallStructure.NO_ARGS) |
| 56 ]); | 53 ]); |
| 57 | 54 |
| 58 Compiler get compiler; | 55 Compiler get compiler; |
| 59 ClosedWorld get closedWorld; | 56 ClosedWorld get closedWorld; |
| 60 ClosedWorldRefiner get closedWorldRefiner; | 57 ClosedWorldRefiner get closedWorldRefiner; |
| 61 JavaScriptBackend get backend => compiler.backend; | 58 JavaScriptBackend get backend => compiler.backend; |
| 62 OptimizerHintsForTests get optimizerHints => backend.optimizerHints; | 59 OptimizerHintsForTests get optimizerHints => backend.optimizerHints; |
| 63 DiagnosticReporter get reporter => compiler.reporter; | 60 DiagnosticReporter get reporter => compiler.reporter; |
| 64 CommonMasks get commonMasks => closedWorld.commonMasks; | 61 CommonMasks get commonMasks => closedWorld.commonMasks; |
| 65 CommonElements get commonElements => closedWorld.commonElements; | 62 CommonElements get commonElements => closedWorld.commonElements; |
| 66 | 63 |
| 67 TypeSystem<ast.Node> get types; | 64 TypeSystem<T> get types; |
| 68 Map<ast.Node, TypeInformation> get concreteTypes; | 65 Map<T, TypeInformation> get concreteTypes; |
| 69 | 66 |
| 70 /// Parallel structure for concreteTypes. | 67 /// Parallel structure for concreteTypes. |
| 71 // TODO(efortuna): Remove concreteTypes and/or parameterize InferrerEngine by | 68 // TODO(efortuna): Remove concreteTypes and/or parameterize InferrerEngine by |
| 72 // ir.Node or ast.Node type. Then remove this in favor of `concreteTypes`. | 69 // ir.Node or ast.Node type. Then remove this in favor of `concreteTypes`. |
| 73 Map<ir.Node, TypeInformation> get concreteKernelTypes; | 70 Map<ir.Node, TypeInformation> get concreteKernelTypes; |
| 74 | 71 |
| 75 FunctionEntity get mainElement; | 72 FunctionEntity get mainElement; |
| 76 | 73 |
| 77 void runOverAllElements(); | 74 void runOverAllElements(); |
| 78 | 75 |
| 79 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments); | 76 void analyze(MemberEntity member, T node, ArgumentsTypes arguments); |
| 80 void analyzeListAndEnqueue(ListTypeInformation info); | 77 void analyzeListAndEnqueue(ListTypeInformation info); |
| 81 void analyzeMapAndEnqueue(MapTypeInformation info); | 78 void analyzeMapAndEnqueue(MapTypeInformation info); |
| 82 | 79 |
| 83 /// Notifies to the inferrer that [analyzedElement] can have return type | 80 /// Notifies to the inferrer that [analyzedElement] can have return type |
| 84 /// [newType]. [currentType] is the type the [ElementGraphBuilder] currently | 81 /// [newType]. [currentType] is the type the [ElementGraphBuilder] currently |
| 85 /// found. | 82 /// found. |
| 86 /// | 83 /// |
| 87 /// Returns the new type for [analyzedElement]. | 84 /// Returns the new type for [analyzedElement]. |
| 88 TypeInformation addReturnTypeForMethod( | 85 TypeInformation addReturnTypeForMethod( |
| 89 FunctionEntity element, TypeInformation unused, TypeInformation newType); | 86 FunctionEntity element, TypeInformation unused, TypeInformation newType); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 void recordExposesThis(ConstructorEntity element, bool exposesThis); | 126 void recordExposesThis(ConstructorEntity element, bool exposesThis); |
| 130 | 127 |
| 131 /// Records that the return type [element] is of type [type]. | 128 /// Records that the return type [element] is of type [type]. |
| 132 void recordReturnType(FunctionEntity element, TypeInformation type); | 129 void recordReturnType(FunctionEntity element, TypeInformation type); |
| 133 | 130 |
| 134 /// Records that [element] is of type [type]. | 131 /// Records that [element] is of type [type]. |
| 135 void recordTypeOfField(FieldEntity element, TypeInformation type); | 132 void recordTypeOfField(FieldEntity element, TypeInformation type); |
| 136 | 133 |
| 137 /// Registers a call to await with an expression of type [argumentType] as | 134 /// Registers a call to await with an expression of type [argumentType] as |
| 138 /// argument. | 135 /// argument. |
| 139 TypeInformation registerAwait(ast.Node node, TypeInformation argument); | 136 TypeInformation registerAwait(T node, TypeInformation argument); |
| 140 | 137 |
| 141 /// Registers a call to yield with an expression of type [argumentType] as | 138 /// Registers a call to yield with an expression of type [argumentType] as |
| 142 /// argument. | 139 /// argument. |
| 143 TypeInformation registerYield(ast.Node node, TypeInformation argument); | 140 TypeInformation registerYield(T node, TypeInformation argument); |
| 144 | 141 |
| 145 /// Registers that [caller] calls [closure] with [arguments]. | 142 /// Registers that [caller] calls [closure] with [arguments]. |
| 146 /// | 143 /// |
| 147 /// [sideEffects] will be updated to incorporate the potential callees' side | 144 /// [sideEffects] will be updated to incorporate the potential callees' side |
| 148 /// effects. | 145 /// effects. |
| 149 /// | 146 /// |
| 150 /// [inLoop] tells whether the call happens in a loop. | 147 /// [inLoop] tells whether the call happens in a loop. |
| 151 TypeInformation registerCalledClosure( | 148 TypeInformation registerCalledClosure( |
| 152 ast.Node node, | 149 T node, |
| 153 Selector selector, | 150 Selector selector, |
| 154 TypeMask mask, | 151 TypeMask mask, |
| 155 TypeInformation closure, | 152 TypeInformation closure, |
| 156 MemberEntity caller, | 153 MemberEntity caller, |
| 157 ArgumentsTypes arguments, | 154 ArgumentsTypes arguments, |
| 158 SideEffects sideEffects, | 155 SideEffects sideEffects, |
| 159 bool inLoop); | 156 bool inLoop); |
| 160 | 157 |
| 161 /// Registers that [caller] calls [callee] at location [node], with | 158 /// Registers that [caller] calls [callee] at location [node], with |
| 162 /// [selector], and [arguments]. Note that [selector] is null for forwarding | 159 /// [selector], and [arguments]. Note that [selector] is null for forwarding |
| (...skipping 14 matching lines...) Expand all Loading... |
| 177 | 174 |
| 178 /// Registers that [caller] calls [selector] with [receiverType] as receiver, | 175 /// Registers that [caller] calls [selector] with [receiverType] as receiver, |
| 179 /// and [arguments]. | 176 /// and [arguments]. |
| 180 /// | 177 /// |
| 181 /// [sideEffects] will be updated to incorporate the potential callees' side | 178 /// [sideEffects] will be updated to incorporate the potential callees' side |
| 182 /// effects. | 179 /// effects. |
| 183 /// | 180 /// |
| 184 /// [inLoop] tells whether the call happens in a loop. | 181 /// [inLoop] tells whether the call happens in a loop. |
| 185 TypeInformation registerCalledSelector( | 182 TypeInformation registerCalledSelector( |
| 186 CallType callType, | 183 CallType callType, |
| 187 ast.Node node, | 184 T node, |
| 188 Selector selector, | 185 Selector selector, |
| 189 TypeMask mask, | 186 TypeMask mask, |
| 190 TypeInformation receiverType, | 187 TypeInformation receiverType, |
| 191 MemberEntity caller, | 188 MemberEntity caller, |
| 192 ArgumentsTypes arguments, | 189 ArgumentsTypes arguments, |
| 193 SideEffects sideEffects, | 190 SideEffects sideEffects, |
| 194 bool inLoop, | 191 bool inLoop, |
| 195 bool isConditional); | 192 bool isConditional); |
| 196 | 193 |
| 197 /// Update the assignments to parameters in the graph. [remove] tells whether | 194 /// Update the assignments to parameters in the graph. [remove] tells whether |
| 198 /// assignments must be added or removed. If [init] is false, parameters are | 195 /// assignments must be added or removed. If [init] is false, parameters are |
| 199 /// added to the work queue. | 196 /// added to the work queue. |
| 200 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, | 197 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, |
| 201 ArgumentsTypes arguments, Selector selector, TypeMask mask, | 198 ArgumentsTypes arguments, Selector selector, TypeMask mask, |
| 202 {bool remove, bool addToQueue: true}); | 199 {bool remove, bool addToQueue: true}); |
| 203 | 200 |
| 204 void updateSelectorInMember(MemberEntity owner, CallType callType, | 201 void updateSelectorInMember(MemberEntity owner, CallType callType, T node, |
| 205 ast.Node node, Selector selector, TypeMask mask); | 202 Selector selector, TypeMask mask); |
| 206 | 203 |
| 207 /// Returns the return type of [element]. | 204 /// Returns the return type of [element]. |
| 208 TypeInformation returnTypeOfMember(MemberEntity element); | 205 TypeInformation returnTypeOfMember(MemberEntity element); |
| 209 | 206 |
| 210 /// Returns the type of [element] when being called with [selector]. | 207 /// Returns the type of [element] when being called with [selector]. |
| 211 TypeInformation typeOfMemberWithSelector( | 208 TypeInformation typeOfMemberWithSelector( |
| 212 MemberEntity element, Selector selector); | 209 MemberEntity element, Selector selector); |
| 213 | 210 |
| 214 /// Returns the type of [element]. | 211 /// Returns the type of [element]. |
| 215 TypeInformation typeOfMember(MemberEntity element); | 212 TypeInformation typeOfMember(MemberEntity element); |
| 216 | 213 |
| 217 /// Returns the type of [element]. | 214 /// Returns the type of [element]. |
| 218 TypeInformation typeOfParameter(Local element); | 215 TypeInformation typeOfParameter(Local element); |
| 219 | 216 |
| 220 /// Returns the type for [nativeBehavior]. See documentation on | 217 /// Returns the type for [nativeBehavior]. See documentation on |
| 221 /// [native.NativeBehavior]. | 218 /// [native.NativeBehavior]. |
| 222 TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior); | 219 TypeInformation typeOfNativeBehavior(native.NativeBehavior nativeBehavior); |
| 223 | 220 |
| 224 bool returnsListElementType(Selector selector, TypeMask mask); | 221 bool returnsListElementType(Selector selector, TypeMask mask); |
| 225 | 222 |
| 226 bool returnsMapValueType(Selector selector, TypeMask mask); | 223 bool returnsMapValueType(Selector selector, TypeMask mask); |
| 227 | 224 |
| 228 void clear(); | 225 void clear(); |
| 229 } | 226 } |
| 230 | 227 |
| 231 class InferrerEngineImpl extends InferrerEngine { | 228 abstract class InferrerEngineImpl<T> extends InferrerEngine<T> { |
| 232 final Map<Local, TypeInformation> defaultTypeOfParameter = | 229 final Map<Local, TypeInformation> defaultTypeOfParameter = |
| 233 new Map<Local, TypeInformation>(); | 230 new Map<Local, TypeInformation>(); |
| 234 final WorkQueue workQueue = new WorkQueue(); | 231 final WorkQueue workQueue = new WorkQueue(); |
| 235 final FunctionEntity mainElement; | 232 final FunctionEntity mainElement; |
| 236 final Set<MemberEntity> analyzedElements = new Set<MemberEntity>(); | 233 final Set<MemberEntity> analyzedElements = new Set<MemberEntity>(); |
| 237 | 234 |
| 238 /// The maximum number of times we allow a node in the graph to | 235 /// The maximum number of times we allow a node in the graph to |
| 239 /// change types. If a node reaches that limit, we give up | 236 /// change types. If a node reaches that limit, we give up |
| 240 /// inferencing on it and give it the dynamic type. | 237 /// inferencing on it and give it the dynamic type. |
| 241 final int MAX_CHANGE_COUNT = 6; | 238 final int MAX_CHANGE_COUNT = 6; |
| 242 | 239 |
| 243 int overallRefineCount = 0; | 240 int overallRefineCount = 0; |
| 244 int addedInGraph = 0; | 241 int addedInGraph = 0; |
| 245 | 242 |
| 246 final Compiler compiler; | 243 final Compiler compiler; |
| 247 | 244 |
| 248 /// The [ClosedWorld] on which inference reasoning is based. | 245 /// The [ClosedWorld] on which inference reasoning is based. |
| 249 final ClosedWorld closedWorld; | 246 final ClosedWorld closedWorld; |
| 250 | 247 |
| 251 final ClosedWorldRefiner closedWorldRefiner; | 248 final ClosedWorldRefiner closedWorldRefiner; |
| 252 final TypeSystem<ast.Node> types; | 249 final TypeSystem<T> types; |
| 253 final Map<ast.Node, TypeInformation> concreteTypes = | 250 final Map<T, TypeInformation> concreteTypes = new Map<T, TypeInformation>(); |
| 254 new Map<ast.Node, TypeInformation>(); | |
| 255 | 251 |
| 256 final Map<ir.Node, TypeInformation> concreteKernelTypes = | 252 final Map<ir.Node, TypeInformation> concreteKernelTypes = |
| 257 new Map<ir.Node, TypeInformation>(); | 253 new Map<ir.Node, TypeInformation>(); |
| 258 final Set<ConstructorEntity> generativeConstructorsExposingThis = | 254 final Set<ConstructorEntity> generativeConstructorsExposingThis = |
| 259 new Set<ConstructorEntity>(); | 255 new Set<ConstructorEntity>(); |
| 260 | 256 |
| 261 /// Data computed internally within elements, like the type-mask of a send a | 257 /// Data computed internally within elements, like the type-mask of a send a |
| 262 /// list allocation, or a for-in loop. | 258 /// list allocation, or a for-in loop. |
| 263 final Map<MemberEntity, GlobalTypeInferenceElementData> _memberData = | 259 final Map<MemberEntity, GlobalTypeInferenceElementData> _memberData = |
| 264 new Map<MemberEntity, GlobalTypeInferenceElementData>(); | 260 new Map<MemberEntity, GlobalTypeInferenceElementData>(); |
| 265 | 261 |
| 266 InferrerEngineImpl(this.compiler, ClosedWorld closedWorld, | 262 InferrerEngineImpl( |
| 267 this.closedWorldRefiner, this.mainElement) | 263 this.compiler, |
| 268 : this.types = new TypeSystem<ast.Node>( | 264 ClosedWorld closedWorld, |
| 269 closedWorld, const TypeSystemStrategyImpl()), | 265 this.closedWorldRefiner, |
| 266 this.mainElement, |
| 267 TypeSystemStrategy<T> typeSystemStrategy) |
| 268 : this.types = new TypeSystem<T>(closedWorld, typeSystemStrategy), |
| 270 this.closedWorld = closedWorld; | 269 this.closedWorld = closedWorld; |
| 271 | 270 |
| 272 void forEachElementMatching( | 271 void forEachElementMatching( |
| 273 Selector selector, TypeMask mask, bool f(MemberEntity element)) { | 272 Selector selector, TypeMask mask, bool f(MemberEntity element)) { |
| 274 Iterable<MemberEntity> elements = closedWorld.locateMembers(selector, mask); | 273 Iterable<MemberEntity> elements = closedWorld.locateMembers(selector, mask); |
| 275 for (MemberEntity e in elements) { | 274 for (MemberEntity e in elements) { |
| 276 if (!f(e)) return; | 275 if (!f(e)) return; |
| 277 } | 276 } |
| 278 } | 277 } |
| 279 | 278 |
| 279 GlobalTypeInferenceElementData<T> createElementData(); |
| 280 |
| 280 // TODO(johnniwinther): Make this private again. | 281 // TODO(johnniwinther): Make this private again. |
| 281 GlobalTypeInferenceElementData dataOfMember(MemberEntity element) => | 282 GlobalTypeInferenceElementData<T> dataOfMember(MemberEntity element) => |
| 282 _memberData.putIfAbsent( | 283 _memberData.putIfAbsent(element, createElementData); |
| 283 element, () => new GlobalTypeInferenceElementData()); | |
| 284 | 284 |
| 285 GlobalTypeInferenceElementData lookupDataOfMember(MemberEntity element) => | 285 GlobalTypeInferenceElementData<T> lookupDataOfMember(MemberEntity element) => |
| 286 _memberData[element]; | 286 _memberData[element]; |
| 287 | 287 |
| 288 /** | 288 /** |
| 289 * Update [sideEffects] with the side effects of [callee] being | 289 * Update [sideEffects] with the side effects of [callee] being |
| 290 * called with [selector]. | 290 * called with [selector]. |
| 291 */ | 291 */ |
| 292 void updateSideEffects( | 292 void updateSideEffects( |
| 293 SideEffects sideEffects, Selector selector, MemberEntity callee) { | 293 SideEffects sideEffects, Selector selector, MemberEntity callee) { |
| 294 assert(!(callee is MemberElement && !callee.isDeclaration)); | 294 assert(!(callee is MemberElement && !callee.isDeclaration)); |
| 295 if (callee.isField) { | 295 if (callee.isField) { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 351 mappedType = types.nonNullSubtype(type.element); | 351 mappedType = types.nonNullSubtype(type.element); |
| 352 } | 352 } |
| 353 returnType = types.computeLUB(returnType, mappedType); | 353 returnType = types.computeLUB(returnType, mappedType); |
| 354 if (returnType == types.dynamicType) { | 354 if (returnType == types.dynamicType) { |
| 355 break; | 355 break; |
| 356 } | 356 } |
| 357 } | 357 } |
| 358 return returnType; | 358 return returnType; |
| 359 } | 359 } |
| 360 | 360 |
| 361 void updateSelectorInMember(MemberEntity owner, CallType callType, | 361 void updateSelectorInMember(MemberEntity owner, CallType callType, T node, |
| 362 ast.Node node, Selector selector, TypeMask mask) { | 362 Selector selector, TypeMask mask) { |
| 363 GlobalTypeInferenceElementData data = dataOfMember(owner); | 363 GlobalTypeInferenceElementData data = dataOfMember(owner); |
| 364 assert(validCallType(callType, node)); | 364 assert(validCallType(callType, node)); |
| 365 switch (callType) { | 365 switch (callType) { |
| 366 case CallType.complex: | 366 case CallType.complex: |
| 367 if (selector.isSetter || selector.isIndexSet) { | 367 if (selector.isSetter || selector.isIndexSet) { |
| 368 data.setTypeMask(node, mask); | 368 data.setTypeMask(node, mask); |
| 369 } else if (selector.isGetter || selector.isIndex) { | 369 } else if (selector.isGetter || selector.isIndex) { |
| 370 data.setGetterTypeMaskInComplexSendSet(node, mask); | 370 data.setGetterTypeMaskInComplexSendSet(node, mask); |
| 371 } else { | 371 } else { |
| 372 assert(selector.isOperator); | 372 assert(selector.isOperator); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 workQueue.addAll(info.addMapAssignment(map)); | 449 workQueue.addAll(info.addMapAssignment(map)); |
| 450 } | 450 } |
| 451 | 451 |
| 452 info.markAsInferred(); | 452 info.markAsInferred(); |
| 453 workQueue.add(info.keyType); | 453 workQueue.add(info.keyType); |
| 454 workQueue.add(info.valueType); | 454 workQueue.add(info.valueType); |
| 455 workQueue.addAll(info.typeInfoMap.values); | 455 workQueue.addAll(info.typeInfoMap.values); |
| 456 workQueue.add(info); | 456 workQueue.add(info); |
| 457 } | 457 } |
| 458 | 458 |
| 459 void runOverAllElements() { | 459 void runOverAllElements(); |
| 460 if (compiler.disableTypeInference) return; | |
| 461 if (compiler.options.verbose) { | |
| 462 compiler.progress.reset(); | |
| 463 } | |
| 464 sortResolvedAsts().forEach((ResolvedAst resolvedAst) { | |
| 465 if (compiler.shouldPrintProgress) { | |
| 466 reporter.log('Added $addedInGraph elements in inferencing graph.'); | |
| 467 compiler.progress.reset(); | |
| 468 } | |
| 469 // This also forces the creation of the [ElementTypeInformation] to ensure | |
| 470 // it is in the graph. | |
| 471 MemberElement member = resolvedAst.element; | |
| 472 types.withMember(member, () => analyze(resolvedAst, null)); | |
| 473 }); | |
| 474 reporter.log('Added $addedInGraph elements in inferencing graph.'); | |
| 475 | 460 |
| 476 TypeGraphDump dump = debug.PRINT_GRAPH ? new TypeGraphDump(this) : null; | 461 void analyze(MemberEntity element, T body, ArgumentsTypes arguments); |
| 477 | |
| 478 dump?.beforeAnalysis(); | |
| 479 buildWorkQueue(); | |
| 480 refine(); | |
| 481 | |
| 482 // Try to infer element types of lists and compute their escape information. | |
| 483 types.allocatedLists.values.forEach((TypeInformation info) { | |
| 484 analyzeListAndEnqueue(info); | |
| 485 }); | |
| 486 | |
| 487 // Try to infer the key and value types for maps and compute the values' | |
| 488 // escape information. | |
| 489 types.allocatedMaps.values.forEach((TypeInformation info) { | |
| 490 analyzeMapAndEnqueue(info); | |
| 491 }); | |
| 492 | |
| 493 Set<FunctionEntity> bailedOutOn = new Set<FunctionEntity>(); | |
| 494 | |
| 495 // Trace closures to potentially infer argument types. | |
| 496 types.allocatedClosures.forEach((dynamic info) { | |
| 497 void trace( | |
| 498 Iterable<FunctionEntity> elements, ClosureTracerVisitor tracer) { | |
| 499 tracer.run(); | |
| 500 if (!tracer.continueAnalyzing) { | |
| 501 elements.forEach((FunctionEntity _element) { | |
| 502 MethodElement element = _element; | |
| 503 MethodElement implementation = element.implementation; | |
| 504 closedWorldRefiner.registerMightBePassedToApply(element); | |
| 505 if (debug.VERBOSE) { | |
| 506 print("traced closure $element as ${true} (bail)"); | |
| 507 } | |
| 508 implementation.functionSignature | |
| 509 .forEachParameter((FormalElement _parameter) { | |
| 510 ParameterElement parameter = _parameter; | |
| 511 types | |
| 512 .getInferredTypeOfParameter(parameter) | |
| 513 .giveUp(this, clearAssignments: false); | |
| 514 }); | |
| 515 }); | |
| 516 bailedOutOn.addAll(elements); | |
| 517 return; | |
| 518 } | |
| 519 elements | |
| 520 .where((e) => !bailedOutOn.contains(e)) | |
| 521 .forEach((FunctionEntity _element) { | |
| 522 MethodElement element = _element; | |
| 523 MethodElement implementation = element.implementation; | |
| 524 implementation.functionSignature | |
| 525 .forEachParameter((FormalElement _parameter) { | |
| 526 ParameterElement parameter = _parameter; | |
| 527 ParameterTypeInformation info = | |
| 528 types.getInferredTypeOfParameter(parameter); | |
| 529 info.maybeResume(); | |
| 530 workQueue.add(info); | |
| 531 }); | |
| 532 if (tracer.tracedType.mightBePassedToFunctionApply) { | |
| 533 closedWorldRefiner.registerMightBePassedToApply(element); | |
| 534 } | |
| 535 if (debug.VERBOSE) { | |
| 536 print("traced closure $element as " | |
| 537 "${closedWorldRefiner | |
| 538 .getCurrentlyKnownMightBePassedToApply(element)}"); | |
| 539 } | |
| 540 }); | |
| 541 } | |
| 542 | |
| 543 if (info is ClosureTypeInformation) { | |
| 544 Iterable<FunctionEntity> elements = [info.closure]; | |
| 545 trace(elements, new ClosureTracerVisitor(elements, info, this)); | |
| 546 } else if (info is CallSiteTypeInformation) { | |
| 547 if (info is StaticCallSiteTypeInformation && | |
| 548 info.selector != null && | |
| 549 info.selector.isCall) { | |
| 550 // This is a constructor call to a class with a call method. So we | |
| 551 // need to trace the call method here. | |
| 552 MethodElement calledElement = info.calledElement; | |
| 553 assert(calledElement.isGenerativeConstructor); | |
| 554 ClassElement cls = calledElement.enclosingClass; | |
| 555 MethodElement callMethod = cls.lookupMember(Identifiers.call); | |
| 556 if (callMethod == null) { | |
| 557 callMethod = cls.lookupMember(Identifiers.noSuchMethod_); | |
| 558 } | |
| 559 assert(callMethod != null, failedAt(cls)); | |
| 560 Iterable<FunctionEntity> elements = [callMethod]; | |
| 561 trace(elements, new ClosureTracerVisitor(elements, info, this)); | |
| 562 } else { | |
| 563 // We only are interested in functions here, as other targets | |
| 564 // of this closure call are not a root to trace but an intermediate | |
| 565 // for some other function. | |
| 566 Iterable<FunctionEntity> elements = new List<FunctionEntity>.from( | |
| 567 info.callees.where((e) => e.isFunction)); | |
| 568 trace(elements, new ClosureTracerVisitor(elements, info, this)); | |
| 569 } | |
| 570 } else if (info is MemberTypeInformation) { | |
| 571 trace(<FunctionEntity>[info.member], | |
| 572 new StaticTearOffClosureTracerVisitor(info.member, info, this)); | |
| 573 } else if (info is ParameterTypeInformation) { | |
| 574 failedAt( | |
| 575 NO_LOCATION_SPANNABLE, 'Unexpected closure allocation info $info'); | |
| 576 } | |
| 577 }); | |
| 578 | |
| 579 dump?.beforeTracing(); | |
| 580 | |
| 581 // Reset all nodes that use lists/maps that have been inferred, as well | |
| 582 // as nodes that use elements fetched from these lists/maps. The | |
| 583 // workset for a new run of the analysis will be these nodes. | |
| 584 Set<TypeInformation> seenTypes = new Set<TypeInformation>(); | |
| 585 while (!workQueue.isEmpty) { | |
| 586 TypeInformation info = workQueue.remove(); | |
| 587 if (seenTypes.contains(info)) continue; | |
| 588 // If the node cannot be reset, we do not need to update its users either. | |
| 589 if (!info.reset(this)) continue; | |
| 590 seenTypes.add(info); | |
| 591 workQueue.addAll(info.users); | |
| 592 } | |
| 593 | |
| 594 workQueue.addAll(seenTypes); | |
| 595 refine(); | |
| 596 | |
| 597 if (debug.PRINT_SUMMARY) { | |
| 598 types.allocatedLists.values.forEach((_info) { | |
| 599 ListTypeInformation info = _info; | |
| 600 print('${info.type} ' | |
| 601 'for ${info.originalType.allocationNode} ' | |
| 602 'at ${info.originalType.allocationElement} ' | |
| 603 'after ${info.refineCount}'); | |
| 604 }); | |
| 605 types.allocatedMaps.values.forEach((_info) { | |
| 606 MapTypeInformation info = _info; | |
| 607 print('${info.type} ' | |
| 608 'for ${info.originalType.allocationNode} ' | |
| 609 'at ${info.originalType.allocationElement} ' | |
| 610 'after ${info.refineCount}'); | |
| 611 }); | |
| 612 types.allocatedClosures.forEach((TypeInformation info) { | |
| 613 if (info is ElementTypeInformation) { | |
| 614 print('${info.getInferredSignature(types)} for ' | |
| 615 '${info.debugName}'); | |
| 616 } else if (info is ClosureTypeInformation) { | |
| 617 print('${info.getInferredSignature(types)} for ' | |
| 618 '${info.debugName}'); | |
| 619 } else if (info is DynamicCallSiteTypeInformation) { | |
| 620 for (MemberEntity target in info.targets) { | |
| 621 if (target is FunctionEntity) { | |
| 622 print( | |
| 623 '${types.getInferredSignatureOfMethod(target)} for ${target}')
; | |
| 624 } else { | |
| 625 print( | |
| 626 '${types.getInferredTypeOfMember(target).type} for ${target}')
; | |
| 627 } | |
| 628 } | |
| 629 } else if (info is StaticCallSiteTypeInformation) { | |
| 630 ClassElement cls = info.calledElement.enclosingClass; | |
| 631 MethodElement callMethod = cls.lookupMember(Identifiers.call); | |
| 632 print('${types.getInferredSignatureOfMethod(callMethod)} for ${cls}'); | |
| 633 } else { | |
| 634 print('${info.type} for some unknown kind of closure'); | |
| 635 } | |
| 636 }); | |
| 637 analyzedElements.forEach((MemberEntity elem) { | |
| 638 TypeInformation type = types.getInferredTypeOfMember(elem); | |
| 639 print('${elem} :: ${type} from ${type.assignments} '); | |
| 640 }); | |
| 641 } | |
| 642 dump?.afterAnalysis(); | |
| 643 | |
| 644 reporter.log('Inferred $overallRefineCount types.'); | |
| 645 | |
| 646 processLoopInformation(); | |
| 647 } | |
| 648 | |
| 649 void analyze(ResolvedAst resolvedAst, ArgumentsTypes arguments) { | |
| 650 MemberElement element = resolvedAst.element; | |
| 651 if (analyzedElements.contains(element)) return; | |
| 652 analyzedElements.add(element); | |
| 653 | |
| 654 dynamic visitor = compiler.options.kernelGlobalInference | |
| 655 ? new KernelTypeGraphBuilder(element, resolvedAst, compiler, this) | |
| 656 : new ElementGraphBuilder(element, resolvedAst, compiler, this); | |
| 657 TypeInformation type; | |
| 658 reporter.withCurrentElement(element, () { | |
| 659 // ignore: UNDEFINED_METHOD | |
| 660 type = visitor.run(); | |
| 661 }); | |
| 662 addedInGraph++; | |
| 663 | |
| 664 if (element.isField) { | |
| 665 FieldElement field = element; | |
| 666 ast.Node initializer = resolvedAst.body; | |
| 667 if (field.isFinal || field.isConst) { | |
| 668 // If [element] is final and has an initializer, we record | |
| 669 // the inferred type. | |
| 670 if (resolvedAst.body != null) { | |
| 671 if (type is! ListTypeInformation && type is! MapTypeInformation) { | |
| 672 // For non-container types, the constant handler does | |
| 673 // constant folding that could give more precise results. | |
| 674 ConstantExpression constant = field.constant; | |
| 675 if (constant != null) { | |
| 676 ConstantValue value = | |
| 677 compiler.backend.constants.getConstantValue(constant); | |
| 678 if (value != null) { | |
| 679 if (value.isFunction) { | |
| 680 FunctionConstantValue functionConstant = value; | |
| 681 MethodElement function = functionConstant.element; | |
| 682 type = types.allocateClosure(function); | |
| 683 } else { | |
| 684 // Although we might find a better type, we have to keep | |
| 685 // the old type around to ensure that we get a complete view | |
| 686 // of the type graph and do not drop any flow edges. | |
| 687 TypeMask refinedType = computeTypeMask(closedWorld, value); | |
| 688 assert(TypeMask.assertIsNormalized(refinedType, closedWorld)); | |
| 689 type = new NarrowTypeInformation(type, refinedType); | |
| 690 types.allocatedTypes.add(type); | |
| 691 } | |
| 692 } else { | |
| 693 assert( | |
| 694 field.isInstanceMember || | |
| 695 constant.isImplicit || | |
| 696 constant.isPotential, | |
| 697 failedAt( | |
| 698 field, | |
| 699 "Constant expression without value: " | |
| 700 "${constant.toStructuredText()}.")); | |
| 701 } | |
| 702 } | |
| 703 } | |
| 704 recordTypeOfField(field, type); | |
| 705 } else if (!element.isInstanceMember) { | |
| 706 recordTypeOfField(field, types.nullType); | |
| 707 } | |
| 708 } else if (initializer == null) { | |
| 709 // Only update types of static fields if there is no | |
| 710 // assignment. Instance fields are dealt with in the constructor. | |
| 711 if (Elements.isStaticOrTopLevelField(element)) { | |
| 712 recordTypeOfField(field, type); | |
| 713 } | |
| 714 } else { | |
| 715 recordTypeOfField(field, type); | |
| 716 } | |
| 717 if (Elements.isStaticOrTopLevelField(field) && | |
| 718 resolvedAst.body != null && | |
| 719 !element.isConst) { | |
| 720 dynamic argument = resolvedAst.body; | |
| 721 // TODO(13429): We could do better here by using the | |
| 722 // constant handler to figure out if it's a lazy field or not. | |
| 723 if (argument.asSend() != null || | |
| 724 (argument.asNewExpression() != null && !argument.isConst)) { | |
| 725 recordTypeOfField(field, types.nullType); | |
| 726 } | |
| 727 } | |
| 728 } else { | |
| 729 MethodElement method = element; | |
| 730 recordReturnType(method, type); | |
| 731 } | |
| 732 } | |
| 733 | 462 |
| 734 void processLoopInformation() { | 463 void processLoopInformation() { |
| 735 types.allocatedCalls.forEach((dynamic info) { | 464 types.allocatedCalls.forEach((dynamic info) { |
| 736 if (!info.inLoop) return; | 465 if (!info.inLoop) return; |
| 737 if (info is StaticCallSiteTypeInformation) { | 466 if (info is StaticCallSiteTypeInformation) { |
| 738 MemberEntity member = info.calledElement; | 467 MemberEntity member = info.calledElement; |
| 739 closedWorldRefiner.addFunctionCalledInLoop(member); | 468 closedWorldRefiner.addFunctionCalledInLoop(member); |
| 740 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) { | 469 } else if (info.mask != null && !info.mask.containsAll(closedWorld)) { |
| 741 // For instance methods, we only register a selector called in a | 470 // For instance methods, we only register a selector called in a |
| 742 // loop if it is a typed selector, to avoid marking too many | 471 // loop if it is a typed selector, to avoid marking too many |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 | 511 |
| 783 void buildWorkQueue() { | 512 void buildWorkQueue() { |
| 784 workQueue.addAll(types.orderedTypeInformations); | 513 workQueue.addAll(types.orderedTypeInformations); |
| 785 workQueue.addAll(types.allocatedTypes); | 514 workQueue.addAll(types.allocatedTypes); |
| 786 workQueue.addAll(types.allocatedClosures); | 515 workQueue.addAll(types.allocatedClosures); |
| 787 workQueue.addAll(types.allocatedCalls); | 516 workQueue.addAll(types.allocatedCalls); |
| 788 } | 517 } |
| 789 | 518 |
| 790 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, | 519 void updateParameterAssignments(TypeInformation caller, MemberEntity callee, |
| 791 ArgumentsTypes arguments, Selector selector, TypeMask mask, | 520 ArgumentsTypes arguments, Selector selector, TypeMask mask, |
| 792 {bool remove, bool addToQueue: true}) { | 521 {bool remove, bool addToQueue: true}); |
| 793 if (callee.name == Identifiers.noSuchMethod_) return; | |
| 794 if (callee.isField) { | |
| 795 if (selector.isSetter) { | |
| 796 ElementTypeInformation info = types.getInferredTypeOfMember(callee); | |
| 797 if (remove) { | |
| 798 info.removeAssignment(arguments.positional[0]); | |
| 799 } else { | |
| 800 info.addAssignment(arguments.positional[0]); | |
| 801 } | |
| 802 if (addToQueue) workQueue.add(info); | |
| 803 } | |
| 804 } else if (callee.isGetter) { | |
| 805 return; | |
| 806 } else if (selector != null && selector.isGetter) { | |
| 807 // We are tearing a function off and thus create a closure. | |
| 808 assert(callee.isFunction); | |
| 809 MethodElement method = callee; | |
| 810 MemberTypeInformation info = types.getInferredTypeOfMember(method); | |
| 811 if (remove) { | |
| 812 info.closurizedCount--; | |
| 813 } else { | |
| 814 info.closurizedCount++; | |
| 815 if (Elements.isStaticOrTopLevel(method)) { | |
| 816 types.allocatedClosures.add(info); | |
| 817 } else { | |
| 818 // We add the call-site type information here so that we | |
| 819 // can benefit from further refinement of the selector. | |
| 820 types.allocatedClosures.add(caller); | |
| 821 } | |
| 822 FunctionElement function = method.implementation; | |
| 823 FunctionSignature signature = function.functionSignature; | |
| 824 signature.forEachParameter((FormalElement _parameter) { | |
| 825 ParameterElement parameter = _parameter; | |
| 826 ParameterTypeInformation info = | |
| 827 types.getInferredTypeOfParameter(parameter); | |
| 828 info.tagAsTearOffClosureParameter(this); | |
| 829 if (addToQueue) workQueue.add(info); | |
| 830 }); | |
| 831 } | |
| 832 } else { | |
| 833 MethodElement method = callee; | |
| 834 FunctionElement function = method.implementation; | |
| 835 FunctionSignature signature = function.functionSignature; | |
| 836 int parameterIndex = 0; | |
| 837 bool visitingRequiredParameter = true; | |
| 838 signature.forEachParameter((FormalElement _parameter) { | |
| 839 ParameterElement parameter = _parameter; | |
| 840 if (signature.hasOptionalParameters && | |
| 841 parameter == signature.optionalParameters.first) { | |
| 842 visitingRequiredParameter = false; | |
| 843 } | |
| 844 TypeInformation type = visitingRequiredParameter | |
| 845 ? arguments.positional[parameterIndex] | |
| 846 : signature.optionalParametersAreNamed | |
| 847 ? arguments.named[parameter.name] | |
| 848 : parameterIndex < arguments.positional.length | |
| 849 ? arguments.positional[parameterIndex] | |
| 850 : null; | |
| 851 if (type == null) type = getDefaultTypeOfParameter(parameter); | |
| 852 TypeInformation info = types.getInferredTypeOfParameter(parameter); | |
| 853 if (remove) { | |
| 854 info.removeAssignment(type); | |
| 855 } else { | |
| 856 info.addAssignment(type); | |
| 857 } | |
| 858 parameterIndex++; | |
| 859 if (addToQueue) workQueue.add(info); | |
| 860 }); | |
| 861 } | |
| 862 } | |
| 863 | 522 |
| 864 void setDefaultTypeOfParameter(Local parameter, TypeInformation type, | 523 void setDefaultTypeOfParameter(Local parameter, TypeInformation type, |
| 865 {bool isInstanceMember}) { | 524 {bool isInstanceMember}) { |
| 866 assert(!(parameter is ParameterElement && !parameter.isImplementation)); | 525 assert(!(parameter is ParameterElement && !parameter.isImplementation)); |
| 867 TypeInformation existing = defaultTypeOfParameter[parameter]; | 526 TypeInformation existing = defaultTypeOfParameter[parameter]; |
| 868 defaultTypeOfParameter[parameter] = type; | 527 defaultTypeOfParameter[parameter] = type; |
| 869 TypeInformation info = types.getInferredTypeOfParameter(parameter); | 528 TypeInformation info = types.getInferredTypeOfParameter(parameter); |
| 870 if (existing != null && existing is PlaceholderTypeInformation) { | 529 if (existing != null && existing is PlaceholderTypeInformation) { |
| 871 // Replace references to [existing] to use [type] instead. | 530 // Replace references to [existing] to use [type] instead. |
| 872 if (isInstanceMember) { | 531 if (isInstanceMember) { |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 975 } | 634 } |
| 976 } | 635 } |
| 977 info.addToGraph(this); | 636 info.addToGraph(this); |
| 978 types.allocatedCalls.add(info); | 637 types.allocatedCalls.add(info); |
| 979 updateSideEffects(sideEffects, selector, callee); | 638 updateSideEffects(sideEffects, selector, callee); |
| 980 return info; | 639 return info; |
| 981 } | 640 } |
| 982 | 641 |
| 983 TypeInformation registerCalledSelector( | 642 TypeInformation registerCalledSelector( |
| 984 CallType callType, | 643 CallType callType, |
| 985 ast.Node node, | 644 T node, |
| 986 Selector selector, | 645 Selector selector, |
| 987 TypeMask mask, | 646 TypeMask mask, |
| 988 TypeInformation receiverType, | 647 TypeInformation receiverType, |
| 989 MemberEntity caller, | 648 MemberEntity caller, |
| 990 ArgumentsTypes arguments, | 649 ArgumentsTypes arguments, |
| 991 SideEffects sideEffects, | 650 SideEffects sideEffects, |
| 992 bool inLoop, | 651 bool inLoop, |
| 993 bool isConditional) { | 652 bool isConditional) { |
| 994 if (selector.isClosureCall) { | 653 if (selector.isClosureCall) { |
| 995 return registerCalledClosure(node, selector, mask, receiverType, caller, | 654 return registerCalledClosure(node, selector, mask, receiverType, caller, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1010 receiverType, | 669 receiverType, |
| 1011 arguments, | 670 arguments, |
| 1012 inLoop, | 671 inLoop, |
| 1013 isConditional); | 672 isConditional); |
| 1014 | 673 |
| 1015 info.addToGraph(this); | 674 info.addToGraph(this); |
| 1016 types.allocatedCalls.add(info); | 675 types.allocatedCalls.add(info); |
| 1017 return info; | 676 return info; |
| 1018 } | 677 } |
| 1019 | 678 |
| 1020 TypeInformation registerAwait(ast.Node node, TypeInformation argument) { | 679 TypeInformation registerAwait(T node, TypeInformation argument) { |
| 1021 AwaitTypeInformation info = | 680 AwaitTypeInformation info = |
| 1022 new AwaitTypeInformation<ast.Node>(types.currentMember, node); | 681 new AwaitTypeInformation<T>(types.currentMember, node); |
| 1023 info.addAssignment(argument); | 682 info.addAssignment(argument); |
| 1024 types.allocatedTypes.add(info); | 683 types.allocatedTypes.add(info); |
| 1025 return info; | 684 return info; |
| 1026 } | 685 } |
| 1027 | 686 |
| 1028 TypeInformation registerYield(ast.Node node, TypeInformation argument) { | 687 TypeInformation registerYield(T node, TypeInformation argument) { |
| 1029 YieldTypeInformation info = | 688 YieldTypeInformation info = |
| 1030 new YieldTypeInformation<ast.Node>(types.currentMember, node); | 689 new YieldTypeInformation<T>(types.currentMember, node); |
| 1031 info.addAssignment(argument); | 690 info.addAssignment(argument); |
| 1032 types.allocatedTypes.add(info); | 691 types.allocatedTypes.add(info); |
| 1033 return info; | 692 return info; |
| 1034 } | 693 } |
| 1035 | 694 |
| 1036 TypeInformation registerCalledClosure( | 695 TypeInformation registerCalledClosure( |
| 1037 ast.Node node, | 696 T node, |
| 1038 Selector selector, | 697 Selector selector, |
| 1039 TypeMask mask, | 698 TypeMask mask, |
| 1040 TypeInformation closure, | 699 TypeInformation closure, |
| 1041 MemberEntity caller, | 700 MemberEntity caller, |
| 1042 ArgumentsTypes arguments, | 701 ArgumentsTypes arguments, |
| 1043 SideEffects sideEffects, | 702 SideEffects sideEffects, |
| 1044 bool inLoop) { | 703 bool inLoop) { |
| 1045 sideEffects.setDependsOnSomething(); | 704 sideEffects.setDependsOnSomething(); |
| 1046 sideEffects.setAllSideEffects(); | 705 sideEffects.setAllSideEffects(); |
| 1047 CallSiteTypeInformation info = new ClosureCallSiteTypeInformation( | 706 CallSiteTypeInformation info = new ClosureCallSiteTypeInformation( |
| 1048 types.currentMember, | 707 types.currentMember, |
| 1049 node, | 708 node, |
| 1050 caller, | 709 caller, |
| 1051 selector, | 710 selector, |
| 1052 mask, | 711 mask, |
| 1053 closure, | 712 closure, |
| 1054 arguments, | 713 arguments, |
| 1055 inLoop); | 714 inLoop); |
| 1056 info.addToGraph(this); | 715 info.addToGraph(this); |
| 1057 types.allocatedCalls.add(info); | 716 types.allocatedCalls.add(info); |
| 1058 return info; | 717 return info; |
| 1059 } | 718 } |
| 1060 | 719 |
| 1061 // Sorts the resolved elements by size. We do this for this inferrer | |
| 1062 // to get the same results for [ListTracer] compared to the | |
| 1063 // [SimpleTypesInferrer]. | |
| 1064 Iterable<ResolvedAst> sortResolvedAsts() { | |
| 1065 int max = 0; | |
| 1066 Map<int, Setlet<ResolvedAst>> methodSizes = <int, Setlet<ResolvedAst>>{}; | |
| 1067 compiler.enqueuer.resolution.processedEntities.forEach((_element) { | |
| 1068 MemberElement element = _element; | |
| 1069 ResolvedAst resolvedAst = element.resolvedAst; | |
| 1070 element = element.implementation; | |
| 1071 if (element.impliesType) return; | |
| 1072 assert( | |
| 1073 element.isField || | |
| 1074 element.isFunction || | |
| 1075 element.isConstructor || | |
| 1076 element.isGetter || | |
| 1077 element.isSetter, | |
| 1078 failedAt(element, 'Unexpected element kind: ${element.kind}')); | |
| 1079 if (element.isAbstract) return; | |
| 1080 // Put the other operators in buckets by length, later to be added in | |
| 1081 // length order. | |
| 1082 int length = 0; | |
| 1083 if (resolvedAst.kind == ResolvedAstKind.PARSED) { | |
| 1084 TreeElementMapping mapping = resolvedAst.elements; | |
| 1085 length = mapping.getSelectorCount(); | |
| 1086 } | |
| 1087 max = length > max ? length : max; | |
| 1088 Setlet<ResolvedAst> set = | |
| 1089 methodSizes.putIfAbsent(length, () => new Setlet<ResolvedAst>()); | |
| 1090 set.add(resolvedAst); | |
| 1091 }); | |
| 1092 | |
| 1093 List<ResolvedAst> result = <ResolvedAst>[]; | |
| 1094 for (int i = 0; i <= max; i++) { | |
| 1095 Setlet<ResolvedAst> set = methodSizes[i]; | |
| 1096 if (set != null) result.addAll(set); | |
| 1097 } | |
| 1098 return result; | |
| 1099 } | |
| 1100 | |
| 1101 void clear() { | 720 void clear() { |
| 1102 void cleanup(TypeInformation info) => info.cleanup(); | 721 void cleanup(TypeInformation info) => info.cleanup(); |
| 1103 | 722 |
| 1104 types.allocatedCalls.forEach(cleanup); | 723 types.allocatedCalls.forEach(cleanup); |
| 1105 types.allocatedCalls.clear(); | 724 types.allocatedCalls.clear(); |
| 1106 | 725 |
| 1107 defaultTypeOfParameter.clear(); | 726 defaultTypeOfParameter.clear(); |
| 1108 | 727 |
| 1109 types.parameterTypeInformations.values.forEach(cleanup); | 728 types.parameterTypeInformations.values.forEach(cleanup); |
| 1110 types.memberTypeInformations.values.forEach(cleanup); | 729 types.memberTypeInformations.values.forEach(cleanup); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1155 return returnTypeOfMember(element); | 774 return returnTypeOfMember(element); |
| 1156 } | 775 } |
| 1157 } else if (element.isGetter || element.isField) { | 776 } else if (element.isGetter || element.isField) { |
| 1158 assert(selector.isCall || selector.isSetter); | 777 assert(selector.isCall || selector.isSetter); |
| 1159 return types.dynamicType; | 778 return types.dynamicType; |
| 1160 } else { | 779 } else { |
| 1161 return returnTypeOfMember(element); | 780 return returnTypeOfMember(element); |
| 1162 } | 781 } |
| 1163 } | 782 } |
| 1164 } | 783 } |
| 1165 | |
| 1166 class TypeSystemStrategyImpl implements TypeSystemStrategy<ast.Node> { | |
| 1167 const TypeSystemStrategyImpl(); | |
| 1168 | |
| 1169 @override | |
| 1170 MemberTypeInformation createMemberTypeInformation( | |
| 1171 covariant MemberElement member) { | |
| 1172 assert(member.isDeclaration, failedAt(member)); | |
| 1173 if (member.isField) { | |
| 1174 FieldElement field = member; | |
| 1175 return new FieldTypeInformation(field, field.type); | |
| 1176 } else if (member.isGetter) { | |
| 1177 GetterElement getter = member; | |
| 1178 return new GetterTypeInformation(getter, getter.type); | |
| 1179 } else if (member.isSetter) { | |
| 1180 SetterElement setter = member; | |
| 1181 return new SetterTypeInformation(setter); | |
| 1182 } else if (member.isFunction) { | |
| 1183 MethodElement method = member; | |
| 1184 return new MethodTypeInformation(method, method.type); | |
| 1185 } else { | |
| 1186 ConstructorElement constructor = member; | |
| 1187 if (constructor.isFactoryConstructor) { | |
| 1188 return new FactoryConstructorTypeInformation( | |
| 1189 constructor, constructor.type); | |
| 1190 } else { | |
| 1191 return new GenerativeConstructorTypeInformation(constructor); | |
| 1192 } | |
| 1193 } | |
| 1194 } | |
| 1195 | |
| 1196 @override | |
| 1197 ParameterTypeInformation createParameterTypeInformation( | |
| 1198 covariant ParameterElement parameter, TypeSystem<ast.Node> types) { | |
| 1199 assert(parameter.isImplementation, failedAt(parameter)); | |
| 1200 FunctionTypedElement function = parameter.functionDeclaration.declaration; | |
| 1201 if (function.isLocal) { | |
| 1202 LocalFunctionElement localFunction = function; | |
| 1203 MethodElement callMethod = localFunction.callMethod; | |
| 1204 return new ParameterTypeInformation.localFunction( | |
| 1205 types.getInferredTypeOfMember(callMethod), | |
| 1206 parameter, | |
| 1207 parameter.type, | |
| 1208 callMethod); | |
| 1209 } else if (function.isInstanceMember) { | |
| 1210 MethodElement method = function; | |
| 1211 return new ParameterTypeInformation.instanceMember( | |
| 1212 types.getInferredTypeOfMember(method), | |
| 1213 parameter, | |
| 1214 parameter.type, | |
| 1215 method, | |
| 1216 new ParameterAssignments()); | |
| 1217 } else { | |
| 1218 MethodElement method = function; | |
| 1219 return new ParameterTypeInformation.static( | |
| 1220 types.getInferredTypeOfMember(method), | |
| 1221 parameter, | |
| 1222 parameter.type, | |
| 1223 method, | |
| 1224 // TODO(johnniwinther): Is this still valid now that initializing | |
| 1225 // formals also introduce locals? | |
| 1226 isInitializingFormal: parameter.isInitializingFormal); | |
| 1227 } | |
| 1228 } | |
| 1229 | |
| 1230 @override | |
| 1231 void forEachParameter( | |
| 1232 covariant MethodElement function, void f(Local parameter)) { | |
| 1233 MethodElement impl = function.implementation; | |
| 1234 FunctionSignature signature = impl.functionSignature; | |
| 1235 signature.forEachParameter((FormalElement _parameter) { | |
| 1236 ParameterElement parameter = _parameter; | |
| 1237 f(parameter); | |
| 1238 }); | |
| 1239 } | |
| 1240 | |
| 1241 @override | |
| 1242 bool checkMapNode(ast.Node node) { | |
| 1243 return node is ast.LiteralMap; | |
| 1244 } | |
| 1245 | |
| 1246 @override | |
| 1247 bool checkListNode(ast.Node node) { | |
| 1248 return node is ast.LiteralList || node is ast.Send; | |
| 1249 } | |
| 1250 | |
| 1251 @override | |
| 1252 bool checkLoopPhiNode(ast.Node node) { | |
| 1253 return node is ast.Loop || node is ast.SwitchStatement; | |
| 1254 } | |
| 1255 | |
| 1256 @override | |
| 1257 bool checkPhiNode(ast.Node node) { | |
| 1258 return true; | |
| 1259 } | |
| 1260 | |
| 1261 @override | |
| 1262 bool checkClassEntity(covariant ClassElement cls) { | |
| 1263 return cls.isDeclaration; | |
| 1264 } | |
| 1265 } | |
| OLD | NEW |