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 '../common/registry.dart' show Registry; | 8 import '../common/registry.dart' show Registry; |
9 import '../compiler.dart' show Compiler; | 9 import '../compiler.dart' show Compiler; |
10 import '../diagnostics/messages.dart' show MessageKind; | 10 import '../diagnostics/diagnostic_listener.dart' show |
| 11 DiagnosticReporter; |
| 12 import '../diagnostics/messages.dart' show |
| 13 MessageKind; |
11 import '../constants/values.dart' show | 14 import '../constants/values.dart' show |
12 ConstantValue, | 15 ConstantValue, |
13 ConstructedConstantValue, | 16 ConstructedConstantValue, |
14 ListConstantValue, | 17 ListConstantValue, |
15 NullConstantValue, | 18 NullConstantValue, |
16 StringConstantValue, | 19 StringConstantValue, |
17 TypeConstantValue; | 20 TypeConstantValue; |
18 import '../dart_types.dart' show DartType; | 21 import '../dart_types.dart' show DartType; |
19 import '../elements/elements.dart' show | 22 import '../elements/elements.dart' show |
20 ClassElement, | 23 ClassElement, |
21 Element, | 24 Element, |
22 Elements, | 25 Elements, |
23 FieldElement, | 26 FieldElement, |
24 FunctionElement, | 27 FunctionElement, |
25 FunctionSignature, | 28 FunctionSignature, |
26 LibraryElement, | 29 LibraryElement, |
27 VariableElement; | 30 VariableElement; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 // TODO(sigmund): add support for const expressions, currently this | 68 // TODO(sigmund): add support for const expressions, currently this |
66 // implementation only supports Type literals. To support const expressions we | 69 // implementation only supports Type literals. To support const expressions we |
67 // need to change some of the invariants below (e.g. we can no longer use the | 70 // need to change some of the invariants below (e.g. we can no longer use the |
68 // ClassElement of a type to refer to keys we need to discover). | 71 // ClassElement of a type to refer to keys we need to discover). |
69 // TODO(sigmund): detect uses of mirrors | 72 // TODO(sigmund): detect uses of mirrors |
70 class LookupMapAnalysis { | 73 class LookupMapAnalysis { |
71 /// Reference to [JavaScriptBackend] to be able to enqueue work when we | 74 /// Reference to [JavaScriptBackend] to be able to enqueue work when we |
72 /// discover that a key in a map is potentially used. | 75 /// discover that a key in a map is potentially used. |
73 final JavaScriptBackend backend; | 76 final JavaScriptBackend backend; |
74 | 77 |
| 78 /// Reference the diagnostic reporting system for logging and reporting issues |
| 79 /// to the end-user. |
| 80 final DiagnosticReporter reporter; |
| 81 |
75 /// The resolved [VariableElement] associated with the top-level `_version`. | 82 /// The resolved [VariableElement] associated with the top-level `_version`. |
76 VariableElement lookupMapVersionVariable; | 83 VariableElement lookupMapVersionVariable; |
77 | 84 |
78 /// The resolved [LibraryElement] associated with | 85 /// The resolved [LibraryElement] associated with |
79 /// `package:lookup_map/lookup_map.dart`. | 86 /// `package:lookup_map/lookup_map.dart`. |
80 LibraryElement lookupMapLibrary; | 87 LibraryElement lookupMapLibrary; |
81 | 88 |
82 /// The resolved [ClassElement] associated with `LookupMap`. | 89 /// The resolved [ClassElement] associated with `LookupMap`. |
83 ClassElement typeLookupMapClass; | 90 ClassElement typeLookupMapClass; |
84 | 91 |
(...skipping 27 matching lines...) Expand all Loading... |
112 final _typesWithEquals = <ClassElement, bool>{}; | 119 final _typesWithEquals = <ClassElement, bool>{}; |
113 | 120 |
114 /// Pending work to do if we discover that a new key is in use. For each key | 121 /// Pending work to do if we discover that a new key is in use. For each key |
115 /// that we haven't seen, we record the list of lookup-maps that contain an | 122 /// that we haven't seen, we record the list of lookup-maps that contain an |
116 /// entry with that key. | 123 /// entry with that key. |
117 final _pending = <ConstantValue, List<_LookupMapInfo>>{}; | 124 final _pending = <ConstantValue, List<_LookupMapInfo>>{}; |
118 | 125 |
119 /// Whether the backend is currently processing the codegen queue. | 126 /// Whether the backend is currently processing the codegen queue. |
120 bool _inCodegen = false; | 127 bool _inCodegen = false; |
121 | 128 |
122 LookupMapAnalysis(this.backend); | 129 LookupMapAnalysis(this.backend, this.reporter); |
123 | 130 |
124 /// Whether this analysis and optimization is enabled. | 131 /// Whether this analysis and optimization is enabled. |
125 bool get _isEnabled { | 132 bool get _isEnabled { |
126 // `lookupMap==off` kept here to make it easy to test disabling this feature | 133 // `lookupMap==off` kept here to make it easy to test disabling this feature |
127 if (const String.fromEnvironment('lookupMap') == 'off') return false; | 134 if (const String.fromEnvironment('lookupMap') == 'off') return false; |
128 return typeLookupMapClass != null; | 135 return typeLookupMapClass != null; |
129 } | 136 } |
130 | 137 |
131 /// Initializes this analysis by providing the resolved library. This is | 138 /// Initializes this analysis by providing the resolved library. This is |
132 /// invoked during resolution when the `lookup_map` library is discovered. | 139 /// invoked during resolution when the `lookup_map` library is discovered. |
133 void init(LibraryElement library) { | 140 void init(LibraryElement library) { |
134 lookupMapLibrary = library; | 141 lookupMapLibrary = library; |
135 // We will enable the lookupMapAnalysis as long as we get a known version of | 142 // We will enable the lookupMapAnalysis as long as we get a known version of |
136 // the lookup_map package. We otherwise produce a warning. | 143 // the lookup_map package. We otherwise produce a warning. |
137 lookupMapVersionVariable = library.implementation.findLocal('_version'); | 144 lookupMapVersionVariable = library.implementation.findLocal('_version'); |
138 if (lookupMapVersionVariable == null) { | 145 if (lookupMapVersionVariable == null) { |
139 backend.compiler.reportInfo(library, | 146 reporter.reportInfo(library, |
140 MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); | 147 MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); |
141 } else { | 148 } else { |
142 backend.compiler.enqueuer.resolution.addToWorkList( | 149 backend.compiler.enqueuer.resolution.addToWorkList( |
143 lookupMapVersionVariable); | 150 lookupMapVersionVariable); |
144 } | 151 } |
145 } | 152 } |
146 | 153 |
147 /// Checks if the version of lookup_map is valid, and if so, enable this | 154 /// Checks if the version of lookup_map is valid, and if so, enable this |
148 /// analysis during codegen. | 155 /// analysis during codegen. |
149 void onCodegenStart() { | 156 void onCodegenStart() { |
150 _inCodegen = true; | 157 _inCodegen = true; |
151 if (lookupMapVersionVariable == null) return; | 158 if (lookupMapVersionVariable == null) return; |
152 | 159 |
153 // At this point, the lookupMapVersionVariable should be resolved and it's | 160 // At this point, the lookupMapVersionVariable should be resolved and it's |
154 // constant value should be available. | 161 // constant value should be available. |
155 StringConstantValue value = | 162 StringConstantValue value = |
156 backend.constants.getConstantValueForVariable(lookupMapVersionVariable); | 163 backend.constants.getConstantValueForVariable(lookupMapVersionVariable); |
157 if (value == null) { | 164 if (value == null) { |
158 backend.compiler.reportInfo(lookupMapVersionVariable, | 165 reporter.reportInfo(lookupMapVersionVariable, |
159 MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); | 166 MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); |
160 return; | 167 return; |
161 } | 168 } |
162 | 169 |
163 // TODO(sigmund): add proper version resolution using the pub_semver package | 170 // TODO(sigmund): add proper version resolution using the pub_semver package |
164 // when we introduce the next version. | 171 // when we introduce the next version. |
165 Version version; | 172 Version version; |
166 try { | 173 try { |
167 version = new Version.parse(value.primitiveValue.slowToString()); | 174 version = new Version.parse(value.primitiveValue.slowToString()); |
168 } catch (e) {} | 175 } catch (e) {} |
169 | 176 |
170 if (version == null || !_validLookupMapVersionConstraint.allows(version)) { | 177 if (version == null || !_validLookupMapVersionConstraint.allows(version)) { |
171 backend.compiler.reportInfo(lookupMapVersionVariable, | 178 reporter.reportInfo(lookupMapVersionVariable, |
172 MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); | 179 MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); |
173 return; | 180 return; |
174 } | 181 } |
175 | 182 |
176 ClassElement cls = lookupMapLibrary.findLocal('LookupMap'); | 183 ClassElement cls = lookupMapLibrary.findLocal('LookupMap'); |
177 cls.computeType(backend.resolution); | 184 cls.computeType(backend.resolution); |
178 entriesField = cls.lookupMember('_entries'); | 185 entriesField = cls.lookupMember('_entries'); |
179 keyField = cls.lookupMember('_key'); | 186 keyField = cls.lookupMember('_key'); |
180 valueField = cls.lookupMember('_value'); | 187 valueField = cls.lookupMember('_value'); |
181 // TODO(sigmund): Maybe inline nested maps to make the output code smaller? | 188 // TODO(sigmund): Maybe inline nested maps to make the output code smaller? |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 if (compiler.verbose) { | 311 if (compiler.verbose) { |
305 var sb = new StringBuffer(); | 312 var sb = new StringBuffer(); |
306 int count = 0; | 313 int count = 0; |
307 for (var info in _lookupMaps.values) { | 314 for (var info in _lookupMaps.values) { |
308 for (var key in info.unusedEntries.keys) { | 315 for (var key in info.unusedEntries.keys) { |
309 if (count != 0) sb.write(','); | 316 if (count != 0) sb.write(','); |
310 sb.write(key.unparse()); | 317 sb.write(key.unparse()); |
311 count++; | 318 count++; |
312 } | 319 } |
313 } | 320 } |
314 compiler.log(count == 0 | 321 reporter.log(count == 0 |
315 ? 'lookup-map: nothing was tree-shaken' | 322 ? 'lookup-map: nothing was tree-shaken' |
316 : 'lookup-map: found $count unused keys ($sb)'); | 323 : 'lookup-map: found $count unused keys ($sb)'); |
317 } | 324 } |
318 | 325 |
319 // Release resources. | 326 // Release resources. |
320 _lookupMaps.clear(); | 327 _lookupMaps.clear(); |
321 _pending.clear(); | 328 _pending.clear(); |
322 _inUse.clear(); | 329 _inUse.clear(); |
323 } | 330 } |
324 } | 331 } |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 } | 437 } |
431 } else { | 438 } else { |
432 original.fields[analysis.entriesField] = | 439 original.fields[analysis.entriesField] = |
433 new ListConstantValue(listType, keyValuePairs); | 440 new ListConstantValue(listType, keyValuePairs); |
434 } | 441 } |
435 } | 442 } |
436 } | 443 } |
437 | 444 |
438 final _validLookupMapVersionConstraint = | 445 final _validLookupMapVersionConstraint = |
439 new VersionConstraint.parse('^0.0.1'); | 446 new VersionConstraint.parse('^0.0.1'); |
OLD | NEW |