summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2012-01-30 15:54:44 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-01-30 15:54:44 -0800
commit0850c69c88d49efd4075288511b70d6c032bd0c8 (patch)
treea924efbf074d38c1f1e6bf1c1fff30146447843c
parentd8c00d04361366a0156943bd98fee57392743e80 (diff)
parentd418edaf4df0a410d678389e171ac6d96ae2af15 (diff)
downloadandroid_art-0850c69c88d49efd4075288511b70d6c032bd0c8.tar.gz
android_art-0850c69c88d49efd4075288511b70d6c032bd0c8.tar.bz2
android_art-0850c69c88d49efd4075288511b70d6c032bd0c8.zip
Merge "Class clean-up and compute name during image writing." into dalvik-dev
-rw-r--r--src/class_linker_test.cc42
-rw-r--r--src/image_writer.cc12
-rw-r--r--src/image_writer.h3
-rw-r--r--src/java_lang_Class.cc86
-rw-r--r--src/java_lang_reflect_Method.cc7
-rw-r--r--src/object.cc42
-rw-r--r--src/object.h35
7 files changed, 102 insertions, 125 deletions
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 0fe52c8c49..096ff2dc5d 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -467,31 +467,31 @@ struct ConstructorOffsets : public MethodOffsets {
struct ClassOffsets : public CheckOffsets<Class> {
ClassOffsets() : CheckOffsets<Class>(false, "Ljava/lang/Class;") {
// alphabetical references
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_loader_), "classLoader"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, component_type_), "componentType"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, dex_cache_), "dexCache"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, direct_methods_), "directMethods"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifields_), "iFields"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, iftable_), "ifTable"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, name_), "name"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_loader_), "shadow$_class_loader_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, component_type_), "shadow$_component_type_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, dex_cache_), "shadow$_dex_cache_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, direct_methods_), "shadow$_direct_methods_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifields_), "shadow$_ifields_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, iftable_), "shadow$_iftable_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, sfields_), "shadow$_sfields_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_), "shadow$_super_class_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, verify_error_class_), "shadow$_verify_error_class_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, virtual_methods_), "shadow$_virtual_methods_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, vtable_), "shadow$_vtable_"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, sfields_), "sFields"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_), "superClass"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, verify_error_class_), "verifyErrorClass"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, virtual_methods_), "virtualMethods"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, vtable_), "vtable"));
// alphabetical 32-bit
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, access_flags_), "accessFlags"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_size_), "classSize"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, clinit_thread_id_), "clinitThreadId"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, dex_type_idx_), "dexTypeIndex"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, access_flags_), "shadow$_access_flags_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_size_), "shadow$_class_size_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, clinit_thread_id_), "shadow$_clinit_thread_id_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_instance_fields_), "shadow$_num_reference_instance_fields_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_static_fields_), "shadow$_num_reference_static_fields_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, object_size_), "shadow$_object_size_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, primitive_type_), "shadow$_primitive_type_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_instance_offsets_), "shadow$_reference_instance_offsets_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_static_offsets_), "shadow$_reference_static_offsets_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, status_), "shadow$_status_"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_instance_fields_), "numReferenceInstanceFields"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_static_fields_), "numReferenceStaticFields"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, object_size_), "objectSize"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, primitive_type_), "primitiveType"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_instance_offsets_), "referenceInstanceOffsets"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_static_offsets_), "referenceStaticOffsets"));
+ offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, status_), "status"));
};
};
diff --git a/src/image_writer.cc b/src/image_writer.cc
index ca57f41e74..293bd96d02 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -59,6 +59,7 @@ bool ImageWriter::Write(const char* image_filename,
return false;
}
PruneNonImageClasses();
+ ComputeLazyFieldsForImageClasses();
Heap::CollectGarbage(false);
#ifndef NDEBUG
CheckNonImageClassesRemoved();
@@ -92,6 +93,17 @@ bool ImageWriter::AllocMemory() {
return true;
}
+void ImageWriter::ComputeLazyFieldsForImageClasses() {
+ Runtime* runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ class_linker->VisitClasses(ComputeLazyFieldsForClassesVisitor, NULL);
+}
+
+bool ImageWriter::ComputeLazyFieldsForClassesVisitor(Class* klass, void* arg) {
+ klass->ComputeName();
+ return true;
+}
+
bool ImageWriter::IsImageClass(const Class* klass) {
if (image_classes_ == NULL) {
return true;
diff --git a/src/image_writer.h b/src/image_writer.h
index d834361bcb..1be07bda56 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -99,6 +99,9 @@ class ImageWriter {
bool IsImageClass(const Class* klass);
void DumpImageClasses();
+ void ComputeLazyFieldsForImageClasses();
+ static bool ComputeLazyFieldsForClassesVisitor(Class* klass, void* arg);
+
void PruneNonImageClasses();
static bool NonImageClassesVisitor(Class* c, void* arg);
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index ece98b3520..826841bffe 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -89,7 +89,7 @@ jobjectArray ToArray(JNIEnv* env, const char* array_class_name, const std::vecto
return result;
}
-bool IsVisibleConstructor(Method* m, bool public_only) {
+static bool IsVisibleConstructor(Method* m, bool public_only) {
if (public_only && !m->IsPublic()) {
return false;
}
@@ -113,7 +113,7 @@ jobjectArray Class_getDeclaredConstructors(JNIEnv* env, jclass javaClass, jboole
return ToArray(env, "java/lang/reflect/Constructor", constructors);
}
-bool IsVisibleField(Field* f, bool public_only) {
+static bool IsVisibleField(Field* f, bool public_only) {
if (public_only && !f->IsPublic()) {
return false;
}
@@ -146,7 +146,7 @@ jobjectArray Class_getDeclaredFields(JNIEnv* env, jclass javaClass, jboolean pub
return ToArray(env, "java/lang/reflect/Field", fields);
}
-bool IsVisibleMethod(Method* m, bool public_only) {
+static bool IsVisibleMethod(Method* m, bool public_only) {
if (public_only && !m->IsPublic()) {
return false;
}
@@ -181,10 +181,6 @@ jobjectArray Class_getDeclaredMethods(JNIEnv* env, jclass javaClass, jboolean pu
return ToArray(env, "java/lang/reflect/Method", methods);
}
-jboolean Class_desiredAssertionStatus(JNIEnv* env, jobject javaThis) {
- return JNI_FALSE;
-}
-
jobject Class_getDex(JNIEnv* env, jobject javaClass) {
Class* c = Decode<Class*>(env, javaClass);
@@ -196,22 +192,7 @@ jobject Class_getDex(JNIEnv* env, jobject javaClass) {
return Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache).GetDexObject(env);
}
-jint Class_getNonInnerClassModifiers(JNIEnv* env, jclass javaClass) {
- Class* c = Decode<Class*>(env, javaClass);
- return c->GetAccessFlags() & kAccJavaFlagsMask;
-}
-
-jobject Class_getClassLoaderNative(JNIEnv* env, jclass javaClass) {
- Class* c = Decode<Class*>(env, javaClass);
- Object* result = c->GetClassLoader();
- return AddLocalReference<jobject>(env, result);
-}
-
-jclass Class_getComponentType(JNIEnv* env, jclass javaClass) {
- return AddLocalReference<jclass>(env, Decode<Class*>(env, javaClass)->GetComponentType());
-}
-
-bool MethodMatches(MethodHelper* mh, const std::string& name, ObjectArray<Class>* arg_array) {
+static bool MethodMatches(MethodHelper* mh, const std::string& name, ObjectArray<Class>* arg_array) {
if (name != mh->GetName()) {
return false;
}
@@ -231,7 +212,7 @@ bool MethodMatches(MethodHelper* mh, const std::string& name, ObjectArray<Class>
return true;
}
-Method* FindConstructorOrMethodInArray(ObjectArray<Method>* methods, const std::string& name,
+static Method* FindConstructorOrMethodInArray(ObjectArray<Method>* methods, const std::string& name,
ObjectArray<Class>* arg_array) {
if (methods == NULL) {
return NULL;
@@ -300,46 +281,9 @@ jobject Class_getDeclaredFieldNative(JNIEnv* env, jclass jklass, jobject jname)
return NULL;
}
-/*
- * private native String getNameNative()
- *
- * Return the class' name. The exact format is bizarre, but it's the specified
- * behavior: keywords for primitive types, regular "[I" form for primitive
- * arrays (so "int" but "[I"), and arrays of reference types written
- * between "L" and ";" but with dots rather than slashes (so "java.lang.String"
- * but "[Ljava.lang.String;"). Madness.
- */
jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
Class* c = Decode<Class*>(env, javaThis);
- std::string descriptor(ClassHelper(c).GetDescriptor());
- if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
- // The descriptor indicates that this is the class for
- // a primitive type; special-case the return value.
- const char* name = NULL;
- switch (descriptor[0]) {
- case 'Z': name = "boolean"; break;
- case 'B': name = "byte"; break;
- case 'C': name = "char"; break;
- case 'S': name = "short"; break;
- case 'I': name = "int"; break;
- case 'J': name = "long"; break;
- case 'F': name = "float"; break;
- case 'D': name = "double"; break;
- case 'V': name = "void"; break;
- default:
- LOG(FATAL) << "Unknown primitive type: " << PrintableChar(descriptor[0]);
- }
- return env->NewStringUTF(name);
- }
-
- // Convert the UTF-8 name to a java.lang.String. The
- // name must use '.' to separate package components.
- if (descriptor.size() > 2 && descriptor[0] == 'L' && descriptor[descriptor.size() - 1] == ';') {
- descriptor.erase(0, 1);
- descriptor.erase(descriptor.size() - 1);
- }
- std::replace(descriptor.begin(), descriptor.end(), '/', '.');
- return env->NewStringUTF(descriptor.c_str());
+ return AddLocalReference<jstring>(env, c->ComputeName());
}
jboolean Class_isAssignableFrom(JNIEnv* env, jobject javaLhs, jclass javaRhs) {
@@ -362,18 +306,8 @@ jboolean Class_isInstance(JNIEnv* env, jobject javaClass, jobject javaObject) {
return o->InstanceOf(c) ? JNI_TRUE : JNI_FALSE;
}
-jboolean Class_isInterface(JNIEnv* env, jobject javaThis) {
- Class* c = Decode<Class*>(env, javaThis);
- return c->IsInterface();
-}
-
-jboolean Class_isPrimitive(JNIEnv* env, jobject javaThis) {
- Class* c = Decode<Class*>(env, javaThis);
- return c->IsPrimitive();
-}
-
// Validate method/field access.
-bool CheckMemberAccess(const Class* access_from, Class* access_to, uint32_t member_flags) {
+static bool CheckMemberAccess(const Class* access_from, Class* access_to, uint32_t member_flags) {
// quick accept for public access */
if (member_flags & kAccPublic) {
return true;
@@ -466,22 +400,16 @@ jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"),
- NATIVE_METHOD(Class, desiredAssertionStatus, "()Z"),
NATIVE_METHOD(Class, getAnnotationDirectoryOffset, "()I"),
- NATIVE_METHOD(Class, getClassLoaderNative, "()Ljava/lang/ClassLoader;"),
- NATIVE_METHOD(Class, getComponentType, "()Ljava/lang/Class;"),
NATIVE_METHOD(Class, getDeclaredConstructorOrMethod, "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Member;"),
NATIVE_METHOD(Class, getDeclaredConstructors, "(Z)[Ljava/lang/reflect/Constructor;"),
NATIVE_METHOD(Class, getDeclaredFieldNative, "(Ljava/lang/String;)Ljava/lang/reflect/Field;"),
NATIVE_METHOD(Class, getDeclaredFields, "(Z)[Ljava/lang/reflect/Field;"),
NATIVE_METHOD(Class, getDeclaredMethods, "(Z)[Ljava/lang/reflect/Method;"),
NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"),
- NATIVE_METHOD(Class, getNonInnerClassModifiers, "()I"),
NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"),
NATIVE_METHOD(Class, isAssignableFrom, "(Ljava/lang/Class;)Z"),
NATIVE_METHOD(Class, isInstance, "(Ljava/lang/Object;)Z"),
- NATIVE_METHOD(Class, isInterface, "()Z"),
- NATIVE_METHOD(Class, isPrimitive, "()Z"),
NATIVE_METHOD(Class, newInstanceImpl, "()Ljava/lang/Object;"),
};
diff --git a/src/java_lang_reflect_Method.cc b/src/java_lang_reflect_Method.cc
index bfdcd391de..10f5779c18 100644
--- a/src/java_lang_reflect_Method.cc
+++ b/src/java_lang_reflect_Method.cc
@@ -48,16 +48,9 @@ jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) {
return AddLocalReference<jobject>(env, declared_exceptions->Clone());
}
-jobject Method_getReturnTypeNative(JNIEnv* env, jobject javaMethod) {
- Method* m = Decode<Object*>(env, javaMethod)->AsMethod();
- MethodHelper mh(m);
- return AddLocalReference<jobject>(env, mh.GetReturnType());
-}
-
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Method, invoke, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"),
NATIVE_METHOD(Method, getExceptionTypesNative, "()[Ljava/lang/Class;"),
- NATIVE_METHOD(Method, getReturnTypeNative, "()Ljava/lang/Class;")
};
} // namespace
diff --git a/src/object.cc b/src/object.cc
index 145f7efe50..32521f8884 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -608,6 +608,48 @@ void Class::SetClassSize(size_t new_class_size) {
SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false);
}
+// Return the class' name. The exact format is bizarre, but it's the specified behavior for
+// Class.getName: keywords for primitive types, regular "[I" form for primitive arrays (so "int"
+// but "[I"), and arrays of reference types written between "L" and ";" but with dots rather than
+// slashes (so "java.lang.String" but "[Ljava.lang.String;"). Madness.
+String* Class::ComputeName() {
+ String* name = GetName();
+ if (name != NULL) {
+ return name;
+ }
+ std::string descriptor(ClassHelper(this).GetDescriptor());
+ if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
+ // The descriptor indicates that this is the class for
+ // a primitive type; special-case the return value.
+ const char* c_name = NULL;
+ switch (descriptor[0]) {
+ case 'Z': c_name = "boolean"; break;
+ case 'B': c_name = "byte"; break;
+ case 'C': c_name = "char"; break;
+ case 'S': c_name = "short"; break;
+ case 'I': c_name = "int"; break;
+ case 'J': c_name = "long"; break;
+ case 'F': c_name = "float"; break;
+ case 'D': c_name = "double"; break;
+ case 'V': c_name = "void"; break;
+ default:
+ LOG(FATAL) << "Unknown primitive type: " << PrintableChar(descriptor[0]);
+ }
+ name = String::AllocFromModifiedUtf8(c_name);
+ } else {
+ // Convert the UTF-8 name to a java.lang.String. The name must use '.' to separate package
+ // components.
+ if (descriptor.size() > 2 && descriptor[0] == 'L' && descriptor[descriptor.size() - 1] == ';') {
+ descriptor.erase(0, 1);
+ descriptor.erase(descriptor.size() - 1);
+ }
+ std::replace(descriptor.begin(), descriptor.end(), '/', '.');
+ name = String::AllocFromModifiedUtf8(descriptor.c_str());
+ }
+ SetName(name);
+ return name;
+}
+
void Class::DumpClass(std::ostream& os, int flags) const {
if ((flags & kDumpClassFullDetail) == 0) {
os << PrettyClass(this);
diff --git a/src/object.h b/src/object.h
index 58c36be1b5..3cbe9d6572 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1059,14 +1059,13 @@ class MANAGED Class : public StaticStorageBase {
//
// kStatusIdx: LoadClass populates with Class with information from
// the DexFile, moving the status to kStatusIdx, indicating that the
- // Class values in super_class_ and interfaces_ have not been
- // populated based on super_class_type_idx_ and
- // interfaces_type_idx_. The new Class can then be inserted into the
- // classes table.
+ // Class value in super_class_ has not been populated. The new Class
+ // can then be inserted into the classes table.
//
// kStatusLoaded: After taking a lock on Class, the ClassLinker will
// attempt to move a kStatusIdx class forward to kStatusLoaded by
- // using ResolveClass to initialize the super_class_ and interfaces_.
+ // using ResolveClass to initialize the super_class_ and ensuring the
+ // interfaces are resolved.
//
// kStatusResolved: Still holding the lock on Class, the ClassLinker
// shows linking is complete and fields of the Class populated by making
@@ -1193,8 +1192,10 @@ class MANAGED Class : public StaticStorageBase {
return (GetAccessFlags() & kAccClassIsPhantomReference) != 0;
}
- String* GetName() const;
- void SetName(String* name);
+
+ String* GetName() const ; // Returns the cached name
+ void SetName(String* name); // Sets the cached name
+ String* ComputeName(); // Computes the name, then sets the cached value
bool IsProxyClass() const {
// Read access flags without using getter as whether something is a proxy can be check in
@@ -1724,9 +1725,6 @@ class MANAGED Class : public StaticStorageBase {
bool IsArrayAssignableFromArray(const Class* klass) const;
bool IsAssignableFromArray(const Class* klass) const;
- // descriptor for the class such as "java.lang.Class" or "[C"
- String* name_; // TODO initialize
-
// defining class loader, or NULL for the "bootstrap" system loader
ClassLoader* class_loader_;
@@ -1768,12 +1766,13 @@ class MANAGED Class : public StaticStorageBase {
// of the concrete vtable_ methods for the methods in the interface.
ObjectArray<InterfaceEntry>* iftable_;
+ // descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName
+ String* name_;
+
// Static fields
ObjectArray<Field>* sfields_;
- // The superclass, or NULL if this is java.lang.Object or a
- // primitive type.
- // see also super_class_type_idx_;
+ // The superclass, or NULL if this is java.lang.Object, an interface or primitive type.
Class* super_class_;
// If class verify fails, we must return same error on subsequent tries.
@@ -1788,10 +1787,6 @@ class MANAGED Class : public StaticStorageBase {
// virtual_ methods_ for miranda methods.
ObjectArray<Method>* vtable_;
- // type index from dex file
- // TODO: really 16bits
- uint32_t dex_type_idx_;
-
// access flags; low 16 bits are defined by VM spec
uint32_t access_flags_;
@@ -1802,6 +1797,10 @@ class MANAGED Class : public StaticStorageBase {
// tid used to check for recursive <clinit> invocation
pid_t clinit_thread_id_;
+ // type index from dex file
+ // TODO: really 16bits
+ uint32_t dex_type_idx_;
+
// number of instance fields that are object refs
size_t num_reference_instance_fields_;
@@ -1813,7 +1812,7 @@ class MANAGED Class : public StaticStorageBase {
// See also class_size_.
size_t object_size_;
- // primitive type index, or Primitive::kPrimNot (0); set for generated prim classes
+ // primitive type value, or Primitive::kPrimNot (0); set for generated prim classes
Primitive::Type primitive_type_;
// Bitmap of offsets of ifields.