TValue GetMergedValue(ArrayBuilder <TValue> values) { Debug.Assert(values.Count > 0); var mergedValue = values[0]; for (var i = 1; i < values.Count; i++) { mergedValue = GetMergedValueCore(mergedValue, values[i]); } return(mergedValue); TValue GetMergedValueCore(TValue value1, TValue value2) { TValue mergedValue = ValueDomain.Merge(value1, value2); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); return(mergedValue); } }
public override DictionaryAnalysisData <AnalysisEntity, TValue> Merge(DictionaryAnalysisData <AnalysisEntity, TValue> map1, DictionaryAnalysisData <AnalysisEntity, TValue> map2) { Debug.Assert(map1 != null); AssertValidAnalysisData(map1); Debug.Assert(map2 != null); AssertValidAnalysisData(map2); TValue GetMergedValueForEntityPresentInOneMap(AnalysisEntity key, TValue value) { if (key.HasConstantValue) { return(value); } var defaultValue = GetDefaultValue(key); return(ValueDomain.Merge(value, defaultValue)); } var resultMap = new DictionaryAnalysisData <AnalysisEntity, TValue>(); var newKeys = PooledHashSet <AnalysisEntity> .GetInstance(); var map2LookupIgnoringInstanceLocation = map2.Keys.Where(IsAnalysisEntityForFieldOrProperty) .ToLookup(entity => entity.EqualsIgnoringInstanceLocationId); foreach (var entry1 in map1) { AnalysisEntity key1 = entry1.Key; TValue value1 = entry1.Value; if (map2LookupIgnoringInstanceLocation.Count > 0 && IsAnalysisEntityForFieldOrProperty(key1)) { var equivalentKeys2 = map2LookupIgnoringInstanceLocation[key1.EqualsIgnoringInstanceLocationId]; if (!equivalentKeys2.Any()) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1); Debug.Assert(!map2.ContainsKey(key1)); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); AssertValidEntryForMergedMap(key1, mergedValue); resultMap.Add(key1, mergedValue); continue; } foreach (AnalysisEntity key2 in equivalentKeys2) { // Confirm that key2 and key1 are indeed EqualsIgnoringInstanceLocation // This ensures that we handle hash code clashes of EqualsIgnoringInstanceLocationId. if (!key1.EqualsIgnoringInstanceLocation(key2)) { continue; } TValue value2 = map2[key2]; TValue mergedValue = ValueDomain.Merge(value1, value2); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); if (key1.InstanceLocation.Equals(key2.InstanceLocation)) { AssertValidEntryForMergedMap(key1, mergedValue); resultMap[key1] = mergedValue; } else { if (key1.SymbolOpt == null || key1.SymbolOpt != key2.SymbolOpt) { // PERF: Do not add a new key-value pair to the resultMap for unrelated entities or non-symbol based entities. continue; } AnalysisEntity mergedKey = key1.WithMergedInstanceLocation(key2); TValue newMergedValue = mergedValue; var isExistingKeyInInput = false; var isExistingKeyInResult = false; if (resultMap.TryGetValue(mergedKey, out var existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInResult = true; } if (map1.TryGetValue(mergedKey, out existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInInput = true; } if (map2.TryGetValue(mergedKey, out existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInInput = true; } Debug.Assert(ValueDomain.Compare(value1, newMergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, newMergedValue) <= 0); Debug.Assert(ValueDomain.Compare(mergedValue, newMergedValue) <= 0); mergedValue = newMergedValue; if (!isExistingKeyInInput && !isExistingKeyInResult && CanSkipNewEntry(mergedKey, mergedValue)) { // PERF: Do not add a new key-value pair to the resultMap if the value can be skipped. continue; } if (!isExistingKeyInInput) { newKeys.Add(mergedKey); } AssertValidEntryForMergedMap(mergedKey, mergedValue); resultMap[mergedKey] = mergedValue; } } } else if (map2.TryGetValue(key1, out var value2)) { TValue mergedValue = ValueDomain.Merge(value1, value2); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); resultMap.Add(key1, mergedValue); continue; } if (!resultMap.ContainsKey(key1)) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); AssertValidEntryForMergedMap(key1, mergedValue); resultMap.Add(key1, mergedValue); } } foreach (var kvp in map2) { var key2 = kvp.Key; var value2 = kvp.Value; if (!resultMap.ContainsKey(key2)) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key2, value2); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); AssertValidEntryForMergedMap(key2, mergedValue); resultMap.Add(key2, mergedValue); } } foreach (var newKey in newKeys) { Debug.Assert(!map1.ContainsKey(newKey)); Debug.Assert(!map2.ContainsKey(newKey)); if (ReferenceEquals(resultMap[newKey], GetDefaultValue(newKey))) { resultMap.Remove(newKey); } } newKeys.Free(); Debug.Assert(Compare(map1, resultMap) <= 0); Debug.Assert(Compare(map2, resultMap) <= 0); AssertValidAnalysisData(resultMap); return(resultMap); bool IsAnalysisEntityForFieldOrProperty(AnalysisEntity entity) => entity.SymbolOpt?.Kind == SymbolKind.Field || entity.SymbolOpt?.Kind == SymbolKind.Property; }
public override DictionaryAnalysisData <AnalysisEntity, TValue> Merge(DictionaryAnalysisData <AnalysisEntity, TValue> map1, DictionaryAnalysisData <AnalysisEntity, TValue> map2) { AssertValidAnalysisData(map1); AssertValidAnalysisData(map2); var resultMap = new DictionaryAnalysisData <AnalysisEntity, TValue>(); using var newKeys = PooledHashSet <AnalysisEntity> .GetInstance(); using var valuesToMergeBuilder = ArrayBuilder <TValue> .GetInstance(5); var map2LookupIgnoringInstanceLocation = map2.Keys.Where(IsAnalysisEntityForFieldOrProperty) .ToLookup(entity => entity.EqualsIgnoringInstanceLocationId); foreach (var entry1 in map1) { AnalysisEntity key1 = entry1.Key; TValue value1 = entry1.Value; if (map2LookupIgnoringInstanceLocation.Count > 0 && IsAnalysisEntityForFieldOrProperty(key1)) { var equivalentKeys2 = map2LookupIgnoringInstanceLocation[key1.EqualsIgnoringInstanceLocationId]; if (!equivalentKeys2.Any()) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1); Debug.Assert(!map2.ContainsKey(key1)); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); AddNewEntryToResultMap(key1, mergedValue); continue; } foreach (AnalysisEntity key2 in equivalentKeys2) { // Confirm that key2 and key1 are indeed EqualsIgnoringInstanceLocation // This ensures that we handle hash code clashes of EqualsIgnoringInstanceLocationId. if (!key1.EqualsIgnoringInstanceLocation(key2)) { continue; } TValue value2 = map2[key2]; valuesToMergeBuilder.Clear(); valuesToMergeBuilder.Add(value1); valuesToMergeBuilder.Add(value2); if (key1.InstanceLocation.Equals(key2.InstanceLocation)) { var mergedValue = GetMergedValue(valuesToMergeBuilder); AddNewEntryToResultMap(key1, mergedValue); } else { if (key1.SymbolOpt == null || !Equals(key1.SymbolOpt, key2.SymbolOpt)) { // PERF: Do not add a new key-value pair to the resultMap for unrelated entities or non-symbol based entities. continue; } AnalysisEntity mergedKey = key1.WithMergedInstanceLocation(key2); var isExistingKeyInInput = false; var isExistingKeyInResult = false; if (resultMap.TryGetValue(mergedKey, out var existingValue)) { valuesToMergeBuilder.Add(existingValue); isExistingKeyInResult = true; } if (map1.TryGetValue(mergedKey, out existingValue)) { valuesToMergeBuilder.Add(existingValue); isExistingKeyInInput = true; } if (map2.TryGetValue(mergedKey, out existingValue)) { valuesToMergeBuilder.Add(existingValue); isExistingKeyInInput = true; } var isCandidateToBeSkipped = !isExistingKeyInInput && !isExistingKeyInResult; if (isCandidateToBeSkipped && CanSkipNewEntity(mergedKey)) { // PERF: Do not add a new key-value pair to the resultMap if the key is not reachable from tracked entities and PointsTo values. continue; } var mergedValue = GetMergedValue(valuesToMergeBuilder); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); if (isCandidateToBeSkipped && CanSkipNewEntry(mergedKey, mergedValue)) { // PERF: Do not add a new key-value pair to the resultMap if the value can be skipped. continue; } if (!isExistingKeyInInput) { newKeys.Add(mergedKey); } AddNewEntryToResultMap(mergedKey, mergedValue, isNewKey: !isExistingKeyInInput); } } } else if (map2.TryGetValue(key1, out var value2)) { TValue mergedValue = ValueDomain.Merge(value1, value2); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); AddNewEntryToResultMap(key1, mergedValue); continue; } if (!resultMap.ContainsKey(key1)) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); AddNewEntryToResultMap(key1, mergedValue); } } foreach (var kvp in map2) { var key2 = kvp.Key; var value2 = kvp.Value; if (!resultMap.ContainsKey(key2)) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key2, value2); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); AddNewEntryToResultMap(key2, mergedValue); } } foreach (var newKey in newKeys) { Debug.Assert(!map1.ContainsKey(newKey)); Debug.Assert(!map2.ContainsKey(newKey)); var value = resultMap[newKey]; if (ReferenceEquals(value, GetDefaultValue(newKey))) { resultMap.Remove(newKey); } else { OnNewMergedValue(value); } } Debug.Assert(Compare(map1, resultMap) <= 0); Debug.Assert(Compare(map2, resultMap) <= 0); AssertValidAnalysisData(resultMap); return(resultMap);
public override IDictionary <AnalysisEntity, TValue> Merge(IDictionary <AnalysisEntity, TValue> map1, IDictionary <AnalysisEntity, TValue> map2) { Debug.Assert(map1 != null); Debug.Assert(map2 != null); TValue GetMergedValueForEntityPresentInOneMap(AnalysisEntity key, TValue value) { var defaultValue = GetDefaultValue(key); return(ValueDomain.Merge(value, defaultValue)); } var resultMap = new Dictionary <AnalysisEntity, TValue>(); var newKeys = new HashSet <AnalysisEntity>(); var map2LookupIgnoringInstanceLocation = map2.Keys.ToLookup(entity => entity.EqualsIgnoringInstanceLocationId); foreach (var entry1 in map1) { AnalysisEntity key1 = entry1.Key; TValue value1 = entry1.Value; var equivalentKeys2 = map2LookupIgnoringInstanceLocation[key1.EqualsIgnoringInstanceLocationId]; if (!equivalentKeys2.Any()) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1); Debug.Assert(!map2.ContainsKey(key1)); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); resultMap.Add(key1, mergedValue); continue; } foreach (AnalysisEntity key2 in equivalentKeys2) { TValue value2 = map2[key2]; TValue mergedValue = ValueDomain.Merge(value1, value2); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); if (key1.InstanceLocation.Equals(key2.InstanceLocation)) { resultMap[key1] = mergedValue; } else { if (key1.SymbolOpt == null || key1.SymbolOpt != key2.SymbolOpt) { // PERF: Do not add a new key-value pair to the resultMap for unrelated entities or non-symbol based entities. continue; } AnalysisEntity mergedKey = key1.WithMergedInstanceLocation(key2); TValue newMergedValue = mergedValue; var isExistingKeyInInput = false; var isExistingKeyInResult = false; if (resultMap.TryGetValue(mergedKey, out var existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInResult = true; } if (map1.TryGetValue(mergedKey, out existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInInput = true; } if (map2.TryGetValue(mergedKey, out existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInInput = true; } Debug.Assert(ValueDomain.Compare(value1, newMergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, newMergedValue) <= 0); Debug.Assert(ValueDomain.Compare(mergedValue, newMergedValue) <= 0); mergedValue = newMergedValue; if (!isExistingKeyInInput && !isExistingKeyInResult && CanSkipNewEntry(mergedKey, mergedValue)) { // PERF: Do not add a new key-value pair to the resultMap if the value can be skipped. continue; } if (!isExistingKeyInInput) { newKeys.Add(mergedKey); } resultMap[mergedKey] = mergedValue; } } if (!resultMap.ContainsKey(key1)) { resultMap[key1] = ValueDomain.UnknownOrMayBeValue; } } foreach (var kvp in map2) { var key2 = kvp.Key; var value2 = kvp.Value; if (!resultMap.ContainsKey(key2)) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key2, value2); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); resultMap.Add(key2, mergedValue); } } foreach (var newKey in newKeys) { Debug.Assert(!map1.ContainsKey(newKey)); Debug.Assert(!map2.ContainsKey(newKey)); if (ReferenceEquals(resultMap[newKey], GetDefaultValue(newKey))) { resultMap.Remove(newKey); } } Debug.Assert(Compare(map1, resultMap) <= 0); Debug.Assert(Compare(map2, resultMap) <= 0); return(resultMap); }