blob: dedc362bc254385555043b11aac1c91b161a2558 [file] [log] [blame]
// Copyright (c) 2016, 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 static com.android.tools.r8.horizontalclassmerging.ClassMerger.CLASS_ID_FIELD_NAME;
import static com.android.tools.r8.ir.analysis.type.ClassTypeElement.computeLeastUpperBoundOfInterfaces;
import static com.android.tools.r8.ir.desugar.LambdaClass.LAMBDA_INSTANCE_FIELD_NAME;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.graph.DexDebugEvent.AdvanceLine;
import com.android.tools.r8.graph.DexDebugEvent.AdvancePC;
import com.android.tools.r8.graph.DexDebugEvent.Default;
import com.android.tools.r8.graph.DexDebugEvent.EndLocal;
import com.android.tools.r8.graph.DexDebugEvent.RestartLocal;
import com.android.tools.r8.graph.DexDebugEvent.SetEpilogueBegin;
import com.android.tools.r8.graph.DexDebugEvent.SetFile;
import com.android.tools.r8.graph.DexDebugEvent.SetInlineFrame;
import com.android.tools.r8.graph.DexDebugEvent.SetPrologueEnd;
import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.InterfaceCollection;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.ReferenceTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.desugar.LambdaClass;
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.LRUCacheTable;
import com.android.tools.r8.utils.ListUtils;
import com.google.common.base.Strings;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class DexItemFactory {
public static final String throwableDescriptorString = "Ljava/lang/Throwable;";
public static final String dalvikAnnotationSignatureString = "Ldalvik/annotation/Signature;";
public static final String recordTagDescriptorString = "Lcom/android/tools/r8/RecordTag;";
public static final String recordDescriptorString = "Ljava/lang/Record;";
/** Set of types that may be synthesized during compilation. */
private final Set<DexType> possibleCompilerSynthesizedTypes = Sets.newIdentityHashSet();
private final Map<DexString, DexString> strings = new ConcurrentHashMap<>();
private final Map<DexString, DexType> types = new ConcurrentHashMap<>();
private final Map<DexField, DexField> fields = new ConcurrentHashMap<>();
private final Map<DexProto, DexProto> protos = new ConcurrentHashMap<>();
private final Map<DexMethod, DexMethod> methods = new ConcurrentHashMap<>();
private final Map<DexMethodHandle, DexMethodHandle> methodHandles =
new ConcurrentHashMap<>();
// DexDebugEvent Canonicalization.
private final Int2ReferenceMap<AdvanceLine> advanceLines = new Int2ReferenceOpenHashMap<>();
private final Int2ReferenceMap<AdvancePC> advancePCs = new Int2ReferenceOpenHashMap<>();
private final Int2ReferenceMap<Default> defaults = new Int2ReferenceOpenHashMap<>();
private final Int2ReferenceMap<EndLocal> endLocals = new Int2ReferenceOpenHashMap<>();
private final Int2ReferenceMap<RestartLocal> restartLocals = new Int2ReferenceOpenHashMap<>();
private final SetEpilogueBegin setEpilogueBegin = new SetEpilogueBegin();
private final SetPrologueEnd setPrologueEnd = new SetPrologueEnd();
private final Map<DexString, SetFile> setFiles = new HashMap<>();
private final Map<SetInlineFrame, SetInlineFrame> setInlineFrames = new HashMap<>();
// ReferenceTypeElement canonicalization.
private final ConcurrentHashMap<DexType, ReferenceTypeElement> referenceTypes =
new ConcurrentHashMap<>();
private final ConcurrentHashMap<DexType, InterfaceCollection> classTypeInterfaces =
new ConcurrentHashMap<>();
public final LRUCacheTable<InterfaceCollection, InterfaceCollection, InterfaceCollection>
leastUpperBoundOfInterfacesTable = LRUCacheTable.create(8, 8);
boolean sorted = false;
// Internal type containing only the null value.
public static final DexType nullValueType = new DexType(new DexString("NULL"));
public static final DexString unknownTypeName = new DexString("UNKNOWN");
private static final IdentityHashMap<DexItem, DexItem> internalSentinels =
new IdentityHashMap<>(
ImmutableMap.of(
nullValueType, nullValueType,
unknownTypeName, unknownTypeName));
public DexItemFactory() {
this.kotlin = new Kotlin(this);
}
public static boolean isInternalSentinel(DexItem item) {
return internalSentinels.containsKey(item);
}
public final DexString booleanDescriptor = createString("Z");
public final DexString byteDescriptor = createString("B");
public final DexString charDescriptor = createString("C");
public final DexString doubleDescriptor = createString("D");
public final DexString floatDescriptor = createString("F");
public final DexString intDescriptor = createString("I");
public final DexString longDescriptor = createString("J");
public final DexString shortDescriptor = createString("S");
public final DexString voidDescriptor = createString("V");
public final DexString descriptorSeparator = createString("/");
private final DexString booleanArrayDescriptor = createString("[Z");
private final DexString byteArrayDescriptor = createString("[B");
private final DexString charArrayDescriptor = createString("[C");
private final DexString doubleArrayDescriptor = createString("[D");
private final DexString floatArrayDescriptor = createString("[F");
private final DexString intArrayDescriptor = createString("[I");
private final DexString longArrayDescriptor = createString("[J");
private final DexString shortArrayDescriptor = createString("[S");
public final DexString boxedBooleanDescriptor = createString("Ljava/lang/Boolean;");
public final DexString boxedByteDescriptor = createString("Ljava/lang/Byte;");
public final DexString boxedCharDescriptor = createString("Ljava/lang/Character;");
public final DexString boxedDoubleDescriptor = createString("Ljava/lang/Double;");
public final DexString boxedFloatDescriptor = createString("Ljava/lang/Float;");
public final DexString boxedIntDescriptor = createString("Ljava/lang/Integer;");
public final DexString boxedLongDescriptor = createString("Ljava/lang/Long;");
public final DexString boxedShortDescriptor = createString("Ljava/lang/Short;");
public final DexString boxedNumberDescriptor = createString("Ljava/lang/Number;");
public final DexString boxedVoidDescriptor = createString("Ljava/lang/Void;");
public final DexString waitMethodName = createString("wait");
public final DexString notifyMethodName = createString("notify");
public final DexString notifyAllMethodName = createString("notifyAll");
public final DexString unboxBooleanMethodName = createString("booleanValue");
public final DexString unboxByteMethodName = createString("byteValue");
public final DexString unboxCharMethodName = createString("charValue");
public final DexString unboxShortMethodName = createString("shortValue");
public final DexString unboxIntMethodName = createString("intValue");
public final DexString unboxLongMethodName = createString("longValue");
public final DexString unboxFloatMethodName = createString("floatValue");
public final DexString unboxDoubleMethodName = createString("doubleValue");
public final DexString isEmptyMethodName = createString("isEmpty");
public final DexString lengthMethodName = createString("length");
public final DexString concatMethodName = createString("concat");
public final DexString containsMethodName = createString("contains");
public final DexString startsWithMethodName = createString("startsWith");
public final DexString endsWithMethodName = createString("endsWith");
public final DexString equalsMethodName = createString("equals");
public final DexString hashCodeMethodName = createString("hashCode");
public final DexString identityHashCodeName = createString("identityHashCode");
public final DexString equalsIgnoreCaseMethodName = createString("equalsIgnoreCase");
public final DexString contentEqualsMethodName = createString("contentEquals");
public final DexString indexOfMethodName = createString("indexOf");
public final DexString lastIndexOfMethodName = createString("lastIndexOf");
public final DexString compareToMethodName = createString("compareTo");
public final DexString compareToIgnoreCaseMethodName = createString("compareToIgnoreCase");
public final DexString cloneMethodName = createString("clone");
public final DexString substringName = createString("substring");
public final DexString trimName = createString("trim");
public final DexString valueOfMethodName = createString("valueOf");
public final DexString valuesMethodName = createString("values");
public final DexString toStringMethodName = createString("toString");
public final DexString internMethodName = createString("intern");
public final DexString convertMethodName = createString("convert");
public final DexString wrapperFieldName = createString("wrappedValue");
public final DexString getClassMethodName = createString("getClass");
public final DexString finalizeMethodName = createString("finalize");
public final DexString ordinalMethodName = createString("ordinal");
public final DexString nameMethodName = createString("name");
public final DexString desiredAssertionStatusMethodName = createString("desiredAssertionStatus");
public final DexString forNameMethodName = createString("forName");
public final DexString getNameName = createString("getName");
public final DexString getCanonicalNameName = createString("getCanonicalName");
public final DexString getSimpleNameName = createString("getSimpleName");
public final DexString getTypeNameName = createString("getTypeName");
public final DexString getDeclaredConstructorName = createString("getDeclaredConstructor");
public final DexString getFieldName = createString("getField");
public final DexString getDeclaredFieldName = createString("getDeclaredField");
public final DexString getMethodName = createString("getMethod");
public final DexString getDeclaredMethodName = createString("getDeclaredMethod");
public final DexString newInstanceName = createString("newInstance");
public final DexString assertionsDisabled = createString("$assertionsDisabled");
public final DexString invokeMethodName = createString("invoke");
public final DexString invokeExactMethodName = createString("invokeExact");
public final DexString runtimeExceptionDescriptor = createString("Ljava/lang/RuntimeException;");
public final DexString assertionErrorDescriptor = createString("Ljava/lang/AssertionError;");
public final DexString charSequenceDescriptor = createString("Ljava/lang/CharSequence;");
public final DexString charSequenceArrayDescriptor = createString("[Ljava/lang/CharSequence;");
public final DexString stringDescriptor = createString("Ljava/lang/String;");
public final DexString stringArrayDescriptor = createString("[Ljava/lang/String;");
public final DexString objectDescriptor = createString("Ljava/lang/Object;");
public final DexString recordDescriptor = createString(recordDescriptorString);
public final DexString recordTagDescriptor = createString(recordTagDescriptorString);
public final DexString objectArrayDescriptor = createString("[Ljava/lang/Object;");
public final DexString classDescriptor = createString("Ljava/lang/Class;");
public final DexString classLoaderDescriptor = createString("Ljava/lang/ClassLoader;");
public final DexString autoCloseableDescriptor = createString("Ljava/lang/AutoCloseable;");
public final DexString classArrayDescriptor = createString("[Ljava/lang/Class;");
public final DexString constructorDescriptor = createString("Ljava/lang/reflect/Constructor;");
public final DexString fieldDescriptor = createString("Ljava/lang/reflect/Field;");
public final DexString methodDescriptor = createString("Ljava/lang/reflect/Method;");
public final DexString enumDescriptor = createString("Ljava/lang/Enum;");
public final DexString javaLangSystemDescriptor = createString("Ljava/lang/System;");
public final DexString annotationDescriptor = createString("Ljava/lang/annotation/Annotation;");
public final DexString objectsDescriptor = createString("Ljava/util/Objects;");
public final DexString collectionsDescriptor = createString("Ljava/util/Collections;");
public final DexString iterableDescriptor = createString("Ljava/lang/Iterable;");
public final DexString mathDescriptor = createString("Ljava/lang/Math;");
public final DexString strictMathDescriptor = createString("Ljava/lang/StrictMath;");
public final DexString closeableDescriptor = createString("Ljava/io/Closeable;");
public final DexString zipFileDescriptor = createString("Ljava/util/zip/ZipFile;");
public final DexString bufferDescriptor = createString("Ljava/nio/Buffer;");
public final DexString byteBufferDescriptor = createString("Ljava/nio/ByteBuffer;");
public final DexString mappedByteBufferDescriptor = createString("Ljava/nio/MappedByteBuffer;");
public final DexString charBufferDescriptor = createString("Ljava/nio/CharBuffer;");
public final DexString shortBufferDescriptor = createString("Ljava/nio/ShortBuffer;");
public final DexString intBufferDescriptor = createString("Ljava/nio/IntBuffer;");
public final DexString longBufferDescriptor = createString("Ljava/nio/LongBuffer;");
public final DexString floatBufferDescriptor = createString("Ljava/nio/FloatBuffer;");
public final DexString doubleBufferDescriptor = createString("Ljava/nio/DoubleBuffer;");
public final DexString stringBuilderDescriptor = createString("Ljava/lang/StringBuilder;");
public final DexString stringBufferDescriptor = createString("Ljava/lang/StringBuffer;");
public final DexString varHandleDescriptor = createString("Ljava/lang/invoke/VarHandle;");
public final DexString methodHandleDescriptor = createString("Ljava/lang/invoke/MethodHandle;");
public final DexString methodTypeDescriptor = createString("Ljava/lang/invoke/MethodType;");
public final DexString invocationHandlerDescriptor =
createString("Ljava/lang/reflect/InvocationHandler;");
public final DexString proxyDescriptor = createString("Ljava/lang/reflect/Proxy;");
public final DexString serviceLoaderDescriptor = createString("Ljava/util/ServiceLoader;");
public final DexString serviceLoaderConfigurationErrorDescriptor =
createString("Ljava/util/ServiceConfigurationError;");
public final DexString listDescriptor = createString("Ljava/util/List;");
public final DexString setDescriptor = createString("Ljava/util/Set;");
public final DexString mapDescriptor = createString("Ljava/util/Map;");
public final DexString mapEntryDescriptor = createString("Ljava/util/Map$Entry;");
public final DexString collectionDescriptor = createString("Ljava/util/Collection;");
public final DexString comparatorDescriptor = createString("Ljava/util/Comparator;");
public final DexString callableDescriptor = createString("Ljava/util/concurrent/Callable;");
public final DexString supplierDescriptor = createString("Ljava/util/function/Supplier;");
public final DexString consumerDescriptor = createString("Ljava/util/function/Consumer;");
public final DexString runnableDescriptor = createString("Ljava/lang/Runnable;");
public final DexString optionalDescriptor = createString("Ljava/util/Optional;");
public final DexString optionalDoubleDescriptor = createString("Ljava/util/OptionalDouble;");
public final DexString optionalIntDescriptor = createString("Ljava/util/OptionalInt;");
public final DexString optionalLongDescriptor = createString("Ljava/util/OptionalLong;");
public final DexString streamDescriptor = createString("Ljava/util/stream/Stream;");
public final DexString arraysDescriptor = createString("Ljava/util/Arrays;");
public final DexString throwableDescriptor = createString(throwableDescriptorString);
public final DexString illegalAccessErrorDescriptor =
createString("Ljava/lang/IllegalAccessError;");
public final DexString illegalArgumentExceptionDescriptor =
createString("Ljava/lang/IllegalArgumentException;");
public final DexString icceDescriptor = createString("Ljava/lang/IncompatibleClassChangeError;");
public final DexString exceptionInInitializerErrorDescriptor =
createString("Ljava/lang/ExceptionInInitializerError;");
public final DexString noClassDefFoundErrorDescriptor =
createString("Ljava/lang/NoClassDefFoundError;");
public final DexString noSuchFieldErrorDescriptor = createString("Ljava/lang/NoSuchFieldError;");
public final DexString npeDescriptor = createString("Ljava/lang/NullPointerException;");
public final DexString reflectiveOperationExceptionDescriptor =
createString("Ljava/lang/ReflectiveOperationException;");
public final DexString kotlinMetadataDescriptor = createString("Lkotlin/Metadata;");
public final DexString intFieldUpdaterDescriptor =
createString("Ljava/util/concurrent/atomic/AtomicIntegerFieldUpdater;");
public final DexString longFieldUpdaterDescriptor =
createString("Ljava/util/concurrent/atomic/AtomicLongFieldUpdater;");
public final DexString referenceFieldUpdaterDescriptor =
createString("Ljava/util/concurrent/atomic/AtomicReferenceFieldUpdater;");
public final DexString newUpdaterName = createString("newUpdater");
public final DexString constructorMethodName = createString(Constants.INSTANCE_INITIALIZER_NAME);
public final DexString classConstructorMethodName =
createString(Constants.CLASS_INITIALIZER_NAME);
public final DexString temporaryConstructorMethodPrefix =
createString(Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX);
public final DexString thisName = createString("this");
public final DexString lambdaInstanceFieldName = createString(LAMBDA_INSTANCE_FIELD_NAME);
public final DexString javacLambdaMethodPrefix =
createString(LambdaClass.JAVAC_EXPECTED_LAMBDA_METHOD_PREFIX);
// As much as possible, R8 should rely on the content of the static enum field, using
// enumMembers.isValuesFieldCandidate or checking the object state in the optimization info.
// The field name is unrealiable since the filed can be minified prior to this compilation.
// We keep enumValuesFieldName as a heuristic only.
public final DexString enumValuesFieldName = createString("$VALUES");
public final DexString enabledFieldName = createString("ENABLED");
public final DexString throwableArrayDescriptor = createString("[Ljava/lang/Throwable;");
public final DexString valueString = createString("value");
public final DexString kindString = createString("kind");
public final DexType booleanType = createStaticallyKnownType(booleanDescriptor);
public final DexType byteType = createStaticallyKnownType(byteDescriptor);
public final DexType charType = createStaticallyKnownType(charDescriptor);
public final DexType doubleType = createStaticallyKnownType(doubleDescriptor);
public final DexType floatType = createStaticallyKnownType(floatDescriptor);
public final DexType intType = createStaticallyKnownType(intDescriptor);
public final DexType longType = createStaticallyKnownType(longDescriptor);
public final DexType shortType = createStaticallyKnownType(shortDescriptor);
public final DexType voidType = createStaticallyKnownType(voidDescriptor);
public final DexType booleanArrayType = createStaticallyKnownType(booleanArrayDescriptor);
public final DexType byteArrayType = createStaticallyKnownType(byteArrayDescriptor);
public final DexType charArrayType = createStaticallyKnownType(charArrayDescriptor);
public final DexType doubleArrayType = createStaticallyKnownType(doubleArrayDescriptor);
public final DexType floatArrayType = createStaticallyKnownType(floatArrayDescriptor);
public final DexType intArrayType = createStaticallyKnownType(intArrayDescriptor);
public final DexType longArrayType = createStaticallyKnownType(longArrayDescriptor);
public final DexType shortArrayType = createStaticallyKnownType(shortArrayDescriptor);
public final DexType boxedBooleanType = createStaticallyKnownType(boxedBooleanDescriptor);
public final DexType boxedByteType = createStaticallyKnownType(boxedByteDescriptor);
public final DexType boxedCharType = createStaticallyKnownType(boxedCharDescriptor);
public final DexType boxedDoubleType = createStaticallyKnownType(boxedDoubleDescriptor);
public final DexType boxedFloatType = createStaticallyKnownType(boxedFloatDescriptor);
public final DexType boxedIntType = createStaticallyKnownType(boxedIntDescriptor);
public final DexType boxedLongType = createStaticallyKnownType(boxedLongDescriptor);
public final DexType boxedShortType = createStaticallyKnownType(boxedShortDescriptor);
public final DexType boxedNumberType = createStaticallyKnownType(boxedNumberDescriptor);
public final DexType boxedVoidType = createStaticallyKnownType(boxedVoidDescriptor);
public final DexType charSequenceType = createStaticallyKnownType(charSequenceDescriptor);
public final DexType charSequenceArrayType =
createStaticallyKnownType(charSequenceArrayDescriptor);
public final DexType stringType = createStaticallyKnownType(stringDescriptor);
public final DexType stringArrayType = createStaticallyKnownType(stringArrayDescriptor);
public final DexType objectType = createStaticallyKnownType(objectDescriptor);
public final DexType recordType = createStaticallyKnownType(recordDescriptor);
public final DexType recordTagType = createStaticallyKnownType(recordTagDescriptor);
public final DexType objectArrayType = createStaticallyKnownType(objectArrayDescriptor);
public final DexType classArrayType = createStaticallyKnownType(classArrayDescriptor);
public final DexType enumType = createStaticallyKnownType(enumDescriptor);
public final DexType annotationType = createStaticallyKnownType(annotationDescriptor);
public final DexType objectsType = createStaticallyKnownType(objectsDescriptor);
public final DexType collectionsType = createStaticallyKnownType(collectionsDescriptor);
public final DexType iterableType = createStaticallyKnownType(iterableDescriptor);
public final DexType mathType = createStaticallyKnownType(mathDescriptor);
public final DexType strictMathType = createStaticallyKnownType(strictMathDescriptor);
public final DexType referenceFieldUpdaterType =
createStaticallyKnownType(referenceFieldUpdaterDescriptor);
public final DexType classType = createStaticallyKnownType(classDescriptor);
public final DexType packageType = createStaticallyKnownType(Package.class);
public final DexType classLoaderType = createStaticallyKnownType(classLoaderDescriptor);
public final DexType constructorType = createStaticallyKnownType(constructorDescriptor);
public final DexType fieldType = createStaticallyKnownType(fieldDescriptor);
public final DexType methodType = createStaticallyKnownType(methodDescriptor);
public final DexType autoCloseableType = createStaticallyKnownType(autoCloseableDescriptor);
public final DexType closeableType = createStaticallyKnownType(closeableDescriptor);
public final DexType zipFileType = createStaticallyKnownType(zipFileDescriptor);
public final DexType stringBuilderType = createStaticallyKnownType(stringBuilderDescriptor);
public final DexType stringBufferType = createStaticallyKnownType(stringBufferDescriptor);
public final DexType javaLangReflectArrayType =
createStaticallyKnownType("Ljava/lang/reflect/Array;");
public final DexType javaLangSystemType = createStaticallyKnownType(javaLangSystemDescriptor);
public final DexType javaIoPrintStreamType = createStaticallyKnownType("Ljava/io/PrintStream;");
public final DexType varHandleType = createStaticallyKnownType(varHandleDescriptor);
public final DexType methodHandleType = createStaticallyKnownType(methodHandleDescriptor);
public final DexType methodTypeType = createStaticallyKnownType(methodTypeDescriptor);
public final DexType invocationHandlerType =
createStaticallyKnownType(invocationHandlerDescriptor);
public final DexType proxyType = createStaticallyKnownType(proxyDescriptor);
public final DexType serviceLoaderType = createStaticallyKnownType(serviceLoaderDescriptor);
public final DexType serviceLoaderConfigurationErrorType =
createStaticallyKnownType(serviceLoaderConfigurationErrorDescriptor);
public final DexType listType = createStaticallyKnownType(listDescriptor);
public final DexType setType = createStaticallyKnownType(setDescriptor);
public final DexType mapType = createStaticallyKnownType(mapDescriptor);
public final DexType mapEntryType = createStaticallyKnownType(mapEntryDescriptor);
public final DexType abstractMapSimpleEntryType =
createStaticallyKnownType("Ljava/util/AbstractMap$SimpleEntry;");
public final DexType collectionType = createStaticallyKnownType(collectionDescriptor);
public final DexType comparatorType = createStaticallyKnownType(comparatorDescriptor);
public final DexType callableType = createStaticallyKnownType(callableDescriptor);
public final DexType supplierType = createStaticallyKnownType(supplierDescriptor);
public final DexType consumerType = createStaticallyKnownType(consumerDescriptor);
public final DexType runnableType = createStaticallyKnownType(runnableDescriptor);
public final DexType optionalType = createStaticallyKnownType(optionalDescriptor);
public final DexType optionalDoubleType = createStaticallyKnownType(optionalDoubleDescriptor);
public final DexType optionalIntType = createStaticallyKnownType(optionalIntDescriptor);
public final DexType optionalLongType = createStaticallyKnownType(optionalLongDescriptor);
public final DexType streamType = createStaticallyKnownType(streamDescriptor);
public final DexType bufferType = createStaticallyKnownType(bufferDescriptor);
public final DexType byteBufferType = createStaticallyKnownType(byteBufferDescriptor);
public final DexType mappedByteBufferType = createStaticallyKnownType(mappedByteBufferDescriptor);
public final DexType charBufferType = createStaticallyKnownType(charBufferDescriptor);
public final DexType shortBufferType = createStaticallyKnownType(shortBufferDescriptor);
public final DexType intBufferType = createStaticallyKnownType(intBufferDescriptor);
public final DexType longBufferType = createStaticallyKnownType(longBufferDescriptor);
public final DexType floatBufferType = createStaticallyKnownType(floatBufferDescriptor);
public final DexType doubleBufferType = createStaticallyKnownType(doubleBufferDescriptor);
public final List<DexType> typeSpecificBuffers =
ImmutableList.of(
byteBufferType,
mappedByteBufferType,
charBufferType,
shortBufferType,
intBufferType,
longBufferType,
floatBufferType,
doubleBufferType);
public final DexType doubleConsumer =
createStaticallyKnownType("Ljava/util/function/DoubleConsumer;");
public final DexType longConsumer =
createStaticallyKnownType("Ljava/util/function/LongConsumer;");
public final DexType intConsumer = createStaticallyKnownType("Ljava/util/function/IntConsumer;");
public final DexType retentionType =
createStaticallyKnownType("Ljava/lang/annotation/Retention;");
public final DexType runtimeExceptionType = createStaticallyKnownType(runtimeExceptionDescriptor);
public final DexType throwableType = createStaticallyKnownType(throwableDescriptor);
public final DexType illegalAccessErrorType =
createStaticallyKnownType(illegalAccessErrorDescriptor);
public final DexType illegalArgumentExceptionType =
createStaticallyKnownType(illegalArgumentExceptionDescriptor);
public final DexType icceType = createStaticallyKnownType(icceDescriptor);
public final DexType exceptionInInitializerErrorType =
createStaticallyKnownType(exceptionInInitializerErrorDescriptor);
public final DexType noClassDefFoundErrorType =
createStaticallyKnownType(noClassDefFoundErrorDescriptor);
public final DexType noSuchFieldErrorType = createStaticallyKnownType(noSuchFieldErrorDescriptor);
public final DexType noSuchMethodErrorType =
createStaticallyKnownType("Ljava/lang/NoSuchMethodError;");
public final DexType npeType = createStaticallyKnownType(npeDescriptor);
public final DexType reflectiveOperationExceptionType =
createStaticallyKnownType(reflectiveOperationExceptionDescriptor);
public final DexType kotlinMetadataType = createStaticallyKnownType(kotlinMetadataDescriptor);
public final DexType doubleSummaryStatisticsConversionsType =
createStaticallyKnownType("Ljava/util/DoubleSummaryStatisticsConversions;");
public final DexType intSummaryStatisticsConversionsType =
createStaticallyKnownType("Ljava/util/IntSummaryStatisticsConversions;");
public final DexType longSummaryStatisticsConversionsType =
createStaticallyKnownType("Ljava/util/LongSummaryStatisticsConversions;");
public final DexType optionalConversionsType =
createStaticallyKnownType("Ljava/util/OptionalConversions;");
public final DexType timeConversionsType =
createStaticallyKnownType("Ljava/time/TimeConversions;");
public final DexType doubleSummaryStatisticsConversionsJ$Type =
createStaticallyKnownType("Lj$/util/DoubleSummaryStatisticsConversions;");
public final DexType intSummaryStatisticsConversionsJ$Type =
createStaticallyKnownType("Lj$/util/IntSummaryStatisticsConversions;");
public final DexType longSummaryStatisticsConversionsJ$Type =
createStaticallyKnownType("Lj$/util/LongSummaryStatisticsConversions;");
public final DexType optionalConversionsJ$Type =
createStaticallyKnownType("Lj$/util/OptionalConversions;");
public final DexType timeConversionsJ$Type =
createStaticallyKnownType("Lj$/time/TimeConversions;");
public Iterable<DexType> getJavaConversionTypes() {
return ImmutableList.of(
doubleSummaryStatisticsConversionsType,
intSummaryStatisticsConversionsType,
longSummaryStatisticsConversionsType,
optionalConversionsType,
timeConversionsType);
}
public Iterable<DexType> getJ$ConversionTypes() {
return ImmutableList.of(
doubleSummaryStatisticsConversionsJ$Type,
intSummaryStatisticsConversionsJ$Type,
longSummaryStatisticsConversionsJ$Type,
optionalConversionsJ$Type,
timeConversionsJ$Type);
}
public final DexType javaIoFileType = createStaticallyKnownType("Ljava/io/File;");
public final DexType javaMathBigIntegerType = createStaticallyKnownType("Ljava/math/BigInteger;");
public final DexType javaNioByteOrderType = createStaticallyKnownType("Ljava/nio/ByteOrder;");
public final DexType javaUtilCollectionsType =
createStaticallyKnownType("Ljava/util/Collections;");
public final DexType javaUtilComparatorType = createStaticallyKnownType("Ljava/util/Comparator;");
public final DexType javaUtilConcurrentTimeUnitType =
createStaticallyKnownType("Ljava/util/concurrent/TimeUnit;");
public final DexType javaUtilListType = createStaticallyKnownType("Ljava/util/List;");
public final DexType javaUtilLocaleType = createStaticallyKnownType("Ljava/util/Locale;");
public final DexType javaUtilLoggingLevelType =
createStaticallyKnownType("Ljava/util/logging/Level;");
public final DexType javaUtilLoggingLoggerType =
createStaticallyKnownType("Ljava/util/logging/Logger;");
public final DexType javaUtilSetType = createStaticallyKnownType("Ljava/util/Set;");
public final DexType androidAppActivity = createStaticallyKnownType("Landroid/app/Activity;");
public final DexType androidOsBuildType = createStaticallyKnownType("Landroid/os/Build;");
public final DexType androidOsBuildVersionType =
createStaticallyKnownType("Landroid/os/Build$VERSION;");
public final DexType androidOsBundleType = createStaticallyKnownType("Landroid/os/Bundle;");
public final DexType androidOsParcelableCreatorType =
createStaticallyKnownType("Landroid/os/Parcelable$Creator;");
public final DexType androidSystemOsConstantsType =
createStaticallyKnownType("Landroid/system/OsConstants;");
public final DexType androidUtilLogType = createStaticallyKnownType("Landroid/util/Log;");
public final DexType androidUtilPropertyType =
createStaticallyKnownType("Landroid/util/Property;");
public final DexType androidViewViewType = createStaticallyKnownType("Landroid/view/View;");
public final DexType androidUtilSparseArrayType =
createStaticallyKnownType("Landroid/util/SparseArray;");
public final StringBuildingMethods stringBuilderMethods =
new StringBuildingMethods(stringBuilderType);
public final StringBuildingMethods stringBufferMethods =
new StringBuildingMethods(stringBufferType);
public final BooleanMembers booleanMembers = new BooleanMembers();
public final ByteMembers byteMembers = new ByteMembers();
public final CharMembers charMembers = new CharMembers();
public final FloatMembers floatMembers = new FloatMembers();
public final IntegerMembers integerMembers = new IntegerMembers();
public final LongMembers longMembers = new LongMembers();
public final ObjectsMethods objectsMethods = new ObjectsMethods();
public final ObjectMembers objectMembers = new ObjectMembers();
public final BufferMembers bufferMembers = new BufferMembers();
public final RecordMembers recordMembers = new RecordMembers();
public final ShortMembers shortMembers = new ShortMembers();
public final StringMembers stringMembers = new StringMembers();
public final SupplierMembers supplierMembers = new SupplierMembers();
public final DoubleMembers doubleMembers = new DoubleMembers();
public final ThrowableMethods throwableMethods = new ThrowableMethods();
public final AssertionErrorMethods assertionErrorMethods = new AssertionErrorMethods();
public final ClassMethods classMethods = new ClassMethods();
public final ConstructorMethods constructorMethods = new ConstructorMethods();
public final EnumMembers enumMembers = new EnumMembers();
public final JavaLangReflectArrayMembers javaLangReflectArrayMembers =
new JavaLangReflectArrayMembers();
public final JavaLangSystemMethods javaLangSystemMethods = new JavaLangSystemMethods();
public final NullPointerExceptionMethods npeMethods = new NullPointerExceptionMethods();
public final IllegalArgumentExceptionMethods illegalArgumentExceptionMethods =
new IllegalArgumentExceptionMethods();
public final PrimitiveTypesBoxedTypeFields primitiveTypesBoxedTypeFields =
new PrimitiveTypesBoxedTypeFields();
public final AtomicFieldUpdaterMethods atomicFieldUpdaterMethods =
new AtomicFieldUpdaterMethods();
public final Kotlin kotlin;
public final PolymorphicMethods polymorphicMethods = new PolymorphicMethods();
public final ProxyMethods proxyMethods = new ProxyMethods();
// android.**
public final AndroidOsBuildMembers androidOsBuildMembers = new AndroidOsBuildMembers();
public final AndroidOsBuildVersionMembers androidOsBuildVersionMembers =
new AndroidOsBuildVersionMembers();
public final AndroidOsBundleMembers androidOsBundleMembers = new AndroidOsBundleMembers();
public final AndroidSystemOsConstantsMembers androidSystemOsConstantsMembers =
new AndroidSystemOsConstantsMembers();
public final AndroidViewViewMembers androidViewViewMembers = new AndroidViewViewMembers();
public final AndroidUtilSparseArrayMembers androidUtilSparseArrayMembers =
new AndroidUtilSparseArrayMembers();
// java.**
public final JavaIoFileMembers javaIoFileMembers = new JavaIoFileMembers();
public final JavaMathBigIntegerMembers javaMathBigIntegerMembers =
new JavaMathBigIntegerMembers();
public final JavaNioByteOrderMembers javaNioByteOrderMembers = new JavaNioByteOrderMembers();
public final JavaUtilArraysMethods javaUtilArraysMethods = new JavaUtilArraysMethods();
public final JavaUtilComparatorMembers javaUtilComparatorMembers =
new JavaUtilComparatorMembers();
public final JavaUtilConcurrentTimeUnitMembers javaUtilConcurrentTimeUnitMembers =
new JavaUtilConcurrentTimeUnitMembers();
public final JavaUtilLocaleMembers javaUtilLocaleMembers = new JavaUtilLocaleMembers();
public final JavaUtilLoggingLevelMembers javaUtilLoggingLevelMembers =
new JavaUtilLoggingLevelMembers();
public final List<LibraryMembers> libraryMembersCollection =
ImmutableList.of(
booleanMembers,
floatMembers,
integerMembers,
longMembers,
stringMembers,
// android.**
androidOsBuildMembers,
androidOsBuildVersionMembers,
androidOsBundleMembers,
androidSystemOsConstantsMembers,
androidViewViewMembers,
// java.**
javaIoFileMembers,
javaMathBigIntegerMembers,
javaNioByteOrderMembers,
javaUtilComparatorMembers,
javaUtilConcurrentTimeUnitMembers,
javaUtilLocaleMembers,
javaUtilLoggingLevelMembers);
public final DexString twrCloseResourceMethodName = createString("$closeResource");
public final DexProto twrCloseResourceMethodProto =
createProto(voidType, throwableType, autoCloseableType);
public final DexString deserializeLambdaMethodName = createString("$deserializeLambda$");
public final DexType serializedLambdaType =
createStaticallyKnownType("Ljava/lang/invoke/SerializedLambda;");
public final DexProto deserializeLambdaMethodProto =
createProto(objectType, serializedLambdaType);
// Dex system annotations.
// See https://source.android.com/devices/tech/dalvik/dex-format.html#system-annotation
public final DexType annotationDefault =
createStaticallyKnownType("Ldalvik/annotation/AnnotationDefault;");
public final DexType annotationEnclosingClass =
createStaticallyKnownType("Ldalvik/annotation/EnclosingClass;");
public final DexType annotationEnclosingMethod =
createStaticallyKnownType("Ldalvik/annotation/EnclosingMethod;");
public final DexType annotationInnerClass =
createStaticallyKnownType("Ldalvik/annotation/InnerClass;");
public final DexType annotationMemberClasses =
createStaticallyKnownType("Ldalvik/annotation/MemberClasses;");
public final DexType annotationMethodParameters =
createStaticallyKnownType("Ldalvik/annotation/MethodParameters;");
public final DexType annotationSignature =
createStaticallyKnownType(dalvikAnnotationSignatureString);
public final DexType annotationSourceDebugExtension =
createStaticallyKnownType("Ldalvik/annotation/SourceDebugExtension;");
public final DexType annotationThrows = createStaticallyKnownType("Ldalvik/annotation/Throws;");
public final DexType annotationSynthesizedClass =
createStaticallyKnownType("Lcom/android/tools/r8/annotations/SynthesizedClass;");
public final DexType annotationCovariantReturnType =
createStaticallyKnownType("Ldalvik/annotation/codegen/CovariantReturnType;");
public final DexType annotationCovariantReturnTypes =
createStaticallyKnownType(
"Ldalvik/annotation/codegen/CovariantReturnType$CovariantReturnTypes;");
public final DexType annotationReachabilitySensitive =
createStaticallyKnownType("Ldalvik/annotation/optimization/ReachabilitySensitive;");
// Runtime affecting yet class-retained annotations.
public final DexType dalvikFastNativeAnnotation =
createStaticallyKnownType("Ldalvik/annotation/optimization/FastNative;");
public final DexType dalvikCriticalNativeAnnotation =
createStaticallyKnownType("Ldalvik/annotation/optimization/CriticalNative;");
private static final String METAFACTORY_METHOD_NAME = "metafactory";
private static final String METAFACTORY_ALT_METHOD_NAME = "altMetafactory";
public final DexType metafactoryType =
createStaticallyKnownType("Ljava/lang/invoke/LambdaMetafactory;");
public final DexType callSiteType = createStaticallyKnownType("Ljava/lang/invoke/CallSite;");
public final DexType lookupType =
createStaticallyKnownType("Ljava/lang/invoke/MethodHandles$Lookup;");
public final DexType objectMethodsType =
createStaticallyKnownType("Ljava/lang/runtime/ObjectMethods;");
public final DexType typeDescriptorType =
createStaticallyKnownType("Ljava/lang/invoke/TypeDescriptor;");
public final DexType iteratorType = createStaticallyKnownType("Ljava/util/Iterator;");
public final DexType listIteratorType = createStaticallyKnownType("Ljava/util/ListIterator;");
public final DexType enumerationType = createStaticallyKnownType("Ljava/util/Enumeration;");
public final DexType serializableType = createStaticallyKnownType("Ljava/io/Serializable;");
public final DexType externalizableType = createStaticallyKnownType("Ljava/io/Externalizable;");
public final DexType cloneableType = createStaticallyKnownType("Ljava/lang/Cloneable;");
public final DexType comparableType = createStaticallyKnownType("Ljava/lang/Comparable;");
public final DexType stringConcatFactoryType =
createStaticallyKnownType("Ljava/lang/invoke/StringConcatFactory;");
public final DexType unsafeType = createStaticallyKnownType("Lsun/misc/Unsafe;");
public final ObjectMethodsMembers objectMethodsMembers = new ObjectMethodsMembers();
public final ServiceLoaderMethods serviceLoaderMethods = new ServiceLoaderMethods();
public final StringConcatFactoryMembers stringConcatFactoryMembers =
new StringConcatFactoryMembers();
public final BiMap<DexType, DexType> primitiveToBoxed = HashBiMap.create(
ImmutableMap.<DexType, DexType>builder()
.put(booleanType, boxedBooleanType)
.put(byteType, boxedByteType)
.put(charType, boxedCharType)
.put(shortType, boxedShortType)
.put(intType, boxedIntType)
.put(longType, boxedLongType)
.put(floatType, boxedFloatType)
.put(doubleType, boxedDoubleType)
.build());
public DexType getBoxedForPrimitiveType(DexType primitive) {
assert primitive.isPrimitiveType();
return primitiveToBoxed.get(primitive);
}
public DexType getPrimitiveFromBoxed(DexType boxedPrimitive) {
return primitiveToBoxed.inverse().get(boxedPrimitive);
}
// Boxed Boxed#valueOf(Primitive), e.g., Boolean Boolean#valueOf(B)
public Set<DexMethod> boxedValueOfMethods() {
return primitiveToBoxed.entrySet().stream()
.map(
entry -> {
DexType primitive = entry.getKey();
DexType boxed = entry.getValue();
return createMethod(
boxed.descriptor,
valueOfMethodName,
boxed.descriptor,
new DexString[] {primitive.descriptor});
})
.collect(Collectors.toSet());
}
public final DexMethod metafactoryMethod =
createMethod(
metafactoryType,
createProto(
callSiteType,
lookupType,
stringType,
methodTypeType,
methodTypeType,
methodHandleType,
methodTypeType),
createString(METAFACTORY_METHOD_NAME));
public final DexMethod metafactoryAltMethod =
createMethod(
metafactoryType,
createProto(callSiteType, lookupType, stringType, methodTypeType, objectArrayType),
createString(METAFACTORY_ALT_METHOD_NAME));
public final DexMethod deserializeLambdaMethod =
createMethod(objectType, deserializeLambdaMethodProto, deserializeLambdaMethodName);
public Map<DexMethod, int[]> libraryMethodsNonNullParamOrThrow =
buildLibraryMethodsNonNullParamOrThrow();
private Map<DexMethod, int[]> buildLibraryMethodsNonNullParamOrThrow() {
ImmutableMap.Builder<DexMethod, int[]> builder = ImmutableMap.builder();
for (DexMethod requireNonNullMethod : objectsMethods.requireNonNullMethods()) {
builder.put(requireNonNullMethod, new int[] {0});
}
return builder.build();
}
public Set<DexMethod> libraryMethodsReturningReceiver =
ImmutableSet.<DexMethod>builder()
.addAll(stringBufferMethods.appendMethods)
.addAll(stringBuilderMethods.appendMethods)
.build();
// Library methods listed here are based on their original implementations. That is, we assume
// these cannot be overridden.
public final Set<DexMethod> libraryMethodsReturningNonNull =
ImmutableSet.<DexMethod>builder()
.add(
classMethods.getName,
classMethods.getSimpleName,
classMethods.forName,
objectMembers.getClass,
objectsMethods.requireNonNull,
objectsMethods.requireNonNullWithMessage,
objectsMethods.requireNonNullWithMessageSupplier,
stringMembers.valueOf)
.addAll(stringBufferMethods.appendMethods)
.addAll(stringBuilderMethods.appendMethods)
.build();
// TODO(b/119596718): More idempotent methods? Any singleton accessors? E.g.,
// java.util.Calendar#getInstance(...) // 4 variants
// java.util.Locale#getDefault() // returns JVM default locale.
// android.os.Looper#myLooper() // returns the associated Looper instance.
// Note that this set is used for canonicalization of method invocations, together with a set of
// library methods that do not have side effects.
public Set<DexMethod> libraryMethodsWithReturnValueDependingOnlyOnArguments =
ImmutableSet.<DexMethod>builder()
.addAll(boxedValueOfMethods())
.build();
public Set<DexType> libraryTypesAssumedToBePresent =
ImmutableSet.<DexType>builder()
.add(
androidAppActivity,
callableType,
enumType,
npeType,
objectType,
stringBufferType,
stringBuilderType,
stringType)
.addAll(primitiveToBoxed.values())
.build();
public Set<DexType> libraryClassesWithoutStaticInitialization =
ImmutableSet.of(
boxedBooleanType,
boxedByteType,
boxedCharType,
boxedDoubleType,
boxedFloatType,
boxedIntType,
boxedLongType,
boxedNumberType,
boxedShortType,
boxedVoidType,
enumType,
npeType,
objectType,
stringBufferType,
stringBuilderType,
stringType);
private boolean skipNameValidationForTesting = false;
public void setSkipNameValidationForTesting(boolean skipNameValidationForTesting) {
this.skipNameValidationForTesting = skipNameValidationForTesting;
}
public boolean getSkipNameValidationForTesting() {
return skipNameValidationForTesting;
}
public boolean isLambdaMetafactoryMethod(DexMethod dexMethod) {
return dexMethod == metafactoryMethod || dexMethod == metafactoryAltMethod;
}
public abstract static class LibraryMembers {
public void forEachFinalField(Consumer<DexField> consumer) {}
}
public class AndroidOsBuildMembers extends LibraryMembers {
public final DexField BOOTLOADER = createField(androidOsBuildType, stringType, "BOOTLOADER");
public final DexField BRAND = createField(androidOsBuildType, stringType, "BRAND");
public final DexField CPU_ABI = createField(androidOsBuildType, stringType, "CPU_ABI");
public final DexField CPU_ABI2 = createField(androidOsBuildType, stringType, "CPU_ABI2");
public final DexField DEVICE = createField(androidOsBuildType, stringType, "DEVICE");
public final DexField DISPLAY = createField(androidOsBuildType, stringType, "DISPLAY");
public final DexField FINGERPRINT = createField(androidOsBuildType, stringType, "FINGERPRINT");
public final DexField HARDWARE = createField(androidOsBuildType, stringType, "HARDWARE");
public final DexField MANUFACTURER =
createField(androidOsBuildType, stringType, "MANUFACTURER");
public final DexField MODEL = createField(androidOsBuildType, stringType, "MODEL");
public final DexField PRODUCT = createField(androidOsBuildType, stringType, "PRODUCT");
public final DexField SERIAL = createField(androidOsBuildType, stringType, "SERIAL");
public final DexField SUPPORTED_32_BIT_ABIS =
createField(androidOsBuildType, stringArrayType, "SUPPORTED_32_BIT_ABIS");
public final DexField SUPPORTED_64_BIT_ABIS =
createField(androidOsBuildType, stringArrayType, "SUPPORTED_64_BIT_ABIS");
public final DexField SUPPORTED_ABIS =
createField(androidOsBuildType, stringArrayType, "SUPPORTED_ABIS");
public final DexField TIME = createField(androidOsBuildType, longType, "TIME");
public final DexField TYPE = createField(androidOsBuildType, stringType, "TYPE");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(BOOTLOADER);
consumer.accept(BRAND);
consumer.accept(CPU_ABI);
consumer.accept(CPU_ABI2);
consumer.accept(DEVICE);
consumer.accept(DISPLAY);
consumer.accept(FINGERPRINT);
consumer.accept(HARDWARE);
consumer.accept(MANUFACTURER);
consumer.accept(MODEL);
consumer.accept(PRODUCT);
consumer.accept(SERIAL);
consumer.accept(SUPPORTED_32_BIT_ABIS);
consumer.accept(SUPPORTED_64_BIT_ABIS);
consumer.accept(SUPPORTED_ABIS);
consumer.accept(TIME);
consumer.accept(TYPE);
}
}
public class AndroidOsBuildVersionMembers extends LibraryMembers {
public final DexField CODENAME = createField(androidOsBuildVersionType, stringType, "CODENAME");
public final DexField RELEASE = createField(androidOsBuildVersionType, stringType, "RELEASE");
public final DexField SDK = createField(androidOsBuildVersionType, stringType, "SDK");
public final DexField SDK_INT = createField(androidOsBuildVersionType, intType, "SDK_INT");
public final DexField SECURITY_PATCH =
createField(androidOsBuildVersionType, stringType, "SECURITY_PATCH");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(CODENAME);
consumer.accept(RELEASE);
consumer.accept(SDK);
consumer.accept(SDK_INT);
consumer.accept(SECURITY_PATCH);
}
}
public class AndroidOsBundleMembers extends LibraryMembers {
public final DexField CREATOR =
createField(androidOsBundleType, androidOsParcelableCreatorType, "CREATOR");
public final DexField EMPTY = createField(androidOsBundleType, androidOsBundleType, "EMPTY");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(CREATOR);
consumer.accept(EMPTY);
}
}
public class AndroidSystemOsConstantsMembers extends LibraryMembers {
public final DexField S_IRUSR = createField(androidSystemOsConstantsType, intType, "S_IRUSR");
public final DexField S_IXUSR = createField(androidSystemOsConstantsType, intType, "S_IXUSR");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(S_IRUSR);
consumer.accept(S_IXUSR);
}
}
public class AndroidViewViewMembers extends LibraryMembers {
public final DexField TRANSLATION_Z =
createField(androidViewViewType, androidUtilPropertyType, "TRANSLATION_Z");
public final DexField EMPTY_STATE_SET =
createField(androidViewViewType, intArrayType, "EMPTY_STATE_SET");
public final DexField ENABLED_STATE_SET =
createField(androidViewViewType, intArrayType, "ENABLED_STATE_SET");
public final DexField PRESSED_ENABLED_STATE_SET =
createField(androidViewViewType, intArrayType, "PRESSED_ENABLED_STATE_SET");
public final DexField SELECTED_STATE_SET =
createField(androidViewViewType, intArrayType, "SELECTED_STATE_SET");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(TRANSLATION_Z);
consumer.accept(EMPTY_STATE_SET);
consumer.accept(ENABLED_STATE_SET);
consumer.accept(PRESSED_ENABLED_STATE_SET);
consumer.accept(SELECTED_STATE_SET);
}
}
public class AndroidUtilSparseArrayMembers extends LibraryMembers {
public final DexMethod put =
createMethod(androidUtilSparseArrayType, createProto(voidType, intType, objectType), "put");
public final DexMethod set =
createMethod(androidUtilSparseArrayType, createProto(voidType, intType, objectType), "set");
}
public class BooleanMembers extends LibraryMembers {
public final DexField FALSE = createField(boxedBooleanType, boxedBooleanType, "FALSE");
public final DexField TRUE = createField(boxedBooleanType, boxedBooleanType, "TRUE");
public final DexField TYPE = createField(boxedBooleanType, classType, "TYPE");
public final DexMethod booleanValue =
createMethod(boxedBooleanType, createProto(booleanType), "booleanValue");
public final DexMethod parseBoolean =
createMethod(boxedBooleanType, createProto(booleanType, stringType), "parseBoolean");
public final DexMethod valueOf =
createMethod(boxedBooleanType, createProto(boxedBooleanType, booleanType), "valueOf");
public final DexMethod toString =
createMethod(boxedBooleanType, createProto(stringType), "toString");
private BooleanMembers() {}
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(FALSE);
consumer.accept(TRUE);
consumer.accept(TYPE);
}
}
public class ByteMembers extends LibraryMembers {
public final DexMethod toString =
createMethod(boxedByteType, createProto(stringType), "toString");
private ByteMembers() {}
}
public class CharMembers extends LibraryMembers {
public final DexMethod toString =
createMethod(boxedCharType, createProto(stringType), "toString");
private CharMembers() {}
}
public class FloatMembers extends LibraryMembers {
public final DexField TYPE = createField(boxedFloatType, classType, "TYPE");
public final DexMethod toString =
createMethod(boxedFloatType, createProto(stringType), "toString");
private FloatMembers() {}
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(TYPE);
}
}
public class JavaIoFileMembers extends LibraryMembers {
public final DexField pathSeparator = createField(javaIoFileType, stringType, "pathSeparator");
public final DexField separator = createField(javaIoFileType, stringType, "separator");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(pathSeparator);
consumer.accept(separator);
}
}
public class JavaMathBigIntegerMembers extends LibraryMembers {
public final DexField ONE = createField(javaMathBigIntegerType, javaMathBigIntegerType, "ONE");
public final DexField ZERO =
createField(javaMathBigIntegerType, javaMathBigIntegerType, "ZERO");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(ONE);
consumer.accept(ZERO);
}
}
public class JavaNioByteOrderMembers extends LibraryMembers {
public final DexField LITTLE_ENDIAN =
createField(javaNioByteOrderType, javaNioByteOrderType, "LITTLE_ENDIAN");
public final DexField BIG_ENDIAN =
createField(javaNioByteOrderType, javaNioByteOrderType, "BIG_ENDIAN");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(LITTLE_ENDIAN);
consumer.accept(BIG_ENDIAN);
}
}
public class JavaUtilArraysMethods {
public final DexMethod asList;
private JavaUtilArraysMethods() {
asList =
createMethod(
arraysDescriptor,
createString("asList"),
listDescriptor,
new DexString[] {objectArrayDescriptor});
}
}
public class JavaUtilComparatorMembers extends LibraryMembers {
public final DexField EMPTY_LIST =
createField(javaUtilCollectionsType, javaUtilListType, "EMPTY_LIST");
public final DexField EMPTY_SET =
createField(javaUtilCollectionsType, javaUtilSetType, "EMPTY_SET");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(EMPTY_LIST);
consumer.accept(EMPTY_SET);
}
}
public class JavaUtilConcurrentTimeUnitMembers extends LibraryMembers {
public final DexField DAYS =
createField(javaUtilConcurrentTimeUnitType, javaUtilConcurrentTimeUnitType, "DAYS");
public final DexField HOURS =
createField(javaUtilConcurrentTimeUnitType, javaUtilConcurrentTimeUnitType, "HOURS");
public final DexField MICROSECONDS =
createField(javaUtilConcurrentTimeUnitType, javaUtilConcurrentTimeUnitType, "MICROSECONDS");
public final DexField MILLISECONDS =
createField(javaUtilConcurrentTimeUnitType, javaUtilConcurrentTimeUnitType, "MILLISECONDS");
public final DexField MINUTES =
createField(javaUtilConcurrentTimeUnitType, javaUtilConcurrentTimeUnitType, "MINUTES");
public final DexField NANOSECONDS =
createField(javaUtilConcurrentTimeUnitType, javaUtilConcurrentTimeUnitType, "NANOSECONDS");
public final DexField SECONDS =
createField(javaUtilConcurrentTimeUnitType, javaUtilConcurrentTimeUnitType, "SECONDS");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(DAYS);
consumer.accept(HOURS);
consumer.accept(MICROSECONDS);
consumer.accept(MILLISECONDS);
consumer.accept(MINUTES);
consumer.accept(NANOSECONDS);
consumer.accept(SECONDS);
}
}
public class JavaUtilLocaleMembers extends LibraryMembers {
public final DexField ENGLISH = createField(javaUtilLocaleType, javaUtilLocaleType, "ENGLISH");
public final DexField ROOT = createField(javaUtilLocaleType, javaUtilLocaleType, "ROOT");
public final DexField US = createField(javaUtilLocaleType, javaUtilLocaleType, "US");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(ENGLISH);
consumer.accept(ROOT);
consumer.accept(US);
}
}
public class JavaUtilLoggingLevelMembers extends LibraryMembers {
public final DexField CONFIG =
createField(javaUtilLoggingLevelType, javaUtilLoggingLevelType, "CONFIG");
public final DexField FINE =
createField(javaUtilLoggingLevelType, javaUtilLoggingLevelType, "FINE");
public final DexField FINER =
createField(javaUtilLoggingLevelType, javaUtilLoggingLevelType, "FINER");
public final DexField FINEST =
createField(javaUtilLoggingLevelType, javaUtilLoggingLevelType, "FINEST");
public final DexField SEVERE =
createField(javaUtilLoggingLevelType, javaUtilLoggingLevelType, "SEVERE");
public final DexField WARNING =
createField(javaUtilLoggingLevelType, javaUtilLoggingLevelType, "WARNING");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(CONFIG);
consumer.accept(FINE);
consumer.accept(FINER);
consumer.accept(FINEST);
consumer.accept(SEVERE);
consumer.accept(WARNING);
}
}
public class LongMembers extends LibraryMembers {
public final DexField TYPE = createField(boxedLongType, classType, "TYPE");
public final DexMethod compare;
public final DexMethod toString =
createMethod(boxedLongType, createProto(stringType), "toString");
private LongMembers() {
compare = createMethod(boxedLongDescriptor,
createString("compare"), intDescriptor, new DexString[]{longDescriptor, longDescriptor});
}
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(TYPE);
}
}
public class DoubleMembers {
public final DexMethod isNaN;
public final DexMethod toString =
createMethod(boxedDoubleType, createProto(stringType), "toString");
private DoubleMembers() {
isNaN =
createMethod(
boxedDoubleDescriptor,
createString("isNaN"),
booleanDescriptor,
new DexString[] {doubleDescriptor});
}
}
public class IntegerMembers extends LibraryMembers {
public final DexField TYPE = createField(boxedIntType, classType, "TYPE");
public final DexMethod toString =
createMethod(boxedIntType, createProto(stringType), "toString");
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(TYPE);
}
}
public class StringConcatFactoryMembers {
public final DexMethod makeConcat =
createMethod(
stringConcatFactoryType,
createProto(callSiteType, lookupType, stringType, methodTypeType),
createString("makeConcat"));
public final DexMethod makeConcatWithConstants =
createMethod(
stringConcatFactoryType,
createProto(
callSiteType, lookupType, stringType, methodTypeType, stringType, objectArrayType),
createString("makeConcatWithConstants"));
}
public class ThrowableMethods {
public final DexMethod addSuppressed;
public final DexMethod getMessage;
public final DexMethod getSuppressed;
public final DexMethod initCause;
private ThrowableMethods() {
addSuppressed = createMethod(throwableDescriptor,
createString("addSuppressed"), voidDescriptor, new DexString[]{throwableDescriptor});
getSuppressed = createMethod(throwableDescriptor,
createString("getSuppressed"), throwableArrayDescriptor, DexString.EMPTY_ARRAY);
initCause = createMethod(throwableDescriptor, createString("initCause"), throwableDescriptor,
new DexString[] { throwableDescriptor });
getMessage =
createMethod(
throwableDescriptor,
createString("getMessage"),
stringDescriptor,
DexString.EMPTY_ARRAY);
}
}
public class AssertionErrorMethods {
public final DexMethod initMessage;
public final DexMethod initMessageAndCause;
private AssertionErrorMethods() {
this.initMessage =
createMethod(assertionErrorDescriptor, constructorMethodName, voidDescriptor,
new DexString[] { objectDescriptor });
this.initMessageAndCause =
createMethod(assertionErrorDescriptor, constructorMethodName, voidDescriptor,
new DexString[] { stringDescriptor, throwableDescriptor });
}
}
public class RecordMembers {
public final DexMethod init = createMethod(recordType, createProto(voidType), "<init>");
public final DexMethod equals =
createMethod(recordType, createProto(booleanType, objectType), "equals");
public final DexMethod hashCode = createMethod(recordType, createProto(intType), "hashCode");
public final DexMethod toString = createMethod(recordType, createProto(stringType), "toString");
}
public class ObjectMethodsMembers {
public final DexMethod bootstrap =
createMethod(
objectMethodsType,
createProto(
objectType,
lookupType,
stringType,
typeDescriptorType,
classType,
stringType,
createArrayType(1, methodHandleType)),
"bootstrap");
}
public class ObjectMembers {
/**
* This field is not on {@link Object}, but will be synthesized on horizontally merged classes
* as an instance field.
*/
public final DexField classIdField = createField(objectType, intType, CLASS_ID_FIELD_NAME);
/**
* This field is not on {@link Object}, but will be synthesized on program classes as a static
* field, for the compiler to have a principled way to trigger the initialization of a given
* class.
*/
public final DexField clinitField = createField(objectType, intType, "$r8$clinit");
public final DexMethod clone;
public final DexMethod equals =
createMethod(objectType, createProto(booleanType, objectType), "equals");
public final DexMethod getClass;
public final DexMethod hashCode = createMethod(objectType, createProto(intType), "hashCode");
public final DexMethod constructor;
public final DexMethod finalize;
public final DexMethod toString;
private ObjectMembers() {
// The clone method is installed on each array, so one has to use method.match(clone).
clone = createMethod(objectType, createProto(objectType), cloneMethodName);
getClass = createMethod(objectDescriptor,
getClassMethodName, classDescriptor, DexString.EMPTY_ARRAY);
constructor = createMethod(objectDescriptor,
constructorMethodName, voidType.descriptor, DexString.EMPTY_ARRAY);
finalize = createMethod(objectDescriptor,
finalizeMethodName, voidType.descriptor, DexString.EMPTY_ARRAY);
toString = createMethod(objectDescriptor,
toStringMethodName, stringDescriptor, DexString.EMPTY_ARRAY);
}
}
public class BufferMembers {
public final DexMethod positionArg =
createMethod(bufferType, createProto(bufferType, intType), "position");
public final DexMethod limitArg =
createMethod(bufferType, createProto(bufferType, intType), "limit");
public final DexMethod mark = createMethod(bufferType, createProto(bufferType), "mark");
public final DexMethod reset = createMethod(bufferType, createProto(bufferType), "reset");
public final DexMethod clear = createMethod(bufferType, createProto(bufferType), "clear");
public final DexMethod flip = createMethod(bufferType, createProto(bufferType), "flip");
public final DexMethod rewind = createMethod(bufferType, createProto(bufferType), "rewind");
public final List<DexMethod> bufferCovariantMethods =
ImmutableList.of(positionArg, limitArg, mark, reset, clear, flip, rewind);
}
public class ObjectsMethods {
public final DexMethod equals =
createMethod(objectsType, createProto(booleanType, objectType, objectType), "equals");
public final DexMethod hashCode =
createMethod(objectsType, createProto(intType, objectType), "hashCode");
public final DexMethod isNull =
createMethod(objectsType, createProto(booleanType, objectType), "isNull");
public final DexMethod nonNull =
createMethod(objectsType, createProto(booleanType, objectType), "nonNull");
public final DexMethod requireNonNull;
public final DexMethod requireNonNullWithMessage;
public final DexMethod requireNonNullWithMessageSupplier;
public final DexMethod requireNonNullElse =
createMethod(
objectsType, createProto(objectType, objectType, objectType), "requireNonNullElse");
public final DexMethod requireNonNullElseGet =
createMethod(
objectsType,
createProto(objectType, objectType, supplierType),
"requireNonNullElseGet");
public final DexMethod toStringWithObject =
createMethod(objectsType, createProto(stringType, objectType), "toString");
public final DexMethod toStringWithObjectAndNullDefault =
createMethod(objectsType, createProto(stringType, objectType, stringType), "toString");
private ObjectsMethods() {
DexString requireNonNullMethodName = createString("requireNonNull");
requireNonNull =
createMethod(objectsType, createProto(objectType, objectType), requireNonNullMethodName);
requireNonNullWithMessage =
createMethod(
objectsType,
createProto(objectType, objectType, stringType),
requireNonNullMethodName);
requireNonNullWithMessageSupplier =
createMethod(
objectsType,
createProto(objectType, objectType, supplierType),
requireNonNullMethodName);
}
public boolean isRequireNonNullMethod(DexMethod method) {
return method == requireNonNull
|| method == requireNonNullWithMessage
|| method == requireNonNullWithMessageSupplier
|| method == requireNonNullElse
|| method == requireNonNullElseGet;
}
public boolean isToStringMethod(DexMethod method) {
return method == toStringWithObject || method == toStringWithObjectAndNullDefault;
}
public Iterable<DexMethod> requireNonNullMethods() {
return ImmutableList.of(
requireNonNull, requireNonNullWithMessage, requireNonNullWithMessageSupplier);
}
}
public class ClassMethods {
public final DexMethod desiredAssertionStatus;
public final DexMethod forName;
public final DexMethod forName3;
public final DexMethod getClassLoader =
createMethod(classType, createProto(classLoaderType), "getClassLoader");
public final DexMethod getName;
public final DexMethod getCanonicalName;
public final DexMethod getSimpleName;
public final DexMethod getTypeName;
public final DexMethod getConstructor;
public final DexMethod getDeclaredConstructor;
public final DexMethod getField;
public final DexMethod getDeclaredField;
public final DexMethod getMethod;
public final DexMethod getDeclaredMethod;
public final DexMethod getPackage =
createMethod(classType, createProto(packageType), "getPackage");
public final DexMethod newInstance;
private final Set<DexMethod> getMembers;
public final Set<DexMethod> getNames;
private ClassMethods() {
desiredAssertionStatus = createMethod(classDescriptor,
desiredAssertionStatusMethodName, booleanDescriptor, DexString.EMPTY_ARRAY);
forName =
createMethod(
classDescriptor,
forNameMethodName,
classDescriptor,
new DexString[] {stringDescriptor});
forName3 =
createMethod(
classDescriptor,
forNameMethodName,
classDescriptor,
new DexString[] {stringDescriptor, booleanDescriptor, classLoaderDescriptor});
getName = createMethod(classDescriptor, getNameName, stringDescriptor, DexString.EMPTY_ARRAY);
getCanonicalName = createMethod(
classDescriptor, getCanonicalNameName, stringDescriptor, DexString.EMPTY_ARRAY);
getSimpleName = createMethod(
classDescriptor, getSimpleNameName, stringDescriptor, DexString.EMPTY_ARRAY);
getTypeName = createMethod(
classDescriptor, getTypeNameName, stringDescriptor, DexString.EMPTY_ARRAY);
getConstructor =
createMethod(classType, createProto(constructorType, classArrayType), "getConstructor");
getDeclaredConstructor =
createMethod(
classDescriptor,
getDeclaredConstructorName,
constructorDescriptor,
new DexString[] {classArrayDescriptor});
getField = createMethod(classDescriptor, getFieldName, fieldDescriptor,
new DexString[] {stringDescriptor});
getDeclaredField = createMethod(classDescriptor, getDeclaredFieldName, fieldDescriptor,
new DexString[] {stringDescriptor});
getMethod = createMethod(classDescriptor, getMethodName, methodDescriptor,
new DexString[] {stringDescriptor, classArrayDescriptor});
getDeclaredMethod = createMethod(classDescriptor, getDeclaredMethodName, methodDescriptor,
new DexString[] {stringDescriptor, classArrayDescriptor});
newInstance =
createMethod(classDescriptor, newInstanceName, objectDescriptor, DexString.EMPTY_ARRAY);
getMembers = ImmutableSet.of(getField, getDeclaredField, getMethod, getDeclaredMethod);
getNames = ImmutableSet.of(getName, getCanonicalName, getSimpleName, getTypeName);
}
public boolean isReflectiveClassLookup(DexMethod method) {
return method == forName || method == forName3;
}
public boolean isReflectiveMemberLookup(DexMethod method) {
return getMembers.contains(method);
}
public boolean isReflectiveNameLookup(DexMethod method) {
return getNames.contains(method);
}
}
public class ConstructorMethods {
public final DexMethod newInstance;
private ConstructorMethods() {
newInstance =
createMethod(
constructorDescriptor,
newInstanceName,
objectDescriptor,
new DexString[] {objectArrayDescriptor});
}
}
public class JavaLangReflectArrayMembers {
public final DexMethod newInstanceMethodWithDimensions =
createMethod(
javaLangReflectArrayType,
createProto(objectType, classType, intArrayType),
"newInstance");
private JavaLangReflectArrayMembers() {}
}
public class JavaLangSystemMethods {
public final DexMethod identityHashCode;
private JavaLangSystemMethods() {
identityHashCode =
createMethod(
javaLangSystemDescriptor,
identityHashCodeName,
intDescriptor,
new DexString[] {objectDescriptor});
}
}
public class EnumMembers {
public final DexField nameField = createField(enumType, stringType, "name");
public final DexField ordinalField = createField(enumType, intType, "ordinal");
public final DexMethod valueOf;
public final DexMethod ordinalMethod;
public final DexMethod nameMethod;
public final DexMethod toString;
public final DexMethod compareTo;
public final DexMethod equals;
public final DexMethod hashCode;
public final DexMethod constructor =
createMethod(enumType, createProto(voidType, stringType, intType), constructorMethodName);
public final DexMethod finalize =
createMethod(enumType, createProto(voidType), finalizeMethodName);
private EnumMembers() {
valueOf =
createMethod(
enumDescriptor,
valueOfMethodName,
enumDescriptor,
new DexString[] {classDescriptor, stringDescriptor});
ordinalMethod =
createMethod(enumDescriptor, ordinalMethodName, intDescriptor, DexString.EMPTY_ARRAY);
nameMethod =
createMethod(enumDescriptor, nameMethodName, stringDescriptor, DexString.EMPTY_ARRAY);
toString =
createMethod(
enumDescriptor,
toStringMethodName,
stringDescriptor,
DexString.EMPTY_ARRAY);
compareTo =
createMethod(
enumDescriptor, compareToMethodName, intDescriptor, new DexString[] {enumDescriptor});
equals =
createMethod(
enumDescriptor,
equalsMethodName,
booleanDescriptor,
new DexString[] {objectDescriptor});
hashCode =
createMethod(enumDescriptor, hashCodeMethodName, intDescriptor, DexString.EMPTY_ARRAY);
}
public void forEachField(Consumer<DexField> fn) {
fn.accept(nameField);
fn.accept(ordinalField);
}
public boolean isNameOrOrdinalField(DexField field) {
return field == nameField || field == ordinalField;
}
public boolean isEnumField(DexEncodedField staticField, DexType enumType) {
assert staticField.isStatic();
return staticField.getType() == enumType && staticField.isEnum() && staticField.isFinal();
}
public boolean isValuesFieldCandidate(DexEncodedField staticField, DexType enumType) {
assert staticField.isStatic();
return staticField.getType().isArrayType()
&& staticField.getType().toArrayElementType(DexItemFactory.this) == enumType
&& staticField.isSynthetic()
&& staticField.isFinal();
}
}
public class NullPointerExceptionMethods {
public final DexMethod init =
createMethod(npeType, createProto(voidType), constructorMethodName);
public final DexMethod initWithMessage =
createMethod(npeType, createProto(voidType, stringType), constructorMethodName);
}
public class IllegalArgumentExceptionMethods {
public final DexMethod initWithMessage =
createMethod(
illegalArgumentExceptionType, createProto(voidType, stringType), constructorMethodName);
}
/**
* All boxed types (Boolean, Byte, ...) have a field named TYPE which contains the Class object
* for the primitive type.
*
* E.g. for Boolean https://docs.oracle.com/javase/8/docs/api/java/lang/Boolean.html#TYPE.
*/
public class PrimitiveTypesBoxedTypeFields {
public final DexField byteTYPE;
public final DexField charTYPE;
public final DexField shortTYPE;
public final DexField intTYPE;
public final DexField longTYPE;
public final DexField floatTYPE;
public final DexField doubleTYPE;
private final Map<DexField, DexType> boxedFieldTypeToPrimitiveType;
private PrimitiveTypesBoxedTypeFields() {
byteTYPE = createField(boxedByteType, classType, "TYPE");
charTYPE = createField(boxedCharType, classType, "TYPE");
shortTYPE = createField(boxedShortType, classType, "TYPE");
intTYPE = createField(boxedIntType, classType, "TYPE");
longTYPE = createField(boxedLongType, classType, "TYPE");
floatTYPE = createField(boxedFloatType, classType, "TYPE");
doubleTYPE = createField(boxedDoubleType, classType, "TYPE");
boxedFieldTypeToPrimitiveType =
ImmutableMap.<DexField, DexType>builder()
.put(booleanMembers.TYPE, booleanType)
.put(byteTYPE, byteType)
.put(charTYPE, charType)
.put(shortTYPE, shortType)
.put(intTYPE, intType)
.put(longTYPE, longType)
.put(floatTYPE, floatType)
.put(doubleTYPE, doubleType)
.build();
}
public DexType boxedFieldTypeToPrimitiveType(DexField field) {
return boxedFieldTypeToPrimitiveType.get(field);
}
}
/**
* A class that encompasses methods that create different types of atomic field updaters:
* Atomic(Integer|Long|Reference)FieldUpdater#newUpdater.
*/
public class AtomicFieldUpdaterMethods {
public final DexMethod intUpdater;
public final DexMethod longUpdater;
public final DexMethod referenceUpdater;
private final Set<DexMethod> updaters;
private AtomicFieldUpdaterMethods() {
intUpdater =
createMethod(
intFieldUpdaterDescriptor,
newUpdaterName,
intFieldUpdaterDescriptor,
new DexString[] {classDescriptor, stringDescriptor});
longUpdater =
createMethod(
longFieldUpdaterDescriptor,
newUpdaterName,
longFieldUpdaterDescriptor,
new DexString[] {classDescriptor, stringDescriptor});
referenceUpdater =
createMethod(
referenceFieldUpdaterDescriptor,
newUpdaterName,
referenceFieldUpdaterDescriptor,
new DexString[] {classDescriptor, classDescriptor, stringDescriptor});
updaters = ImmutableSet.of(intUpdater, longUpdater, referenceUpdater);
}
public boolean isFieldUpdater(DexMethod method) {
return updaters.contains(method);
}
}
public class ShortMembers extends LibraryMembers {
public final DexMethod toString =
createMethod(boxedShortType, createProto(stringType), "toString");
private ShortMembers() {}
}
public class StringMembers extends LibraryMembers {
public final DexField CASE_INSENSITIVE_ORDER =
createField(stringType, javaUtilComparatorType, "CASE_INSENSITIVE_ORDER");
public final DexMethod isEmpty;
public final DexMethod length;
public final DexMethod concat;
public final DexMethod constructor =
createMethod(stringType, createProto(voidType, stringType), constructorMethodName);
public final DexMethod contains;
public final DexMethod startsWith;
public final DexMethod endsWith;
public final DexMethod equals;
public final DexMethod equalsIgnoreCase;
public final DexMethod contentEqualsCharSequence;
public final DexMethod indexOfInt;
public final DexMethod indexOfString;
public final DexMethod lastIndexOfInt;
public final DexMethod lastIndexOfString;
public final DexMethod compareTo;
public final DexMethod compareToIgnoreCase;
public final DexMethod hashCode;
public final DexMethod valueOf;
public final DexMethod toString;
public final DexMethod intern;
public final DexMethod trim = createMethod(stringType, createProto(stringType), trimName);
private StringMembers() {
isEmpty = createMethod(
stringDescriptor, isEmptyMethodName, booleanDescriptor, DexString.EMPTY_ARRAY);
length = createMethod(
stringDescriptor, lengthMethodName, intDescriptor, DexString.EMPTY_ARRAY);
DexString[] needsOneCharSequence = { charSequenceDescriptor };
DexString[] needsOneString = { stringDescriptor };
DexString[] needsOneObject = { objectDescriptor };
DexString[] needsOneInt = { intDescriptor };
concat = createMethod(stringDescriptor, concatMethodName, stringDescriptor, needsOneString);
contains = createMethod(
stringDescriptor, containsMethodName, booleanDescriptor, needsOneCharSequence);
startsWith = createMethod(
stringDescriptor, startsWithMethodName, booleanDescriptor, needsOneString);
endsWith = createMethod(
stringDescriptor, endsWithMethodName, booleanDescriptor, needsOneString);
equals = createMethod(
stringDescriptor, equalsMethodName, booleanDescriptor, needsOneObject);
equalsIgnoreCase = createMethod(
stringDescriptor, equalsIgnoreCaseMethodName, booleanDescriptor, needsOneString);
contentEqualsCharSequence = createMethod(
stringDescriptor, contentEqualsMethodName, booleanDescriptor, needsOneCharSequence);
indexOfString =
createMethod(stringDescriptor, indexOfMethodName, intDescriptor, needsOneString);
indexOfInt =
createMethod(stringDescriptor, indexOfMethodName, intDescriptor, needsOneInt);
lastIndexOfString =
createMethod(stringDescriptor, lastIndexOfMethodName, intDescriptor, needsOneString);
lastIndexOfInt =
createMethod(stringDescriptor, lastIndexOfMethodName, intDescriptor, needsOneInt);
compareTo =
createMethod(stringDescriptor, compareToMethodName, intDescriptor, needsOneString);
compareToIgnoreCase =
createMethod(stringDescriptor, compareToIgnoreCaseMethodName, intDescriptor,
needsOneString);
hashCode = createMethod(stringType, createProto(intType), hashCodeMethodName);
valueOf = createMethod(
stringDescriptor, valueOfMethodName, stringDescriptor, needsOneObject);
toString = createMethod(
stringDescriptor, toStringMethodName, stringDescriptor, DexString.EMPTY_ARRAY);
intern = createMethod(
stringDescriptor, internMethodName, stringDescriptor, DexString.EMPTY_ARRAY);
}
@Override
public void forEachFinalField(Consumer<DexField> consumer) {
consumer.accept(CASE_INSENSITIVE_ORDER);
}
}
public class StringBuildingMethods {
public final DexMethod appendBoolean;
public final DexMethod appendChar;
public final DexMethod appendCharArray;
public final DexMethod appendSubCharArray;
public final DexMethod appendCharSequence;
public final DexMethod appendSubCharSequence;
public final DexMethod appendInt;
public final DexMethod appendDouble;
public final DexMethod appendFloat;
public final DexMethod appendLong;
public final DexMethod appendObject;
public final DexMethod appendString;
public final DexMethod appendStringBuffer;
public final DexMethod charSequenceConstructor;
public final DexMethod defaultConstructor;
public final DexMethod intConstructor;
public final DexMethod stringConstructor;
public final DexMethod toString;
private final Set<DexMethod> appendMethods;
private final Set<DexMethod> appendPrimitiveMethods;
private StringBuildingMethods(DexType receiver) {
DexString append = createString("append");
appendBoolean = createMethod(receiver, createProto(receiver, booleanType), append);
appendChar = createMethod(receiver, createProto(receiver, charType), append);
appendCharArray = createMethod(receiver, createProto(receiver, charArrayType), append);
appendSubCharArray =
createMethod(receiver, createProto(receiver, charArrayType, intType, intType), append);
appendCharSequence = createMethod(receiver, createProto(receiver, charSequenceType), append);
appendSubCharSequence =
createMethod(receiver, createProto(receiver, charSequenceType, intType, intType), append);
appendInt = createMethod(receiver, createProto(receiver, intType), append);
appendDouble = createMethod(receiver, createProto(receiver, doubleType), append);
appendFloat = createMethod(receiver, createProto(receiver, floatType), append);
appendLong = createMethod(receiver, createProto(receiver, longType), append);
appendObject = createMethod(receiver, createProto(receiver, objectType), append);
appendString = createMethod(receiver, createProto(receiver, stringType), append);
appendStringBuffer = createMethod(receiver, createProto(receiver, stringBufferType), append);
charSequenceConstructor =
createMethod(receiver, createProto(voidType, charSequenceType), constructorMethodName);
defaultConstructor = createMethod(receiver, createProto(voidType), constructorMethodName);
intConstructor =
createMethod(receiver, createProto(voidType, intType), constructorMethodName);
stringConstructor =
createMethod(receiver, createProto(voidType, stringType), constructorMethodName);
toString = createMethod(receiver, createProto(stringType), toStringMethodName);
appendMethods =
ImmutableSet.of(
appendBoolean,
appendChar,
appendCharArray,
appendSubCharArray,
appendCharSequence,
appendSubCharSequence,
appendInt,
appendDouble,
appendFloat,
appendLong,
appendObject,
appendString,
appendStringBuffer);
appendPrimitiveMethods =
ImmutableSet.of(
appendBoolean, appendChar, appendInt, appendDouble, appendFloat, appendLong);
constructorMethods =
ImmutableSet.of(
charSequenceConstructor, defaultConstructor, intConstructor, stringConstructor);
}
public final Set<DexMethod> constructorMethods;
public boolean isAppendMethod(DexMethod method) {
return appendMethods.contains(method);
}
public boolean isAppendObjectMethod(DexMethod method) {
return method == appendObject;
}
public boolean isAppendPrimitiveMethod(DexMethod method) {
return appendPrimitiveMethods.contains(method);
}
public boolean isAppendStringMethod(DexMethod method) {
return method == appendString;
}
public boolean isConstructorMethod(DexMethod method) {
return constructorMethods.contains(method);
}
public boolean constructorInvokeIsSideEffectFree(
DexMethod invokedMethod, List<Value> arguments) {
if (invokedMethod == defaultConstructor) {
return true;
}
if (invokedMethod == charSequenceConstructor) {
// Performs callbacks on the given CharSequence, which may have side effects.
TypeElement charSequenceType = arguments.get(1).getType();
return charSequenceType.isClassType()
&& charSequenceType.asClassType().getClassType() == stringType;
}
if (invokedMethod == intConstructor) {
// NegativeArraySizeException - if the capacity argument is less than 0.
Value capacityValue = arguments.get(1);
if (capacityValue.hasValueRange()) {
return capacityValue.getValueRange().getMin() >= 0;
}
return false;
}
if (invokedMethod == stringConstructor) {
// NullPointerException - if str is null.
Value strValue = arguments.get(1);
return !strValue.getType().isNullable();
}
assert false : "Unexpected invoke targeting `" + invokedMethod.toSourceString() + "`";
return false;
}
}
public class SupplierMembers extends LibraryMembers {
public final DexMethod get = createMethod(supplierType, createProto(objectType), "get");
private SupplierMembers() {}
}
public class PolymorphicMethods {
private final DexProto signature = createProto(objectType, objectArrayType);
private final DexProto setSignature = createProto(voidType, objectArrayType);
private final DexProto compareAndSetSignature = createProto(booleanType, objectArrayType);
private final Set<DexString> varHandleMethods =
createStrings(
"compareAndExchange",
"compareAndExchangeAcquire",
"compareAndExchangeRelease",
"get",
"getAcquire",
"getAndAdd",
"getAndAddAcquire",
"getAndAddRelease",
"getAndBitwiseAnd",
"getAndBitwiseAndAcquire",
"getAndBitwiseAndRelease",
"getAndBitwiseOr",
"getAndBitwiseOrAcquire",
"getAndBitwiseOrRelease",
"getAndBitwiseXor",
"getAndBitwiseXorAcquire",
"getAndBitwiseXorRelease",
"getAndSet",
"getAndSetAcquire",
"getAndSetRelease",
"getOpaque",
"getVolatile");
private final Set<DexString> varHandleSetMethods =
createStrings("set", "setOpaque", "setRelease", "setVolatile");
private final Set<DexString> varHandleCompareAndSetMethods =
createStrings(
"compareAndSet",
"weakCompareAndSet",
"weakCompareAndSetAcquire",
"weakCompareAndSetPlain",
"weakCompareAndSetRelease");
public DexMethod canonicalize(DexMethod invokeProto) {
if (invokeProto.holder == methodHandleType) {
if (invokeProto.name == invokeMethodName || invokeProto.name == invokeExactMethodName) {
return createMethod(methodHandleType, signature, invokeProto.name);
}
} else if (invokeProto.holder == varHandleType) {
if (varHandleMethods.contains(invokeProto.name)) {
return createMethod(varHandleType, signature, invokeProto.name);
} else if (varHandleSetMethods.contains(invokeProto.name)) {
return createMethod(varHandleType, setSignature, invokeProto.name);
} else if (varHandleCompareAndSetMethods.contains(invokeProto.name)) {
return createMethod(varHandleType, compareAndSetSignature, invokeProto.name);
}
}
return null;
}
private Set<DexString> createStrings(String... strings) {
IdentityHashMap<DexString, DexString> map = new IdentityHashMap<>();
for (String string : strings) {
DexString dexString = createString(string);
map.put(dexString, dexString);
}
return map.keySet();
}
}
public class ProxyMethods {
public final DexMethod newProxyInstance;
private ProxyMethods() {
newProxyInstance =
createMethod(
proxyType,
createProto(objectType, classLoaderType, classArrayType, invocationHandlerType),
createString("newProxyInstance"));
}
}
public class ServiceLoaderMethods {
public final DexMethod load;
public final DexMethod loadWithClassLoader;
public final DexMethod loadInstalled;
public final DexMethod iterator;
private ServiceLoaderMethods() {
DexString loadName = createString("load");
load = createMethod(serviceLoaderType, createProto(serviceLoaderType, classType), loadName);
loadWithClassLoader =
createMethod(
serviceLoaderType,
createProto(serviceLoaderType, classType, classLoaderType),
loadName);
loadInstalled =
createMethod(
serviceLoaderType,
createProto(serviceLoaderType, classType),
createString("loadInstalled"));
iterator =
createMethod(serviceLoaderType, createProto(iteratorType), createString("iterator"));
}
public boolean isLoadMethod(DexMethod method) {
return method == load || method == loadWithClassLoader || method == loadInstalled;
}
}
private static <T extends DexItem> T canonicalize(Map<T, T> map, T item) {
assert item != null;
assert !DexItemFactory.isInternalSentinel(item);
T previous = map.putIfAbsent(item, item);
return previous == null ? item : previous;
}
public DexString createString(int size, byte[] content) {
assert !sorted;
return canonicalize(strings, new DexString(size, content));
}
public DexString createString(String source) {
assert !sorted;
return canonicalize(strings, new DexString(source));
}
public static String escapeMemberString(String str) {
return str.replace('.', '$');
}
public String createMemberString(String baseName, DexType holder, int index) {
StringBuilder sb = new StringBuilder().append(baseName);
if (holder != null) {
sb.append('$').append(escapeMemberString(holder.toSourceString()));
}
if (index > 0) {
sb.append("$").append(index);
}
return sb.toString();
}
/**
* Find a fresh method name that is not used by any other method. The method name takes the form
* "basename$holdername" or "basename$holdername$index".
*
* @param tryString callback to check if the method name is in use.
*/
public <T> T createFreshMember(
Function<DexString, Optional<T>> tryString, String baseName, DexType holder) {
int index = 0;
while (true) {
assert index < 1000;
DexString name = createString(createMemberString(baseName, holder, index++));
Optional<T> result = tryString.apply(name);
if (result.isPresent()) {
return result.get();
}
}
}
/**
* Find a fresh method name that is not used by any other method. The method name takes the form
* "basename" or "basename$index".
*
* @param tryString callback to check if the method name is in use.
*/
public <T extends DexMember<?, ?>> T createFreshMember(
Function<DexString, Optional<T>> tryString, String baseName) {
return createFreshMember(tryString, baseName, null);
}
/**
* Find a fresh method name that is not in the string pool. The name takes the form
* "basename$holdername" or "basename$holdername$index".
*/
public DexString createGloballyFreshMemberString(String baseName, DexType holder) {
assert !sorted;
int index = 0;
while (true) {
String name = createMemberString(baseName, holder, index++);
DexString dexName = lookupString(name);
if (dexName == null) {
return createString(name);
}
}
}
/**
* Find a fresh method name that is not in the string pool. The name takes the form "basename" or
* "basename$index".
*/
public DexString createGloballyFreshMemberString(String baseName) {
return createGloballyFreshMemberString(baseName, null);
}
public DexType createFreshTypeName(DexType type, Predicate<DexType> isFresh) {
return createFreshTypeName(type, isFresh, 0);
}
public DexType createFreshTypeName(DexType type, Predicate<DexType> isFresh, int index) {
while (true) {
DexType newType = type.addSuffixId(index++, this);
if (isFresh.test(newType)) {
return newType;
}
}
}
/**
* Tries to find a method name for insertion into the class {@code target} of the form
* baseName$holder$n, where {@code baseName} and {@code holder} are supplied by the user, and
* {@code n} is picked to be the first number so that {@code isFresh.apply(method)} returns {@code
* true}.
*
* @param holder indicates where the method originates from.
*/
public DexMethod createFreshMethodNameWithHolder(
String baseName,
DexType holder,
DexProto proto,
DexType target,
Predicate<DexMethod> isFresh) {
assert holder != null;
return internalCreateFreshMethodNameWithHolder(baseName, holder, proto, target, isFresh);
}
/**
* Tries to find a method name for insertion into the class {@code target} of the form baseName$n,
* where {@code baseName} is supplied by the user, and {@code n} is picked to be the first number
* so that {@code isFresh.apply(method)} returns {@code true}.
*/
public DexMethod createFreshMethodNameWithoutHolder(
String baseName, DexProto proto, DexType target, Predicate<DexMethod> isFresh) {
return internalCreateFreshMethodNameWithHolder(baseName, null, proto, target, isFresh);
}
/**
* Used to find a fresh method name of the from {@code baseName$n}, or {@code baseName$holder$n}
* if {@param holder} is non-null.
*/
private DexMethod internalCreateFreshMethodNameWithHolder(
String baseName,
DexType holder,
DexProto proto,
DexType target,
Predicate<DexMethod> isFresh) {
return createFreshMember(
name -> {
DexMethod tryMethod = createMethod(target, proto, name);
if (isFresh.test(tryMethod)) {
return Optional.of(tryMethod);
} else {
return Optional.empty();
}
},
baseName,
holder);
}
/**
* Tries to find a method name for insertion into the class {@code target} of the form
* baseName$holder$n, where {@code baseName} and {@code holder} are supplied by the user, and
* {@code n} is picked to be the first number so that {@code isFresh.apply(method)} returns {@code
* true}.
*
* @param holder indicates where the method originates from.
*/
public DexMethodSignature createFreshMethodSignatureName(
String baseName, DexType holder, DexProto proto, Predicate<DexMethodSignature> isFresh) {
return createFreshMember(
name -> {
DexMethodSignature trySignature = new DexMethodSignature(proto, name);
if (isFresh.test(trySignature)) {
return Optional.of(trySignature);
} else {
return Optional.empty();
}
},
baseName,
holder);
}
/**
* Tries to find a method name for insertion into the class {@code target} of the form baseName$n,
* where {@code baseName} is supplied by the user, and {@code n} is picked to be the first number
* so that {@code isFresh.apply(method)} returns {@code true}.
*/
public DexField createFreshFieldName(DexField template, Predicate<DexField> isFresh) {
return internalCreateFreshFieldName(template, null, isFresh);
}
/**
* Tries to find a method name for insertion into the class {@code target} of the form
* baseName$holder$n, where {@code baseName} and {@code holder} are supplied by the user, and
* {@code n} is picked to be the first number so that {@code isFresh.apply(method)} returns {@code
* true}.
*
* @param holder indicates where the method originates from.
*/
public DexField createFreshFieldNameWithHolderSuffix(
DexField template, DexType holder, Predicate<DexField> isFresh) {
return internalCreateFreshFieldName(template, holder, isFresh);
}
private DexField internalCreateFreshFieldName(
DexField template, DexType holder, Predicate<DexField> isFresh) {
return createFreshMember(
name -> Optional.of(template.withName(name, this)).filter(isFresh),
template.name.toSourceString(),
holder);
}
public DexMethod createClassInitializer(DexType holder) {
return createMethod(holder, createProto(voidType), classConstructorMethodName);
}
public DexMethod createInstanceInitializer(DexType holder, DexType... parameters) {
return createMethod(holder, createProto(voidType, parameters), constructorMethodName);
}
public DexMethod createInstanceInitializer(DexType holder, DexTypeList parameters) {
return createInstanceInitializer(holder, parameters.values);
}
public DexMethod createInstanceInitializerWithFreshProto(
DexMethod method, List<DexType> extraTypes, Predicate<DexMethod> isFresh) {
assert method.isInstanceInitializer(this);
return createInstanceInitializerWithFreshProto(
method.proto,
extraTypes,
proto -> Optional.of(method.withProto(proto, this)).filter(isFresh));
}
public DexMethod createInstanceInitializerWithFreshProto(
DexMethod method, DexType extraType, Predicate<DexMethod> isFresh) {
assert method.isInstanceInitializer(this);
return createInstanceInitializerWithFreshProto(
method.proto,
ImmutableList.of(extraType),
proto -> Optional.of(method.withProto(proto, this)).filter(isFresh));
}
private DexMethod createInstanceInitializerWithFreshProto(
DexProto proto, List<DexType> extraTypes, Function<DexProto, Optional<DexMethod>> isFresh) {
Queue<Iterable<DexProto>> tryProtos = new LinkedList<>();
Iterator<DexProto> current = IterableUtils.singleton(proto).iterator();
int count = 0;
while (true) {
assert count++ < 100;
if (!current.hasNext()) {
assert !tryProtos.isEmpty();
current = tryProtos.remove().iterator();
assert current.hasNext();
}
DexProto tryProto = current.next();
Optional<DexMethod> object = isFresh.apply(tryProto);
if (object.isPresent()) {
return object.get();
}
assert !extraTypes.isEmpty();
tryProtos.add(
Iterables.transform(extraTypes, extraType -> appendTypeToProto(tryProto, extraType)));
}
}
public DexString lookupString(int size, byte[] content) {
return strings.get(new DexString(size, content));
}
public DexString lookupString(String source) {
return strings.get(new DexString(source));
}
// Debugging support to extract marking string.
// Find all markers.
public synchronized List<Marker> extractMarkers() {
// This is slow but it is not needed for any production code yet.
List<Marker> markers = new ArrayList<>();
for (DexString dexString : strings.keySet()) {
Marker marker = Marker.parse(dexString);
if (marker != null) {
markers.add(marker);
}
}
return markers;
}
// Non-synchronized internal create.
private DexType internalCreateType(DexString descriptor) {
assert !sorted;
assert descriptor != null;
DexType result = types.get(descriptor);
if (result == null) {
result = new DexType(descriptor);
assert result.isArrayType()
|| result.isClassType()
|| result.isPrimitiveType()
|| result.isVoidType();
assert !isInternalSentinel(result);
types.put(descriptor, result);
}
return result;
}
private DexType createStaticallyKnownType(String descriptor) {
return createStaticallyKnownType(createString(descriptor));
}
private DexType createStaticallyKnownType(Class<?> clazz) {
// This uses Class.getName() and not Class.getTypeName(), as the compilers are also
// running on Art versions where Class.getTypeName() is not present (7.0 and before).
return createStaticallyKnownType(
createString(DescriptorUtils.javaTypeToDescriptor(clazz.getName())));
}
private DexType createStaticallyKnownType(DexString descriptor) {
DexType type = internalCreateType(descriptor);
// Conservatively add all statically known types to "compiler synthesized types set".
addPossiblySynthesizedType(type);
return type;
}
// Safe synchronized external create. May be used for statically known types in synthetic code.
// See the generated BackportedMethods.java for reference.
public synchronized DexType createSynthesizedType(String descriptor) {
DexType type = internalCreateType(createString(descriptor));
addPossiblySynthesizedType(type);
return type;
}
// Registration of a type that is only dynamically known (eg, in the desugared lib spec), but
// will be referenced during desugaring.
public void registerTypeNeededForDesugaring(DexType type) {
addPossiblySynthesizedType(type);
}
private void addPossiblySynthesizedType(DexType type) {
if (type.isArrayType()) {
type = type.toBaseType(this);
}
if (type.isClassType()) {
possibleCompilerSynthesizedTypes.add(type);
}
}
public boolean isPossiblyCompilerSynthesizedType(DexType type) {
return possibleCompilerSynthesizedTypes.contains(type);
}
public void forEachPossiblyCompilerSynthesizedType(Consumer<DexType> fn) {
possibleCompilerSynthesizedTypes.forEach(fn);
}
// Safe synchronized external create. Should never be used to create a statically known type!
public synchronized DexType createType(DexString descriptor) {
return internalCreateType(descriptor);
}
public DexType createType(String descriptor) {
return createType(createString(descriptor));
}
public DexType lookupType(DexString descriptor) {
return types.get(descriptor);
}
public DexType createArrayType(int nesting, DexType baseType) {
assert nesting > 0;
return createType(Strings.repeat("[", nesting) + baseType.toDescriptorString());
}
public DexField createField(DexType clazz, DexType type, DexString name) {
assert !sorted;
DexField field = new DexField(clazz, type, name, skipNameValidationForTesting);
return canonicalize(fields, field);
}
public DexField createField(DexType clazz, DexType type, String name) {
return createField(clazz, type, createString(name));
}
public DexField createField(FieldReference fieldReference) {
return createField(
createType(fieldReference.getHolderClass().getDescriptor()),
createType(fieldReference.getFieldType().getDescriptor()),
fieldReference.getFieldName());
}
public DexProto createProto(DexType returnType, DexTypeList parameters, DexString shorty) {
assert !sorted;
DexProto proto = new DexProto(shorty, returnType, parameters);
return canonicalize(protos, proto);
}
public DexProto createProto(DexType returnType, DexType... parameters) {
assert !sorted;
return createProto(
returnType,
parameters.length == 0 ? DexTypeList.empty() : new DexTypeList(parameters),
createShorty(returnType, parameters));
}
public DexProto createProto(DexType returnType, List<DexType> parameters) {
return createProto(returnType, parameters.toArray(DexType.EMPTY_ARRAY));
}
public DexProto protoWithDifferentFirstParameter(DexProto proto, DexType firstParameter) {
DexType[] parameterTypes = proto.parameters.values.clone();
parameterTypes[0] = firstParameter;
return createProto(proto.returnType, parameterTypes);
}
public DexProto prependHolderToProto(DexMethod method) {
return prependTypeToProto(method.holder, method.proto);
}
public DexProto prependTypeToProto(DexType extraFirstType, DexProto initialProto) {
DexType[] parameterTypes = new DexType[initialProto.parameters.size() + 1];
parameterTypes[0] = extraFirstType;
System.arraycopy(
initialProto.parameters.values, 0, parameterTypes, 1, initialProto.parameters.size());
return createProto(initialProto.returnType, parameterTypes);
}
public DexProto appendTypeToProto(DexProto initialProto, DexType extraLastType) {
DexType[] parameterTypes = new DexType[initialProto.parameters.size() + 1];
System.arraycopy(
initialProto.parameters.values, 0, parameterTypes, 0, initialProto.parameters.size());
parameterTypes[parameterTypes.length - 1] = extraLastType;
return createProto(initialProto.returnType, parameterTypes);
}
public DexMethod appendTypeToMethod(DexMethod initialMethod, DexType extraLastType) {
DexProto newProto = appendTypeToProto(initialMethod.proto, extraLastType);
return createMethod(initialMethod.holder, newProto, initialMethod.name);
}
public DexProto applyClassMappingToProto(
DexProto proto, Function<DexType, DexType> mapping, Map<DexProto, DexProto> cache) {
assert cache != null;
DexProto result = cache.get(proto);
if (result == null) {
DexType returnType = mapping.apply(proto.returnType);
DexType[] parameters = applyClassMappingToDexTypes(proto.parameters.values, mapping);
if (returnType == proto.returnType && parameters == proto.parameters.values) {
result = proto;
} else {
// Should be different if reference has changed.
assert returnType == proto.returnType || !returnType.equals(proto.returnType);
assert parameters == proto.parameters.values
|| !Arrays.equals(parameters, proto.parameters.values);
result = createProto(returnType, parameters);
}
cache.put(proto, result);
}
return result;
}
private static DexType[] applyClassMappingToDexTypes(
DexType[] types, Function<DexType, DexType> mapping) {
Map<Integer, DexType> changed = new Int2ReferenceArrayMap<>();
for (int i = 0; i < types.length; i++) {
DexType applied = mapping.apply(types[i]);
if (applied != types[i]) {
changed.put(i, applied);
}
}
return changed.isEmpty()
? types
: ArrayUtils.copyWithSparseChanges(DexType[].class, types, changed);
}
private DexString createShorty(DexType returnType, DexType[] argumentTypes) {
StringBuilder shortyBuilder = new StringBuilder();
shortyBuilder.append(returnType.toShorty());
for (DexType argumentType : argumentTypes) {
shortyBuilder.append(argumentType.toShorty());
}
return createString(shortyBuilder.toString());
}
public DexMethod createMethod(DexType holder, DexProto proto, DexString name) {
assert !sorted;
DexMethod method = new DexMethod(holder, proto, name, skipNameValidationForTesting);
return canonicalize(methods, method);
}
public DexMethod createMethod(DexType holder, DexProto proto, String name) {
return createMethod(holder, proto, createString(name));
}
public DexMethod createMethod(MethodReference methodReference) {
DexString[] formals = new DexString[methodReference.getFormalTypes().size()];
ListUtils.forEachWithIndex(
methodReference.getFormalTypes(),
(formal, index) -> {
formals[index] = createString(formal.getDescriptor());
});
return createMethod(
createString(methodReference.getHolderClass().getDescriptor()),
createString(methodReference.getMethodName()),
methodReference.getReturnType() == null
? voidDescriptor
: createString(methodReference.getReturnType().getDescriptor()),
formals);
}
public DexMethodHandle createMethodHandle(
MethodHandleType type,
DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod,
boolean isInterface) {
return createMethodHandle(type, fieldOrMethod, isInterface, null);
}
public DexMethodHandle createMethodHandle(
MethodHandleType type,
DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod,
boolean isInterface,
DexMethod rewrittenTarget) {
assert !sorted;
DexMethodHandle methodHandle =
new DexMethodHandle(type, fieldOrMethod, isInterface, rewrittenTarget);
return canonicalize(methodHandles, methodHandle);
}
public DexCallSite createCallSite(
DexString methodName,
DexProto methodProto,
DexMethodHandle bootstrapMethod,
List<DexValue> bootstrapArgs) {
// Call sites are never equal and therefore we do not canonicalize.
assert !sorted;
return new DexCallSite(methodName, methodProto, bootstrapMethod, bootstrapArgs);
}
public DexMethod createMethod(
DexString clazzDescriptor,
DexString name,
DexString returnTypeDescriptor,
DexString[] parameterDescriptors) {
assert !sorted;
DexType clazz = createType(clazzDescriptor);
DexType returnType = createType(returnTypeDescriptor);
DexType[] parameterTypes = new DexType[parameterDescriptors.length];
for (int i = 0; i < parameterDescriptors.length; i++) {
parameterTypes[i] = createType(parameterDescriptors[i]);
}
DexProto proto = createProto(returnType, parameterTypes);
return createMethod(clazz, proto, name);
}
public DexMethod createClinitMethod(DexType holder) {
return createMethod(holder, createProto(voidType), classConstructorMethodName);
}
public AdvanceLine createAdvanceLine(int delta) {
synchronized (advanceLines) {
return advanceLines.computeIfAbsent(delta, AdvanceLine::new);
}
}
public AdvancePC createAdvancePC(int delta) {
synchronized (advancePCs) {
return advancePCs.computeIfAbsent(delta, AdvancePC::new);
}
}
public Default createDefault(int value) {
synchronized (defaults) {
return defaults.computeIfAbsent(value, Default::new);
}
}
public EndLocal createEndLocal(int registerNum) {
synchronized (endLocals) {
return endLocals.computeIfAbsent(registerNum, EndLocal::new);
}
}
public RestartLocal createRestartLocal(int registerNum) {
synchronized (restartLocals) {
return restartLocals.computeIfAbsent(registerNum, RestartLocal::new);
}
}
public SetEpilogueBegin createSetEpilogueBegin() {
return setEpilogueBegin;
}
public SetPrologueEnd createSetPrologueEnd() {
return setPrologueEnd;
}
public SetFile createSetFile(DexString fileName) {
synchronized (setFiles) {
return setFiles.computeIfAbsent(fileName, SetFile::new);
}
}
// TODO(tamaskenez) b/69024229 Measure if canonicalization is worth it.
public SetInlineFrame createSetInlineFrame(DexMethod callee, Position caller) {
synchronized (setInlineFrames) {
return setInlineFrames.computeIfAbsent(new SetInlineFrame(callee, caller), p -> p);
}
}
public boolean isConstructor(DexMethod method) {
return method.name == constructorMethodName;
}
public boolean isClassConstructor(DexMethod method) {
return method.name == classConstructorMethodName;
}
public void clearTypeElementsCache() {
referenceTypes.clear();
classTypeInterfaces.clear();
leastUpperBoundOfInterfacesTable.clear();
}
public boolean verifyNoCachedTypeElements() {
assert referenceTypes.isEmpty();
assert classTypeInterfaces.isEmpty();
assert leastUpperBoundOfInterfacesTable.isEmpty();
return true;
}
public ReferenceTypeElement createReferenceTypeElement(
DexType type, Nullability nullability, AppView<?> appView) {
// Class case:
// If two concurrent threads will try to create the same class-type the concurrent hash map will
// synchronize on the type in .computeIfAbsent and only a single class type is created.
//
// Array case:
// Arrays will create a lattice element for its base type thus we take special care here.
// Multiple threads may race recursively to create a base type. We have two cases:
// (i) If base type is class type and the threads will race to create the class type but only a
// single one will be created (Class case).
// (ii) If base is ArrayLattice case we can use our induction hypothesis to get that only one
// element is created for us up to this case. Threads will now race to return from the
// latest recursive call and fight to get access to .computeIfAbsent to add the
// ArrayTypeElement but only one will enter. The property that only one
// ArrayTypeElement is created per level therefore holds inductively.
TypeElement memberType = null;
if (type.isArrayType()) {
ReferenceTypeElement existing = referenceTypes.get(type);
if (existing != null) {
return existing.getOrCreateVariant(nullability);
}
memberType =
TypeElement.fromDexType(
type.toArrayElementType(this), Nullability.maybeNull(), appView, true);
}
TypeElement finalMemberType = memberType;
return referenceTypes
.computeIfAbsent(
type,
t -> {
if (type.isClassType()) {
if (!appView.enableWholeProgramOptimizations()) {
// Don't reason at the level of interfaces in D8.
return ClassTypeElement.createForD8(type, nullability);
}
assert appView.appInfo().hasClassHierarchy();
if (appView.isInterface(type).isTrue()) {
return ClassTypeElement.create(
objectType,
nullability,
appView.withClassHierarchy(),
InterfaceCollection.singleton(type));
}
// In theory, `interfaces` is the least upper bound of implemented interfaces.
// It is expensive to walk through type hierarchy; collect implemented interfaces;
// and compute the least upper bound of two interface sets. Hence, lazy
// computations. Most likely during lattice join. See {@link
// ClassTypeElement#getInterfaces}.
return ClassTypeElement.create(type, nullability, appView.withClassHierarchy());
}
assert type.isArrayType();
return ArrayTypeElement.create(finalMemberType, nullability);
})
.getOrCreateVariant(nullability);
}
public InterfaceCollection getOrComputeLeastUpperBoundOfImplementedInterfaces(
DexType type, AppView<? extends AppInfoWithClassHierarchy> appView) {
return classTypeInterfaces.computeIfAbsent(
type,
t -> {
InterfaceCollection itfs = appView.appInfo().implementedInterfaces(t);
return computeLeastUpperBoundOfInterfaces(appView, itfs, itfs);
});
}
@Deprecated
synchronized public void forAllTypes(Consumer<DexType> f) {
new ArrayList<>(types.values()).forEach(f);
}
}