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, SynthesizedCallMethodElementX; |
8 import 'common/backend_api.dart' show BackendClasses; | 8 import 'common/backend_api.dart' show BackendClasses; |
9 import 'common.dart'; | 9 import 'common.dart'; |
10 import 'constants/constant_system.dart'; | 10 import 'constants/constant_system.dart'; |
11 import 'common_elements.dart' show CommonElements; | 11 import 'common_elements.dart' show CommonElements; |
12 import 'elements/entities.dart'; | 12 import 'elements/entities.dart'; |
13 import 'elements/elements.dart' | 13 import 'elements/elements.dart' |
14 show | 14 show |
15 ClassElement, | 15 ClassElement, |
16 Element, | 16 Element, |
17 FunctionElement, | |
18 MemberElement, | 17 MemberElement, |
19 MixinApplicationElement, | 18 MixinApplicationElement, |
20 TypedefElement; | 19 TypedefElement; |
21 import 'elements/resolution_types.dart'; | 20 import 'elements/resolution_types.dart'; |
22 import 'elements/types.dart'; | 21 import 'elements/types.dart'; |
23 import 'js_backend/backend.dart' show JavaScriptBackend; | 22 import 'js_backend/backend.dart' show JavaScriptBackend; |
24 import 'js_backend/interceptor_data.dart' show InterceptorData; | 23 import 'js_backend/interceptor_data.dart' show InterceptorData; |
25 import 'js_backend/native_data.dart' show NativeData; | 24 import 'js_backend/native_data.dart' show NativeData; |
26 import 'ordered_typeset.dart'; | 25 import 'ordered_typeset.dart'; |
27 import 'types/masks.dart' show CommonMasks, FlatTypeMask, TypeMask; | 26 import 'types/masks.dart' show CommonMasks, FlatTypeMask, TypeMask; |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
292 /// Returns the single [Element] that matches a call to [selector] on a | 291 /// Returns the single [Element] that matches a call to [selector] on a |
293 /// receiver of type [mask]. If multiple targets exist, `null` is returned. | 292 /// receiver of type [mask]. If multiple targets exist, `null` is returned. |
294 MemberEntity locateSingleElement(Selector selector, TypeMask mask); | 293 MemberEntity locateSingleElement(Selector selector, TypeMask mask); |
295 | 294 |
296 /// Returns the single field that matches a call to [selector] on a | 295 /// Returns the single field that matches a call to [selector] on a |
297 /// receiver of type [mask]. If multiple targets exist or the single target | 296 /// receiver of type [mask]. If multiple targets exist or the single target |
298 /// is not a field, `null` is returned. | 297 /// is not a field, `null` is returned. |
299 FieldEntity locateSingleField(Selector selector, TypeMask mask); | 298 FieldEntity locateSingleField(Selector selector, TypeMask mask); |
300 | 299 |
301 /// Returns the side effects of executing [element]. | 300 /// Returns the side effects of executing [element]. |
302 SideEffects getSideEffectsOfElement(Element element); | 301 SideEffects getSideEffectsOfElement(Entity element); |
303 | 302 |
304 /// Returns the side effects of calling [selector] on a receiver of type | 303 /// Returns the side effects of calling [selector] on a receiver of type |
305 /// [mask]. | 304 /// [mask]. |
306 SideEffects getSideEffectsOfSelector(Selector selector, TypeMask mask); | 305 SideEffects getSideEffectsOfSelector(Selector selector, TypeMask mask); |
307 | 306 |
308 /// Returns `true` if [element] is guaranteed not to throw an exception. | 307 /// Returns `true` if [element] is guaranteed not to throw an exception. |
309 bool getCannotThrow(Element element); | 308 bool getCannotThrow(Entity element); |
310 | 309 |
311 /// Returns `true` if [element] is called in a loop. | 310 /// Returns `true` if [element] is called in a loop. |
312 // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? | 311 // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? |
313 bool isCalledInLoop(Element element); | 312 bool isCalledInLoop(Entity element); |
314 | 313 |
315 /// Returns `true` if [element] might be passed to `Function.apply`. | 314 /// Returns `true` if [element] might be passed to `Function.apply`. |
316 // TODO(johnniwinther): Is this 'passed invocation target` or | 315 // TODO(johnniwinther): Is this 'passed invocation target` or |
317 // `passed as argument`? | 316 // `passed as argument`? |
318 bool getMightBePassedToApply(Element element); | 317 bool getMightBePassedToApply(Entity element); |
319 | 318 |
320 /// Returns a string representation of the closed world. | 319 /// Returns a string representation of the closed world. |
321 /// | 320 /// |
322 /// If [cls] is provided, the dump will contain only classes related to [cls]. | 321 /// If [cls] is provided, the dump will contain only classes related to [cls]. |
323 String dump([ClassEntity cls]); | 322 String dump([ClassEntity cls]); |
324 } | 323 } |
325 | 324 |
326 /// Interface for computing side effects and uses of elements. This is used | 325 /// Interface for computing side effects and uses of elements. This is used |
327 /// during type inference to compute the [ClosedWorld] for code generation. | 326 /// during type inference to compute the [ClosedWorld] for code generation. |
328 abstract class ClosedWorldRefiner { | 327 abstract class ClosedWorldRefiner { |
329 /// The closed world being refined. | 328 /// The closed world being refined. |
330 ClosedWorld get closedWorld; | 329 ClosedWorld get closedWorld; |
331 | 330 |
332 /// Registers the side [effects] of executing [element]. | 331 /// Registers the side [effects] of executing [element]. |
333 void registerSideEffects(Element element, SideEffects effects); | 332 void registerSideEffects(Entity element, SideEffects effects); |
334 | 333 |
335 /// Registers the executing of [element] as without side effects. | 334 /// Registers the executing of [element] as without side effects. |
336 void registerSideEffectsFree(Element element); | 335 void registerSideEffectsFree(Entity element); |
337 | 336 |
338 /// Returns the currently known side effects of executing [element]. | 337 /// Returns the currently known side effects of executing [element]. |
339 SideEffects getCurrentlyKnownSideEffects(Element element); | 338 SideEffects getCurrentlyKnownSideEffects(Entity element); |
340 | 339 |
341 /// Registers that [element] might be passed to `Function.apply`. | 340 /// Registers that [element] might be passed to `Function.apply`. |
342 // TODO(johnniwinther): Is this 'passed invocation target` or | 341 // TODO(johnniwinther): Is this 'passed invocation target` or |
343 // `passed as argument`? | 342 // `passed as argument`? |
344 void registerMightBePassedToApply(Element element); | 343 void registerMightBePassedToApply(Entity element); |
345 | 344 |
346 /// Returns `true` if [element] might be passed to `Function.apply` given the | 345 /// Returns `true` if [element] might be passed to `Function.apply` given the |
347 /// currently inferred information. | 346 /// currently inferred information. |
348 bool getCurrentlyKnownMightBePassedToApply(Element element); | 347 bool getCurrentlyKnownMightBePassedToApply(Entity element); |
349 | 348 |
350 /// Registers that [element] is called in a loop. | 349 /// Registers that [element] is called in a loop. |
351 // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? | 350 // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? |
352 void addFunctionCalledInLoop(Element element); | 351 void addFunctionCalledInLoop(Entity element); |
353 | 352 |
354 /// Registers that [element] is guaranteed not to throw an exception. | 353 /// Registers that [element] is guaranteed not to throw an exception. |
355 void registerCannotThrow(Element element); | 354 void registerCannotThrow(Entity element); |
356 | 355 |
357 /// Adds the closure class [cls] to the inference world. The class is | 356 /// Adds the closure class [cls] to the inference world. The class is |
358 /// considered directly instantiated. | 357 /// considered directly instantiated. |
359 void registerClosureClass(ClassElement cls); | 358 void registerClosureClass(ClassElement cls); |
360 } | 359 } |
361 | 360 |
362 abstract class OpenWorld implements World { | 361 abstract class OpenWorld implements World { |
363 /// Called to add [cls] to the set of known classes. | 362 /// Called to add [cls] to the set of known classes. |
364 /// | 363 /// |
365 /// This ensures that class hierarchy queries can be performed on [cls] and | 364 /// This ensures that class hierarchy queries can be performed on [cls] and |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
402 final Map<ClassEntity, Set<ClassEntity>> _typesImplementedBySubclasses; | 401 final Map<ClassEntity, Set<ClassEntity>> _typesImplementedBySubclasses; |
403 | 402 |
404 // We keep track of subtype and subclass relationships in four | 403 // We keep track of subtype and subclass relationships in four |
405 // distinct sets to make class hierarchy analysis faster. | 404 // distinct sets to make class hierarchy analysis faster. |
406 final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes; | 405 final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes; |
407 final Map<ClassEntity, ClassSet> _classSets; | 406 final Map<ClassEntity, ClassSet> _classSets; |
408 | 407 |
409 final Map<ClassEntity, Map<ClassEntity, bool>> _subtypeCoveredByCache = | 408 final Map<ClassEntity, Map<ClassEntity, bool>> _subtypeCoveredByCache = |
410 <ClassEntity, Map<ClassEntity, bool>>{}; | 409 <ClassEntity, Map<ClassEntity, bool>>{}; |
411 | 410 |
412 final Set<Element> functionsCalledInLoop = new Set<Element>(); | 411 final Set<Entity> _functionsCalledInLoop = new Set<Entity>(); |
413 final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); | 412 final Map<Entity, SideEffects> _sideEffects = new Map<Entity, SideEffects>(); |
414 | 413 |
415 final Set<Element> sideEffectsFreeElements = new Set<Element>(); | 414 final Set<Entity> _sideEffectsFreeElements = new Set<Entity>(); |
416 | 415 |
417 final Set<Element> elementsThatCannotThrow = new Set<Element>(); | 416 final Set<Entity> _elementsThatCannotThrow = new Set<Entity>(); |
418 | 417 |
419 final Set<Element> functionsThatMightBePassedToApply = | 418 final Set<Entity> _functionsThatMightBePassedToApply = new Set<Entity>(); |
420 new Set<FunctionElement>(); | |
421 | 419 |
422 CommonMasks _commonMasks; | 420 CommonMasks _commonMasks; |
423 | 421 |
424 final CommonElements commonElements; | 422 final CommonElements commonElements; |
425 | 423 |
426 final ResolutionWorldBuilder _resolverWorld; | 424 final ResolutionWorldBuilder _resolverWorld; |
427 | 425 |
428 ClosedWorldBase( | 426 ClosedWorldBase( |
429 {JavaScriptBackend backend, | 427 {JavaScriptBackend backend, |
430 this.commonElements, | 428 this.commonElements, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
463 } | 461 } |
464 | 462 |
465 ConstantSystem get constantSystem => _backend.constantSystem; | 463 ConstantSystem get constantSystem => _backend.constantSystem; |
466 | 464 |
467 TypeMask getCachedMask(ClassEntity base, int flags, TypeMask createMask()) { | 465 TypeMask getCachedMask(ClassEntity base, int flags, TypeMask createMask()) { |
468 Map<ClassEntity, TypeMask> cachedMasks = | 466 Map<ClassEntity, TypeMask> cachedMasks = |
469 _canonicalizedTypeMasks[flags] ??= <ClassEntity, TypeMask>{}; | 467 _canonicalizedTypeMasks[flags] ??= <ClassEntity, TypeMask>{}; |
470 return cachedMasks.putIfAbsent(base, createMask); | 468 return cachedMasks.putIfAbsent(base, createMask); |
471 } | 469 } |
472 | 470 |
471 bool _checkEntity(Entity element); | |
472 | |
473 bool _checkClass(ClassEntity cls); | 473 bool _checkClass(ClassEntity cls); |
474 | 474 |
475 bool _checkInvariants(ClassEntity cls, {bool mustBeInstantiated: true}); | 475 bool _checkInvariants(ClassEntity cls, {bool mustBeInstantiated: true}); |
476 | 476 |
477 @override | 477 @override |
478 bool isInstantiated(ClassEntity cls) { | 478 bool isInstantiated(ClassEntity cls) { |
479 assert(_checkClass(cls)); | 479 assert(_checkClass(cls)); |
480 ClassHierarchyNode node = _classHierarchyNodes[cls]; | 480 ClassHierarchyNode node = _classHierarchyNodes[cls]; |
481 return node != null && node.isInstantiated; | 481 return node != null && node.isInstantiated; |
482 } | 482 } |
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
895 assert(selector.isCall); | 895 assert(selector.isCall); |
896 sideEffects.setAllSideEffects(); | 896 sideEffects.setAllSideEffects(); |
897 sideEffects.setDependsOnSomething(); | 897 sideEffects.setDependsOnSomething(); |
898 } | 898 } |
899 } else { | 899 } else { |
900 sideEffects.add(getSideEffectsOfElement(e)); | 900 sideEffects.add(getSideEffectsOfElement(e)); |
901 } | 901 } |
902 } | 902 } |
903 return sideEffects; | 903 return sideEffects; |
904 } | 904 } |
905 | |
906 SideEffects getSideEffectsOfElement(Entity element) { | |
Emily Fortuna
2017/04/12 18:07:18
getSideEffectsOfEntity?
Johnni Winther
2017/04/18 07:36:08
I'll stick with the name for now. I think needs to
| |
907 assert(_checkEntity(element)); | |
908 return _sideEffects.putIfAbsent(element, () { | |
909 return new SideEffects(); | |
910 }); | |
911 } | |
912 | |
913 @override | |
914 SideEffects getCurrentlyKnownSideEffects(Entity element) { | |
915 return getSideEffectsOfElement(element); | |
916 } | |
917 | |
918 void registerSideEffects(Entity element, SideEffects effects) { | |
919 assert(_checkEntity(element)); | |
920 if (_sideEffectsFreeElements.contains(element)) return; | |
921 _sideEffects[element] = effects; | |
922 } | |
923 | |
924 void registerSideEffectsFree(Entity element) { | |
925 assert(_checkEntity(element)); | |
926 _sideEffects[element] = new SideEffects.empty(); | |
927 _sideEffectsFreeElements.add(element); | |
928 } | |
929 | |
930 void addFunctionCalledInLoop(Entity element) { | |
931 assert(_checkEntity(element)); | |
932 _functionsCalledInLoop.add(element); | |
933 } | |
934 | |
935 bool isCalledInLoop(Entity element) { | |
936 assert(_checkEntity(element)); | |
937 return _functionsCalledInLoop.contains(element); | |
938 } | |
939 | |
940 void registerCannotThrow(Entity element) { | |
941 assert(_checkEntity(element)); | |
942 _elementsThatCannotThrow.add(element); | |
943 } | |
944 | |
945 bool getCannotThrow(Entity element) { | |
946 return _elementsThatCannotThrow.contains(element); | |
947 } | |
948 | |
949 void registerMightBePassedToApply(Entity element) { | |
950 _functionsThatMightBePassedToApply.add(element); | |
951 } | |
952 | |
953 bool getMightBePassedToApply(Entity element) { | |
954 // We have to check whether the element we look at was created after | |
955 // type inference ran. This is currently only the case for the call | |
956 // method of function classes that were generated for function | |
957 // expressions. In such a case, we have to look at the original | |
958 // function expressions's element. | |
959 // TODO(herhut): Generate classes for function expressions earlier. | |
960 if (element is SynthesizedCallMethodElementX) { | |
961 return getMightBePassedToApply(element.expression); | |
962 } | |
963 return _functionsThatMightBePassedToApply.contains(element); | |
964 } | |
965 | |
966 @override | |
967 bool getCurrentlyKnownMightBePassedToApply(Entity element) { | |
968 return getMightBePassedToApply(element); | |
969 } | |
905 } | 970 } |
906 | 971 |
907 class ClosedWorldImpl extends ClosedWorldBase { | 972 class ClosedWorldImpl extends ClosedWorldBase { |
908 ClosedWorldImpl( | 973 ClosedWorldImpl( |
909 {JavaScriptBackend backend, | 974 {JavaScriptBackend backend, |
910 CommonElements commonElements, | 975 CommonElements commonElements, |
911 ResolutionWorldBuilder resolutionWorldBuilder, | 976 ResolutionWorldBuilder resolutionWorldBuilder, |
912 FunctionSetBuilder functionSetBuilder, | 977 FunctionSetBuilder functionSetBuilder, |
913 Iterable<TypedefElement> allTypedefs, | 978 Iterable<TypedefElement> allTypedefs, |
914 Map<ClassEntity, Set<ClassEntity>> mixinUses, | 979 Map<ClassEntity, Set<ClassEntity>> mixinUses, |
915 Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses, | 980 Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses, |
916 Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes, | 981 Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes, |
917 Map<ClassEntity, ClassSet> classSets}) | 982 Map<ClassEntity, ClassSet> classSets}) |
918 : super( | 983 : super( |
919 backend: backend, | 984 backend: backend, |
920 commonElements: commonElements, | 985 commonElements: commonElements, |
921 resolutionWorldBuilder: resolutionWorldBuilder, | 986 resolutionWorldBuilder: resolutionWorldBuilder, |
922 functionSetBuilder: functionSetBuilder, | 987 functionSetBuilder: functionSetBuilder, |
923 allTypedefs: allTypedefs, | 988 allTypedefs: allTypedefs, |
924 mixinUses: mixinUses, | 989 mixinUses: mixinUses, |
925 typesImplementedBySubclasses: typesImplementedBySubclasses, | 990 typesImplementedBySubclasses: typesImplementedBySubclasses, |
926 classHierarchyNodes: classHierarchyNodes, | 991 classHierarchyNodes: classHierarchyNodes, |
927 classSets: classSets); | 992 classSets: classSets); |
928 | 993 |
929 bool _checkClass(ClassElement cls) => cls.isDeclaration; | 994 bool _checkClass(ClassElement cls) => cls.isDeclaration; |
995 bool _checkEntity(Element element) => element.isDeclaration; | |
930 | 996 |
931 bool _checkInvariants(ClassElement cls, {bool mustBeInstantiated: true}) { | 997 bool _checkInvariants(ClassElement cls, {bool mustBeInstantiated: true}) { |
932 return invariant(cls, cls.isDeclaration, | 998 return invariant(cls, cls.isDeclaration, |
933 message: '$cls must be the declaration.') && | 999 message: '$cls must be the declaration.') && |
934 invariant(cls, cls.isResolved, | 1000 invariant(cls, cls.isResolved, |
935 message: | 1001 message: |
936 '$cls must be resolved.') /* && | 1002 '$cls must be resolved.') /* && |
937 // TODO(johnniwinther): Reinsert this or similar invariant. Currently | 1003 // TODO(johnniwinther): Reinsert this or similar invariant. Currently |
938 // various call sites use uninstantiated classes for isSubtypeOf or | 1004 // various call sites use uninstantiated classes for isSubtypeOf or |
939 // isSubclassOf. Some are valid, some are not. Work out better invariants | 1005 // isSubclassOf. Some are valid, some are not. Work out better invariants |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1145 | 1211 |
1146 SideEffects getSideEffectsOfElement(Element element) { | 1212 SideEffects getSideEffectsOfElement(Element element) { |
1147 // The type inferrer (where the side effects are being computed), | 1213 // The type inferrer (where the side effects are being computed), |
1148 // does not see generative constructor bodies because they are | 1214 // does not see generative constructor bodies because they are |
1149 // created by the backend. Also, it does not make any distinction | 1215 // created by the backend. Also, it does not make any distinction |
1150 // between a constructor and its body for side effects. This | 1216 // between a constructor and its body for side effects. This |
1151 // implies that currently, the side effects of a constructor body | 1217 // implies that currently, the side effects of a constructor body |
1152 // contain the side effects of the initializers. | 1218 // contain the side effects of the initializers. |
1153 assert(!element.isGenerativeConstructorBody); | 1219 assert(!element.isGenerativeConstructorBody); |
1154 assert(!element.isField); | 1220 assert(!element.isField); |
1155 return sideEffects.putIfAbsent(element.declaration, () { | 1221 return super.getSideEffectsOfElement(element); |
1156 return new SideEffects(); | |
1157 }); | |
1158 } | |
1159 | |
1160 @override | |
1161 SideEffects getCurrentlyKnownSideEffects(Element element) { | |
1162 return getSideEffectsOfElement(element); | |
1163 } | |
1164 | |
1165 void registerSideEffects(Element element, SideEffects effects) { | |
1166 if (sideEffectsFreeElements.contains(element)) return; | |
1167 sideEffects[element.declaration] = effects; | |
1168 } | |
1169 | |
1170 void registerSideEffectsFree(Element element) { | |
1171 sideEffects[element.declaration] = new SideEffects.empty(); | |
1172 sideEffectsFreeElements.add(element); | |
1173 } | |
1174 | |
1175 void addFunctionCalledInLoop(Element element) { | |
1176 functionsCalledInLoop.add(element.declaration); | |
1177 } | |
1178 | |
1179 bool isCalledInLoop(Element element) { | |
1180 return functionsCalledInLoop.contains(element.declaration); | |
1181 } | |
1182 | |
1183 void registerCannotThrow(Element element) { | |
1184 elementsThatCannotThrow.add(element); | |
1185 } | |
1186 | |
1187 bool getCannotThrow(Element element) { | |
1188 return elementsThatCannotThrow.contains(element); | |
1189 } | |
1190 | |
1191 void registerMightBePassedToApply(Element element) { | |
1192 functionsThatMightBePassedToApply.add(element); | |
1193 } | |
1194 | |
1195 bool getMightBePassedToApply(Element element) { | |
1196 // We have to check whether the element we look at was created after | |
1197 // type inference ran. This is currently only the case for the call | |
1198 // method of function classes that were generated for function | |
1199 // expressions. In such a case, we have to look at the original | |
1200 // function expressions's element. | |
1201 // TODO(herhut): Generate classes for function expressions earlier. | |
1202 if (element is SynthesizedCallMethodElementX) { | |
1203 return getMightBePassedToApply(element.expression); | |
1204 } | |
1205 return functionsThatMightBePassedToApply.contains(element); | |
1206 } | |
1207 | |
1208 @override | |
1209 bool getCurrentlyKnownMightBePassedToApply(Element element) { | |
1210 return getMightBePassedToApply(element); | |
1211 } | 1222 } |
1212 } | 1223 } |
OLD | NEW |