Avoid computing class def indices.
Bug: 10244719
Also tidy AnnotationAccess.
(cherry-picked from 8b2c0b9abc3f520495f4387ea040132ba85cae69)
Change-Id: I6ec8fd4e36b428d7e16e01d98b7bebc143fac8c3
Conflicts:
libdvm/src/main/java/java/lang/Class.java
diff --git a/dex/src/main/java/com/android/dex/Dex.java b/dex/src/main/java/com/android/dex/Dex.java
index 89edf6e..116a33c 100644
--- a/dex/src/main/java/com/android/dex/Dex.java
+++ b/dex/src/main/java/com/android/dex/Dex.java
@@ -357,6 +357,19 @@
return Collections.binarySearch(methodIds, methodId);
}
+ public int findClassDefIndexFromTypeIndex(int typeIndex) {
+ checkBounds(typeIndex, tableOfContents.typeIds.size);
+ if (!tableOfContents.classDefs.exists()) {
+ return -1;
+ }
+ for (int i = 0; i < tableOfContents.classDefs.size; i++) {
+ if (typeIndexFromClassDefIndex(i) == typeIndex) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
/**
* Look up a field id type index from a field index. Cheaper than:
* {@code fieldIds().get(fieldDexIndex).getTypeIndex();}
@@ -369,6 +382,16 @@
}
/**
+ * Look up a method id declaring class index from a method index. Cheaper than:
+ * {@code methodIds().get(methodIndex).getDeclaringClassIndex();}
+ */
+ public int declaringClassIndexFromMethodIndex(int methodIndex) {
+ checkBounds(methodIndex, tableOfContents.methodIds.size);
+ int position = tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * methodIndex);
+ return data.getShort(position) & 0xFFFF; // declaringClassIndex
+ }
+
+ /**
* Look up a method id name index from a method index. Cheaper than:
* {@code methodIds().get(methodIndex).getNameIndex();}
*/
@@ -430,12 +453,63 @@
* Look up a descriptor index from a type index. Cheaper than:
* {@code open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();}
*/
- private int descriptorIndexFromTypeIndex(int typeIndex) {
+ public int descriptorIndexFromTypeIndex(int typeIndex) {
checkBounds(typeIndex, tableOfContents.typeIds.size);
int position = tableOfContents.typeIds.off + (SizeOf.TYPE_ID_ITEM * typeIndex);
return data.getInt(position);
}
+ /**
+ * Look up a type index index from a class def index.
+ */
+ public int typeIndexFromClassDefIndex(int classDefIndex) {
+ checkBounds(classDefIndex, tableOfContents.classDefs.size);
+ int position = tableOfContents.classDefs.off + (SizeOf.CLASS_DEF_ITEM * classDefIndex);
+ return data.getInt(position);
+ }
+
+ /**
+ * Look up a type index index from a class def index.
+ */
+ public int annotationDirectoryOffsetFromClassDefIndex(int classDefIndex) {
+ checkBounds(classDefIndex, tableOfContents.classDefs.size);
+ int position = tableOfContents.classDefs.off + (SizeOf.CLASS_DEF_ITEM * classDefIndex);
+ position += SizeOf.UINT; // type
+ position += SizeOf.UINT; // accessFlags
+ position += SizeOf.UINT; // superType
+ position += SizeOf.UINT; // interfacesOffset
+ position += SizeOf.UINT; // sourceFileIndex
+ return data.getInt(position);
+ }
+
+ /**
+ * Look up interface types indices from a return type index from a method index. Cheaper than:
+ * {@code ...getClassDef(classDefIndex).getInterfaces();}
+ */
+ public short[] interfaceTypeIndicesFromClassDefIndex(int classDefIndex) {
+ checkBounds(classDefIndex, tableOfContents.classDefs.size);
+ int position = tableOfContents.classDefs.off + (SizeOf.CLASS_DEF_ITEM * classDefIndex);
+ position += SizeOf.UINT; // type
+ position += SizeOf.UINT; // accessFlags
+ position += SizeOf.UINT; // superType
+ int interfacesOffset = data.getInt(position);
+ if (interfacesOffset == 0) {
+ return EMPTY_SHORT_ARRAY;
+ }
+ position = interfacesOffset;
+ int size = data.getInt(position);
+ if (size <= 0) {
+ throw new AssertionError("Unexpected interfaces 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;
+ }
+
public final class Section implements ByteInput, ByteOutput {
private final String name;
private final ByteBuffer data;
diff --git a/libart/src/main/java/java/lang/Class.java b/libart/src/main/java/java/lang/Class.java
index 6783796..d1b9a18 100644
--- a/libart/src/main/java/java/lang/Class.java
+++ b/libart/src/main/java/java/lang/Class.java
@@ -60,6 +60,7 @@
import libcore.reflect.GenericSignatureParser;
import libcore.reflect.InternalNames;
import libcore.reflect.Types;
+import libcore.util.BasicLruCache;
import libcore.util.CollectionUtils;
import libcore.util.EmptyArray;
@@ -203,10 +204,18 @@
private transient int clinitThreadId;
/**
- * Type index from dex file.
- * TODO: really 16bits
+ * Class def index from dex file. An index of 65535 indicates that there is no class definition,
+ * for example for an array type.
+ * TODO: really 16bits as type indices are 16bit.
*/
- private transient int dexTypeIndex;
+ private transient int dexClassDefIndex;
+
+ /**
+ * Class type index from dex file, lazily computed. An index of 65535 indicates that the type
+ * index isn't known. Volatile to avoid double-checked locking bugs.
+ * TODO: really 16bits as type indices are 16bit.
+ */
+ private transient volatile int dexTypeIndex;
/** Number of instance fields that are object references. */
private transient int numReferenceInstanceFields;
@@ -430,10 +439,15 @@
*
* @hide
*/
- public native Dex getDex();
+ public Dex getDex() {
+ if (dexCache == null) {
+ return null;
+ }
+ return dexCache.getDex();
+ }
/**
- * Returns a string from the dex cache, computing the string from the dex file if necessary
+ * Returns a string from the dex cache, computing the string from the dex file if necessary.
*
* @hide
*/
@@ -441,15 +455,15 @@
String[] dexCacheStrings = dexCache.strings;
String s = dexCacheStrings[dexStringIndex];
if (s == null) {
- s = dex.strings().get(dexStringIndex);
+ s = dex.strings().get(dexStringIndex).intern();
dexCacheStrings[dexStringIndex] = s;
}
return s;
}
/**
- * Returns a resolved type from the dex cache, computing the string from the dex file if
- * necessary
+ * Returns a resolved type from the dex cache, computing the type from the dex file if
+ * necessary.
*
* @hide
*/
@@ -1101,13 +1115,22 @@
* void} then an empty array is returned.
*/
public Type[] getGenericInterfaces() {
- String annotationSignature = AnnotationAccess.getSignature(this);
- if (annotationSignature == null) {
- return getInterfaces();
+ Type[] result;
+ synchronized (Caches.genericInterfaces) {
+ result = Caches.genericInterfaces.get(this);
+ if (result == null) {
+ String annotationSignature = AnnotationAccess.getSignature(this);
+ if (annotationSignature == null) {
+ result = getInterfaces();
+ } else {
+ GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
+ parser.parseForClass(this, annotationSignature);
+ result = Types.getTypeArray(parser.interfaceTypes, false);
+ }
+ Caches.genericInterfaces.put(this, result);
+ }
}
- GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
- parser.parseForClass(this, annotationSignature);
- return Types.getTypeArray(parser.interfaceTypes, false);
+ return (result.length == 0) ? result : result.clone();
}
/**
@@ -1142,7 +1165,16 @@
} else if (isProxy()) {
return getProxyInterfaces();
}
- return AnnotationAccess.typeIndexToInterfaces(this, getDex(), getTypeIndex());
+ Dex dex = getDex();
+ if (dex == null) {
+ return EmptyArray.CLASS;
+ }
+ short[] interfaces = dex.interfaceTypeIndicesFromClassDefIndex(dexClassDefIndex);
+ Class<?>[] result = new Class<?>[interfaces.length];
+ for (int i = 0; i < interfaces.length; i++) {
+ result[i] = getDexCacheType(dex, interfaces[i]);
+ }
+ return result;
}
// Returns the interfaces that this proxy class directly implements.
@@ -1420,7 +1452,7 @@
* {@code enum}.
*/
public boolean isEnum() {
- return ((getModifiers() & 0x4000) != 0) && (getSuperclass() == Enum.class);
+ return (getSuperclass() == Enum.class) && ((accessFlags & 0x4000) != 0);
}
/**
@@ -1654,22 +1686,41 @@
}
/**
- * The type index of this class in its own Dex, or 0 if it is unknown. If a
- * class is referenced by multiple Dex files, it will have a different type
- * index in each. Dex files support 65534 type indices, with 65535
- * representing no index.
- *
- * TODO: 0 is a valid index; this should be -1 if it is unknown
+ * The class def of this class in its own Dex, or -1 if there is no class def.
*
* @hide
*/
- public int getTypeIndex() {
- int result = dexTypeIndex;
- if (result == 0) { // uncomputed => Dalvik
- result = AnnotationAccess.computeTypeIndex(getDex(), this);
- dexTypeIndex = result;
+ public int getDexClassDefIndex() {
+ return (dexClassDefIndex == 65535) ? -1 : dexClassDefIndex;
+ }
+
+ /**
+ * The type index of this class in its own Dex, or -1 if it is unknown. If a class is referenced
+ * by multiple Dex files, it will have a different type index in each. Dex files support 65534
+ * type indices, with 65535 representing no index.
+ *
+ * @hide
+ */
+ public int getDexTypeIndex() {
+ int typeIndex = dexTypeIndex;
+ if (typeIndex != 65535) {
+ return typeIndex;
}
- return result;
+ synchronized (this) {
+ typeIndex = dexTypeIndex;
+ if (typeIndex == 65535) {
+ if (dexClassDefIndex >= 0) {
+ typeIndex = getDex().typeIndexFromClassDefIndex(dexClassDefIndex);
+ } else {
+ typeIndex = getDex().findTypeIndex(InternalNames.getInternalName(this));
+ if (typeIndex < 0) {
+ typeIndex = -1;
+ }
+ }
+ dexTypeIndex = typeIndex;
+ }
+ }
+ return typeIndex;
}
/**
@@ -1680,10 +1731,26 @@
*
* @hide
*/
- public native int getAnnotationDirectoryOffset();
- // TODO: Use native code rather than:
- // return AnnotationAccess.typeIndexToAnnotationDirectoryOffset(getDex(), getTypeIndex());
- // as native code has access to fast maps between type indices and class
- // defs. Move fast maps to managed code.
+ public int getDexAnnotationDirectoryOffset() {
+ Dex dex = getDex();
+ if (dex == null) {
+ return 0;
+ }
+ int classDefIndex = getDexClassDefIndex();
+ if (classDefIndex < 0) {
+ return 0;
+ }
+ return dex.annotationDirectoryOffsetFromClassDefIndex(classDefIndex);
+ }
+ private static class Caches {
+ /**
+ * Cache to avoid frequent recalculation of generic interfaces, which is generally uncommon.
+ * Sized sufficient to allow ConcurrentHashMapTest to run without recalculating its generic
+ * interfaces (required to avoid time outs). Validated by running reflection heavy code
+ * such as applications using Guice-like frameworks.
+ */
+ private static final BasicLruCache<Class, Type[]> genericInterfaces
+ = new BasicLruCache<Class, Type[]>(8);
+ }
}
diff --git a/libart/src/main/java/java/lang/DexCache.java b/libart/src/main/java/java/lang/DexCache.java
index 5cb6792..3603f9c 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -1,21 +1,38 @@
/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package java.lang;
+
+import com.android.dex.Dex;
import java.lang.reflect.ArtField;
import java.lang.reflect.ArtMethod;
@@ -23,17 +40,58 @@
* A dex cache holds resolved copies of strings, fields, methods, and classes from the dexfile.
*/
final class DexCache {
+ /** Lazily initialized dex file wrapper. Volatile to avoid double-check locking issues. */
+ private volatile Dex dex;
+
+ /** Indexed by the type index array of locations of initialized static storage. */
+ Object[] initializedStaticStorage;
+
+ /** The location of the associated dex file. */
+ String location;
+
+ /**
+ * References to fields as they become resolved following interpreter semantics. May refer to
+ * fields defined in other dex files.
+ */
+ ArtField[] resolvedFields;
+
+ /**
+ * References to methods as they become resolved following interpreter semantics. May refer to
+ * methods defined in other dex files.
+ */
+ ArtMethod[] resolvedMethods;
+
+ /**
+ * References to types as they become resolved following interpreter semantics. May refer to
+ * types defined in other dex files.
+ */
+ Class[] resolvedTypes;
+
+ /**
+ * References to strings as they become resolved following interpreter semantics. All strings
+ * are interned.
+ */
+ String[] strings;
+
+ /** Holds C pointer to dexFile. */
+ private int dexFile;
+
// Only created by the VM.
private DexCache() {}
- Object[] initializedStaticStorage;
- String location;
- ArtField[] resolvedFields;
- ArtMethod[] resolvedMethods;
- Class[] resolvedTypes;
- String[] strings;
+ Dex getDex() {
+ Dex result = dex;
+ if (result == null) {
+ synchronized (this) {
+ result = dex;
+ if (result == null) {
+ dex = result = getDexNative();
+ }
+ }
+ }
+ return result;
+ }
- // Holds pointer to dexFile.
- private int dexFile;
+ private native Dex getDexNative();
}
diff --git a/libart/src/main/java/java/lang/reflect/ArtMethod.java b/libart/src/main/java/java/lang/reflect/ArtMethod.java
index 5e56d87..fd73331 100644
--- a/libart/src/main/java/java/lang/reflect/ArtMethod.java
+++ b/libart/src/main/java/java/lang/reflect/ArtMethod.java
@@ -35,7 +35,6 @@
import com.android.dex.Dex;
import java.lang.annotation.Annotation;
import libcore.reflect.AnnotationAccess;
-import libcore.reflect.InternalNames;
import libcore.util.EmptyArray;
/**
@@ -181,7 +180,7 @@
private String getDexCacheString(Dex dex, int dexStringIndex) {
String s = (String) dexCacheStrings[dexStringIndex];
if (s == null) {
- s = dex.strings().get(dexStringIndex);
+ s = dex.strings().get(dexStringIndex).intern();
dexCacheStrings[dexStringIndex] = s;
}
return s;
@@ -189,17 +188,13 @@
/**
* 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)},
+ * necessary. Note this method delegates to {@link java.lang.Class#getDexCacheType(Dex, int)},
* but in Method we can avoid one indirection.
*/
private 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;
+ resolvedType = declaringClass.getDexCacheType(dex, dexTypeIndex);
}
return resolvedType;
}
diff --git a/libart/src/main/java/java/lang/reflect/Constructor.java b/libart/src/main/java/java/lang/reflect/Constructor.java
index 62dfdfd..b3df2f0 100644
--- a/libart/src/main/java/java/lang/reflect/Constructor.java
+++ b/libart/src/main/java/java/lang/reflect/Constructor.java
@@ -308,8 +308,9 @@
public String toString() {
StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
- if (result.length() != 0)
+ if (result.length() != 0) {
result.append(' ');
+ }
result.append(getDeclaringClass().getName());
result.append("(");
Class<?>[] parameterTypes = getParameterTypes();
diff --git a/libdvm/src/main/java/java/lang/Class.java b/libdvm/src/main/java/java/lang/Class.java
index 4ad9614..4b36f3c 100644
--- a/libdvm/src/main/java/java/lang/Class.java
+++ b/libdvm/src/main/java/java/lang/Class.java
@@ -54,13 +54,14 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
-import libcore.util.BasicLruCache;
-import libcore.util.CollectionUtils;
-import libcore.util.EmptyArray;
import org.apache.harmony.kernel.vm.StringUtils;
import libcore.reflect.AnnotationAccess;
import libcore.reflect.GenericSignatureParser;
+import libcore.reflect.InternalNames;
import libcore.reflect.Types;
+import libcore.util.BasicLruCache;
+import libcore.util.CollectionUtils;
+import libcore.util.EmptyArray;
/**
* The in-memory representation of a Java class. This representation serves as
@@ -122,12 +123,24 @@
private static final long serialVersionUID = 3206093459760846163L;
/**
+ * Class def index from dex file. An index of -1 indicates that there is no class definition,
+ * for example for an array type.
+ */
+ private transient int dexClassDefIndex;
+
+ /** The type index of this class within the dex file that defines it. */
+ private transient int dexTypeIndex;
+
+ /**
+ * Have we computed the type and class def indices? Volatile to avoid double check locking bugs.
+ */
+ private transient volatile boolean dexIndicesInitialized;
+
+ /**
* Lazily computed name of this class; always prefer calling getName().
*/
private transient String name;
- private transient int dexTypeIndex;
-
private Class() {
// Prevent this class to be instantiated, instance
// should be created by JVM only
@@ -139,23 +152,45 @@
*/
public native Dex getDex();
+ /** Lazily compute indices in to Dex */
+ private synchronized void computeDexIndices() {
+ if (!dexIndicesInitialized) {
+ Dex dex = getDex();
+ dexTypeIndex = dex.findTypeIndex(InternalNames.getInternalName(this));
+ if (dexTypeIndex < 0) {
+ dexTypeIndex = -1;
+ dexClassDefIndex = -1;
+ } else {
+ dexClassDefIndex = dex.findClassDefIndexFromTypeIndex(dexTypeIndex);
+ }
+ dexIndicesInitialized = true;
+ }
+ }
+
/**
- * The type index of this class in its own Dex, or 0 if it is unknown. If a
- * class is referenced by multiple Dex files, it will have a different type
- * index in each. Dex files support 65534 type indices, with 65535
- * representing no index.
- *
- * TODO: 0 is a valid index; this should be -1 if it is unknown
+ * The class def of this class in its own Dex, or -1 if there is no class def.
*
* @hide
*/
- public int getTypeIndex() {
- int result = dexTypeIndex;
- if (result == 0) { // uncomputed => Dalvik
- result = AnnotationAccess.computeTypeIndex(getDex(), this);
- dexTypeIndex = result;
+ public int getDexClassDefIndex() {
+ if (!dexIndicesInitialized) {
+ computeDexIndices();
}
- return result;
+ return dexClassDefIndex;
+ }
+
+ /**
+ * The type index of this class in its own Dex, or -1 if it is unknown. If a class is referenced
+ * by multiple Dex files, it will have a different type index in each. Dex files support 65534
+ * type indices, with 65535 representing no index.
+ *
+ * @hide
+ */
+ public int getDexTypeIndex() {
+ if (!dexIndicesInitialized) {
+ computeDexIndices();
+ }
+ return dexTypeIndex;
}
/**
@@ -777,7 +812,7 @@
Caches.genericInterfaces.put(this, result);
}
}
- return result;
+ return (result.length == 0) ? result : result.clone();
}
/**
@@ -1100,7 +1135,11 @@
* {@code enum}.
*/
public boolean isEnum() {
- return ((getModifiers() & 0x4000) != 0) && (getSuperclass() == Enum.class);
+ if (getSuperclass() != Enum.class) {
+ return false;
+ }
+ int mod = getModifiers(this, true);
+ return (mod & 0x4000) != 0;
}
/**
@@ -1262,12 +1301,48 @@
*
* @hide
*/
- public int getAnnotationDirectoryOffset() {
- return AnnotationAccess.typeIndexToAnnotationDirectoryOffset(getDex(), getTypeIndex());
+ public int getDexAnnotationDirectoryOffset() {
+ Dex dex = getDex();
+ if (dex == null) {
+ return 0;
+ }
+ int classDefIndex = getDexClassDefIndex();
+ if (classDefIndex < 0) {
+ return 0;
+ }
+ return dex.annotationDirectoryOffsetFromClassDefIndex(classDefIndex);
}
+
+ /**
+ * Returns a resolved type from the dex cache, computing the type from the dex file if
+ * necessary.
+ * TODO: use Dalvik's dex cache.
+ * @hide
+ */
+ public Class<?> getDexCacheType(Dex dex, int typeIndex) {
+ String internalName = dex.typeNames().get(typeIndex);
+ return InternalNames.getClass(getClassLoader(), internalName);
+ }
+
+ /**
+ * Returns a string from the dex cache, computing the string from the dex file if necessary.
+ *
+ * @hide
+ */
+ public String getDexCacheString(Dex dex, int dexStringIndex) {
+ return dex.strings().get(dexStringIndex);
+ }
+
+
private static class Caches {
+ /**
+ * Cache to avoid frequent recalculation of generic interfaces, which is generally uncommon.
+ * Sized sufficient to allow ConcurrentHashMapTest to run without recalculating its generic
+ * interfaces (required to avoid time outs). Validated by running reflection heavy code
+ * such as applications using Guice-like frameworks.
+ */
private static final BasicLruCache<Class, Type[]> genericInterfaces
- = new BasicLruCache<Class, Type[]>(50);
+ = new BasicLruCache<Class, Type[]>(8);
}
}
diff --git a/luni/src/main/java/libcore/reflect/AnnotationAccess.java b/luni/src/main/java/libcore/reflect/AnnotationAccess.java
index 0a5f655..064151e 100644
--- a/luni/src/main/java/libcore/reflect/AnnotationAccess.java
+++ b/luni/src/main/java/libcore/reflect/AnnotationAccess.java
@@ -187,11 +187,25 @@
Dex dex = dexClass.getDex();
int annotationTypeIndex = getTypeIndex(dex, annotationClass);
if (annotationTypeIndex == -1) {
- return null; // the dex file doesn't use this annotation
+ return null; // The dex file doesn't use this annotation.
}
int annotationSetOffset = getAnnotationSetOffset(element);
- return getAnnotationFromAnnotationSet(dex, annotationSetOffset, annotationTypeIndex);
+ if (annotationSetOffset == 0) {
+ return null; // no annotation
+ }
+
+ Dex.Section setIn = dex.open(annotationSetOffset); // annotation_set_item
+ for (int i = 0, size = setIn.readInt(); i < size; i++) {
+ int annotationOffset = setIn.readInt();
+ Dex.Section annotationIn = dex.open(annotationOffset); // annotation_item
+ com.android.dex.Annotation candidate = annotationIn.readAnnotation();
+ if (candidate.getTypeIndex() == annotationTypeIndex) {
+ return candidate;
+ }
+ }
+
+ return null; // This set doesn't contain the annotation.
}
/**
@@ -199,7 +213,7 @@
*/
private static int getAnnotationSetOffset(AnnotatedElement element) {
Class<?> dexClass = getDexClass(element);
- int directoryOffset = dexClass.getAnnotationDirectoryOffset();
+ int directoryOffset = dexClass.getDexAnnotationDirectoryOffset();
if (directoryOffset == 0) {
return 0; // nothing on this class has annotations
}
@@ -280,7 +294,7 @@
short[] types = parametersList.getTypes();
int typesCount = types.length;
- int directoryOffset = declaringClass.getAnnotationDirectoryOffset();
+ int directoryOffset = declaringClass.getDexAnnotationDirectoryOffset();
if (directoryOffset == 0) {
return new Annotation[typesCount][0]; // nothing on this class has annotations
}
@@ -383,7 +397,7 @@
if (reader == null) {
return null;
}
- return indexToType(c, dex, reader.readType());
+ return c.getDexCacheType(dex, reader.readType());
}
public static AccessibleObject getEnclosingMethodOrConstructor(Class<?> c) {
@@ -523,11 +537,11 @@
* was derived.
*/
+ /** Find dex's type index for the class c */
private static int getTypeIndex(Dex dex, Class<?> c) {
- return dex == c.getDex() ? c.getTypeIndex() : computeTypeIndex(dex, c);
- }
-
- public static int computeTypeIndex(Dex dex, Class<?> c) {
+ if (dex == c.getDex()) {
+ return c.getDexTypeIndex();
+ }
if (dex == null) {
return -1;
}
@@ -538,24 +552,6 @@
return typeIndex;
}
- private static com.android.dex.Annotation getAnnotationFromAnnotationSet(
- Dex dex, int annotationSetOffset, int annotationType) {
- if (annotationSetOffset == 0) {
- return null; // no annotation
- }
-
- Dex.Section setIn = dex.open(annotationSetOffset); // annotation_set_item
- for (int i = 0, size = setIn.readInt(); i < size; i++) {
- int annotationOffset = setIn.readInt();
- Dex.Section annotationIn = dex.open(annotationOffset); // annotation_item
- com.android.dex.Annotation candidate = annotationIn.readAnnotation();
- if (candidate.getTypeIndex() == annotationType) {
- return candidate;
- }
- }
-
- return null; // this set doesn't carry the annotation
- }
private static EncodedValueReader getAnnotationReader(
Dex dex, AnnotatedElement element, String annotationName, int expectedFieldCount) {
@@ -564,16 +560,28 @@
return null; // no annotations on the class
}
- int annotationTypeIndex = dex.findTypeIndex(annotationName);
- com.android.dex.Annotation annotation = getAnnotationFromAnnotationSet(
- dex, annotationSetOffset, annotationTypeIndex);
+ Dex.Section setIn = dex.open(annotationSetOffset); // annotation_set_item
+ com.android.dex.Annotation annotation = null;
+ // TODO: is it better to compute the index of the annotation name in the dex file and check
+ // indices below?
+ for (int i = 0, size = setIn.readInt(); i < size; i++) {
+ int annotationOffset = setIn.readInt();
+ Dex.Section annotationIn = dex.open(annotationOffset); // annotation_item
+ com.android.dex.Annotation candidate = annotationIn.readAnnotation();
+ String candidateAnnotationName = dex.typeNames().get(candidate.getTypeIndex());
+ if (annotationName.equals(candidateAnnotationName)) {
+ annotation = candidate;
+ break;
+ }
+ }
if (annotation == null) {
return null; // no annotation
}
EncodedValueReader reader = annotation.getReader();
int fieldCount = reader.readAnnotation();
- if (reader.getAnnotationType() != annotationTypeIndex) {
+ String readerAnnotationName = dex.typeNames().get(reader.getAnnotationType());
+ if (!readerAnnotationName.equals(annotationName)) {
throw new AssertionError();
}
if (fieldCount != expectedFieldCount) {
@@ -601,8 +609,8 @@
int typeIndex) {
try {
@SuppressWarnings("unchecked") // we do a runtime check
- Class<? extends Annotation> result = (Class<? extends Annotation>) indexToType(context,
- dex, typeIndex);
+ Class<? extends Annotation> result =
+ (Class<? extends Annotation>) context.getDexCacheType(dex, typeIndex);
if (!result.isAnnotation()) {
throw new IncompatibleClassChangeError("Expected annotation: " + result.getName());
}
@@ -612,65 +620,23 @@
}
}
- private static Class<?> indexToType(Class<?> context, Dex dex, int typeIndex) {
- String internalName = dex.typeNames().get(typeIndex);
- return InternalNames.getClass(context.getClassLoader(), internalName);
- }
-
private static AccessibleObject indexToMethod(Class<?> context, Dex dex, int methodIndex) {
- MethodId methodId = dex.methodIds().get(methodIndex);
- Class<?> declaringClass = indexToType(context, dex, methodId.getDeclaringClassIndex());
- String name = dex.strings().get(methodId.getNameIndex());
- Class<?>[] parametersArray = protoIndexToParameters(context, dex, methodId.getProtoIndex());
- try {
- return name.equals("<init>")
- ? declaringClass.getDeclaredConstructor(parametersArray)
- : declaringClass.getDeclaredMethod(name, parametersArray);
- } catch (NoSuchMethodException e) {
- throw new IncompatibleClassChangeError("Couldn't find " + declaringClass.getName()
- + "." + name + Arrays.toString(parametersArray));
- }
- }
-
- public static Class<?>[] protoIndexToParameters(Class<?> context, Dex dex, int protoIndex) {
- ProtoId proto = dex.protoIds().get(protoIndex);
- TypeList parametersList = dex.readTypeList(proto.getParametersOffset());
- short[] types = parametersList.getTypes();
+ Class<?> declaringClass =
+ context.getDexCacheType(dex, dex.declaringClassIndexFromMethodIndex(methodIndex));
+ String name = context.getDexCacheString(dex, dex.nameIndexFromMethodIndex(methodIndex));
+ short[] types = dex.parameterTypeIndicesFromMethodIndex(methodIndex);
Class<?>[] parametersArray = new Class[types.length];
for (int i = 0; i < types.length; i++) {
- parametersArray[i] = indexToType(context, dex, types[i]);
+ parametersArray[i] = context.getDexCacheType(dex, types[i]);
}
- return parametersArray;
- }
-
- public static Class<?>[] typeIndexToInterfaces(Class<?> context, Dex dex, int typeIndex) {
- ClassDef def = getClassDef(dex, typeIndex);
- if (def == null) {
- return EmptyArray.CLASS;
+ try {
+ return name.equals("<init>")
+ ? declaringClass.getDeclaredConstructor(parametersArray)
+ : declaringClass.getDeclaredMethod(name, parametersArray);
+ } catch (NoSuchMethodException e) {
+ throw new IncompatibleClassChangeError("Couldn't find " + declaringClass.getName()
+ + "." + name + Arrays.toString(parametersArray));
}
- short[] interfaces = def.getInterfaces();
- Class<?>[] result = new Class<?>[interfaces.length];
- for (int i = 0; i < interfaces.length; i++) {
- result[i] = indexToType(context, dex, interfaces[i]);
- }
- return result;
- }
-
- public static int typeIndexToAnnotationDirectoryOffset(Dex dex, int typeIndex) {
- ClassDef def = getClassDef(dex, typeIndex);
- return def == null ? 0 : def.getAnnotationsOffset();
- }
-
- private static ClassDef getClassDef(Dex dex, int typeIndex) {
- if (typeIndex == -1) {
- return null;
- }
- for (ClassDef def : dex.classDefs()) {
- if (def.getTypeIndex() == typeIndex) {
- return def;
- }
- }
- throw new AssertionError();
}
private static List<Annotation> annotationSetToAnnotations(Class<?> context, int offset) {
@@ -708,7 +674,7 @@
private static <A extends Annotation> A toAnnotationInstance(Class<?> context, Dex dex,
Class<A> annotationClass, EncodedValueReader reader) {
int fieldCount = reader.readAnnotation();
- if (annotationClass != indexToType(context, dex, reader.getAnnotationType())) {
+ if (annotationClass != context.getDexCacheType(dex, reader.getAnnotationType())) {
throw new AssertionError("annotation value type != return type");
}
AnnotationMember[] members = new AnnotationMember[fieldCount];
@@ -752,10 +718,10 @@
return toAnnotationInstance(context, dex, annotationClass, reader);
} else if (type == String.class) {
int index = reader.readString();
- return dex.strings().get(index);
+ return context.getDexCacheString(dex, index);
} else if (type == Class.class) {
int index = reader.readType();
- return indexToType(context, dex, index);
+ return context.getDexCacheType(dex, index);
} else if (type == byte.class) {
return reader.readByte();
} else if (type == short.class) {
diff --git a/luni/src/main/java/libcore/reflect/GenericSignatureParser.java b/luni/src/main/java/libcore/reflect/GenericSignatureParser.java
index 0f1ed64..5e86c49 100644
--- a/luni/src/main/java/libcore/reflect/GenericSignatureParser.java
+++ b/luni/src/main/java/libcore/reflect/GenericSignatureParser.java
@@ -474,7 +474,7 @@
}
}
- boolean isStopSymbol(char ch) {
+ static boolean isStopSymbol(char ch) {
switch (ch) {
case ':':
case '/':
@@ -497,7 +497,7 @@
char ch = buffer[pos];
if ((ch >= 'a') && (ch <= 'z') || (ch >= 'A') && (ch <= 'Z')
|| !isStopSymbol(ch)) {
- identBuf.append(buffer[pos]);
+ identBuf.append(ch);
pos++;
} else {
identifier = identBuf.toString();