| 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 |