| // 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.optimize.argumentpropagation.codescanner; |
| |
| import com.android.tools.r8.graph.AppView; |
| import com.android.tools.r8.graph.DexMethodSignature; |
| import com.android.tools.r8.graph.ProgramMethod; |
| import com.android.tools.r8.shaking.AppInfoWithLiveness; |
| import com.android.tools.r8.utils.Timing; |
| import java.util.Map; |
| import java.util.function.BiConsumer; |
| import java.util.function.Function; |
| import java.util.function.Supplier; |
| |
| abstract class MethodStateCollection<K> { |
| |
| private final Map<K, MethodState> methodStates; |
| |
| MethodStateCollection(Map<K, MethodState> methodStates) { |
| assert methodStates.values().stream().noneMatch(MethodState::isBottom); |
| this.methodStates = methodStates; |
| } |
| |
| abstract K getKey(ProgramMethod method); |
| |
| abstract DexMethodSignature getSignature(K method); |
| |
| public void addMethodState( |
| AppView<AppInfoWithLiveness> appView, ProgramMethod method, MethodState methodState) { |
| addMethodState(appView, getKey(method), methodState); |
| } |
| |
| private void addMethodState( |
| AppView<AppInfoWithLiveness> appView, K method, MethodState methodState) { |
| if (methodState.isUnknown()) { |
| methodStates.put(method, methodState); |
| } else { |
| methodStates.compute( |
| method, |
| (ignore, existingMethodState) -> { |
| MethodState newMethodState; |
| if (existingMethodState == null) { |
| newMethodState = methodState.mutableCopy(); |
| } else { |
| newMethodState = |
| existingMethodState.mutableJoin(appView, getSignature(method), methodState); |
| } |
| assert !newMethodState.isBottom(); |
| return newMethodState; |
| }); |
| } |
| } |
| |
| /** |
| * This intentionally takes a {@link Supplier<MethodState>} to avoid computing the method state |
| * for a given call site when nothing is known about the arguments of the method. |
| */ |
| public void addTemporaryMethodState( |
| AppView<AppInfoWithLiveness> appView, |
| K method, |
| Function<MethodState, MethodState> methodStateSupplier, |
| Timing timing) { |
| methodStates.compute( |
| method, |
| (ignore, existingMethodState) -> { |
| if (existingMethodState == null) { |
| MethodState newMethodState = methodStateSupplier.apply(MethodState.bottom()); |
| assert !newMethodState.isBottom(); |
| return newMethodState; |
| } |
| assert !existingMethodState.isBottom(); |
| timing.begin("Join temporary method state"); |
| MethodState joinResult = |
| existingMethodState.mutableJoin(appView, getSignature(method), methodStateSupplier); |
| assert !joinResult.isBottom(); |
| timing.end(); |
| return joinResult; |
| }); |
| } |
| |
| public void addMethodStates( |
| AppView<AppInfoWithLiveness> appView, MethodStateCollection<K> other) { |
| other.methodStates.forEach( |
| (method, methodState) -> addMethodState(appView, method, methodState)); |
| } |
| |
| public void forEach(BiConsumer<K, MethodState> consumer) { |
| methodStates.forEach(consumer); |
| } |
| |
| public MethodState get(ProgramMethod method) { |
| return get(getKey(method)); |
| } |
| |
| public MethodState get(K method) { |
| return methodStates.getOrDefault(method, MethodState.bottom()); |
| } |
| |
| public boolean isEmpty() { |
| return methodStates.isEmpty(); |
| } |
| |
| public MethodState remove(ProgramMethod method) { |
| return removeOrElse(method, MethodState.bottom()); |
| } |
| |
| public MethodState removeOrElse(ProgramMethod method, MethodState defaultValue) { |
| MethodState removed = methodStates.remove(getKey(method)); |
| return removed != null ? removed : defaultValue; |
| } |
| |
| public void set(ProgramMethod method, MethodState methodState) { |
| set(getKey(method), methodState); |
| } |
| |
| private void set(K method, MethodState methodState) { |
| if (methodState.isBottom()) { |
| methodStates.remove(method); |
| } else { |
| methodStates.put(method, methodState); |
| } |
| } |
| } |