| // Copyright (c) 2019, 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.naming; |
| |
| import com.android.tools.r8.graph.DexEncodedMethod; |
| import com.android.tools.r8.graph.DexMethod; |
| import com.android.tools.r8.graph.DexString; |
| import com.android.tools.r8.naming.MethodReservationState.InternalReservationState; |
| import com.android.tools.r8.utils.MethodSignatureEquivalence; |
| import com.google.common.base.Equivalence.Wrapper; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.function.Function; |
| |
| class MethodReservationState<KeyType> |
| extends MethodNamingStateBase<KeyType, InternalReservationState> { |
| |
| private final MethodReservationState<KeyType> parentNamingState; |
| |
| private MethodReservationState( |
| MethodReservationState<KeyType> parentNamingState, |
| Function<DexMethod, KeyType> keyTransform) { |
| super(keyTransform); |
| this.parentNamingState = parentNamingState; |
| } |
| |
| public static <KeyType> MethodReservationState<KeyType> createRoot( |
| Function<DexMethod, KeyType> keyTransform) { |
| return new MethodReservationState<>(null, keyTransform); |
| } |
| |
| MethodReservationState<KeyType> createChild() { |
| return new MethodReservationState<>(this, this.keyTransform); |
| } |
| |
| void reserveName(DexString reservedName, DexEncodedMethod method) { |
| try { |
| getOrCreateInternalState(method.getReference()).reserveName(method, reservedName); |
| } catch (AssertionError err) { |
| throw new RuntimeException( |
| String.format( |
| "Assertion error when trying to reserve name '%s' for method '%s'", |
| reservedName, method), |
| err); |
| } |
| } |
| |
| boolean isReserved(DexString name, DexMethod method) { |
| InternalReservationState internalState = getInternalState(method); |
| if (internalState != null && internalState.isReserved(name)) { |
| return true; |
| } |
| if (parentNamingState != null) { |
| return parentNamingState.isReserved(name, method); |
| } |
| return false; |
| } |
| |
| Set<DexString> getReservedNamesFor(DexMethod method) { |
| InternalReservationState internalState = getInternalState(method); |
| Set<DexString> reservedName = null; |
| if (internalState != null) { |
| reservedName = internalState.getAssignedNamesFor(method); |
| } |
| if (reservedName == null && parentNamingState != null) { |
| reservedName = parentNamingState.getReservedNamesFor(method); |
| } |
| return reservedName; |
| } |
| |
| @Override |
| InternalReservationState createInternalState(DexMethod method) { |
| return new InternalReservationState(); |
| } |
| |
| static class InternalReservationState { |
| private Map<Wrapper<DexMethod>, Set<DexString>> originalToReservedNames = null; |
| private Set<DexString> reservedNames = null; |
| |
| boolean isReserved(DexString name) { |
| return reservedNames != null && reservedNames.contains(name); |
| } |
| |
| Set<DexString> getAssignedNamesFor(DexMethod method) { |
| if (originalToReservedNames == null) { |
| return null; |
| } |
| return originalToReservedNames.get(MethodSignatureEquivalence.get().wrap(method)); |
| } |
| |
| void reserveName(DexEncodedMethod method, DexString name) { |
| if (reservedNames == null) { |
| assert originalToReservedNames == null; |
| originalToReservedNames = new HashMap<>(); |
| reservedNames = new HashSet<>(); |
| } |
| final Wrapper<DexMethod> wrapped = |
| MethodSignatureEquivalence.get().wrap(method.getReference()); |
| originalToReservedNames.computeIfAbsent(wrapped, ignore -> new HashSet<>()).add(name); |
| reservedNames.add(name); |
| } |
| } |
| } |