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();