| // Copyright (c) 2022, 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.AppView; |
| import com.android.tools.r8.graph.DexField; |
| import com.android.tools.r8.graph.DexItemFactory; |
| import com.android.tools.r8.graph.DexMethod; |
| import com.android.tools.r8.graph.DexString; |
| import com.android.tools.r8.graph.DexType; |
| import com.android.tools.r8.graph.InnerClassAttribute; |
| import com.android.tools.r8.naming.NamingLens.NonIdentityNamingLens; |
| import com.android.tools.r8.utils.InternalOptions; |
| import java.util.IdentityHashMap; |
| import java.util.Map; |
| |
| // Naming lens for VarHandle desugaring rewriting. Rewriting java.lang.invoke.MethodHandles$Lookup |
| // to com.android.tools.r8.DesugarMethodHandlesLookup. |
| public class VarHandleDesugaringRewritingNamingLens extends NonIdentityNamingLens { |
| |
| private final DexItemFactory factory; |
| private final NamingLens namingLens; |
| private final Map<DexType, DexString> mapping; |
| |
| public static NamingLens createVarHandleDesugaringRewritingNamingLens(AppView<?> appView) { |
| DexItemFactory factory = appView.dexItemFactory(); |
| if (appView.options().shouldDesugarVarHandle() |
| && (appView.appInfo().definitionForWithoutExistenceAssert(factory.lookupType) != null |
| || appView.appInfo().definitionForWithoutExistenceAssert(factory.varHandleType) |
| != null)) { |
| |
| // Prune all inner classes attributes referring to MethodHandles$Lookup, as that is rewritten |
| // to the toplevel class DesugarMethodHandlesLookup. |
| appView |
| .appInfo() |
| .classes() |
| .forEach( |
| clazz -> { |
| clazz.removeInnerClasses( |
| innerClassAttribute -> innerClassAttribute.getInner() == factory.lookupType); |
| }); |
| |
| // Function to prefix type namespace, e.g. rename L... to Lj$/... |
| Map<DexType, DexString> mapping = new IdentityHashMap<>(); |
| addRewritingForGlobalSynthetic( |
| appView, factory.lookupType, factory.desugarMethodHandlesLookupType, mapping); |
| addRewritingForGlobalSynthetic( |
| appView, factory.varHandleType, factory.desugarVarHandleType, mapping); |
| return new VarHandleDesugaringRewritingNamingLens(appView, mapping); |
| } |
| return appView.getNamingLens(); |
| } |
| |
| private static void addRewritingForGlobalSynthetic( |
| AppView<?> appView, |
| DexType globalSynthetic, |
| DexType desugaredGlobalSynthetic, |
| Map<DexType, DexString> mapping) { |
| DexItemFactory factory = appView.dexItemFactory(); |
| // The VarHandle global synthetics and synthetics derived from them are rewritten to use the |
| // desugared name. |
| assert appView.appInfo().getSyntheticItems().isFinalized(); |
| String globalSyntheticString = globalSynthetic.descriptor.toString(); |
| DexString currentPrefix = |
| factory.createString( |
| globalSyntheticString.substring(0, globalSyntheticString.length() - 1)); |
| String desugaredGlobalSyntheticString = desugaredGlobalSynthetic.descriptor.toString(); |
| DexString newPrefix = |
| appView.options().synthesizedClassPrefix.isEmpty() |
| ? factory.createString( |
| "L" |
| + desugaredGlobalSyntheticString.substring( |
| 1, desugaredGlobalSyntheticString.length() - 1)) |
| : factory.createString( |
| "L" |
| + appView.options().synthesizedClassPrefix |
| + desugaredGlobalSyntheticString.substring( |
| 1, desugaredGlobalSyntheticString.length() - 1)); |
| // Rewrite the global synthetic in question and all the synthetics derived from it. |
| appView |
| .appInfo() |
| .getSyntheticItems() |
| .collectSyntheticsFromContext(globalSynthetic) |
| .forEach( |
| synthetic -> |
| mapping.put( |
| synthetic, |
| synthetic.descriptor.withNewPrefix(currentPrefix, newPrefix, factory))); |
| } |
| |
| private VarHandleDesugaringRewritingNamingLens( |
| AppView<?> appView, Map<DexType, DexString> mapping) { |
| super(appView.dexItemFactory()); |
| this.factory = appView.dexItemFactory(); |
| this.namingLens = appView.getNamingLens(); |
| this.mapping = mapping; |
| } |
| |
| private boolean isRenamed(DexType type) { |
| return getRenaming(type) != null; |
| } |
| |
| private DexString getRenaming(DexType type) { |
| assert type != factory.desugarMethodHandlesLookupType; |
| assert type != factory.desugarVarHandleType; |
| return mapping.get(type); |
| } |
| |
| @Override |
| protected DexString internalLookupClassDescriptor(DexType type) { |
| DexString renaming = getRenaming(type); |
| return renaming != null ? renaming : namingLens.lookupDescriptor(type); |
| } |
| |
| @Override |
| public DexString lookupInnerName(InnerClassAttribute attribute, InternalOptions options) { |
| assert !isRenamed(attribute.getInner()); |
| return namingLens.lookupInnerName(attribute, options); |
| } |
| |
| @Override |
| public DexString lookupName(DexMethod method) { |
| // VarHandle desugaring rewriting does not influence method name. |
| return namingLens.lookupName(method); |
| } |
| |
| @Override |
| public DexString lookupName(DexField field) { |
| // VarHandle desugaring rewriting does not influence method name. |
| return namingLens.lookupName(field); |
| } |
| |
| @Override |
| public boolean hasPrefixRewritingLogic() { |
| return namingLens.hasPrefixRewritingLogic(); |
| } |
| |
| @Override |
| public DexString prefixRewrittenType(DexType type) { |
| return namingLens.prefixRewrittenType(type); |
| } |
| |
| @Override |
| public String lookupPackageName(String packageName) { |
| return namingLens.lookupPackageName(packageName); |
| } |
| |
| @Override |
| public boolean verifyRenamingConsistentWithResolution(DexMethod item) { |
| return namingLens.verifyRenamingConsistentWithResolution(item); |
| } |
| } |