• 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.graph;
5 
6 import com.android.tools.r8.dex.Constants;
7 import com.android.tools.r8.graph.DexDebugEvent.AdvanceLine;
8 import com.android.tools.r8.graph.DexDebugEvent.AdvancePC;
9 import com.android.tools.r8.graph.DexDebugEvent.Default;
10 import com.android.tools.r8.graph.DexDebugEvent.EndLocal;
11 import com.android.tools.r8.graph.DexDebugEvent.RestartLocal;
12 import com.android.tools.r8.graph.DexDebugEvent.SetEpilogueBegin;
13 import com.android.tools.r8.graph.DexDebugEvent.SetFile;
14 import com.android.tools.r8.graph.DexDebugEvent.SetPrologueEnd;
15 import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
16 import com.android.tools.r8.naming.NamingLens;
17 import com.google.common.collect.ImmutableSet;
18 import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
19 import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.function.Consumer;
27 
28 public class DexItemFactory {
29 
30   private final Map<String, DexString> strings = new HashMap<>();
31   private final Map<DexType, DexType> types = new HashMap<>();
32   private final Map<DexField, DexField> fields = new HashMap<>();
33   private final Map<DexProto, DexProto> protos = new HashMap<>();
34   private final Map<DexMethod, DexMethod> methods = new HashMap<>();
35   private final Map<DexCallSite, DexCallSite> callSites = new HashMap<>();
36   private final Map<DexMethodHandle, DexMethodHandle> methodHandles = new HashMap<>();
37 
38   // DexDebugEvent Canonicalization.
39   private final Int2ObjectMap<AdvanceLine> advanceLines = new Int2ObjectOpenHashMap<>();
40   private final Int2ObjectMap<AdvancePC> advancePCs = new Int2ObjectOpenHashMap<>();
41   private final Int2ObjectMap<Default> defaults = new Int2ObjectOpenHashMap<>();
42   private final Int2ObjectMap<EndLocal> endLocals = new Int2ObjectOpenHashMap<>();
43   private final Int2ObjectMap<RestartLocal> restartLocals = new Int2ObjectOpenHashMap<>();
44   private final SetEpilogueBegin setEpilogueBegin = new SetEpilogueBegin();
45   private final SetPrologueEnd setPrologueEnd = new SetPrologueEnd();
46   private final Map<DexString, SetFile> setFiles = new HashMap<>();
47 
48   boolean sorted = false;
49 
50   public static final DexType catchAllType = new DexType(new DexString("CATCH_ALL"));
51   private static final Set<DexItem> internalSentinels = ImmutableSet.of(catchAllType);
52 
53   public DexString booleanDescriptor = createString("Z");
54   public DexString byteDescriptor = createString("B");
55   public DexString charDescriptor = createString("C");
56   public DexString doubleDescriptor = createString("D");
57   public DexString floatDescriptor = createString("F");
58   public DexString intDescriptor = createString("I");
59   public DexString longDescriptor = createString("J");
60   public DexString shortDescriptor = createString("S");
61   public DexString voidDescriptor = createString("V");
62 
63   public DexString boxedBooleanDescriptor = createString("Ljava/lang/Boolean;");
64   public DexString boxedByteDescriptor = createString("Ljava/lang/Byte;");
65   public DexString boxedCharDescriptor = createString("Ljava/lang/Character;");
66   public DexString boxedDoubleDescriptor = createString("Ljava/lang/Double;");
67   public DexString boxedFloatDescriptor = createString("Ljava/lang/Float;");
68   public DexString boxedIntDescriptor = createString("Ljava/lang/Integer;");
69   public DexString boxedLongDescriptor = createString("Ljava/lang/Long;");
70   public DexString boxedShortDescriptor = createString("Ljava/lang/Short;");
71   public DexString boxedNumberDescriptor = createString("Ljava/lang/Number;");
72 
73   public DexString unboxBooleanMethodName = createString("booleanValue");
74   public DexString unboxByteMethodName = createString("byteValue");
75   public DexString unboxCharMethodName = createString("charValue");
76   public DexString unboxShortMethodName = createString("shortValue");
77   public DexString unboxIntMethodName = createString("intValue");
78   public DexString unboxLongMethodName = createString("longValue");
79   public DexString unboxFloatMethodName = createString("floatValue");
80   public DexString unboxDoubleMethodName = createString("doubleValue");
81 
82   public DexString valueOfMethodName = createString("valueOf");
83 
84   public DexString getClassMethodName = createString("getClass");
85   public DexString ordinalMethodName = createString("ordinal");
86   public final DexString desiredAssertionStatusMethodName = createString("desiredAssertionStatus");
87   public final DexString assertionsDisabled = createString("$assertionsDisabled");
88 
89   public DexString stringDescriptor = createString("Ljava/lang/String;");
90   public DexString objectDescriptor = createString("Ljava/lang/Object;");
91   public DexString classDescriptor = createString("Ljava/lang/Class;");
92   public DexString enumDescriptor = createString("Ljava/lang/Enum;");
93   public DexString annotationDescriptor = createString("Ljava/lang/annotation/Annotation;");
94   public DexString throwableDescriptor = createString("Ljava/lang/Throwable;");
95   public DexString objectsDescriptor = createString("Ljava/util/Objects;");
96 
97   public DexString constructorMethodName = createString(Constants.INSTANCE_INITIALIZER_NAME);
98   public DexString classConstructorMethodName = createString(Constants.CLASS_INITIALIZER_NAME);
99 
100   public DexString thisName = createString("this");
101 
102   private DexString charArrayDescriptor = createString("[C");
103   private DexType charArrayType = createType(charArrayDescriptor);
104   public DexString throwableArrayDescriptor = createString("[Ljava/lang/Throwable;");
105 
106   public DexType booleanType = createType(booleanDescriptor);
107   public DexType byteType = createType(byteDescriptor);
108   public DexType charType = createType(charDescriptor);
109   public DexType doubleType = createType(doubleDescriptor);
110   public DexType floatType = createType(floatDescriptor);
111   public DexType intType = createType(intDescriptor);
112   public DexType longType = createType(longDescriptor);
113   public DexType shortType = createType(shortDescriptor);
114   public DexType voidType = createType(voidDescriptor);
115 
116   public DexType boxedBooleanType = createType(boxedBooleanDescriptor);
117   public DexType boxedByteType = createType(boxedByteDescriptor);
118   public DexType boxedCharType = createType(boxedCharDescriptor);
119   public DexType boxedDoubleType = createType(boxedDoubleDescriptor);
120   public DexType boxedFloatType = createType(boxedFloatDescriptor);
121   public DexType boxedIntType = createType(boxedIntDescriptor);
122   public DexType boxedLongType = createType(boxedLongDescriptor);
123   public DexType boxedShortType = createType(boxedShortDescriptor);
124   public DexType boxedNumberType = createType(boxedNumberDescriptor);
125 
126   public DexType stringType = createType(stringDescriptor);
127   public DexType objectType = createType(objectDescriptor);
128   public DexType enumType = createType(enumDescriptor);
129   public DexType annotationType = createType(annotationDescriptor);
130   public DexType throwableType = createType(throwableDescriptor);
131 
132   public DexType stringBuilderType = createType("Ljava/lang/StringBuilder;");
133   public DexType stringBufferType = createType("Ljava/lang/StringBuffer;");
134 
135   public StringBuildingMethods stringBuilderMethods = new StringBuildingMethods(stringBuilderType);
136   public StringBuildingMethods stringBufferMethods = new StringBuildingMethods(stringBufferType);
137   public ObjectsMethods objectsMethods = new ObjectsMethods();
138   public ObjectMethods objectMethods = new ObjectMethods();
139   public LongMethods longMethods = new LongMethods();
140   public ThrowableMethods throwableMethods = new ThrowableMethods();
141   public ClassMethods classMethods = new ClassMethods();
142 
143   // Dex system annotations.
144   // See https://source.android.com/devices/tech/dalvik/dex-format.html#system-annotation
145   public final DexType annotationDefault = createType("Ldalvik/annotation/AnnotationDefault;");
146   public final DexType annotationEnclosingClass = createType("Ldalvik/annotation/EnclosingClass;");
147   public final DexType annotationEnclosingMethod = createType(
148       "Ldalvik/annotation/EnclosingMethod;");
149   public final DexType annotationInnerClass = createType("Ldalvik/annotation/InnerClass;");
150   public final DexType annotationMemberClasses = createType("Ldalvik/annotation/MemberClasses;");
151   public final DexType annotationMethodParameters = createType(
152       "Ldalvik/annotation/MethodParameters;");
153   public final DexType annotationSignature = createType("Ldalvik/annotation/Signature;");
154   public final DexType annotationSourceDebugExtension = createType(
155       "Ldalvik/annotation/SourceDebugExtension;");
156   public final DexType annotationThrows = createType("Ldalvik/annotation/Throws;");
157 
clearSubtypeInformation()158   public void clearSubtypeInformation() {
159     types.values().forEach(DexType::clearSubtypeInformation);
160   }
161 
162   public class LongMethods {
163 
164     public DexMethod compare;
165 
LongMethods()166     private LongMethods() {
167       compare = createMethod(boxedLongDescriptor,
168           createString("compare"), intDescriptor, new DexString[]{longDescriptor, longDescriptor});
169     }
170   }
171 
172   public class ThrowableMethods {
173 
174     public final DexMethod addSuppressed;
175     public final DexMethod getSuppressed;
176 
ThrowableMethods()177     private ThrowableMethods() {
178       addSuppressed = createMethod(throwableDescriptor,
179           createString("addSuppressed"), voidDescriptor, new DexString[]{throwableDescriptor});
180       getSuppressed = createMethod(throwableDescriptor,
181           createString("getSuppressed"), throwableArrayDescriptor, DexString.EMPTY_ARRAY);
182     }
183   }
184 
185   public class ObjectMethods {
186 
187     public DexMethod getClass;
188 
ObjectMethods()189     private ObjectMethods() {
190       getClass = createMethod(objectsDescriptor,
191           getClassMethodName, classDescriptor, new DexString[]{});
192     }
193   }
194 
195   public class ObjectsMethods {
196 
197     public DexMethod requireNonNull;
198 
ObjectsMethods()199     private ObjectsMethods() {
200       requireNonNull = createMethod(objectsDescriptor,
201           createString("requireNonNull"), objectDescriptor, new DexString[]{objectDescriptor});
202     }
203   }
204 
205   public class ClassMethods {
206 
207     public DexMethod desiredAssertionStatus;
208 
ClassMethods()209     private ClassMethods() {
210       desiredAssertionStatus = createMethod(classDescriptor,
211           desiredAssertionStatusMethodName, booleanDescriptor, new DexString[]{});
212     }
213   }
214 
215 
216   public class StringBuildingMethods {
217 
218     public DexMethod appendBoolean;
219     public DexMethod appendChar;
220     public DexMethod appendCharArray;
221     public DexMethod appendSubCharArray;
222     public DexMethod appendCharSequence;
223     public DexMethod appendSubCharSequence;
224     public DexMethod appendInt;
225     public DexMethod appendDouble;
226     public DexMethod appendFloat;
227     public DexMethod appendLong;
228     public DexMethod appendObject;
229     public DexMethod appendString;
230     public DexMethod appendStringBuffer;
231     public DexMethod toString;
232 
StringBuildingMethods(DexType receiver)233     private StringBuildingMethods(DexType receiver) {
234       DexType sbufType = createType(createString("Ljava/lang/StringBuffer;"));
235       DexType charSequenceType = createType(createString("Ljava/lang/CharSequence;"));
236       DexString append = createString("append");
237       DexString toStringMethodName = createString("toString");
238 
239 
240       appendBoolean = createMethod(receiver, createProto(receiver, booleanType), append);
241       appendChar = createMethod(receiver, createProto(receiver, charType), append);
242       appendCharArray = createMethod(receiver, createProto(receiver, charArrayType), append);
243       appendSubCharArray =
244           createMethod(receiver, createProto(receiver, charArrayType, intType, intType), append);
245       appendCharSequence = createMethod(receiver, createProto(receiver, charSequenceType), append);
246       appendSubCharSequence =
247           createMethod(receiver, createProto(receiver, charSequenceType, intType, intType), append);
248       appendInt = createMethod(receiver, createProto(receiver, intType), append);
249       appendDouble = createMethod(receiver, createProto(receiver, doubleType), append);
250       appendFloat = createMethod(receiver, createProto(receiver, floatType), append);
251       appendLong = createMethod(receiver, createProto(receiver, longType), append);
252       appendObject = createMethod(receiver, createProto(receiver, objectType), append);
253       appendString = createMethod(receiver, createProto(receiver, stringType), append);
254       appendStringBuffer = createMethod(receiver, createProto(receiver, sbufType), append);
255       toString = createMethod(receiver, createProto(stringType), toStringMethodName);
256     }
257 
forEachAppendMethod(Consumer<DexMethod> consumer)258     public void forEachAppendMethod(Consumer<DexMethod> consumer) {
259       consumer.accept(appendBoolean);
260       consumer.accept(appendChar);
261       consumer.accept(appendCharArray);
262       consumer.accept(appendSubCharArray);
263       consumer.accept(appendCharSequence);
264       consumer.accept(appendSubCharSequence);
265       consumer.accept(appendInt);
266       consumer.accept(appendDouble);
267       consumer.accept(appendFloat);
268       consumer.accept(appendLong);
269       consumer.accept(appendObject);
270       consumer.accept(appendString);
271       consumer.accept(appendStringBuffer);
272       consumer.accept(appendBoolean);
273     }
274   }
275 
canonicalize(Map<T, T> map, T item)276   synchronized private static <T extends DexItem> T canonicalize(Map<T, T> map, T item) {
277     assert item != null;
278     assert !internalSentinels.contains(item);
279     T previous = map.putIfAbsent(item, item);
280     return previous == null ? item : previous;
281   }
282 
canonicalizeString(String key)283   synchronized private DexString canonicalizeString(String key) {
284     assert key != null;
285     return strings.computeIfAbsent(key, k -> new DexString(k));
286   }
287 
createString(int size, byte[] content)288   public DexString createString(int size, byte[] content) {
289     assert !sorted;
290     return canonicalizeString(new DexString(size, content).toString());
291   }
292 
createString(String source)293   public DexString createString(String source) {
294     assert !sorted;
295     return canonicalizeString(source);
296   }
297 
createType(DexString descriptor)298   public DexType createType(DexString descriptor) {
299     assert !sorted;
300     DexType type = new DexType(descriptor);
301     return canonicalize(types, type);
302   }
303 
createType(String descriptor)304   public DexType createType(String descriptor) {
305     return createType(createString(descriptor));
306   }
307 
createField(DexType clazz, DexType type, DexString name)308   public DexField createField(DexType clazz, DexType type, DexString name) {
309     assert !sorted;
310     DexField field = new DexField(clazz, type, name);
311     return canonicalize(fields, field);
312   }
313 
createField(DexType clazz, DexType type, String name)314   public DexField createField(DexType clazz, DexType type, String name) {
315     return createField(clazz, type, createString(name));
316   }
317 
createProto(DexString shorty, DexType returnType, DexTypeList parameters)318   public DexProto createProto(DexString shorty, DexType returnType, DexTypeList parameters) {
319     assert !sorted;
320     DexProto proto = new DexProto(shorty, returnType, parameters);
321     return canonicalize(protos, proto);
322   }
323 
createProto(DexString shorty, DexType returnType, DexType[] parameters)324   public DexProto createProto(DexString shorty, DexType returnType, DexType[] parameters) {
325     assert !sorted;
326     return createProto(shorty, returnType,
327         parameters.length == 0 ? DexTypeList.empty() : new DexTypeList(parameters));
328   }
329 
createProto(DexType returnType, DexType... parameters)330   public DexProto createProto(DexType returnType, DexType... parameters) {
331     return createProto(createShorty(returnType, parameters), returnType, parameters);
332   }
333 
createShorty(DexType returnType, DexType[] argumentTypes)334   public DexString createShorty(DexType returnType, DexType[] argumentTypes) {
335     StringBuilder shortyBuilder = new StringBuilder();
336     shortyBuilder.append(returnType.toShorty());
337     for (DexType argumentType : argumentTypes) {
338       shortyBuilder.append(argumentType.toShorty());
339     }
340     return createString(shortyBuilder.toString());
341   }
342 
createMethod(DexType holder, DexProto proto, DexString name)343   public DexMethod createMethod(DexType holder, DexProto proto, DexString name) {
344     assert !sorted;
345     DexMethod method = new DexMethod(holder, proto, name);
346     return canonicalize(methods, method);
347   }
348 
createMethod(DexType holder, DexProto proto, String name)349   public DexMethod createMethod(DexType holder, DexProto proto, String name) {
350     return createMethod(holder, proto, createString(name));
351   }
352 
createMethodHandle( MethodHandleType type, Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod)353   public DexMethodHandle createMethodHandle(
354       MethodHandleType type, Descriptor<? extends DexItem, ? extends Descriptor> fieldOrMethod) {
355     assert !sorted;
356     DexMethodHandle methodHandle = new DexMethodHandle(type, fieldOrMethod);
357     return canonicalize(methodHandles, methodHandle);
358   }
359 
createCallSite( DexString methodName, DexProto methodProto, DexMethodHandle bootstrapMethod, List<DexValue> bootstrapArgs)360   public DexCallSite createCallSite(
361       DexString methodName, DexProto methodProto,
362       DexMethodHandle bootstrapMethod, List<DexValue> bootstrapArgs) {
363     assert !sorted;
364     DexCallSite callSite = new DexCallSite(methodName, methodProto, bootstrapMethod, bootstrapArgs);
365     return canonicalize(callSites, callSite);
366   }
367 
createMethod(DexString clazzDescriptor, DexString name, DexString returnTypeDescriptor, DexString[] parameterDescriptors)368   public DexMethod createMethod(DexString clazzDescriptor, DexString name,
369       DexString returnTypeDescriptor,
370       DexString[] parameterDescriptors) {
371     assert !sorted;
372     DexType clazz = createType(clazzDescriptor);
373     DexType returnType = createType(returnTypeDescriptor);
374     DexType[] parameterTypes = new DexType[parameterDescriptors.length];
375     for (int i = 0; i < parameterDescriptors.length; i++) {
376       parameterTypes[i] = createType(parameterDescriptors[i]);
377     }
378     DexProto proto = createProto(shorty(returnType, parameterTypes), returnType, parameterTypes);
379 
380     return createMethod(clazz, proto, name);
381   }
382 
createAdvanceLine(int delta)383   public AdvanceLine createAdvanceLine(int delta) {
384     synchronized (advanceLines) {
385       AdvanceLine result = advanceLines.get(delta);
386       if (result == null) {
387         result = new AdvanceLine(delta);
388         advanceLines.put(delta, result);
389       }
390       return result;
391     }
392   }
393 
createAdvancePC(int delta)394   public AdvancePC createAdvancePC(int delta) {
395     synchronized (advancePCs) {
396       AdvancePC result = advancePCs.get(delta);
397       if (result == null) {
398         result = new AdvancePC(delta);
399         advancePCs.put(delta, result);
400       }
401       return result;
402     }
403   }
404 
createDefault(int value)405   public Default createDefault(int value) {
406     synchronized (defaults) {
407       Default result = defaults.get(value);
408       if (result == null) {
409         result = new Default(value);
410         defaults.put(value, result);
411       }
412       return result;
413     }
414   }
415 
createEndLocal(int registerNum)416   public EndLocal createEndLocal(int registerNum) {
417     synchronized (endLocals) {
418       EndLocal result = endLocals.get(registerNum);
419       if (result == null) {
420         result = new EndLocal(registerNum);
421         endLocals.put(registerNum, result);
422       }
423       return result;
424     }
425   }
426 
createRestartLocal(int registerNum)427   public RestartLocal createRestartLocal(int registerNum) {
428     synchronized (restartLocals) {
429       RestartLocal result = restartLocals.get(registerNum);
430       if (result == null) {
431         result = new RestartLocal(registerNum);
432         restartLocals.put(registerNum, result);
433       }
434       return result;
435     }
436   }
437 
createSetEpilogueBegin()438   public SetEpilogueBegin createSetEpilogueBegin() {
439     return setEpilogueBegin;
440   }
441 
createSetPrologueEnd()442   public SetPrologueEnd createSetPrologueEnd() {
443     return setPrologueEnd;
444   }
445 
createSetFile(DexString fileName)446   public SetFile createSetFile(DexString fileName) {
447     synchronized (setFiles) {
448       SetFile result = setFiles.get(fileName);
449       if (result == null) {
450         result = new SetFile(fileName);
451         setFiles.put(fileName, result);
452       }
453       return result;
454     }
455   }
456 
isConstructor(DexMethod method)457   public boolean isConstructor(DexMethod method) {
458     return method.name == constructorMethodName;
459   }
460 
isClassConstructor(DexMethod method)461   public boolean isClassConstructor(DexMethod method) {
462     return method.name == classConstructorMethodName;
463   }
464 
shorty(DexType returnType, DexType[] parameters)465   private DexString shorty(DexType returnType, DexType[] parameters) {
466     StringBuilder builder = new StringBuilder();
467     addToShorty(builder, returnType);
468     for (DexType parameter : parameters) {
469       addToShorty(builder, parameter);
470     }
471     return createString(builder.toString());
472   }
473 
addToShorty(StringBuilder builder, DexType type)474   private void addToShorty(StringBuilder builder, DexType type) {
475     char first = type.toDescriptorString().charAt(0);
476     builder.append(first == '[' ? 'L' : first);
477   }
478 
assignSortedIndices(Collection<S> items, NamingLens namingLens)479   private static <S extends PresortedComparable<S>> void assignSortedIndices(Collection<S> items,
480       NamingLens namingLens) {
481     List<S> sorted = new ArrayList<>(items);
482     sorted.sort((a, b) -> a.layeredCompareTo(b, namingLens));
483     int i = 0;
484     for (S value : sorted) {
485       value.setSortedIndex(i++);
486     }
487   }
488 
sort(NamingLens namingLens)489   synchronized public void sort(NamingLens namingLens) {
490     assert !sorted;
491     assignSortedIndices(strings.values(), namingLens);
492     assignSortedIndices(types.values(), namingLens);
493     assignSortedIndices(fields.values(), namingLens);
494     assignSortedIndices(protos.values(), namingLens);
495     assignSortedIndices(methods.values(), namingLens);
496     sorted = true;
497   }
498 
resetSortedIndices()499   synchronized public void resetSortedIndices() {
500     if (!sorted) {
501       return;
502     }
503     // Only used for asserting that we don't use the sorted index after we build the graph.
504     strings.values().forEach(IndexedDexItem::resetSortedIndex);
505     types.values().forEach(IndexedDexItem::resetSortedIndex);
506     fields.values().forEach(IndexedDexItem::resetSortedIndex);
507     protos.values().forEach(IndexedDexItem::resetSortedIndex);
508     methods.values().forEach(IndexedDexItem::resetSortedIndex);
509     sorted = false;
510   }
511 
forAllTypes(Consumer<DexType> f)512   synchronized public void forAllTypes(Consumer<DexType> f) {
513     new ArrayList<>(types.values()).forEach(f);
514   }
515 }
516