| // Copyright (c) 2021, the R8 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. |
| |
| package com.android.tools.r8.ir.optimize.classinliner.analysis; |
| |
| import com.google.common.collect.ImmutableMap; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.function.BiConsumer; |
| import java.util.function.BiFunction; |
| |
| class NonEmptyParameterUsagePerContext extends ParameterUsagePerContext { |
| |
| private final Map<AnalysisContext, ParameterUsage> backing; |
| |
| private NonEmptyParameterUsagePerContext(Map<AnalysisContext, ParameterUsage> backing) { |
| assert !backing.isEmpty(); |
| this.backing = backing; |
| } |
| |
| static ParameterUsagePerContext create(Map<AnalysisContext, ParameterUsage> backing) { |
| return backing.isEmpty() ? bottom() : new NonEmptyParameterUsagePerContext(backing); |
| } |
| |
| static NonEmptyParameterUsagePerContext createInitial() { |
| return new NonEmptyParameterUsagePerContext( |
| ImmutableMap.of(DefaultAnalysisContext.getInstance(), ParameterUsage.bottom())); |
| } |
| |
| void forEach(BiConsumer<AnalysisContext, ParameterUsage> consumer) { |
| backing.forEach(consumer); |
| } |
| |
| ParameterUsagePerContext join(NonEmptyParameterUsagePerContext parameterUsagePerContext) { |
| if (isBottom()) { |
| return parameterUsagePerContext; |
| } |
| if (parameterUsagePerContext.isBottom()) { |
| return this; |
| } |
| Map<AnalysisContext, ParameterUsage> newBacking = new HashMap<>(backing); |
| parameterUsagePerContext.forEach( |
| (context, parameterUsage) -> |
| newBacking.put( |
| context, |
| parameterUsage.join(newBacking.getOrDefault(context, ParameterUsage.bottom())))); |
| return create(newBacking); |
| } |
| |
| @Override |
| NonEmptyParameterUsagePerContext asKnown() { |
| return this; |
| } |
| |
| @Override |
| ParameterUsagePerContext externalize() { |
| boolean allBottom = true; |
| boolean allTop = true; |
| for (ParameterUsage usage : backing.values()) { |
| if (!usage.isBottom()) { |
| allBottom = false; |
| } |
| if (!usage.isTop()) { |
| allTop = false; |
| } |
| } |
| if (allBottom) { |
| return bottom(); |
| } |
| if (allTop) { |
| return top(); |
| } |
| // Remove mappings to top. These mappings represent unknown information, which there is no point |
| // in storing. After the removal of these mappings, the result should still be non-empty. |
| ParameterUsagePerContext rebuilt = |
| rebuild((context, usage) -> usage.isTop() ? null : usage.externalize()); |
| assert !rebuilt.isBottom(); |
| assert !rebuilt.isTop(); |
| return rebuilt; |
| } |
| |
| @Override |
| public ParameterUsage get(AnalysisContext context) { |
| return backing.getOrDefault(context, ParameterUsage.top()); |
| } |
| |
| @Override |
| ParameterUsagePerContext rebuild( |
| BiFunction<AnalysisContext, ParameterUsage, ParameterUsage> transformation) { |
| ImmutableMap.Builder<AnalysisContext, ParameterUsage> builder = null; |
| for (Map.Entry<AnalysisContext, ParameterUsage> entry : backing.entrySet()) { |
| AnalysisContext context = entry.getKey(); |
| ParameterUsage usage = entry.getValue(); |
| ParameterUsage newUsage = transformation.apply(context, usage); |
| if (newUsage != null) { |
| if (newUsage != usage) { |
| if (builder == null) { |
| builder = ImmutableMap.builder(); |
| for (Map.Entry<AnalysisContext, ParameterUsage> previousEntry : backing.entrySet()) { |
| AnalysisContext previousContext = previousEntry.getKey(); |
| if (previousContext == context) { |
| break; |
| } |
| builder.put(previousContext, previousEntry.getValue()); |
| } |
| } |
| builder.put(context, newUsage); |
| } else if (builder != null) { |
| builder.put(context, newUsage); |
| } |
| } |
| } |
| return builder != null ? create(builder.build()) : this; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj == null || obj.getClass() != getClass()) { |
| return false; |
| } |
| NonEmptyParameterUsagePerContext knownParameterUsagePerContext = |
| (NonEmptyParameterUsagePerContext) obj; |
| return backing.equals(knownParameterUsagePerContext.backing); |
| } |
| |
| @Override |
| public int hashCode() { |
| return backing.hashCode(); |
| } |
| } |