diff options
author | Ian Rogers <irogers@google.com> | 2012-01-30 15:54:44 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-01-30 15:54:44 -0800 |
commit | 0850c69c88d49efd4075288511b70d6c032bd0c8 (patch) | |
tree | a924efbf074d38c1f1e6bf1c1fff30146447843c | |
parent | d8c00d04361366a0156943bd98fee57392743e80 (diff) | |
parent | d418edaf4df0a410d678389e171ac6d96ae2af15 (diff) | |
download | android_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.cc | 42 | ||||
-rw-r--r-- | src/image_writer.cc | 12 | ||||
-rw-r--r-- | src/image_writer.h | 3 | ||||
-rw-r--r-- | src/java_lang_Class.cc | 86 | ||||
-rw-r--r-- | src/java_lang_reflect_Method.cc | 7 | ||||
-rw-r--r-- | src/object.cc | 42 | ||||
-rw-r--r-- | src/object.h | 35 |
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. |