blob: 614d497ba835939c570ad8fe3917fc6bb8f99f7c [file] [log] [blame]
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/// This data structure assigns a unique integer identifier to everything that
/// might undergo promotion in the user's code (local variables and properties).
/// An integer identifier is also assigned to `this` (even though `this` is not
/// promotable), because promotable properties can be reached using `this` as a
/// starting point.
class PromotionKeyStore<Variable extends Object> {
/// Special promotion key to represent `this`.
late final int thisPromotionKey = _makeNewKey();
final Map<Variable, int> _variableKeys = new Map<Variable, int>.identity();
final List<_PromotionKeyInfo<Variable>> _keyToInfo = [];
/// Gets the key of the next promotable entity whose [_rootVariableKey] is the
/// same as [key]. Keys with the same root are linked together in a loop (so
/// to iterate through them, continue walking the chain until you reach your
/// starting point).
int getNextKeyWithSameRoot(int key) => _keyToInfo[key].nextKeyWithSameRoot;
int getProperty(int targetKey, String propertyName) =>
(_keyToInfo[targetKey].properties ??= {})[propertyName] ??=
_makeNewKey(targetKey: targetKey);
/// Gets the variable key for the variable that forms the root of the property
/// accesses that led to [promotionKey]. For example, the root variable key
/// for a property access `a.b.c` is the promotion key for `a`.
int getRootVariableKey(int promotionKey) =>
_keyToInfo[promotionKey].rootVariableKey;
int keyForVariable(Variable variable) =>
_variableKeys[variable] ??= _makeNewKey(variable: variable);
/// Creates a fresh promotion key that hasn't been used before (and won't be
/// reused again). This is used by flow analysis to model the synthetic
/// variables used during pattern matching to cache the values that the
/// pattern, and its subpatterns, are being matched against.
int makeTemporaryKey() => _makeNewKey();
Variable? variableForKey(int variableKey) => _keyToInfo[variableKey].variable;
int _makeNewKey({Variable? variable, int? targetKey}) {
int key = _keyToInfo.length;
int rootVariableKey;
int nextKeyWithSameRoot;
if (targetKey == null) {
rootVariableKey = key;
// This key does not represent a property, so its nextKeyWithSameRoot
// pointer should point to itself.
nextKeyWithSameRoot = key;
} else {
_PromotionKeyInfo<Variable> targetInfo = _keyToInfo[targetKey];
rootVariableKey = targetInfo.rootVariableKey;
// This key represents a property of [targetKey], so its
// nextKeyWithSameRoot should be linked into whatever chain [targetKey]
// is in.
nextKeyWithSameRoot = targetInfo.nextKeyWithSameRoot;
targetInfo.nextKeyWithSameRoot = key;
}
_keyToInfo.add(new _PromotionKeyInfo(
variable: variable,
nextKeyWithSameRoot: nextKeyWithSameRoot,
rootVariableKey: rootVariableKey));
return key;
}
}
/// Class storing detailed information about a single promotion key.
class _PromotionKeyInfo<Variable extends Object> {
/// The variable associated with the key, if any.
final Variable? variable;
/// Map indicating the set of properties of this promotable entity being
/// tracked by flow analysis. The map is indexed by the property name.
///
/// Null is considered equivalent to an empty map (this allows us to save
/// memory due to the fact that most promotion keys won't be subject to any
/// property access).
Map<String, int>? properties;
/// The key of the next promotable entity whose [_rootVariableKey] is the same
/// as this one. Keys with the same root are linked together in a loop (so to
/// iterate through them, continue walking the chain until you reach your
/// starting point).
int nextKeyWithSameRoot;
/// The variable key for the variable that forms the root of the property
/// accesses that led to this variable key. For example, the entry for a
/// property access `a.b.c` points to the promotion key for `a`.
final int rootVariableKey;
_PromotionKeyInfo(
{required this.variable,
required this.nextKeyWithSameRoot,
required this.rootVariableKey});
}