diff options
-rw-r--r-- | dex/src/main/java/com/android/dex/Dex.java | 207 | ||||
-rw-r--r-- | dex/src/main/java/com/android/dex/TypeList.java | 2 | ||||
-rw-r--r-- | libart/src/main/java/java/lang/Class.java | 6 | ||||
-rw-r--r-- | libart/src/main/java/java/lang/reflect/AbstractMethod.java | 45 | ||||
-rw-r--r-- | libart/src/main/java/java/lang/reflect/Constructor.java | 51 | ||||
-rw-r--r-- | libart/src/main/java/java/lang/reflect/Field.java | 15 | ||||
-rw-r--r-- | libart/src/main/java/java/lang/reflect/Method.java | 132 |
7 files changed, 259 insertions, 199 deletions
diff --git a/dex/src/main/java/com/android/dex/Dex.java b/dex/src/main/java/com/android/dex/Dex.java index 29cd30ea7..bf249985f 100644 --- a/dex/src/main/java/com/android/dex/Dex.java +++ b/dex/src/main/java/com/android/dex/Dex.java @@ -53,7 +53,9 @@ public final class Dex { private static final int CHECKSUM_SIZE = 4; private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE; private static final int SIGNATURE_SIZE = 20; - + // Provided as a convenience to avoid a memory allocation to benefit Dalvik. + // Note: libcore.util.EmptyArray cannot be accessed when this code isn't run on Dalvik. + static final short[] EMPTY_SHORT_ARRAY = new short[0]; private ByteBuffer data; private final TableOfContents tableOfContents = new TableOfContents(); private int nextSectionStart = 0; @@ -450,6 +452,9 @@ public final class Dex { } public short[] readShortArray(int length) { + if (length == 0) { + return EMPTY_SHORT_ARRAY; + } short[] result = new short[length]; for (int i = 0; i < length; i++) { result[i] = readShort(); @@ -475,10 +480,7 @@ public final class Dex { public TypeList readTypeList() { int size = readInt(); - short[] types = new short[size]; - for (int i = 0; i < size; i++) { - types[i] = readShort(); - } + short[] types = readShortArray(size); alignToFourBytes(); return new TypeList(Dex.this, types); } @@ -552,71 +554,71 @@ public final class Dex { Try[] tries; CatchHandler[] catchHandlers; if (triesSize > 0) { - if (instructions.length % 2 == 1) { - readShort(); // padding - } - - /* - * We can't read the tries until we've read the catch handlers. - * Unfortunately they're in the opposite order in the dex file - * so we need to read them out-of-order. - */ - Section triesSection = open(data.position()); - skip(triesSize * SizeOf.TRY_ITEM); - catchHandlers = readCatchHandlers(); - tries = triesSection.readTries(triesSize, catchHandlers); - } else { - tries = new Try[0]; - catchHandlers = new CatchHandler[0]; - } - return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions, - tries, catchHandlers); + if (instructions.length % 2 == 1) { + readShort(); // padding + } + + /* + * We can't read the tries until we've read the catch handlers. + * Unfortunately they're in the opposite order in the dex file + * so we need to read them out-of-order. + */ + Section triesSection = open(data.position()); + skip(triesSize * SizeOf.TRY_ITEM); + catchHandlers = readCatchHandlers(); + tries = triesSection.readTries(triesSize, catchHandlers); + } else { + tries = new Try[0]; + catchHandlers = new CatchHandler[0]; + } + return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions, + tries, catchHandlers); } private CatchHandler[] readCatchHandlers() { - int baseOffset = data.position(); - int catchHandlersSize = readUleb128(); - CatchHandler[] result = new CatchHandler[catchHandlersSize]; - for (int i = 0; i < catchHandlersSize; i++) { - int offset = data.position() - baseOffset; - result[i] = readCatchHandler(offset); - } - return result; + int baseOffset = data.position(); + int catchHandlersSize = readUleb128(); + CatchHandler[] result = new CatchHandler[catchHandlersSize]; + for (int i = 0; i < catchHandlersSize; i++) { + int offset = data.position() - baseOffset; + result[i] = readCatchHandler(offset); + } + return result; } private Try[] readTries(int triesSize, CatchHandler[] catchHandlers) { - Try[] result = new Try[triesSize]; - for (int i = 0; i < triesSize; i++) { - int startAddress = readInt(); - int instructionCount = readUnsignedShort(); - int handlerOffset = readUnsignedShort(); - int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset); - result[i] = new Try(startAddress, instructionCount, catchHandlerIndex); - } - return result; + Try[] result = new Try[triesSize]; + for (int i = 0; i < triesSize; i++) { + int startAddress = readInt(); + int instructionCount = readUnsignedShort(); + int handlerOffset = readUnsignedShort(); + int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset); + result[i] = new Try(startAddress, instructionCount, catchHandlerIndex); + } + return result; } private int findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset) { - for (int i = 0; i < catchHandlers.length; i++) { - CatchHandler catchHandler = catchHandlers[i]; - if (catchHandler.getOffset() == offset) { - return i; + for (int i = 0; i < catchHandlers.length; i++) { + CatchHandler catchHandler = catchHandlers[i]; + if (catchHandler.getOffset() == offset) { + return i; + } } - } - throw new IllegalArgumentException(); + throw new IllegalArgumentException(); } private CatchHandler readCatchHandler(int offset) { - int size = readSleb128(); - int handlersCount = Math.abs(size); - int[] typeIndexes = new int[handlersCount]; - int[] addresses = new int[handlersCount]; - for (int i = 0; i < handlersCount; i++) { - typeIndexes[i] = readUleb128(); - addresses[i] = readUleb128(); - } - int catchAllAddress = size <= 0 ? readUleb128() : -1; - return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset); + int size = readSleb128(); + int handlersCount = Math.abs(size); + int[] typeIndexes = new int[handlersCount]; + int[] addresses = new int[handlersCount]; + for (int i = 0; i < handlersCount; i++) { + typeIndexes[i] = readUleb128(); + addresses[i] = readUleb128(); + } + int catchAllAddress = size <= 0 ? readUleb128() : -1; + return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset); } private ClassData readClassData() { @@ -680,11 +682,11 @@ public final class Dex { } public void skip(int count) { - if (count < 0) { - throw new IllegalArgumentException(); - } - data.position(data.position() + count); - } + if (count < 0) { + throw new IllegalArgumentException(); + } + data.position(data.position() + count); + } /** * Skips bytes until the position is aligned to a multiple of 4. @@ -788,4 +790,85 @@ public final class Dex { return data.position() - initialPosition; } } + + /** + * Look up a field id name index from a field index. Equivalent to: + * {@code fieldIds().get(fieldDexIndex).getNameIndex();} + */ + public int nameIndexFromFieldIndex(int fieldIndex) { + checkBounds(fieldIndex, tableOfContents.fieldIds.size); + int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex); + position += SizeOf.USHORT; // declaringClassIndex + position += SizeOf.USHORT; // typeIndex + return data.getInt(position); // nameIndex + } + + /** + * Look up a field id type index from a field index. Equivalent to: + * {@code fieldIds().get(fieldDexIndex).getTypeIndex();} + */ + public int typeIndexFromFieldIndex(int fieldIndex) { + checkBounds(fieldIndex, tableOfContents.fieldIds.size); + int position = tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * fieldIndex); + position += SizeOf.USHORT; // declaringClassIndex + return data.getShort(position) & 0xFFFF; // typeIndex + } + + /** + * Look up a method id name index from a method index. Equivalent to: + * {@code methodIds().get(methodIndex).getNameIndex();} + */ + public int nameIndexFromMethodIndex(int methodIndex) { + checkBounds(methodIndex, tableOfContents.methodIds.size); + int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex); + position += SizeOf.USHORT; // declaringClassIndex + position += SizeOf.USHORT; // protoIndex + return data.getInt(position); // nameIndex + } + + /** + * Lookup a parameter type ids from a method index. Equivalent to: + * {@code readTypeList(protoIds.get(methodIds().get(methodDexIndex).getProtoIndex()).getParametersOffset()).getTypes();} + */ + public short[] parameterTypeIndicesFromMethodIndex(int methodIndex) { + checkBounds(methodIndex, tableOfContents.methodIds.size); + int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex); + position += SizeOf.USHORT; // declaringClassIndex + int protoIndex = data.getShort(position) & 0xFFFF; + checkBounds(protoIndex, tableOfContents.protoIds.size); + position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex); + position += SizeOf.UINT; // shortyIndex + position += SizeOf.UINT; // returnTypeIndex + int parametersOffset = data.getInt(position); + if (parametersOffset == 0) { + return EMPTY_SHORT_ARRAY; + } + position = parametersOffset; + int size = data.getInt(position); + if (size <= 0) { + throw new AssertionError("Unexpected parameter type list size: " + size); + } + position += SizeOf.UINT; + short[] types = new short[size]; + for (int i = 0; i < size; i++) { + types[i] = data.getShort(position); + position += SizeOf.USHORT; + } + return types; + } + + /** + * Look up a method id return type index from a method index. Equivalent to: + * {@code protoIds().get(methodIds().get(methodDexIndex).getProtoIndex()).getReturnTypeIndex();} + */ + public int returnTypeIndexFromMethodIndex(int methodIndex) { + checkBounds(methodIndex, tableOfContents.methodIds.size); + int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex); + position += SizeOf.USHORT; // declaringClassIndex + int protoIndex = data.getShort(position) & 0xFFFF; + checkBounds(protoIndex, tableOfContents.protoIds.size); + position = tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * protoIndex); + position += SizeOf.UINT; // shortyIndex + return data.getInt(position); // returnTypeIndex + } } diff --git a/dex/src/main/java/com/android/dex/TypeList.java b/dex/src/main/java/com/android/dex/TypeList.java index 6e321fbd7..123e82c9a 100644 --- a/dex/src/main/java/com/android/dex/TypeList.java +++ b/dex/src/main/java/com/android/dex/TypeList.java @@ -20,7 +20,7 @@ import com.android.dex.util.Unsigned; public final class TypeList implements Comparable<TypeList> { - public static final TypeList EMPTY = new TypeList(null, new short[0]); + public static final TypeList EMPTY = new TypeList(null, Dex.EMPTY_SHORT_ARRAY); private final Dex dex; private final short[] types; diff --git a/libart/src/main/java/java/lang/Class.java b/libart/src/main/java/java/lang/Class.java index 044bb0463..0d0b64d45 100644 --- a/libart/src/main/java/java/lang/Class.java +++ b/libart/src/main/java/java/lang/Class.java @@ -520,7 +520,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe private Constructor<T> getDeclaredConstructorInternal(Class<?>[] args) { if (directMethods != null) { for (AbstractMethod m : directMethods) { - if (m instanceof Constructor && Arrays.equals(args, m.getParameterTypes())) { + if (m instanceof Constructor && m.equalParameters(args)) { return (Constructor<T>) m; } } @@ -671,7 +671,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe Method result = null; if (virtualMethods != null) { for (Method m : virtualMethods) { - if (name.equals(m.getName()) && Arrays.equals(args, m.getParameterTypes())) { + if (name.equals(m.getName()) && m.equalParameters(args)) { int modifiers = m.getAccessFlags(); if ((modifiers & skipModifiers) == 0) { return m; @@ -686,7 +686,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe if (directMethods != null) { for (AbstractMethod m : directMethods) { if (m instanceof Method && name.equals(m.getName()) && - Arrays.equals(args, m.getParameterTypes())) { + m.equalParameters(args)) { int modifiers = m.getAccessFlags(); if ((modifiers & skipModifiers) == 0) { return (Method) m; diff --git a/libart/src/main/java/java/lang/reflect/AbstractMethod.java b/libart/src/main/java/java/lang/reflect/AbstractMethod.java index ba7c0c35b..c1412e154 100644 --- a/libart/src/main/java/java/lang/reflect/AbstractMethod.java +++ b/libart/src/main/java/java/lang/reflect/AbstractMethod.java @@ -45,6 +45,7 @@ import libcore.reflect.GenericSignatureParser; import libcore.reflect.InternalNames; import libcore.reflect.ListOfTypes; import libcore.reflect.Types; +import libcore.util.EmptyArray; /** * This class represents an abstract method. Abstract methods are either methods or constructors. @@ -152,7 +153,12 @@ public abstract class AbstractMethod extends AccessibleObject { return declaringClass; } - public int getDexMethodIndex() { + /** + * Returns the index of this method's ID in its dex file. + * + * @hide + */ + public final int getDexMethodIndex() { return methodDexIndex; } @@ -180,7 +186,38 @@ public abstract class AbstractMethod extends AccessibleObject { * * @return the parameter types */ - public abstract Class<?>[] getParameterTypes(); + public Class<?>[] getParameterTypes() { + Dex dex = declaringClass.getDex(); + short[] types = dex.parameterTypeIndicesFromMethodIndex(methodDexIndex); + if (types.length == 0) { + return EmptyArray.CLASS; + } + Class<?>[] parametersArray = new Class[types.length]; + for (int i = 0; i < types.length; i++) { + // Note, in the case of a Proxy the dex cache types are equal. + parametersArray[i] = getDexCacheType(dex, types[i]); + } + return parametersArray; + } + + /** + * Returns true if the given parameters match those of the method in the given order. + * + * @hide + */ + public boolean equalParameters(Class<?>[] params) { + Dex dex = getDeclaringClass().getDex(); + short[] types = dex.parameterTypeIndicesFromMethodIndex(methodDexIndex); + if (types.length != params.length) { + return false; + } + for (int i = 0; i < types.length; i++) { + if (getDexCacheType(dex, types[i]) != params[i]) { + return false; + } + } + return true; + } /** * Returns true if {@code other} has the same declaring class, name, @@ -243,7 +280,7 @@ public abstract class AbstractMethod extends AccessibleObject { * Note this method replicates {@link java.lang.Class#getDexCacheString(Dex, int)}, but in * Method we can avoid one indirection. */ - String getDexCacheString(Dex dex, int dexStringIndex) { + final String getDexCacheString(Dex dex, int dexStringIndex) { String s = (String) dexCacheStrings[dexStringIndex]; if (s == null) { s = dex.strings().get(dexStringIndex); @@ -257,7 +294,7 @@ public abstract class AbstractMethod extends AccessibleObject { * necessary. Note this method replicates {@link java.lang.Class#getDexCacheType(Dex, int)}, * but in Method we can avoid one indirection. */ - Class<?> getDexCacheType(Dex dex, int dexTypeIndex) { + final Class<?> getDexCacheType(Dex dex, int dexTypeIndex) { Class<?> resolvedType = dexCacheResolvedTypes[dexTypeIndex]; if (resolvedType == null) { int descriptorIndex = dex.typeIds().get(dexTypeIndex); diff --git a/libart/src/main/java/java/lang/reflect/Constructor.java b/libart/src/main/java/java/lang/reflect/Constructor.java index 982653be1..364c7a778 100644 --- a/libart/src/main/java/java/lang/reflect/Constructor.java +++ b/libart/src/main/java/java/lang/reflect/Constructor.java @@ -33,8 +33,6 @@ package java.lang.reflect; import com.android.dex.Dex; -import com.android.dex.ProtoId; -import com.android.dex.TypeList; import java.lang.annotation.Annotation; import java.util.Comparator; @@ -93,15 +91,6 @@ public final class Constructor<T> extends AbstractMethod implements GenericDecla } /** - * Returns the index of this constructor's method ID in its dex file. - * - * @hide used by AnnotationAccess - */ - public int getDexMethodIndex() { - return super.getDexMethodIndex(); - } - - /** * Returns the class that declares this constructor. */ @Override public Class<T> getDeclaringClass() { @@ -124,16 +113,7 @@ public final class Constructor<T> extends AbstractMethod implements GenericDecla * no parameters, an empty array will be returned. */ public Class<?>[] getParameterTypes() { - Dex dex = declaringClass.getDex(); - int protoIndex = dex.methodIds().get(methodDexIndex).getProtoIndex(); - ProtoId proto = dex.protoIds().get(protoIndex); - TypeList parametersList = dex.readTypeList(proto.getParametersOffset()); - short[] types = parametersList.getTypes(); - Class<?>[] parametersArray = new Class[types.length]; - for (int i = 0; i < types.length; i++) { - parametersArray[i] = getDexCacheType(dex, types[i]); - } - return parametersArray; + return super.getParameterTypes(); } /** @@ -344,33 +324,4 @@ public final class Constructor<T> extends AbstractMethod implements GenericDecla return result.toString(); } - - /** - * Returns a string from the dex cache, computing the string from the dex file if necessary. - * Note this method replicates {@link java.lang.Class#getDexCacheString(Dex, int)}, but in - * Method we can avoid one indirection. - * - * @hide - */ - String getDexCacheString(Dex dex, int dexStringIndex) { - return super.getDexCacheString(dex, dexStringIndex); - } - - /** - * Returns a resolved type from the dex cache, computing the string from the dex file if - * necessary. Note this method replicates {@link java.lang.Class#getDexCacheType(Dex, int)}, - * but in Method we can avoid one indirection. - * - * @hide - */ - Class<?> getDexCacheType(Dex dex, int dexTypeIndex) { - Class<?> resolvedType = dexCacheResolvedTypes[dexTypeIndex]; - if (resolvedType == null) { - int descriptorIndex = dex.typeIds().get(dexTypeIndex); - String descriptor = getDexCacheString(dex, descriptorIndex); - resolvedType = InternalNames.getClass(declaringClass.getClassLoader(), descriptor); - dexCacheResolvedTypes[dexTypeIndex] = resolvedType; - } - return resolvedType; - } } diff --git a/libart/src/main/java/java/lang/reflect/Field.java b/libart/src/main/java/java/lang/reflect/Field.java index 2d0570a9f..55dc54b06 100644 --- a/libart/src/main/java/java/lang/reflect/Field.java +++ b/libart/src/main/java/java/lang/reflect/Field.java @@ -54,11 +54,20 @@ public final class Field extends AccessibleObject implements Member { public static final Comparator<Field> ORDER_BY_NAME_AND_DECLARING_CLASS = new Comparator<Field>() { @Override public int compare(Field a, Field b) { + if (a == b) { + return 0; + } int comparison = a.getName().compareTo(b.getName()); if (comparison != 0) { return comparison; } - return a.getDeclaringClass().getName().compareTo(b.getDeclaringClass().getName()); + Class<?> aType = a.getDeclaringClass(); + Class<?> bType = b.getDeclaringClass(); + if (aType == bType) { + return 0; + } else { + return aType.getName().compareTo(bType.getName()); + } } }; @@ -120,7 +129,7 @@ public final class Field extends AccessibleObject implements Member { return "throws"; } Dex dex = declaringClass.getDex(); - int nameIndex = dex.fieldIds().get(fieldDexIndex).getNameIndex(); + int nameIndex = dex.nameIndexFromFieldIndex(fieldDexIndex); return declaringClass.getDexCacheString(dex, nameIndex); } @@ -147,7 +156,7 @@ public final class Field extends AccessibleObject implements Member { return Class[][].class; } Dex dex = declaringClass.getDex(); - int typeIndex = dex.fieldIds().get(fieldDexIndex).getTypeIndex(); + int typeIndex = dex.typeIndexFromFieldIndex(fieldDexIndex); return declaringClass.getDexCacheType(dex, typeIndex); } diff --git a/libart/src/main/java/java/lang/reflect/Method.java b/libart/src/main/java/java/lang/reflect/Method.java index 555afc9c8..5096745f3 100644 --- a/libart/src/main/java/java/lang/reflect/Method.java +++ b/libart/src/main/java/java/lang/reflect/Method.java @@ -33,11 +33,7 @@ package java.lang.reflect; import com.android.dex.Dex; -import com.android.dex.ProtoId; -import com.android.dex.TypeList; - import java.lang.annotation.Annotation; -import java.util.Arrays; import java.util.Comparator; import java.util.List; import libcore.reflect.AnnotationAccess; @@ -61,23 +57,20 @@ public final class Method extends AbstractMethod implements GenericDeclaration, return 0; } int comparison = a.getName().compareTo(b.getName()); - if (comparison != 0) { - return comparison; - } - Class<?>[] aParameters = a.getParameterTypes(); - Class<?>[] bParameters = b.getParameterTypes(); - int length = Math.min(aParameters.length, bParameters.length); - for (int i = 0; i < length; i++) { - comparison = aParameters[i].getName().compareTo(bParameters[i].getName()); - if (comparison != 0) { - return comparison; + if (comparison == 0) { + comparison = a.compareParameters(b.getParameterTypes()); + if (comparison == 0) { + // This is necessary for methods that have covariant return types. + Class<?> aReturnType = a.getReturnType(); + Class<?> bReturnType = b.getReturnType(); + if (aReturnType == bReturnType) { + comparison = 0; + } else { + comparison = aReturnType.getName().compareTo(bReturnType.getName()); + } } } - if (aParameters.length != bParameters.length) { - return aParameters.length - bParameters.length; - } - // this is necessary for methods that have covariant return types. - return a.getReturnType().getName().compareTo(b.getReturnType().getName()); + return comparison; } }; @@ -144,7 +137,7 @@ public final class Method extends AbstractMethod implements GenericDeclaration, method = findOverriddenMethod(); } Dex dex = method.declaringClass.getDex(); - int nameIndex = dex.methodIds().get(methodDexIndex).getNameIndex(); + int nameIndex = dex.nameIndexFromMethodIndex(methodDexIndex); // Note, in the case of a Proxy the dex cache strings are equal. return getDexCacheString(dex, nameIndex); } @@ -157,15 +150,6 @@ public final class Method extends AbstractMethod implements GenericDeclaration, } /** - * Returns the index of this method's ID in its dex file. - * - * @hide - */ - public int getDexMethodIndex() { - return super.getDexMethodIndex(); - } - - /** * Returns the exception types as an array of {@code Class} instances. If * this method has no declared exceptions, an empty array is returned. * @@ -189,23 +173,13 @@ public final class Method extends AbstractMethod implements GenericDeclaration, * * @return the parameter types */ - public Class<?>[] getParameterTypes() { + @Override public Class<?>[] getParameterTypes() { Method method = this; if (declaringClass.isProxy()) { - // For proxies use their interface method - method = findOverriddenMethod(); - } - Dex dex = method.declaringClass.getDex(); - int protoIndex = dex.methodIds().get(methodDexIndex).getProtoIndex(); - ProtoId proto = dex.protoIds().get(protoIndex); - TypeList parametersList = dex.readTypeList(proto.getParametersOffset()); - short[] types = parametersList.getTypes(); - Class<?>[] parametersArray = new Class[types.length]; - for (int i = 0; i < types.length; i++) { - // Note, in the case of a Proxy the dex cache types are equal. - parametersArray[i] = getDexCacheType(dex, types[i]); + // For proxies use their interface method. + return findOverriddenMethod().getParameterTypes(); } - return parametersArray; + return super.getParameterTypes(); } /** @@ -221,9 +195,7 @@ public final class Method extends AbstractMethod implements GenericDeclaration, method = findOverriddenMethod(); } Dex dex = method.declaringClass.getDex(); - int proto_idx = dex.methodIds().get(methodDexIndex).getProtoIndex(); - ProtoId proto = dex.protoIds().get(proto_idx); - int returnTypeIndex = proto.getReturnTypeIndex(); + int returnTypeIndex = dex.returnTypeIndexFromMethodIndex(methodDexIndex); // Note, in the case of a Proxy the dex cache types are equal. return getDexCacheType(dex, returnTypeIndex); } @@ -253,13 +225,46 @@ public final class Method extends AbstractMethod implements GenericDeclaration, * @hide needed by Proxy */ boolean equalNameAndParameters(Method m) { - if (!getName().equals(m.getName())) { - return false; + return getName().equals(m.getName()) && equalParameters(m.getParameterTypes()); + } + + /** + * Returns true if the given parameters match those of this method in the given order. + * + * @hide + */ + @Override public boolean equalParameters(Class<?>[] params) { + if (declaringClass.isProxy()) { + // For proxies use their interface method. + return findOverriddenMethod().equalParameters(params); } - if (!Arrays.equals(getParameterTypes(), m.getParameterTypes())) { - return false; + return super.equalParameters(params); + } + + /** + * Performs a comparison of the parameters to this method with the given parameters. + * + * @hide + */ + int compareParameters(Class<?>[] params) { + if (declaringClass.isProxy()) { + // For proxies use their interface method. + return findOverriddenMethod().compareParameters(params); + } + Dex dex = getDeclaringClass().getDex(); + short[] types = dex.parameterTypeIndicesFromMethodIndex(methodDexIndex); + int length = Math.min(types.length, params.length); + for (int i = 0; i < types.length; i++) { + Class<?> aType = getDexCacheType(dex, types[i]); + Class<?> bType = params[i]; + if (aType != bType) { + int comparison = aType.getName().compareTo(bType.getName()); + if (comparison != 0) { + return comparison; + } + } } - return true; + return types.length - params.length; } /** @@ -496,31 +501,6 @@ public final class Method extends AbstractMethod implements GenericDeclaration, } /** - * Returns a string from the dex cache, computing the string from the dex file if necessary. - * Note this method replicates {@link java.lang.Class#getDexCacheString(Dex, int)}, but in - * Method we can avoid one indirection. - */ - String getDexCacheString(Dex dex, int dexStringIndex) { - return super.getDexCacheString(dex, dexStringIndex); - } - - /** - * Returns a resolved type from the dex cache, computing the string from the dex file if - * necessary. Note this method replicates {@link java.lang.Class#getDexCacheType(Dex, int)}, - * but in Method we can avoid one indirection. - */ - Class<?> getDexCacheType(Dex dex, int dexTypeIndex) { - Class<?> resolvedType = dexCacheResolvedTypes[dexTypeIndex]; - if (resolvedType == null) { - int descriptorIndex = dex.typeIds().get(dexTypeIndex); - String descriptor = getDexCacheString(dex, descriptorIndex); - resolvedType = InternalNames.getClass(declaringClass.getClassLoader(), descriptor); - dexCacheResolvedTypes[dexTypeIndex] = resolvedType; - } - return resolvedType; - } - - /** * Returns the {@code Method} that this method overrides. Used to determine the interface * method overridden by a proxy method (as the proxy method doesn't directly support operations * such as {@link Method#getName}). This method works for non-proxy methods. |