diff options
author | Ian Rogers <irogers@google.com> | 2013-09-19 02:51:22 -0700 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2013-09-21 22:05:00 -0700 |
commit | a6e22fc9b70ebe39abd716ce37450bda935c0fb8 (patch) | |
tree | 2bbdf94c92895e7c2faf1db2e8482bf85906a129 /libart | |
parent | 98430d0d75f4cfd40614b77debeb3c8d0abf40df (diff) | |
download | libcore-a6e22fc9b70ebe39abd716ce37450bda935c0fb8.zip libcore-a6e22fc9b70ebe39abd716ce37450bda935c0fb8.tar.gz libcore-a6e22fc9b70ebe39abd716ce37450bda935c0fb8.tar.bz2 |
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
Diffstat (limited to 'libart')
-rw-r--r-- | libart/src/main/java/java/lang/Class.java | 131 | ||||
-rw-r--r-- | libart/src/main/java/java/lang/DexCache.java | 86 | ||||
-rw-r--r-- | libart/src/main/java/java/lang/reflect/ArtMethod.java | 11 | ||||
-rw-r--r-- | libart/src/main/java/java/lang/reflect/Constructor.java | 3 |
4 files changed, 176 insertions, 55 deletions
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.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; @@ -203,10 +204,18 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe 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 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe * * @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 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe 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 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe * 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 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe } 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 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe * {@code enum}. */ public boolean isEnum() { - return ((getModifiers() & 0x4000) != 0) && (getSuperclass() == Enum.class); + return (getSuperclass() == Enum.class) && ((accessFlags & 0x4000) != 0); } /** @@ -1654,22 +1686,41 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe } /** - * 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. + * The class def of this class in its own Dex, or -1 if there is no class def. * - * TODO: 0 is a valid index; this should be -1 if it is unknown + * @hide + */ + 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 getTypeIndex() { - int result = dexTypeIndex; - if (result == 0) { // uncomputed => Dalvik - result = AnnotationAccess.computeTypeIndex(getDex(), this); - dexTypeIndex = result; + public int getDexTypeIndex() { + int typeIndex = dexTypeIndex; + if (typeIndex != 65535) { + return typeIndex; + } + 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 result; + return typeIndex; } /** @@ -1680,10 +1731,26 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe * * @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 @@ import java.lang.reflect.ArtMethod; * A dex cache holds resolved copies of strings, fields, methods, and classes from the dexfile. */ final class DexCache { - // Only created by the VM. - private 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 pointer to dexFile. + /** Holds C pointer to dexFile. */ private int dexFile; + + // Only created by the VM. + private DexCache() {} + + Dex getDex() { + Dex result = dex; + if (result == null) { + synchronized (this) { + result = dex; + if (result == null) { + dex = result = getDexNative(); + } + } + } + return result; + } + + 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 @@ package java.lang.reflect; 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 @@ public final class ArtMethod { 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 @@ public final class ArtMethod { /** * 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 final class Constructor<T> extends AbstractMethod implements GenericDecla 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(); |