| // Copyright (c) 2020, 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.graph; | |
| import com.android.tools.r8.graph.GraphLens.MethodLookupResult; | |
| import com.android.tools.r8.ir.code.Invoke.Type; | |
| import com.android.tools.r8.utils.ConsumerUtils; | |
| import com.android.tools.r8.utils.collections.ProgramMethodSet; | |
| import com.google.common.collect.Sets; | |
| import java.util.IdentityHashMap; | |
| import java.util.Map; | |
| import java.util.Set; | |
| import java.util.concurrent.ConcurrentHashMap; | |
| import java.util.function.BiConsumer; | |
| import java.util.function.Consumer; | |
| import java.util.function.Supplier; | |
| public class MethodAccessInfoCollection { | |
| private final Map<DexMethod, ProgramMethodSet> directInvokes; | |
| private final Map<DexMethod, ProgramMethodSet> interfaceInvokes; | |
| private final Map<DexMethod, ProgramMethodSet> staticInvokes; | |
| private final Map<DexMethod, ProgramMethodSet> superInvokes; | |
| private final Map<DexMethod, ProgramMethodSet> virtualInvokes; | |
| private MethodAccessInfoCollection( | |
| Map<DexMethod, ProgramMethodSet> directInvokes, | |
| Map<DexMethod, ProgramMethodSet> interfaceInvokes, | |
| Map<DexMethod, ProgramMethodSet> staticInvokes, | |
| Map<DexMethod, ProgramMethodSet> superInvokes, | |
| Map<DexMethod, ProgramMethodSet> virtualInvokes) { | |
| this.directInvokes = directInvokes; | |
| this.interfaceInvokes = interfaceInvokes; | |
| this.staticInvokes = staticInvokes; | |
| this.superInvokes = superInvokes; | |
| this.virtualInvokes = virtualInvokes; | |
| } | |
| public static ConcurrentBuilder concurrentBuilder() { | |
| return new ConcurrentBuilder(); | |
| } | |
| public static IdentityBuilder identityBuilder() { | |
| return new IdentityBuilder(); | |
| } | |
| public Modifier modifier() { | |
| return new Modifier( | |
| directInvokes, interfaceInvokes, staticInvokes, superInvokes, virtualInvokes); | |
| } | |
| public void forEachMethodReference(Consumer<DexMethod> method) { | |
| Set<DexMethod> seen = Sets.newIdentityHashSet(); | |
| directInvokes.keySet().forEach(ConsumerUtils.acceptIfNotSeen(method, seen)); | |
| interfaceInvokes.keySet().forEach(ConsumerUtils.acceptIfNotSeen(method, seen)); | |
| staticInvokes.keySet().forEach(ConsumerUtils.acceptIfNotSeen(method, seen)); | |
| superInvokes.keySet().forEach(ConsumerUtils.acceptIfNotSeen(method, seen)); | |
| virtualInvokes.keySet().forEach(ConsumerUtils.acceptIfNotSeen(method, seen)); | |
| } | |
| public void forEachDirectInvoke(BiConsumer<DexMethod, ProgramMethodSet> consumer) { | |
| directInvokes.forEach(consumer); | |
| } | |
| public void forEachInterfaceInvoke(BiConsumer<DexMethod, ProgramMethodSet> consumer) { | |
| interfaceInvokes.forEach(consumer); | |
| } | |
| public void forEachStaticInvoke(BiConsumer<DexMethod, ProgramMethodSet> consumer) { | |
| staticInvokes.forEach(consumer); | |
| } | |
| public void forEachSuperInvoke(BiConsumer<DexMethod, ProgramMethodSet> consumer) { | |
| superInvokes.forEach(consumer); | |
| } | |
| public void forEachSuperInvokeContext(DexMethod method, Consumer<ProgramMethod> consumer) { | |
| superInvokes.getOrDefault(method, ProgramMethodSet.empty()).forEach(consumer); | |
| } | |
| public void forEachVirtualInvoke(BiConsumer<DexMethod, ProgramMethodSet> consumer) { | |
| virtualInvokes.forEach(consumer); | |
| } | |
| public void forEachVirtualInvokeContext(DexMethod method, Consumer<ProgramMethod> consumer) { | |
| virtualInvokes.getOrDefault(method, ProgramMethodSet.empty()).forEach(consumer); | |
| } | |
| public MethodAccessInfoCollection rewrittenWithLens( | |
| DexDefinitionSupplier definitions, GraphLens lens) { | |
| MethodAccessInfoCollection.Builder<?> builder = identityBuilder(); | |
| rewriteInvokesWithLens(builder, directInvokes, definitions, lens, Type.DIRECT); | |
| rewriteInvokesWithLens(builder, interfaceInvokes, definitions, lens, Type.INTERFACE); | |
| rewriteInvokesWithLens(builder, staticInvokes, definitions, lens, Type.STATIC); | |
| rewriteInvokesWithLens(builder, superInvokes, definitions, lens, Type.SUPER); | |
| rewriteInvokesWithLens(builder, virtualInvokes, definitions, lens, Type.VIRTUAL); | |
| return builder.build(); | |
| } | |
| private static void rewriteInvokesWithLens( | |
| MethodAccessInfoCollection.Builder<?> builder, | |
| Map<DexMethod, ProgramMethodSet> invokes, | |
| DexDefinitionSupplier definitions, | |
| GraphLens lens, | |
| Type type) { | |
| invokes.forEach( | |
| (reference, contexts) -> { | |
| ProgramMethodSet newContexts = contexts.rewrittenWithLens(definitions, lens); | |
| for (ProgramMethod newContext : newContexts) { | |
| MethodLookupResult methodLookupResult = | |
| lens.lookupMethod(reference, newContext.getReference(), type); | |
| DexMethod newReference = methodLookupResult.getReference(); | |
| Type newType = methodLookupResult.getType(); | |
| builder.registerInvokeInContext(newReference, newContext, newType); | |
| } | |
| }); | |
| } | |
| public abstract static class Builder<T extends Map<DexMethod, ProgramMethodSet>> { | |
| private final T directInvokes; | |
| private final T interfaceInvokes; | |
| private final T staticInvokes; | |
| private final T superInvokes; | |
| private final T virtualInvokes; | |
| private Builder(Supplier<T> factory) { | |
| this(factory.get(), factory.get(), factory.get(), factory.get(), factory.get()); | |
| } | |
| private Builder( | |
| T directInvokes, T interfaceInvokes, T staticInvokes, T superInvokes, T virtualInvokes) { | |
| this.directInvokes = directInvokes; | |
| this.interfaceInvokes = interfaceInvokes; | |
| this.staticInvokes = staticInvokes; | |
| this.superInvokes = superInvokes; | |
| this.virtualInvokes = virtualInvokes; | |
| } | |
| public T getDirectInvokes() { | |
| return directInvokes; | |
| } | |
| public T getInterfaceInvokes() { | |
| return interfaceInvokes; | |
| } | |
| public T getStaticInvokes() { | |
| return staticInvokes; | |
| } | |
| public T getSuperInvokes() { | |
| return superInvokes; | |
| } | |
| public T getVirtualInvokes() { | |
| return virtualInvokes; | |
| } | |
| public boolean registerInvokeInContext( | |
| DexMethod invokedMethod, ProgramMethod context, Type type) { | |
| switch (type) { | |
| case DIRECT: | |
| return registerInvokeDirectInContext(invokedMethod, context); | |
| case INTERFACE: | |
| return registerInvokeInterfaceInContext(invokedMethod, context); | |
| case STATIC: | |
| return registerInvokeStaticInContext(invokedMethod, context); | |
| case SUPER: | |
| return registerInvokeSuperInContext(invokedMethod, context); | |
| case VIRTUAL: | |
| return registerInvokeVirtualInContext(invokedMethod, context); | |
| default: | |
| assert false; | |
| return false; | |
| } | |
| } | |
| public boolean registerInvokeDirectInContext(DexMethod invokedMethod, ProgramMethod context) { | |
| return registerInvokeMethodInContext(invokedMethod, context, directInvokes); | |
| } | |
| public void registerInvokeDirectInContexts(DexMethod invokedMethod, ProgramMethodSet contexts) { | |
| contexts.forEach(context -> registerInvokeDirectInContext(invokedMethod, context)); | |
| } | |
| public boolean registerInvokeInterfaceInContext( | |
| DexMethod invokedMethod, ProgramMethod context) { | |
| return registerInvokeMethodInContext(invokedMethod, context, interfaceInvokes); | |
| } | |
| public void registerInvokeInterfaceInContexts( | |
| DexMethod invokedMethod, ProgramMethodSet contexts) { | |
| contexts.forEach(context -> registerInvokeInterfaceInContext(invokedMethod, context)); | |
| } | |
| public boolean registerInvokeStaticInContext(DexMethod invokedMethod, ProgramMethod context) { | |
| return registerInvokeMethodInContext(invokedMethod, context, staticInvokes); | |
| } | |
| public void registerInvokeStaticInContexts(DexMethod invokedMethod, ProgramMethodSet contexts) { | |
| contexts.forEach(context -> registerInvokeStaticInContext(invokedMethod, context)); | |
| } | |
| public boolean registerInvokeSuperInContext(DexMethod invokedMethod, ProgramMethod context) { | |
| return registerInvokeMethodInContext(invokedMethod, context, superInvokes); | |
| } | |
| public void registerInvokeSuperInContexts(DexMethod invokedMethod, ProgramMethodSet contexts) { | |
| contexts.forEach(context -> registerInvokeSuperInContext(invokedMethod, context)); | |
| } | |
| public boolean registerInvokeVirtualInContext(DexMethod invokedMethod, ProgramMethod context) { | |
| return registerInvokeMethodInContext(invokedMethod, context, virtualInvokes); | |
| } | |
| public void registerInvokeVirtualInContexts( | |
| DexMethod invokedMethod, ProgramMethodSet contexts) { | |
| contexts.forEach(context -> registerInvokeVirtualInContext(invokedMethod, context)); | |
| } | |
| private static boolean registerInvokeMethodInContext( | |
| DexMethod invokedMethod, ProgramMethod context, Map<DexMethod, ProgramMethodSet> invokes) { | |
| return invokes | |
| .computeIfAbsent(invokedMethod, ignore -> ProgramMethodSet.create()) | |
| .add(context); | |
| } | |
| public MethodAccessInfoCollection build() { | |
| return new MethodAccessInfoCollection( | |
| directInvokes, interfaceInvokes, staticInvokes, superInvokes, virtualInvokes); | |
| } | |
| } | |
| public static class ConcurrentBuilder | |
| extends Builder<ConcurrentHashMap<DexMethod, ProgramMethodSet>> { | |
| private ConcurrentBuilder() { | |
| super(ConcurrentHashMap::new); | |
| } | |
| } | |
| public static class IdentityBuilder | |
| extends Builder<IdentityHashMap<DexMethod, ProgramMethodSet>> { | |
| private IdentityBuilder() { | |
| super(IdentityHashMap::new); | |
| } | |
| } | |
| public static class Modifier extends Builder<Map<DexMethod, ProgramMethodSet>> { | |
| private Modifier( | |
| Map<DexMethod, ProgramMethodSet> directInvokes, | |
| Map<DexMethod, ProgramMethodSet> interfaceInvokes, | |
| Map<DexMethod, ProgramMethodSet> staticInvokes, | |
| Map<DexMethod, ProgramMethodSet> superInvokes, | |
| Map<DexMethod, ProgramMethodSet> virtualInvokes) { | |
| super(directInvokes, interfaceInvokes, staticInvokes, superInvokes, virtualInvokes); | |
| } | |
| public void addAll(MethodAccessInfoCollection collection) { | |
| collection.forEachDirectInvoke(this::registerInvokeDirectInContexts); | |
| collection.forEachInterfaceInvoke(this::registerInvokeInterfaceInContexts); | |
| collection.forEachStaticInvoke(this::registerInvokeStaticInContexts); | |
| collection.forEachSuperInvoke(this::registerInvokeSuperInContexts); | |
| collection.forEachVirtualInvoke(this::registerInvokeVirtualInContexts); | |
| } | |
| } | |
| } |