| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 /// Analysis to determine how to generate code for `LookupMap`s. | 5 /// Analysis to determine how to generate code for `LookupMap`s. |
| 6 library compiler.src.js_backend.lookup_map_analysis; | 6 library compiler.src.js_backend.lookup_map_analysis; |
| 7 | 7 |
| 8 import 'package:pub_semver/pub_semver.dart'; | 8 import 'package:pub_semver/pub_semver.dart'; |
| 9 | 9 |
| 10 import '../common.dart'; | 10 import '../common.dart'; |
| 11 import '../common/registry.dart' show Registry; | 11 import '../common/registry.dart' show Registry; |
| 12 import '../compiler.dart' show Compiler; | 12 import '../compiler.dart' show Compiler; |
| 13 import '../constants/values.dart' | 13 import '../constants/values.dart' |
| 14 show | 14 show |
| 15 ConstantValue, | 15 ConstantValue, |
| 16 ConstructedConstantValue, | 16 ConstructedConstantValue, |
| 17 ListConstantValue, | 17 ListConstantValue, |
| 18 NullConstantValue, | 18 NullConstantValue, |
| 19 StringConstantValue, | 19 StringConstantValue, |
| 20 TypeConstantValue; | 20 TypeConstantValue; |
| 21 import '../dart_types.dart' show DartType; | 21 import '../dart_types.dart' show DartType; |
| 22 import '../dart_types.dart' show InterfaceType; | 22 import '../dart_types.dart' show InterfaceType; |
| 23 import '../elements/elements.dart' | 23 import '../elements/elements.dart' |
| 24 show ClassElement, FieldElement, LibraryElement, VariableElement; | 24 show ClassElement, FieldElement, LibraryElement, VariableElement; |
| 25 import '../enqueue.dart'; |
| 26 import '../universe/world_impact.dart' |
| 27 show WorldImpact, StagedWorldImpactBuilder; |
| 25 import 'js_backend.dart' show JavaScriptBackend; | 28 import 'js_backend.dart' show JavaScriptBackend; |
| 26 | 29 |
| 27 /// An analysis and optimization to remove unused entries from a `LookupMap`. | 30 /// An analysis and optimization to remove unused entries from a `LookupMap`. |
| 28 /// | 31 /// |
| 29 /// `LookupMaps` are defined in `package:lookup_map/lookup_map.dart`. They are | 32 /// `LookupMaps` are defined in `package:lookup_map/lookup_map.dart`. They are |
| 30 /// simple maps that contain constant expressions as keys, and that only support | 33 /// simple maps that contain constant expressions as keys, and that only support |
| 31 /// the lookup operation. | 34 /// the lookup operation. |
| 32 /// | 35 /// |
| 33 /// This analysis and optimization will tree-shake the contents of the maps by | 36 /// This analysis and optimization will tree-shake the contents of the maps by |
| 34 /// looking at the program and finding which keys are clearly unused. Not all | 37 /// looking at the program and finding which keys are clearly unused. Not all |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 111 /// runtime. Technically if we limit lookup-maps to check for identical keys, | 114 /// runtime. Technically if we limit lookup-maps to check for identical keys, |
| 112 /// we could allow const instances of these types. However, we internally use | 115 /// we could allow const instances of these types. However, we internally use |
| 113 /// a hash map within lookup-maps today, so we need this restriction. | 116 /// a hash map within lookup-maps today, so we need this restriction. |
| 114 final _typesWithEquals = <ClassElement, bool>{}; | 117 final _typesWithEquals = <ClassElement, bool>{}; |
| 115 | 118 |
| 116 /// Pending work to do if we discover that a new key is in use. For each key | 119 /// Pending work to do if we discover that a new key is in use. For each key |
| 117 /// that we haven't seen, we record the list of lookup-maps that contain an | 120 /// that we haven't seen, we record the list of lookup-maps that contain an |
| 118 /// entry with that key. | 121 /// entry with that key. |
| 119 final _pending = <ConstantValue, List<_LookupMapInfo>>{}; | 122 final _pending = <ConstantValue, List<_LookupMapInfo>>{}; |
| 120 | 123 |
| 124 final StagedWorldImpactBuilder impactBuilder = new StagedWorldImpactBuilder(); |
| 125 |
| 121 /// Whether the backend is currently processing the codegen queue. | 126 /// Whether the backend is currently processing the codegen queue. |
| 122 bool _inCodegen = false; | 127 bool _inCodegen = false; |
| 123 | 128 |
| 124 LookupMapAnalysis(this.backend, this.reporter); | 129 LookupMapAnalysis(this.backend, this.reporter); |
| 125 | 130 |
| 131 void onQueueEmpty(Enqueuer enqueuer) { |
| 132 if (enqueuer.isResolutionQueue) return; |
| 133 enqueuer.applyImpact(null, impactBuilder.flush()); |
| 134 } |
| 135 |
| 126 /// Whether this analysis and optimization is enabled. | 136 /// Whether this analysis and optimization is enabled. |
| 127 bool get _isEnabled { | 137 bool get _isEnabled { |
| 128 // `lookupMap==off` kept here to make it easy to test disabling this feature | 138 // `lookupMap==off` kept here to make it easy to test disabling this feature |
| 129 if (const String.fromEnvironment('lookupMap') == 'off') return false; | 139 if (const String.fromEnvironment('lookupMap') == 'off') return false; |
| 130 return typeLookupMapClass != null; | 140 return typeLookupMapClass != null; |
| 131 } | 141 } |
| 132 | 142 |
| 133 /// Initializes this analysis by providing the resolved library. This is | 143 /// Initializes this analysis by providing the resolved library. This is |
| 134 /// invoked during resolution when the `lookup_map` library is discovered. | 144 /// invoked during resolution when the `lookup_map` library is discovered. |
| 135 void init(LibraryElement library) { | 145 void init(LibraryElement library) { |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 } | 251 } |
| 242 | 252 |
| 243 /// Callback from the enqueuer, invoked when [element] is instantiated. | 253 /// Callback from the enqueuer, invoked when [element] is instantiated. |
| 244 void registerInstantiatedClass(ClassElement element) { | 254 void registerInstantiatedClass(ClassElement element) { |
| 245 if (!_isEnabled || !_inCodegen) return; | 255 if (!_isEnabled || !_inCodegen) return; |
| 246 // TODO(sigmund): only add if .runtimeType is ever used | 256 // TODO(sigmund): only add if .runtimeType is ever used |
| 247 _addClassUse(element); | 257 _addClassUse(element); |
| 248 } | 258 } |
| 249 | 259 |
| 250 /// Callback from the enqueuer, invoked when [type] is instantiated. | 260 /// Callback from the enqueuer, invoked when [type] is instantiated. |
| 251 void registerInstantiatedType(InterfaceType type, Registry registry) { | 261 void registerInstantiatedType(InterfaceType type) { |
| 252 if (!_isEnabled || !_inCodegen) return; | 262 if (!_isEnabled || !_inCodegen) return; |
| 253 // TODO(sigmund): only add if .runtimeType is ever used | 263 // TODO(sigmund): only add if .runtimeType is ever used |
| 254 _addClassUse(type.element); | 264 _addClassUse(type.element); |
| 255 // TODO(sigmund): only do this when type-argument expressions are used? | 265 // TODO(sigmund): only do this when type-argument expressions are used? |
| 256 _addGenerics(type, registry); | 266 _addGenerics(type); |
| 257 } | 267 } |
| 258 | 268 |
| 259 /// Records generic type arguments in [type], in case they are retrieved and | 269 /// Records generic type arguments in [type], in case they are retrieved and |
| 260 /// returned using a type-argument expression. | 270 /// returned using a type-argument expression. |
| 261 void _addGenerics(InterfaceType type, Registry registry) { | 271 void _addGenerics(InterfaceType type) { |
| 262 if (!type.isGeneric) return; | 272 if (!type.isGeneric) return; |
| 263 for (var arg in type.typeArguments) { | 273 for (var arg in type.typeArguments) { |
| 264 if (arg is InterfaceType) { | 274 if (arg is InterfaceType) { |
| 265 _addClassUse(arg.element); | 275 _addClassUse(arg.element); |
| 266 // Note: this call was needed to generate correct code for | 276 // Note: this call was needed to generate correct code for |
| 267 // type_lookup_map/generic_type_test | 277 // type_lookup_map/generic_type_test |
| 268 // TODO(sigmund): can we get rid of this? | 278 // TODO(sigmund): can we get rid of this? |
| 269 backend.registerInstantiatedConstantType( | 279 backend.computeImpactForInstantiatedConstantType( |
| 270 backend.typeImplementation.rawType, registry); | 280 backend.typeImplementation.rawType, impactBuilder); |
| 271 _addGenerics(arg, registry); | 281 _addGenerics(arg); |
| 272 } | 282 } |
| 273 } | 283 } |
| 274 } | 284 } |
| 275 | 285 |
| 276 /// Callback from the codegen enqueuer, invoked when a constant (which is | 286 /// Callback from the codegen enqueuer, invoked when a constant (which is |
| 277 /// possibly a const key or a type literal) is used in the program. | 287 /// possibly a const key or a type literal) is used in the program. |
| 278 void registerTypeConstant(ClassElement element) { | 288 void registerTypeConstant(ClassElement element) { |
| 279 if (!_isEnabled || !_inCodegen) return; | 289 if (!_isEnabled || !_inCodegen) return; |
| 280 _addClassUse(element); | 290 _addClassUse(element); |
| 281 } | 291 } |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 400 } | 410 } |
| 401 | 411 |
| 402 /// Marks that [key] has been seen, and thus, the corresponding entry in this | 412 /// Marks that [key] has been seen, and thus, the corresponding entry in this |
| 403 /// map should be considered reachable. | 413 /// map should be considered reachable. |
| 404 _markUsed(ConstantValue key) { | 414 _markUsed(ConstantValue key) { |
| 405 assert(!emitted); | 415 assert(!emitted); |
| 406 assert(unusedEntries.containsKey(key)); | 416 assert(unusedEntries.containsKey(key)); |
| 407 assert(!usedEntries.containsKey(key)); | 417 assert(!usedEntries.containsKey(key)); |
| 408 ConstantValue constant = unusedEntries.remove(key); | 418 ConstantValue constant = unusedEntries.remove(key); |
| 409 usedEntries[key] = constant; | 419 usedEntries[key] = constant; |
| 410 analysis.backend.registerCompileTimeConstant( | 420 analysis.backend.computeImpactForCompileTimeConstant( |
| 411 constant, analysis.backend.compiler.globalDependencies); | 421 constant, analysis.impactBuilder, false); |
| 412 } | 422 } |
| 413 | 423 |
| 414 /// Restores [original] to contain all of the entries marked as possibly used. | 424 /// Restores [original] to contain all of the entries marked as possibly used. |
| 415 void _prepareForEmission() { | 425 void _prepareForEmission() { |
| 416 ListConstantValue originalEntries = original.fields[analysis.entriesField]; | 426 ListConstantValue originalEntries = original.fields[analysis.entriesField]; |
| 417 DartType listType = originalEntries.type; | 427 DartType listType = originalEntries.type; |
| 418 List<ConstantValue> keyValuePairs = <ConstantValue>[]; | 428 List<ConstantValue> keyValuePairs = <ConstantValue>[]; |
| 419 usedEntries.forEach((key, value) { | 429 usedEntries.forEach((key, value) { |
| 420 keyValuePairs.add(key); | 430 keyValuePairs.add(key); |
| 421 keyValuePairs.add(value); | 431 keyValuePairs.add(value); |
| 422 }); | 432 }); |
| 423 | 433 |
| 424 // Note: we are restoring the entries here, see comment in [original]. | 434 // Note: we are restoring the entries here, see comment in [original]. |
| 425 if (singlePair) { | 435 if (singlePair) { |
| 426 assert(keyValuePairs.length == 0 || keyValuePairs.length == 2); | 436 assert(keyValuePairs.length == 0 || keyValuePairs.length == 2); |
| 427 if (keyValuePairs.length == 2) { | 437 if (keyValuePairs.length == 2) { |
| 428 original.fields[analysis.keyField] = keyValuePairs[0]; | 438 original.fields[analysis.keyField] = keyValuePairs[0]; |
| 429 original.fields[analysis.valueField] = keyValuePairs[1]; | 439 original.fields[analysis.valueField] = keyValuePairs[1]; |
| 430 } | 440 } |
| 431 } else { | 441 } else { |
| 432 original.fields[analysis.entriesField] = | 442 original.fields[analysis.entriesField] = |
| 433 new ListConstantValue(listType, keyValuePairs); | 443 new ListConstantValue(listType, keyValuePairs); |
| 434 } | 444 } |
| 435 } | 445 } |
| 436 } | 446 } |
| 437 | 447 |
| 438 final _validLookupMapVersionConstraint = new VersionConstraint.parse('^0.0.1'); | 448 final _validLookupMapVersionConstraint = new VersionConstraint.parse('^0.0.1'); |
| OLD | NEW |