Index: pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart |
diff --git a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart |
index bd1b3a422912eb88dd5216efaacb1d3da772fab9..e71589e9f99d7f05e9a9d6d075d8c42b5f0e59f6 100644 |
--- a/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart |
+++ b/pkg/compiler/lib/src/js_backend/lookup_map_analysis.dart |
@@ -10,6 +10,8 @@ import 'package:pub_semver/pub_semver.dart'; |
import '../common.dart'; |
import '../common_elements.dart'; |
import '../common/backend_api.dart'; |
+import '../compile_time_constants.dart'; |
+import '../constants/constant_system.dart'; |
import '../constants/values.dart' |
show |
ConstantValue, |
@@ -25,7 +27,6 @@ import '../options.dart'; |
import '../universe/use.dart' show ConstantUse, StaticUse; |
import '../universe/world_impact.dart' |
show WorldImpact, StagedWorldImpactBuilder; |
-import 'backend.dart' show JavaScriptBackend; |
import 'backend_helpers.dart'; |
/// Lookup map handling for resolution. |
@@ -113,20 +114,90 @@ class LookupMapLibraryAccess { |
// ClassElement of a type to refer to keys we need to discover). |
// TODO(sigmund): detect uses of mirrors |
class LookupMapAnalysis { |
- static final Uri PACKAGE_LOOKUP_MAP = |
- new Uri(scheme: 'package', path: 'lookup_map/lookup_map.dart'); |
+ const LookupMapAnalysis._(); |
+ |
+ factory LookupMapAnalysis( |
+ DiagnosticReporter reporter, |
+ ConstantSystem constantSystem, |
+ ConstantEnvironment constants, |
+ ElementEnvironment elementEnvironment, |
+ CommonElements commonElements, |
+ BackendHelpers helpers, |
+ BackendClasses backendClasses, |
+ LookupMapLibraryAccess analysis) { |
+ /// Checks if the version of lookup_map is valid, and if so, enable this |
+ /// analysis during codegen. |
+ FieldElement lookupMapVersionVariable = analysis.lookupMapVersionVariable; |
+ if (lookupMapVersionVariable == null) return const LookupMapAnalysis._(); |
- /// Reference to [JavaScriptBackend] to be able to enqueue work when we |
- /// discover that a key in a map is potentially used. |
- final JavaScriptBackend _backend; |
+ // At this point, the lookupMapVersionVariable should be resolved and it's |
+ // constant value should be available. |
+ StringConstantValue value = |
+ constants.getConstantValue(lookupMapVersionVariable.constant); |
+ if (value == null) { |
+ reporter.reportHintMessage(lookupMapVersionVariable, |
+ MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); |
+ return const LookupMapAnalysis._(); |
+ } |
- final CompilerOptions _options; |
+ // TODO(sigmund): add proper version resolution using the pub_semver package |
+ // when we introduce the next version. |
+ Version version; |
+ try { |
+ version = new Version.parse(value.primitiveValue.slowToString()); |
+ } catch (e) {} |
- /// Reference the diagnostic reporting system for logging and reporting issues |
- /// to the end-user. |
- final DiagnosticReporter _reporter; |
+ if (version == null || !_validLookupMapVersionConstraint.allows(version)) { |
+ reporter.reportHintMessage(lookupMapVersionVariable, |
+ MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); |
+ return const LookupMapAnalysis._(); |
+ } |
- final ElementEnvironment _elementEnvironment; |
+ ClassEntity typeLookupMapClass = |
+ elementEnvironment.lookupClass(analysis.lookupMapLibrary, 'LookupMap'); |
+ FieldElement entriesField = |
+ elementEnvironment.lookupClassMember(typeLookupMapClass, '_entries'); |
+ FieldElement keyField = |
+ elementEnvironment.lookupClassMember(typeLookupMapClass, '_key'); |
+ FieldElement valueField = |
+ elementEnvironment.lookupClassMember(typeLookupMapClass, '_value'); |
+ // TODO(sigmund): Maybe inline nested maps to make the output code smaller? |
+ |
+ return new _LookupMapAnalysis(constantSystem, commonElements, helpers, |
+ backendClasses, entriesField, keyField, valueField, typeLookupMapClass); |
+ } |
+ |
+ /// Compute the [WorldImpact] for the constants registered since last flush. |
+ WorldImpact flush() => const WorldImpact(); |
+ |
+ /// Whether [constant] is an instance of a `LookupMap`. |
+ bool isLookupMap(ConstantValue constant) => false; |
+ |
+ /// Registers an instance of a lookup-map with the analysis. |
+ void registerLookupMapReference(ConstantValue lookupMap) {} |
+ |
+ /// Callback from the enqueuer, invoked when [element] is instantiated. |
+ void registerInstantiatedClass(ClassElement element) {} |
+ |
+ /// Callback from the enqueuer, invoked when [type] is instantiated. |
+ void registerInstantiatedType(ResolutionInterfaceType type) {} |
+ |
+ /// Callback from the codegen enqueuer, invoked when a constant (which is |
+ /// possibly a const key or a type literal) is used in the program. |
+ void registerTypeConstant(ClassElement element) {} |
+ |
+ void registerConstantKey(ConstantValue constant) {} |
+ |
+ void logSummary(void log(String message)) {} |
+ |
+ void onQueueClosed() {} |
+} |
+ |
+class _LookupMapAnalysis implements LookupMapAnalysis { |
+ static final Uri PACKAGE_LOOKUP_MAP = |
+ new Uri(scheme: 'package', path: 'lookup_map/lookup_map.dart'); |
+ |
+ final ConstantSystem _constantSystem; |
final CommonElements _commonElements; |
@@ -135,16 +206,16 @@ class LookupMapAnalysis { |
final BackendClasses _backendClasses; |
/// The resolved [ClassElement] associated with `LookupMap`. |
- ClassElement typeLookupMapClass; |
+ final ClassElement _typeLookupMapClass; |
/// The resolved [FieldElement] for `LookupMap._entries`. |
- FieldElement entriesField; |
+ final FieldElement _entriesField; |
/// The resolved [FieldElement] for `LookupMap._key`. |
- FieldElement keyField; |
+ final FieldElement _keyField; |
/// The resolved [FieldElement] for `LookupMap._value`. |
- FieldElement valueField; |
+ final FieldElement _valueField; |
/// Constant instances of `LookupMap` and information about them tracked by |
/// this analysis. |
@@ -174,81 +245,32 @@ class LookupMapAnalysis { |
final StagedWorldImpactBuilder _impactBuilder = |
new StagedWorldImpactBuilder(); |
- /// Whether the backend is currently processing the codegen queue. |
- bool _inCodegen = false; |
- |
- LookupMapAnalysis( |
- this._backend, |
- this._options, |
- this._reporter, |
- this._elementEnvironment, |
+ _LookupMapAnalysis( |
+ this._constantSystem, |
this._commonElements, |
this._helpers, |
- this._backendClasses); |
+ this._backendClasses, |
+ this._entriesField, |
+ this._keyField, |
+ this._valueField, |
+ this._typeLookupMapClass); |
/// Compute the [WorldImpact] for the constants registered since last flush. |
WorldImpact flush() { |
return _impactBuilder.flush(); |
} |
- /// Whether this analysis and optimization is enabled. |
- bool get _isEnabled { |
- // `lookupMap==off` kept here to make it easy to test disabling this feature |
- if (const String.fromEnvironment('lookupMap') == 'off') return false; |
- return typeLookupMapClass != null; |
- } |
- |
- /// Checks if the version of lookup_map is valid, and if so, enable this |
- /// analysis during codegen. |
- void onCodegenStart(LookupMapLibraryAccess analysis) { |
- _inCodegen = true; |
- FieldElement lookupMapVersionVariable = analysis.lookupMapVersionVariable; |
- if (lookupMapVersionVariable == null) return; |
- |
- // At this point, the lookupMapVersionVariable should be resolved and it's |
- // constant value should be available. |
- StringConstantValue value = |
- _backend.constants.getConstantValue(lookupMapVersionVariable.constant); |
- if (value == null) { |
- _reporter.reportHintMessage(lookupMapVersionVariable, |
- MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); |
- return; |
- } |
- |
- // TODO(sigmund): add proper version resolution using the pub_semver package |
- // when we introduce the next version. |
- Version version; |
- try { |
- version = new Version.parse(value.primitiveValue.slowToString()); |
- } catch (e) {} |
- |
- if (version == null || !_validLookupMapVersionConstraint.allows(version)) { |
- _reporter.reportHintMessage(lookupMapVersionVariable, |
- MessageKind.UNRECOGNIZED_VERSION_OF_LOOKUP_MAP); |
- return; |
- } |
- |
- ClassEntity cls = |
- _elementEnvironment.lookupClass(analysis.lookupMapLibrary, 'LookupMap'); |
- entriesField = _elementEnvironment.lookupClassMember(cls, '_entries'); |
- keyField = _elementEnvironment.lookupClassMember(cls, '_key'); |
- valueField = _elementEnvironment.lookupClassMember(cls, '_value'); |
- // TODO(sigmund): Maybe inline nested maps to make the output code smaller? |
- typeLookupMapClass = cls; |
- } |
- |
/// Whether [constant] is an instance of a `LookupMap`. |
bool isLookupMap(ConstantValue constant) { |
- if (_isEnabled && constant is ConstructedConstantValue) { |
+ if (constant is ConstructedConstantValue) { |
ResolutionInterfaceType type = constant.type; |
- return type.element.isSubclassOf(typeLookupMapClass); |
+ return type.element.isSubclassOf(_typeLookupMapClass); |
} |
return false; |
} |
/// Registers an instance of a lookup-map with the analysis. |
void registerLookupMapReference(ConstantValue lookupMap) { |
- if (!_isEnabled || !_inCodegen) return; |
assert(isLookupMap(lookupMap)); |
_lookupMaps.putIfAbsent( |
lookupMap, () => new _LookupMapInfo(lookupMap, this).._updateUsed()); |
@@ -273,8 +295,8 @@ class LookupMapAnalysis { |
void _addClassUse(ClassElement cls) { |
ConstantValue key = _typeConstants.putIfAbsent( |
cls, |
- () => _backend.constantSystem |
- .createType(_commonElements, _backendClasses, cls.rawType)); |
+ () => _constantSystem.createType( |
+ _commonElements, _backendClasses, cls.rawType)); |
_addUse(key); |
} |
@@ -299,14 +321,12 @@ class LookupMapAnalysis { |
/// Callback from the enqueuer, invoked when [element] is instantiated. |
void registerInstantiatedClass(ClassElement element) { |
- if (!_isEnabled || !_inCodegen) return; |
// TODO(sigmund): only add if .runtimeType is ever used |
_addClassUse(element); |
} |
/// Callback from the enqueuer, invoked when [type] is instantiated. |
void registerInstantiatedType(ResolutionInterfaceType type) { |
- if (!_isEnabled || !_inCodegen) return; |
// TODO(sigmund): only add if .runtimeType is ever used |
_addClassUse(type.element); |
// TODO(sigmund): only do this when type-argument expressions are used? |
@@ -335,46 +355,42 @@ class LookupMapAnalysis { |
/// Callback from the codegen enqueuer, invoked when a constant (which is |
/// possibly a const key or a type literal) is used in the program. |
void registerTypeConstant(ClassElement element) { |
- if (!_isEnabled || !_inCodegen) return; |
_addClassUse(element); |
} |
void registerConstantKey(ConstantValue constant) { |
- if (!_isEnabled || !_inCodegen) return; |
if (constant.isPrimitive || _overridesEquals(constant)) return; |
_addUse(constant); |
} |
+ void logSummary(void log(String message)) { |
+ // When --verbose is passed, we show the total number and set of keys that |
+ // were tree-shaken from lookup maps. |
+ var sb = new StringBuffer(); |
+ int count = 0; |
+ for (var info in _lookupMaps.values) { |
+ for (var key in info.unusedEntries.keys) { |
+ if (count != 0) sb.write(','); |
+ sb.write(key.toDartText()); |
+ count++; |
+ } |
+ } |
+ log(count == 0 |
+ ? 'lookup-map: nothing was tree-shaken' |
+ : 'lookup-map: found $count unused keys ($sb)'); |
+ } |
+ |
/// Callback from the backend, invoked when reaching the end of the enqueuing |
/// process, but before emitting the code. At this moment we have discovered |
/// all types used in the program and we can tree-shake anything that is |
/// unused. |
void onQueueClosed() { |
- if (!_isEnabled || !_inCodegen) return; |
- |
_lookupMaps.values.forEach((info) { |
assert(!info.emitted); |
info.emitted = true; |
info._prepareForEmission(); |
}); |
- // When --verbose is passed, we show the total number and set of keys that |
- // were tree-shaken from lookup maps. |
- if (_options.verbose) { |
- var sb = new StringBuffer(); |
- int count = 0; |
- for (var info in _lookupMaps.values) { |
- for (var key in info.unusedEntries.keys) { |
- if (count != 0) sb.write(','); |
- sb.write(key.toDartText()); |
- count++; |
- } |
- } |
- _reporter.log(count == 0 |
- ? 'lookup-map: nothing was tree-shaken' |
- : 'lookup-map: found $count unused keys ($sb)'); |
- } |
- |
// Release resources. |
_lookupMaps.clear(); |
_pending.clear(); |
@@ -397,7 +413,7 @@ class _LookupMapInfo { |
/// Reference to the lookup map analysis to be able to refer to data shared |
/// accross infos. |
- final LookupMapAnalysis analysis; |
+ final _LookupMapAnalysis analysis; |
/// Whether we have already emitted this constant. |
bool emitted = false; |
@@ -418,17 +434,17 @@ class _LookupMapInfo { |
/// Creates and initializes the information containing all keys of the |
/// original map marked as unused. |
_LookupMapInfo(this.original, this.analysis) { |
- ConstantValue key = original.fields[analysis.keyField]; |
+ ConstantValue key = original.fields[analysis._keyField]; |
singlePair = !key.isNull; |
if (singlePair) { |
- unusedEntries[key] = original.fields[analysis.valueField]; |
+ unusedEntries[key] = original.fields[analysis._valueField]; |
// Note: we modify the constant in-place, see comment in [original]. |
- original.fields[analysis.keyField] = new NullConstantValue(); |
- original.fields[analysis.valueField] = new NullConstantValue(); |
+ original.fields[analysis._keyField] = new NullConstantValue(); |
+ original.fields[analysis._valueField] = new NullConstantValue(); |
} else { |
- ListConstantValue list = original.fields[analysis.entriesField]; |
+ ListConstantValue list = original.fields[analysis._entriesField]; |
List<ConstantValue> keyValuePairs = list.entries; |
for (int i = 0; i < keyValuePairs.length; i += 2) { |
ConstantValue key = keyValuePairs[i]; |
@@ -436,7 +452,7 @@ class _LookupMapInfo { |
} |
// Note: we modify the constant in-place, see comment in [original]. |
- original.fields[analysis.entriesField] = |
+ original.fields[analysis._entriesField] = |
new ListConstantValue(list.type, []); |
} |
} |
@@ -471,7 +487,7 @@ class _LookupMapInfo { |
/// Restores [original] to contain all of the entries marked as possibly used. |
void _prepareForEmission() { |
- ListConstantValue originalEntries = original.fields[analysis.entriesField]; |
+ ListConstantValue originalEntries = original.fields[analysis._entriesField]; |
ResolutionInterfaceType listType = originalEntries.type; |
List<ConstantValue> keyValuePairs = <ConstantValue>[]; |
usedEntries.forEach((key, value) { |
@@ -483,11 +499,11 @@ class _LookupMapInfo { |
if (singlePair) { |
assert(keyValuePairs.length == 0 || keyValuePairs.length == 2); |
if (keyValuePairs.length == 2) { |
- original.fields[analysis.keyField] = keyValuePairs[0]; |
- original.fields[analysis.valueField] = keyValuePairs[1]; |
+ original.fields[analysis._keyField] = keyValuePairs[0]; |
+ original.fields[analysis._valueField] = keyValuePairs[1]; |
} |
} else { |
- original.fields[analysis.entriesField] = |
+ original.fields[analysis._entriesField] = |
new ListConstantValue(listType, keyValuePairs); |
} |
} |