summaryrefslogtreecommitdiffstats
path: root/libart
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2013-09-19 02:51:22 -0700
committerIan Rogers <irogers@google.com>2013-09-21 22:05:00 -0700
commita6e22fc9b70ebe39abd716ce37450bda935c0fb8 (patch)
tree2bbdf94c92895e7c2faf1db2e8482bf85906a129 /libart
parent98430d0d75f4cfd40614b77debeb3c8d0abf40df (diff)
downloadlibcore-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.java131
-rw-r--r--libart/src/main/java/java/lang/DexCache.java86
-rw-r--r--libart/src/main/java/java/lang/reflect/ArtMethod.java11
-rw-r--r--libart/src/main/java/java/lang/reflect/Constructor.java3
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();