Home | History | Annotate | Download | only in graph
      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 
    158   public void clearSubtypeInformation() {
    159     types.values().forEach(DexType::clearSubtypeInformation);
    160   }
    161 
    162   public class LongMethods {
    163 
    164     public DexMethod compare;
    165 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    283   synchronized private DexString canonicalizeString(String key) {
    284     assert key != null;
    285     return strings.computeIfAbsent(key, k -> new DexString(k));
    286   }
    287 
    288   public DexString createString(int size, byte[] content) {
    289     assert !sorted;
    290     return canonicalizeString(new DexString(size, content).toString());
    291   }
    292 
    293   public DexString createString(String source) {
    294     assert !sorted;
    295     return canonicalizeString(source);
    296   }
    297 
    298   public DexType createType(DexString descriptor) {
    299     assert !sorted;
    300     DexType type = new DexType(descriptor);
    301     return canonicalize(types, type);
    302   }
    303 
    304   public DexType createType(String descriptor) {
    305     return createType(createString(descriptor));
    306   }
    307 
    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 
    314   public DexField createField(DexType clazz, DexType type, String name) {
    315     return createField(clazz, type, createString(name));
    316   }
    317 
    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 
    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 
    330   public DexProto createProto(DexType returnType, DexType... parameters) {
    331     return createProto(createShorty(returnType, parameters), returnType, parameters);
    332   }
    333 
    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 
    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 
    349   public DexMethod createMethod(DexType holder, DexProto proto, String name) {
    350     return createMethod(holder, proto, createString(name));
    351   }
    352 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    438   public SetEpilogueBegin createSetEpilogueBegin() {
    439     return setEpilogueBegin;
    440   }
    441 
    442   public SetPrologueEnd createSetPrologueEnd() {
    443     return setPrologueEnd;
    444   }
    445 
    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 
    457   public boolean isConstructor(DexMethod method) {
    458     return method.name == constructorMethodName;
    459   }
    460 
    461   public boolean isClassConstructor(DexMethod method) {
    462     return method.name == classConstructorMethodName;
    463   }
    464 
    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 
    474   private void addToShorty(StringBuilder builder, DexType type) {
    475     char first = type.toDescriptorString().charAt(0);
    476     builder.append(first == '[' ? 'L' : first);
    477   }
    478 
    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 
    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 
    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 
    512   synchronized public void forAllTypes(Consumer<DexType> f) {
    513     new ArrayList<>(types.values()).forEach(f);
    514   }
    515 }
    516