• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 package com.android.tools.r8.naming;
5 
6 import com.android.tools.r8.errors.CompilationError;
7 import com.android.tools.r8.graph.AppInfo;
8 import com.android.tools.r8.graph.DexClass;
9 import com.android.tools.r8.graph.DexEncodedMethod;
10 import com.android.tools.r8.graph.DexField;
11 import com.android.tools.r8.graph.DexItem;
12 import com.android.tools.r8.graph.DexMethod;
13 import com.android.tools.r8.graph.DexString;
14 import com.android.tools.r8.graph.DexType;
15 import com.android.tools.r8.optimize.MemberRebindingAnalysis;
16 import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
17 import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
18 import com.android.tools.r8.utils.InternalOptions;
19 import com.android.tools.r8.utils.Timing;
20 import com.google.common.collect.Iterables;
21 import java.util.IdentityHashMap;
22 import java.util.Map;
23 import java.util.function.Consumer;
24 
25 public class Minifier {
26 
27   private final AppInfoWithLiveness appInfo;
28   private final RootSet rootSet;
29   private final InternalOptions options;
30 
Minifier(AppInfoWithLiveness appInfo, RootSet rootSet, InternalOptions options)31   public Minifier(AppInfoWithLiveness appInfo, RootSet rootSet, InternalOptions options) {
32     this.appInfo = appInfo;
33     this.rootSet = rootSet;
34     this.options = options;
35   }
36 
run(Timing timing)37   public NamingLens run(Timing timing) {
38     assert !options.skipMinification;
39     if (!options.allowAccessModification) {
40       throw new CompilationError("Minification requires allowaccessmodification.");
41     }
42     timing.begin("MinifyClasses");
43     Map<DexType, DexString> classRenaming =
44         new ClassNameMinifier(
45             appInfo, rootSet, options.packagePrefix, options.classObfuscationDictionary,
46             options.attributeRemoval.signature)
47             .computeRenaming();
48     timing.end();
49     timing.begin("MinifyMethods");
50     Map<DexMethod, DexString> methodRenaming =
51         new MethodNameMinifier(appInfo, rootSet, options.obfuscationDictionary)
52             .computeRenaming(timing);
53     timing.end();
54     timing.begin("MinifyFields");
55     Map<DexField, DexString> fieldRenaming =
56         new FieldNameMinifier(appInfo, rootSet, options.obfuscationDictionary).computeRenaming();
57     timing.end();
58     return new MinifiedRenaming(classRenaming, methodRenaming, fieldRenaming, appInfo);
59   }
60 
61   private static class MinifiedRenaming extends NamingLens {
62 
63     private final AppInfo appInfo;
64     private final Map<DexItem, DexString> renaming = new IdentityHashMap<>();
65 
MinifiedRenaming(Map<DexType, DexString> classRenaming, Map<DexMethod, DexString> methodRenaming, Map<DexField, DexString> fieldRenaming, AppInfo appInfo)66     private MinifiedRenaming(Map<DexType, DexString> classRenaming,
67         Map<DexMethod, DexString> methodRenaming, Map<DexField, DexString> fieldRenaming,
68         AppInfo appInfo) {
69       this.appInfo = appInfo;
70       renaming.putAll(classRenaming);
71       renaming.putAll(methodRenaming);
72       renaming.putAll(fieldRenaming);
73     }
74 
75     @Override
lookupDescriptor(DexType type)76     public DexString lookupDescriptor(DexType type) {
77       return renaming.getOrDefault(type, type.descriptor);
78     }
79 
80     @Override
lookupName(DexMethod method)81     public DexString lookupName(DexMethod method) {
82       return renaming.getOrDefault(method, method.name);
83     }
84 
85     @Override
lookupName(DexField field)86     public DexString lookupName(DexField field) {
87       return renaming.getOrDefault(field, field.name);
88     }
89 
90     @Override
forAllRenamedTypes(Consumer<DexType> consumer)91     void forAllRenamedTypes(Consumer<DexType> consumer) {
92       Iterables.filter(renaming.keySet(), DexType.class).forEach(consumer);
93     }
94 
95     /**
96      * Checks whether the target is precise enough to be translated,
97      * <p>
98      * We only track the renaming of actual definitions, Thus, if we encounter a method id that
99      * does not directly point at a definition, we won't find the actual renaming. To avoid
100      * dispatching on every lookup, we assume that the tree has been fully dispatched by
101      * {@link MemberRebindingAnalysis}.
102      * <p>
103      * Library methods are excluded from this check, as those are never renamed.
104      */
105     @Override
checkTargetCanBeTranslated(DexMethod item)106     public boolean checkTargetCanBeTranslated(DexMethod item) {
107       if (item.holder.isArrayType()) {
108         // Array methods are never renamed, so do not bother to check.
109         return true;
110       }
111       DexClass holder = appInfo.definitionFor(item.holder);
112       if (holder == null || holder.isLibraryClass()) {
113         return true;
114       }
115       // We don't know which invoke type this method is used for, so checks that it has been
116       // rebound either way.
117       DexEncodedMethod staticTarget = appInfo.lookupStaticTarget(item);
118       DexEncodedMethod directTarget = appInfo.lookupDirectTarget(item);
119       DexEncodedMethod virtualTarget = appInfo.lookupVirtualTarget(item.holder, item);
120       DexClass staticTargetHolder =
121           staticTarget != null ? appInfo.definitionFor(staticTarget.method.getHolder()) : null;
122       DexClass directTargetHolder =
123           directTarget != null ? appInfo.definitionFor(directTarget.method.getHolder()) : null;
124       DexClass virtualTargetHolder =
125           virtualTarget != null ? appInfo.definitionFor(virtualTarget.method.getHolder()) : null;
126       return directTarget == null && staticTarget == null && virtualTarget == null
127           || virtualTarget != null && virtualTarget.method == item
128           || directTarget != null && directTarget.method == item
129           || staticTarget != null && staticTarget.method == item
130           || directTargetHolder != null && directTargetHolder.isLibraryClass()
131           || virtualTargetHolder != null && virtualTargetHolder.isLibraryClass()
132           || staticTargetHolder != null && staticTargetHolder.isLibraryClass();
133     }
134   }
135 }
136