Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 dart2js.world; | 5 library dart2js.world; |
| 6 | 6 |
| 7 import 'closure.dart' show ClosureClassElement, SynthesizedCallMethodElementX; | 7 import 'closure.dart' show ClosureClassElement; |
| 8 import 'common.dart'; | 8 import 'common.dart'; |
| 9 import 'constants/constant_system.dart'; | 9 import 'constants/constant_system.dart'; |
| 10 import 'common_elements.dart' show CommonElements, ElementEnvironment; | 10 import 'common_elements.dart' show CommonElements, ElementEnvironment; |
| 11 import 'elements/entities.dart'; | 11 import 'elements/entities.dart'; |
| 12 import 'elements/elements.dart' | 12 import 'elements/elements.dart' |
| 13 show | 13 show |
| 14 ClassElement, | 14 ClassElement, |
| 15 Element, | 15 Element, |
| 16 MemberElement, | 16 MemberElement, |
| 17 MethodElement, | |
| 17 MixinApplicationElement, | 18 MixinApplicationElement, |
| 18 TypedefElement; | 19 TypedefElement; |
| 19 import 'elements/resolution_types.dart'; | 20 import 'elements/resolution_types.dart'; |
| 20 import 'elements/types.dart'; | 21 import 'elements/types.dart'; |
| 21 import 'js_backend/backend_usage.dart' show BackendUsage; | 22 import 'js_backend/backend_usage.dart' show BackendUsage; |
| 22 import 'js_backend/interceptor_data.dart' show InterceptorData; | 23 import 'js_backend/interceptor_data.dart' show InterceptorData; |
| 23 import 'js_backend/native_data.dart' show NativeData; | 24 import 'js_backend/native_data.dart' show NativeData; |
| 24 import 'ordered_typeset.dart'; | 25 import 'ordered_typeset.dart'; |
| 25 import 'types/masks.dart' show CommonMasks, FlatTypeMask, TypeMask; | 26 import 'types/masks.dart' show CommonMasks, FlatTypeMask, TypeMask; |
| 26 import 'universe/class_set.dart'; | 27 import 'universe/class_set.dart'; |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 304 /// Returns the single [MemberEntity] that matches a call to [selector] on a | 305 /// Returns the single [MemberEntity] that matches a call to [selector] on a |
| 305 /// receiver of type [mask]. If multiple targets exist, `null` is returned. | 306 /// receiver of type [mask]. If multiple targets exist, `null` is returned. |
| 306 MemberEntity locateSingleElement(Selector selector, TypeMask mask); | 307 MemberEntity locateSingleElement(Selector selector, TypeMask mask); |
| 307 | 308 |
| 308 /// Returns the single field that matches a call to [selector] on a | 309 /// Returns the single field that matches a call to [selector] on a |
| 309 /// receiver of type [mask]. If multiple targets exist or the single target | 310 /// receiver of type [mask]. If multiple targets exist or the single target |
| 310 /// is not a field, `null` is returned. | 311 /// is not a field, `null` is returned. |
| 311 FieldEntity locateSingleField(Selector selector, TypeMask mask); | 312 FieldEntity locateSingleField(Selector selector, TypeMask mask); |
| 312 | 313 |
| 313 /// Returns the side effects of executing [element]. | 314 /// Returns the side effects of executing [element]. |
| 314 SideEffects getSideEffectsOfElement(Entity element); | 315 SideEffects getSideEffectsOfElement(FunctionEntity element); |
| 315 | 316 |
| 316 /// Returns the side effects of calling [selector] on a receiver of type | 317 /// Returns the side effects of calling [selector] on a receiver of type |
| 317 /// [mask]. | 318 /// [mask]. |
| 318 SideEffects getSideEffectsOfSelector(Selector selector, TypeMask mask); | 319 SideEffects getSideEffectsOfSelector(Selector selector, TypeMask mask); |
| 319 | 320 |
| 320 /// Returns `true` if [element] is guaranteed not to throw an exception. | 321 /// Returns `true` if [element] is guaranteed not to throw an exception. |
| 321 bool getCannotThrow(Entity element); | 322 bool getCannotThrow(FunctionEntity element); |
| 322 | 323 |
| 323 /// Returns `true` if [element] is called in a loop. | 324 /// Returns `true` if [element] is called in a loop. |
| 324 // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? | 325 // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? |
| 325 bool isCalledInLoop(Entity element); | 326 // TODO(johnniwinther): Change [MemberEntity] to [FunctionEntity]. |
| 327 bool isCalledInLoop(MemberEntity element); | |
| 326 | 328 |
| 327 /// Returns `true` if [element] might be passed to `Function.apply`. | 329 /// Returns `true` if [element] might be passed to `Function.apply`. |
| 328 // TODO(johnniwinther): Is this 'passed invocation target` or | 330 // TODO(johnniwinther): Is this 'passed invocation target` or |
| 329 // `passed as argument`? | 331 // `passed as argument`? |
| 330 bool getMightBePassedToApply(Entity element); | 332 bool getMightBePassedToApply(FunctionEntity element); |
| 331 | 333 |
| 332 /// Returns a string representation of the closed world. | 334 /// Returns a string representation of the closed world. |
| 333 /// | 335 /// |
| 334 /// If [cls] is provided, the dump will contain only classes related to [cls]. | 336 /// If [cls] is provided, the dump will contain only classes related to [cls]. |
| 335 String dump([ClassEntity cls]); | 337 String dump([ClassEntity cls]); |
| 336 } | 338 } |
| 337 | 339 |
| 338 /// Interface for computing side effects and uses of elements. This is used | 340 /// Interface for computing side effects and uses of elements. This is used |
| 339 /// during type inference to compute the [ClosedWorld] for code generation. | 341 /// during type inference to compute the [ClosedWorld] for code generation. |
| 340 abstract class ClosedWorldRefiner { | 342 abstract class ClosedWorldRefiner { |
| 341 /// The closed world being refined. | 343 /// The closed world being refined. |
| 342 ClosedWorld get closedWorld; | 344 ClosedWorld get closedWorld; |
| 343 | 345 |
| 344 /// Registers the side [effects] of executing [element]. | 346 /// Registers the side [effects] of executing [element]. |
| 345 void registerSideEffects(Entity element, SideEffects effects); | 347 void registerSideEffects(FunctionEntity element, SideEffects effects); |
| 346 | 348 |
| 347 /// Registers the executing of [element] as without side effects. | 349 /// Registers the executing of [element] as without side effects. |
| 348 void registerSideEffectsFree(Entity element); | 350 void registerSideEffectsFree(FunctionEntity element); |
| 349 | 351 |
| 350 /// Returns the currently known side effects of executing [element]. | 352 /// Returns the currently known side effects of executing [element]. |
| 351 SideEffects getCurrentlyKnownSideEffects(Entity element); | 353 SideEffects getCurrentlyKnownSideEffects(FunctionEntity element); |
| 352 | 354 |
| 353 /// Registers that [element] might be passed to `Function.apply`. | 355 /// Registers that [element] might be passed to `Function.apply`. |
| 354 // TODO(johnniwinther): Is this 'passed invocation target` or | 356 // TODO(johnniwinther): Is this 'passed invocation target` or |
| 355 // `passed as argument`? | 357 // `passed as argument`? |
| 356 void registerMightBePassedToApply(Entity element); | 358 void registerMightBePassedToApply(FunctionEntity element); |
| 357 | 359 |
| 358 /// Returns `true` if [element] might be passed to `Function.apply` given the | 360 /// Returns `true` if [element] might be passed to `Function.apply` given the |
| 359 /// currently inferred information. | 361 /// currently inferred information. |
| 360 bool getCurrentlyKnownMightBePassedToApply(Entity element); | 362 bool getCurrentlyKnownMightBePassedToApply(FunctionEntity element); |
| 361 | 363 |
| 362 /// Registers that [element] is called in a loop. | 364 /// Registers that [element] is called in a loop. |
| 363 // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? | 365 // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? |
| 364 void addFunctionCalledInLoop(Entity element); | 366 void addFunctionCalledInLoop(MemberEntity element); |
| 365 | 367 |
| 366 /// Registers that [element] is guaranteed not to throw an exception. | 368 /// Registers that [element] is guaranteed not to throw an exception. |
| 367 void registerCannotThrow(Entity element); | 369 void registerCannotThrow(FunctionEntity element); |
| 368 | 370 |
| 369 /// Adds the closure class [cls] to the inference world. The class is | 371 /// Adds the closure class [cls] to the inference world. The class is |
| 370 /// considered directly instantiated. | 372 /// considered directly instantiated. |
| 371 void registerClosureClass(covariant ClassElement cls); | 373 void registerClosureClass(covariant ClassElement cls); |
| 372 } | 374 } |
| 373 | 375 |
| 374 abstract class OpenWorld implements World { | 376 abstract class OpenWorld implements World { |
| 375 /// Called to add [cls] to the set of known classes. | 377 /// Called to add [cls] to the set of known classes. |
| 376 /// | 378 /// |
| 377 /// This ensures that class hierarchy queries can be performed on [cls] and | 379 /// This ensures that class hierarchy queries can be performed on [cls] and |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 416 final Map<ClassEntity, Set<ClassEntity>> _typesImplementedBySubclasses; | 418 final Map<ClassEntity, Set<ClassEntity>> _typesImplementedBySubclasses; |
| 417 | 419 |
| 418 // We keep track of subtype and subclass relationships in four | 420 // We keep track of subtype and subclass relationships in four |
| 419 // distinct sets to make class hierarchy analysis faster. | 421 // distinct sets to make class hierarchy analysis faster. |
| 420 final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes; | 422 final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes; |
| 421 final Map<ClassEntity, ClassSet> _classSets; | 423 final Map<ClassEntity, ClassSet> _classSets; |
| 422 | 424 |
| 423 final Map<ClassEntity, Map<ClassEntity, bool>> _subtypeCoveredByCache = | 425 final Map<ClassEntity, Map<ClassEntity, bool>> _subtypeCoveredByCache = |
| 424 <ClassEntity, Map<ClassEntity, bool>>{}; | 426 <ClassEntity, Map<ClassEntity, bool>>{}; |
| 425 | 427 |
| 426 final Set<Entity> _functionsCalledInLoop = new Set<Entity>(); | 428 final Set<MemberEntity> _functionsCalledInLoop = new Set<MemberEntity>(); |
| 427 final Map<Entity, SideEffects> _sideEffects = new Map<Entity, SideEffects>(); | 429 final Map<FunctionEntity, SideEffects> _sideEffects = |
| 430 new Map<FunctionEntity, SideEffects>(); | |
| 428 | 431 |
| 429 final Set<Entity> _sideEffectsFreeElements = new Set<Entity>(); | 432 final Set<FunctionEntity> _sideEffectsFreeElements = |
| 433 new Set<FunctionEntity>(); | |
| 430 | 434 |
| 431 final Set<Entity> _elementsThatCannotThrow = new Set<Entity>(); | 435 final Set<FunctionEntity> _elementsThatCannotThrow = |
| 436 new Set<FunctionEntity>(); | |
| 432 | 437 |
| 433 final Set<Entity> _functionsThatMightBePassedToApply = new Set<Entity>(); | 438 final Set<FunctionEntity> _functionsThatMightBePassedToApply = |
| 439 new Set<FunctionEntity>(); | |
| 434 | 440 |
| 435 CommonMasks _commonMasks; | 441 CommonMasks _commonMasks; |
| 436 | 442 |
| 437 final ElementEnvironment elementEnvironment; | 443 final ElementEnvironment elementEnvironment; |
| 438 final DartTypes dartTypes; | 444 final DartTypes dartTypes; |
| 439 final CommonElements commonElements; | 445 final CommonElements commonElements; |
| 440 | 446 |
| 441 // TODO(johnniwinther): Avoid this. | 447 // TODO(johnniwinther): Avoid this. |
| 442 final ResolutionWorldBuilder _resolverWorld; | 448 final ResolutionWorldBuilder _resolverWorld; |
| 443 | 449 |
| (...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1074 sideEffects.setAllSideEffects(); | 1080 sideEffects.setAllSideEffects(); |
| 1075 sideEffects.setDependsOnSomething(); | 1081 sideEffects.setDependsOnSomething(); |
| 1076 } | 1082 } |
| 1077 } else { | 1083 } else { |
| 1078 sideEffects.add(getSideEffectsOfElement(e)); | 1084 sideEffects.add(getSideEffectsOfElement(e)); |
| 1079 } | 1085 } |
| 1080 } | 1086 } |
| 1081 return sideEffects; | 1087 return sideEffects; |
| 1082 } | 1088 } |
| 1083 | 1089 |
| 1084 SideEffects getSideEffectsOfElement(covariant Entity element) { | 1090 SideEffects getSideEffectsOfElement(FunctionEntity element) { |
| 1085 assert(checkEntity(element)); | 1091 assert(checkEntity(element)); |
| 1086 return _sideEffects.putIfAbsent(element, _makeSideEffects); | 1092 return _sideEffects.putIfAbsent(element, _makeSideEffects); |
| 1087 } | 1093 } |
| 1088 | 1094 |
| 1089 static SideEffects _makeSideEffects() => new SideEffects(); | 1095 static SideEffects _makeSideEffects() => new SideEffects(); |
| 1090 | 1096 |
| 1091 @override | 1097 @override |
| 1092 SideEffects getCurrentlyKnownSideEffects(Entity element) { | 1098 SideEffects getCurrentlyKnownSideEffects(FunctionEntity element) { |
| 1093 return getSideEffectsOfElement(element); | 1099 return getSideEffectsOfElement(element); |
| 1094 } | 1100 } |
| 1095 | 1101 |
| 1096 void registerSideEffects(Entity element, SideEffects effects) { | 1102 void registerSideEffects(FunctionEntity element, SideEffects effects) { |
| 1097 assert(checkEntity(element)); | 1103 assert(checkEntity(element)); |
| 1098 if (_sideEffectsFreeElements.contains(element)) return; | 1104 if (_sideEffectsFreeElements.contains(element)) return; |
| 1099 _sideEffects[element] = effects; | 1105 _sideEffects[element] = effects; |
| 1100 } | 1106 } |
| 1101 | 1107 |
| 1102 void registerSideEffectsFree(Entity element) { | 1108 void registerSideEffectsFree(FunctionEntity element) { |
| 1103 assert(checkEntity(element)); | 1109 assert(checkEntity(element)); |
| 1104 _sideEffects[element] = new SideEffects.empty(); | 1110 _sideEffects[element] = new SideEffects.empty(); |
| 1105 _sideEffectsFreeElements.add(element); | 1111 _sideEffectsFreeElements.add(element); |
| 1106 } | 1112 } |
| 1107 | 1113 |
| 1108 void addFunctionCalledInLoop(Entity element) { | 1114 void addFunctionCalledInLoop(MemberEntity element) { |
| 1109 assert(checkEntity(element)); | 1115 assert(checkEntity(element)); |
| 1110 _functionsCalledInLoop.add(element); | 1116 _functionsCalledInLoop.add(element); |
| 1111 } | 1117 } |
| 1112 | 1118 |
| 1113 bool isCalledInLoop(Entity element) { | 1119 bool isCalledInLoop(MemberEntity element) { |
| 1114 assert(checkEntity(element)); | 1120 assert(checkEntity(element)); |
| 1115 return _functionsCalledInLoop.contains(element); | 1121 return _functionsCalledInLoop.contains(element); |
| 1116 } | 1122 } |
| 1117 | 1123 |
| 1118 void registerCannotThrow(Entity element) { | 1124 void registerCannotThrow(FunctionEntity element) { |
| 1119 assert(checkEntity(element)); | 1125 assert(checkEntity(element)); |
| 1120 _elementsThatCannotThrow.add(element); | 1126 _elementsThatCannotThrow.add(element); |
| 1121 } | 1127 } |
| 1122 | 1128 |
| 1123 bool getCannotThrow(Entity element) { | 1129 bool getCannotThrow(FunctionEntity element) { |
| 1124 return _elementsThatCannotThrow.contains(element); | 1130 return _elementsThatCannotThrow.contains(element); |
| 1125 } | 1131 } |
| 1126 | 1132 |
| 1127 void registerMightBePassedToApply(Entity element) { | 1133 void registerMightBePassedToApply(FunctionEntity element) { |
| 1128 _functionsThatMightBePassedToApply.add(element); | 1134 _functionsThatMightBePassedToApply.add(element); |
| 1129 } | 1135 } |
| 1130 | 1136 |
| 1131 bool getMightBePassedToApply(Entity element) { | 1137 bool getMightBePassedToApply(FunctionEntity element) { |
| 1132 // We have to check whether the element we look at was created after | |
| 1133 // type inference ran. This is currently only the case for the call | |
| 1134 // method of function classes that were generated for function | |
| 1135 // expressions. In such a case, we have to look at the original | |
| 1136 // function expressions's element. | |
| 1137 // TODO(herhut): Generate classes for function expressions earlier. | |
| 1138 if (element is SynthesizedCallMethodElementX) { | |
| 1139 return getMightBePassedToApply(element.expression); | |
|
Siggi Cherem (dart-lang)
2017/06/30 18:13:54
neat to get rid of this, but this is unrelated to
Johnni Winther
2017/06/30 19:02:02
No, this was a fix for the same kind of discrepanc
Siggi Cherem (dart-lang)
2017/06/30 20:34:36
I see - the comment above was misleading, it gave
Johnni Winther
2017/07/03 07:26:07
When the comment was written they _were_ created a
| |
| 1140 } | |
| 1141 return _functionsThatMightBePassedToApply.contains(element); | 1138 return _functionsThatMightBePassedToApply.contains(element); |
| 1142 } | 1139 } |
| 1143 | 1140 |
| 1144 @override | 1141 @override |
| 1145 bool getCurrentlyKnownMightBePassedToApply(Entity element) { | 1142 bool getCurrentlyKnownMightBePassedToApply(FunctionEntity element) { |
| 1146 return getMightBePassedToApply(element); | 1143 return getMightBePassedToApply(element); |
| 1147 } | 1144 } |
| 1148 | 1145 |
| 1149 @override | 1146 @override |
| 1150 String dump([ClassEntity cls]) { | 1147 String dump([ClassEntity cls]) { |
| 1151 if (cls is! ClassElement) { | 1148 if (cls is! ClassElement) { |
| 1152 // TODO(johnniwinther): Support [cls] as a [ClassEntity]. | 1149 // TODO(johnniwinther): Support [cls] as a [ClassEntity]. |
| 1153 cls = null; | 1150 cls = null; |
| 1154 } | 1151 } |
| 1155 StringBuffer sb = new StringBuffer(); | 1152 StringBuffer sb = new StringBuffer(); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1293 if (cls != commonElements.functionClass && | 1290 if (cls != commonElements.functionClass && |
| 1294 cls.implementsFunction(commonElements)) { | 1291 cls.implementsFunction(commonElements)) { |
| 1295 ClassSet subtypeSet = getClassSet(commonElements.functionClass); | 1292 ClassSet subtypeSet = getClassSet(commonElements.functionClass); |
| 1296 subtypeSet.addSubtype(node); | 1293 subtypeSet.addSubtype(node); |
| 1297 } | 1294 } |
| 1298 if (!node.isInstantiated && node.parentNode != null) { | 1295 if (!node.isInstantiated && node.parentNode != null) { |
| 1299 _updateSuperClassHierarchyNodeForClass(node.parentNode); | 1296 _updateSuperClassHierarchyNodeForClass(node.parentNode); |
| 1300 } | 1297 } |
| 1301 } | 1298 } |
| 1302 | 1299 |
| 1303 SideEffects getSideEffectsOfElement(Element element) { | 1300 SideEffects getSideEffectsOfElement(covariant MethodElement element) { |
| 1304 // The type inferrer (where the side effects are being computed), | 1301 // The type inferrer (where the side effects are being computed), |
| 1305 // does not see generative constructor bodies because they are | 1302 // does not see generative constructor bodies because they are |
| 1306 // created by the backend. Also, it does not make any distinction | 1303 // created by the backend. Also, it does not make any distinction |
| 1307 // between a constructor and its body for side effects. This | 1304 // between a constructor and its body for side effects. This |
| 1308 // implies that currently, the side effects of a constructor body | 1305 // implies that currently, the side effects of a constructor body |
| 1309 // contain the side effects of the initializers. | 1306 // contain the side effects of the initializers. |
| 1310 assert(!element.isGenerativeConstructorBody); | 1307 assert(!element.isGenerativeConstructorBody); |
| 1311 assert(!element.isField); | 1308 assert(!element.isField); |
| 1312 return super.getSideEffectsOfElement(element); | 1309 return super.getSideEffectsOfElement(element); |
| 1313 } | 1310 } |
| 1314 } | 1311 } |
| OLD | NEW |