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 '../compiler.dart' show Compiler; | 11 import '../compiler.dart' show Compiler; |
12 import '../constants/values.dart' | 12 import '../constants/values.dart' |
13 show | 13 show |
14 ConstantValue, | 14 ConstantValue, |
15 ConstructedConstantValue, | 15 ConstructedConstantValue, |
16 ListConstantValue, | 16 ListConstantValue, |
17 NullConstantValue, | 17 NullConstantValue, |
18 StringConstantValue, | 18 StringConstantValue, |
19 TypeConstantValue; | 19 TypeConstantValue; |
20 import '../dart_types.dart' show DartType; | 20 import '../dart_types.dart' show DartType; |
21 import '../dart_types.dart' show InterfaceType; | 21 import '../dart_types.dart' show InterfaceType; |
22 import '../elements/elements.dart' | 22 import '../elements/elements.dart' |
23 show ClassElement, FieldElement, LibraryElement, VariableElement; | 23 show ClassElement, FieldElement, LibraryElement, VariableElement; |
24 import '../enqueue.dart'; | 24 import '../universe/use.dart' show StaticUse; |
25 import '../universe/world_impact.dart' | 25 import '../universe/world_impact.dart' |
26 show WorldImpact, StagedWorldImpactBuilder; | 26 show WorldImpact, StagedWorldImpactBuilder; |
27 import 'js_backend.dart' show JavaScriptBackend; | 27 import 'js_backend.dart' show JavaScriptBackend; |
28 | 28 |
29 /// An analysis and optimization to remove unused entries from a `LookupMap`. | 29 /// An analysis and optimization to remove unused entries from a `LookupMap`. |
30 /// | 30 /// |
31 /// `LookupMaps` are defined in `package:lookup_map/lookup_map.dart`. They are | 31 /// `LookupMaps` are defined in `package:lookup_map/lookup_map.dart`. They are |
32 /// simple maps that contain constant expressions as keys, and that only support | 32 /// simple maps that contain constant expressions as keys, and that only support |
33 /// the lookup operation. | 33 /// the lookup operation. |
34 /// | 34 /// |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 /// runtime. Technically if we limit lookup-maps to check for identical keys, | 113 /// runtime. Technically if we limit lookup-maps to check for identical keys, |
114 /// we could allow const instances of these types. However, we internally use | 114 /// we could allow const instances of these types. However, we internally use |
115 /// a hash map within lookup-maps today, so we need this restriction. | 115 /// a hash map within lookup-maps today, so we need this restriction. |
116 final _typesWithEquals = <ClassElement, bool>{}; | 116 final _typesWithEquals = <ClassElement, bool>{}; |
117 | 117 |
118 /// Pending work to do if we discover that a new key is in use. For each key | 118 /// Pending work to do if we discover that a new key is in use. For each key |
119 /// that we haven't seen, we record the list of lookup-maps that contain an | 119 /// that we haven't seen, we record the list of lookup-maps that contain an |
120 /// entry with that key. | 120 /// entry with that key. |
121 final _pending = <ConstantValue, List<_LookupMapInfo>>{}; | 121 final _pending = <ConstantValue, List<_LookupMapInfo>>{}; |
122 | 122 |
123 final StagedWorldImpactBuilder impactBuilder = new StagedWorldImpactBuilder(); | 123 final StagedWorldImpactBuilder impactBuilderForResolution = |
| 124 new StagedWorldImpactBuilder(); |
| 125 final StagedWorldImpactBuilder impactBuilderForCodegen = |
| 126 new StagedWorldImpactBuilder(); |
124 | 127 |
125 /// Whether the backend is currently processing the codegen queue. | 128 /// Whether the backend is currently processing the codegen queue. |
126 bool _inCodegen = false; | 129 bool _inCodegen = false; |
127 | 130 |
128 LookupMapAnalysis(this.backend, this.reporter); | 131 LookupMapAnalysis(this.backend, this.reporter); |
129 | 132 |
130 /// Compute the [WorldImpact] for the constants registered since last flush. | 133 /// Compute the [WorldImpact] for the constants registered since last flush. |
131 WorldImpact flush({bool forResolution}) { | 134 WorldImpact flush({bool forResolution}) { |
132 if (forResolution) return const WorldImpact(); | 135 if (forResolution) { |
133 return impactBuilder.flush(); | 136 return impactBuilderForResolution.flush(); |
| 137 } else { |
| 138 return impactBuilderForCodegen.flush(); |
| 139 } |
134 } | 140 } |
135 | 141 |
136 /// Whether this analysis and optimization is enabled. | 142 /// Whether this analysis and optimization is enabled. |
137 bool get _isEnabled { | 143 bool get _isEnabled { |
138 // `lookupMap==off` kept here to make it easy to test disabling this feature | 144 // `lookupMap==off` kept here to make it easy to test disabling this feature |
139 if (const String.fromEnvironment('lookupMap') == 'off') return false; | 145 if (const String.fromEnvironment('lookupMap') == 'off') return false; |
140 return typeLookupMapClass != null; | 146 return typeLookupMapClass != null; |
141 } | 147 } |
142 | 148 |
143 /// Initializes this analysis by providing the resolved library. This is | 149 /// Initializes this analysis by providing the resolved library. This is |
144 /// invoked during resolution when the `lookup_map` library is discovered. | 150 /// invoked during resolution when the `lookup_map` library is discovered. |
145 void init(LibraryElement library) { | 151 void init(LibraryElement library) { |
146 lookupMapLibrary = library; | 152 lookupMapLibrary = library; |
147 // We will enable the lookupMapAnalysis as long as we get a known version of | 153 // We will enable the lookupMapAnalysis as long as we get a known version of |
148 // the lookup_map package. We otherwise produce a warning. | 154 // the lookup_map package. We otherwise produce a warning. |
149 lookupMapVersionVariable = library.implementation.findLocal('_version'); | 155 lookupMapVersionVariable = library.implementation.findLocal('_version'); |
150 if (lookupMapVersionVariable == null) { | 156 if (lookupMapVersionVariable == null) { |
151 reporter.reportInfo( | 157 reporter.reportInfo( |
152 library, MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); | 158 library, MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); |
153 } else { | 159 } else { |
154 backend.compiler.enqueuer.resolution | 160 impactBuilderForResolution.registerStaticUse( |
155 .addToWorkList(lookupMapVersionVariable); | 161 new StaticUse.foreignUse(lookupMapVersionVariable)); |
156 } | 162 } |
157 } | 163 } |
158 | 164 |
159 /// Checks if the version of lookup_map is valid, and if so, enable this | 165 /// Checks if the version of lookup_map is valid, and if so, enable this |
160 /// analysis during codegen. | 166 /// analysis during codegen. |
161 void onCodegenStart() { | 167 void onCodegenStart() { |
162 _inCodegen = true; | 168 _inCodegen = true; |
163 if (lookupMapVersionVariable == null) return; | 169 if (lookupMapVersionVariable == null) return; |
164 | 170 |
165 // At this point, the lookupMapVersionVariable should be resolved and it's | 171 // At this point, the lookupMapVersionVariable should be resolved and it's |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 /// returned using a type-argument expression. | 276 /// returned using a type-argument expression. |
271 void _addGenerics(InterfaceType type) { | 277 void _addGenerics(InterfaceType type) { |
272 if (!type.isGeneric) return; | 278 if (!type.isGeneric) return; |
273 for (var arg in type.typeArguments) { | 279 for (var arg in type.typeArguments) { |
274 if (arg is InterfaceType) { | 280 if (arg is InterfaceType) { |
275 _addClassUse(arg.element); | 281 _addClassUse(arg.element); |
276 // Note: this call was needed to generate correct code for | 282 // Note: this call was needed to generate correct code for |
277 // type_lookup_map/generic_type_test | 283 // type_lookup_map/generic_type_test |
278 // TODO(sigmund): can we get rid of this? | 284 // TODO(sigmund): can we get rid of this? |
279 backend.computeImpactForInstantiatedConstantType( | 285 backend.computeImpactForInstantiatedConstantType( |
280 backend.backendClasses.typeImplementation.rawType, impactBuilder); | 286 backend.backendClasses.typeImplementation.rawType, |
| 287 impactBuilderForCodegen); |
281 _addGenerics(arg); | 288 _addGenerics(arg); |
282 } | 289 } |
283 } | 290 } |
284 } | 291 } |
285 | 292 |
286 /// Callback from the codegen enqueuer, invoked when a constant (which is | 293 /// Callback from the codegen enqueuer, invoked when a constant (which is |
287 /// possibly a const key or a type literal) is used in the program. | 294 /// possibly a const key or a type literal) is used in the program. |
288 void registerTypeConstant(ClassElement element) { | 295 void registerTypeConstant(ClassElement element) { |
289 if (!_isEnabled || !_inCodegen) return; | 296 if (!_isEnabled || !_inCodegen) return; |
290 _addClassUse(element); | 297 _addClassUse(element); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
411 | 418 |
412 /// Marks that [key] has been seen, and thus, the corresponding entry in this | 419 /// Marks that [key] has been seen, and thus, the corresponding entry in this |
413 /// map should be considered reachable. | 420 /// map should be considered reachable. |
414 _markUsed(ConstantValue key) { | 421 _markUsed(ConstantValue key) { |
415 assert(!emitted); | 422 assert(!emitted); |
416 assert(unusedEntries.containsKey(key)); | 423 assert(unusedEntries.containsKey(key)); |
417 assert(!usedEntries.containsKey(key)); | 424 assert(!usedEntries.containsKey(key)); |
418 ConstantValue constant = unusedEntries.remove(key); | 425 ConstantValue constant = unusedEntries.remove(key); |
419 usedEntries[key] = constant; | 426 usedEntries[key] = constant; |
420 analysis.backend.computeImpactForCompileTimeConstant( | 427 analysis.backend.computeImpactForCompileTimeConstant( |
421 constant, analysis.impactBuilder, false); | 428 constant, analysis.impactBuilderForCodegen, false); |
422 } | 429 } |
423 | 430 |
424 /// Restores [original] to contain all of the entries marked as possibly used. | 431 /// Restores [original] to contain all of the entries marked as possibly used. |
425 void _prepareForEmission() { | 432 void _prepareForEmission() { |
426 ListConstantValue originalEntries = original.fields[analysis.entriesField]; | 433 ListConstantValue originalEntries = original.fields[analysis.entriesField]; |
427 DartType listType = originalEntries.type; | 434 DartType listType = originalEntries.type; |
428 List<ConstantValue> keyValuePairs = <ConstantValue>[]; | 435 List<ConstantValue> keyValuePairs = <ConstantValue>[]; |
429 usedEntries.forEach((key, value) { | 436 usedEntries.forEach((key, value) { |
430 keyValuePairs.add(key); | 437 keyValuePairs.add(key); |
431 keyValuePairs.add(value); | 438 keyValuePairs.add(value); |
432 }); | 439 }); |
433 | 440 |
434 // Note: we are restoring the entries here, see comment in [original]. | 441 // Note: we are restoring the entries here, see comment in [original]. |
435 if (singlePair) { | 442 if (singlePair) { |
436 assert(keyValuePairs.length == 0 || keyValuePairs.length == 2); | 443 assert(keyValuePairs.length == 0 || keyValuePairs.length == 2); |
437 if (keyValuePairs.length == 2) { | 444 if (keyValuePairs.length == 2) { |
438 original.fields[analysis.keyField] = keyValuePairs[0]; | 445 original.fields[analysis.keyField] = keyValuePairs[0]; |
439 original.fields[analysis.valueField] = keyValuePairs[1]; | 446 original.fields[analysis.valueField] = keyValuePairs[1]; |
440 } | 447 } |
441 } else { | 448 } else { |
442 original.fields[analysis.entriesField] = | 449 original.fields[analysis.entriesField] = |
443 new ListConstantValue(listType, keyValuePairs); | 450 new ListConstantValue(listType, keyValuePairs); |
444 } | 451 } |
445 } | 452 } |
446 } | 453 } |
447 | 454 |
448 final _validLookupMapVersionConstraint = new VersionConstraint.parse('^0.0.1'); | 455 final _validLookupMapVersionConstraint = new VersionConstraint.parse('^0.0.1'); |
OLD | NEW |