Merge "Class clean-up and compute name during image writing." into dalvik-dev
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 0fe52c8..096ff2d 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -467,31 +467,31 @@
 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 ca57f41..293bd96 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -59,6 +59,7 @@
     return false;
   }
   PruneNonImageClasses();
+  ComputeLazyFieldsForImageClasses();
   Heap::CollectGarbage(false);
 #ifndef NDEBUG
   CheckNonImageClassesRemoved();
@@ -92,6 +93,17 @@
   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 d834361..1be07bd 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -99,6 +99,9 @@
   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 ece98b3..826841b 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -89,7 +89,7 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
   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 @@
 
 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 bfdcd39..10f5779 100644
--- a/src/java_lang_reflect_Method.cc
+++ b/src/java_lang_reflect_Method.cc
@@ -48,16 +48,9 @@
   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 145f7ef..32521f8 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -608,6 +608,48 @@
   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 58c36be..3cbe9d6 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1059,14 +1059,13 @@
   //
   // 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 @@
     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 @@
   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 @@
   // 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 @@
   // 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 @@
   // 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 @@
   // 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.