Setting klass_ fields of heap allocated objects

Change-Id: Ib1ab43254430497cce0660156394eebddd2cc445
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 15c2e40..19f2f93 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -27,12 +27,23 @@
 }
 
 void ClassLinker::Init() {
-  // Allocate and partially initialize the Object and Class classes.
+  // Allocate and partially initialize the Class, Object, Field, Method classes.
   // Initialization will be completed when the definitions are loaded.
-  java_lang_Object_ = Heap::AllocClass(NULL);
-  java_lang_Object_->descriptor_ = "Ljava/lang/Object;";
-  java_lang_Class_ = Heap::AllocClass(NULL);
+  java_lang_Class_ = reinterpret_cast<Class*>(Heap::AllocRaw(sizeof(Class), NULL));
   java_lang_Class_->descriptor_ = "Ljava/lang/Class;";
+  java_lang_Class_->object_size_ = sizeof(Class);
+  java_lang_Class_->klass_ = java_lang_Class_;
+
+  java_lang_Object_ = AllocClass(NULL);
+  java_lang_Object_->descriptor_ = "Ljava/lang/Object;";
+
+  java_lang_Class_->super_class_ = java_lang_Object_;
+
+  java_lang_ref_Field_ = AllocClass(NULL);
+  java_lang_ref_Field_->descriptor_ = "Ljava/lang/ref/Field;";
+
+  java_lang_ref_Method_ = AllocClass(NULL);
+  java_lang_ref_Method_->descriptor_ = "Ljava/lang/Method;";
 
   // Allocate and initialize the primitive type classes.
   primitive_byte_ = CreatePrimitiveClass(kTypeByte, "B");
@@ -44,6 +55,32 @@
   primitive_short_ = CreatePrimitiveClass(kTypeShort, "S");
   primitive_boolean_ = CreatePrimitiveClass(kTypeBoolean, "Z");
   primitive_void_ = CreatePrimitiveClass(kTypeVoid, "V");
+
+  char_array_class_ = AllocClass(NULL);
+  char_array_class_->descriptor_ = "[C";
+  char_array_class_->status_ = Class::kStatusInitialized;
+  char_array_class_->component_type_ = primitive_char_;
+  char_array_class_->array_rank_ = 1;
+  char_array_class_->primitive_type_ = Class::kPrimNot;
+  char_array_class_->super_class_ = java_lang_Object_;
+}
+
+Class* ClassLinker::AllocClass(DexFile* dex_file) {
+  Class* klass = reinterpret_cast<Class*>(Heap::AllocObject(java_lang_Class_));
+  klass->dex_file_ = dex_file;
+  return klass;
+}
+
+StaticField* ClassLinker::AllocStaticField() {
+  return reinterpret_cast<StaticField*>(Heap::AllocRaw(sizeof(StaticField), java_lang_ref_Field_));
+}
+
+InstanceField* ClassLinker::AllocInstanceField() {
+  return reinterpret_cast<InstanceField*>(Heap::AllocRaw(sizeof(InstanceField), java_lang_ref_Field_));
+}
+
+Method* ClassLinker::AllocMethod() {
+  return reinterpret_cast<Method*>(Heap::AllocRaw(sizeof(Method), java_lang_ref_Method_));
 }
 
 Class* ClassLinker::FindClass(const char* descriptor,
@@ -55,25 +92,52 @@
   Class* klass = LookupClass(descriptor, class_loader);
   if (klass == NULL) {
     // Class is not yet loaded.
+    const RawDexFile::ClassDef* class_def;
     if (dex_file == NULL) {
       // No .dex file specified, search the class path.
-      dex_file = FindInClassPath(descriptor);
-      if (dex_file == NULL) {
+      ClassPathEntry pair = FindInClassPath(descriptor);
+      if (pair.first == NULL) {
         LG << "Class " << descriptor << " really not found";
         return NULL;
       }
+      dex_file = pair.first;
+      class_def = pair.second;
+    } else {
+      class_def = dex_file->GetRaw()->FindClassDef(descriptor);
     }
     // Load the class from the dex file.
     if (!strcmp(descriptor, "Ljava/lang/Object;")) {
       klass = java_lang_Object_;
       klass->dex_file_ = dex_file;
+      klass->object_size_ = sizeof(Object);
+      if (class_def != NULL) {
+        char_array_class_->super_class_idx_ = class_def->class_idx_;
+      }
     } else if (!strcmp(descriptor, "Ljava/lang/Class;")) {
       klass = java_lang_Class_;
       klass->dex_file_ = dex_file;
+      klass->object_size_ = sizeof(Class);
+    } else if (!strcmp(descriptor, "Ljava/lang/ref/Field;")) {
+      klass = java_lang_ref_Field_;
+      klass->dex_file_ = dex_file;
+      klass->object_size_ = sizeof(Field);
+    } else if (!strcmp(descriptor, "Ljava/lang/ref/Method;")) {
+      klass = java_lang_ref_Method_;
+      klass->dex_file_ = dex_file;
+      klass->object_size_ = sizeof(Method);
+    } else if (!strcmp(descriptor, "Ljava/lang/String;")) {
+      klass = java_lang_String_;
+      klass->dex_file_ = dex_file;
+      klass->object_size_ = sizeof(String);
     } else {
-      klass = Heap::AllocClass(dex_file);
+      klass = AllocClass(dex_file);
     }
-    bool is_loaded = LoadClass(descriptor, klass);
+    bool is_loaded;
+    if (class_def == NULL) {
+      is_loaded = false;
+    } else {
+      is_loaded = LoadClass(*class_def, klass);
+    }
     if (!is_loaded) {
       // TODO: this occurs only when a dex file is provided.
       LG << "Class not found";  // TODO: NoClassDefFoundError
@@ -177,7 +241,7 @@
     for (size_t i = 0; i < klass->num_sfields_; ++i) {
       RawDexFile::Field raw_field;
       raw->dexReadClassDataField(&class_data, &raw_field, &last_idx);
-      StaticField* sfield = Heap::AllocStaticField();
+      StaticField* sfield = AllocStaticField();
       klass->sfields_[i] = sfield;
       LoadField(klass, raw_field, sfield);
     }
@@ -191,7 +255,7 @@
     for (size_t i = 0; i < klass->NumInstanceFields(); ++i) {
       RawDexFile::Field raw_field;
       raw->dexReadClassDataField(&class_data, &raw_field, &last_idx);
-      InstanceField* ifield = Heap::AllocInstanceField();
+      InstanceField* ifield = AllocInstanceField();
       klass->ifields_[i] = ifield;
       LoadField(klass, raw_field, ifield);
     }
@@ -205,7 +269,7 @@
     for (size_t i = 0; i < klass->NumDirectMethods(); ++i) {
       RawDexFile::Method raw_method;
       raw->dexReadClassDataMethod(&class_data, &raw_method, &last_idx);
-      Method* meth = Heap::AllocMethod();
+      Method* meth = AllocMethod();
       klass->direct_methods_[i] = meth;
       LoadMethod(klass, raw_method, meth);
       // TODO: register maps
@@ -220,14 +284,13 @@
     for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
       RawDexFile::Method raw_method;
       raw->dexReadClassDataMethod(&class_data, &raw_method, &last_idx);
-      Method* meth = Heap::AllocMethod();
+      Method* meth = AllocMethod();
       klass->virtual_methods_[i] = meth;
       LoadMethod(klass, raw_method, meth);
       // TODO: register maps
     }
   }
-
-  return klass;
+  return true;
 }
 
 void ClassLinker::LoadInterfaces(const RawDexFile::ClassDef& class_def,
@@ -283,14 +346,15 @@
   }
 }
 
-DexFile* ClassLinker::FindInClassPath(const char* descriptor) {
+ClassLinker::ClassPathEntry ClassLinker::FindInClassPath(const char* descriptor) {
   for (size_t i = 0; i != class_path_.size(); ++i) {
     DexFile* dex_file = class_path_[i];
-    if (dex_file->HasClass(descriptor)) {
-      return dex_file;
+    const RawDexFile::ClassDef* class_def = dex_file->GetRaw()->FindClassDef(descriptor);
+    if (class_def != NULL) {
+      return ClassPathEntry(dex_file, class_def);
     }
   }
-  return NULL;
+  return ClassPathEntry(NULL, NULL);
 }
 
 void ClassLinker::AppendToClassPath(DexFile* dex_file) {
@@ -298,9 +362,9 @@
 }
 
 Class* ClassLinker::CreatePrimitiveClass(JType type, const char* descriptor) {
-  Class* klass = Heap::AllocClass(NULL);
+  Class* klass = AllocClass(NULL);
   CHECK(klass != NULL);
-  klass->super_class_ = java_lang_Class_;
+  klass->super_class_ = NULL;
   klass->access_flags_ = kAccPublic | kAccFinal | kAccAbstract;
   klass->descriptor_ = descriptor;
   klass->status_ = Class::kStatusInitialized;
@@ -946,7 +1010,7 @@
     klass->vtable_count_ += miranda_count;
 
     for (int i = 0; i < miranda_count; i++) {
-      Method* meth = Heap::AllocMethod();
+      Method* meth = AllocMethod();
       memcpy(meth, miranda_list[i], sizeof(Method));
       meth->klass_ = klass;
       meth->access_flags_ |= kAccMiranda;
@@ -968,11 +1032,11 @@
 }
 
 bool ClassLinker::LinkInstanceFields(Class* klass) {
-  int fieldOffset;
+  int field_offset;
   if (klass->GetSuperClass() != NULL) {
-    fieldOffset = klass->GetSuperClass()->object_size_;
+    field_offset = klass->GetSuperClass()->object_size_;
   } else {
-    fieldOffset = OFFSETOF_MEMBER(DataObject, fields_);
+    field_offset = OFFSETOF_MEMBER(DataObject, fields_);
   }
   // Move references to the front.
   klass->num_reference_ifields_ = 0;
@@ -1000,22 +1064,22 @@
     if (c != '[' && c != 'L') {
       break;
     }
-    pField->SetOffset(fieldOffset);
-    fieldOffset += sizeof(uint32_t);
+    pField->SetOffset(field_offset);
+    field_offset += sizeof(uint32_t);
   }
 
   // Now we want to pack all of the double-wide fields together.  If
   // we're not aligned, though, we want to shuffle one 32-bit field
   // into place.  If we can't find one, we'll have to pad it.
-  if (i != klass->NumInstanceFields() && (fieldOffset & 0x04) != 0) {
+  if (i != klass->NumInstanceFields() && (field_offset & 0x04) != 0) {
     InstanceField* pField = klass->GetInstanceField(i);
     char c = pField->GetType();
 
     if (c != 'J' && c != 'D') {
       // The field that comes next is 32-bit, so just advance past it.
       assert(c != '[' && c != 'L');
-      pField->SetOffset(fieldOffset);
-      fieldOffset += sizeof(uint32_t);
+      pField->SetOffset(field_offset);
+      field_offset += sizeof(uint32_t);
       i++;
     } else {
       // Next field is 64-bit, so search for a 32-bit field we can
@@ -1028,22 +1092,22 @@
           klass->SetInstanceField(i, singleField);
           klass->SetInstanceField(j, pField);
           pField = singleField;
-          pField->SetOffset(fieldOffset);
-          fieldOffset += sizeof(uint32_t);
+          pField->SetOffset(field_offset);
+          field_offset += sizeof(uint32_t);
           found = true;
           i++;
           break;
         }
       }
       if (!found) {
-        fieldOffset += sizeof(uint32_t);
+        field_offset += sizeof(uint32_t);
       }
     }
   }
 
   // Alignment is good, shuffle any double-wide fields forward, and
   // finish assigning field offsets to all fields.
-  assert(i == klass->NumInstanceFields() || (fieldOffset & 0x04) == 0);
+  assert(i == klass->NumInstanceFields() || (field_offset & 0x04) == 0);
   for ( ; i < klass->NumInstanceFields(); i++) {
     InstanceField* pField = klass->GetInstanceField(i);
     char c = pField->GetType();
@@ -1063,10 +1127,10 @@
       // This is a double-wide field, leave it be.
     }
 
-    pField->SetOffset(fieldOffset);
-    fieldOffset += sizeof(uint32_t);
+    pField->SetOffset(field_offset);
+    field_offset += sizeof(uint32_t);
     if (c == 'J' || c == 'D')
-      fieldOffset += sizeof(uint32_t);
+      field_offset += sizeof(uint32_t);
   }
 
 #ifndef NDEBUG
@@ -1096,7 +1160,7 @@
   }
 #endif
 
-  klass->object_size_ = fieldOffset;
+  klass->object_size_ = field_offset;
   return true;
 }
 
@@ -1170,7 +1234,7 @@
   const RawDexFile* raw = referring->GetDexFile()->GetRaw();
   const RawDexFile::StringId& string_id = raw->GetStringId(string_idx);
   const char* string_data = raw->GetStringData(string_id);
-  String* new_string = Heap::AllocStringFromModifiedUtf8(string_data);
+  String* new_string = Heap::AllocStringFromModifiedUtf8(java_lang_String_, char_array_class_, string_data);
   // TODO: intern the new string
   referring->GetDexFile()->SetResolvedString(new_string, string_idx);
   return new_string;
diff --git a/src/class_linker.h b/src/class_linker.h
index 00271a5..e4c5ff9 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -20,6 +20,11 @@
 
   ~ClassLinker() {}
 
+  Class* AllocClass(DexFile* dex_file);
+  StaticField* AllocStaticField();
+  InstanceField* AllocInstanceField();
+  Method* AllocMethod();
+
   // Finds a class by its descriptor name.
   Class* FindClass(const char* descriptor,
                    Object* class_loader,
@@ -43,7 +48,9 @@
 
   String* ResolveString(const Class* referring, uint32_t string_idx);
 
-  DexFile* FindInClassPath(const char* descriptor);
+  typedef std::pair<DexFile*, const RawDexFile::ClassDef*> ClassPathEntry;
+
+  ClassPathEntry FindInClassPath(const char* descriptor);
 
   void AppendToClassPath(DexFile* dex_file);
 
@@ -117,8 +124,12 @@
   Class* primitive_long_;
   Class* primitive_void_;
 
-  Class* java_lang_Object_;
   Class* java_lang_Class_;
+  Class* java_lang_Object_;
+  Class* java_lang_ref_Field_;
+  Class* java_lang_ref_Method_;
+  Class* java_lang_String_;
+  Class* char_array_class_;
 
   DISALLOW_COPY_AND_ASSIGN(ClassLinker);
 };
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index d755e3e..bbe6ebc 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -15,7 +15,7 @@
   scoped_ptr<ClassLinker> linker(ClassLinker::Create());
   linker->AppendToClassPath(dex.get());
 
-  scoped_ptr<Class> klass(Heap::AllocClass(dex.get()));
+  scoped_ptr<Class> klass(linker.get()->AllocClass(dex.get()));
   bool result1 = linker->LoadClass("NoSuchClass", klass.get());
   EXPECT_FALSE(result1);
   bool result2 = linker->LoadClass("LNoSuchClass;", klass.get());
@@ -29,7 +29,7 @@
   scoped_ptr<ClassLinker> linker(ClassLinker::Create());
   linker->AppendToClassPath(dex.get());
 
-  scoped_ptr<Class> klass(Heap::AllocClass(dex.get()));
+  scoped_ptr<Class> klass(linker.get()->AllocClass(dex.get()));
   bool result = linker->LoadClass("LNested;", klass.get());
   ASSERT_TRUE(result);
 
@@ -52,7 +52,9 @@
 
   Class* JavaLangObject = linker->FindClass("Ljava/lang/Object;", NULL, dex.get());
   ASSERT_TRUE(JavaLangObject != NULL);
-  EXPECT_TRUE(JavaLangObject->GetClass() != NULL);
+  ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
+  ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
+  EXPECT_EQ(JavaLangObject->GetClass()->GetSuperClass(), JavaLangObject);
   ASSERT_TRUE(JavaLangObject->GetDescriptor() == "Ljava/lang/Object;");
   EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
   EXPECT_FALSE(JavaLangObject->HasSuperClass());
@@ -72,7 +74,9 @@
 
   Class* MyClass = linker->FindClass("LMyClass;", NULL, dex.get());
   ASSERT_TRUE(MyClass != NULL);
-  EXPECT_TRUE(MyClass->GetClass() != NULL);
+  ASSERT_TRUE(MyClass->GetClass() != NULL);
+  ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
+  EXPECT_EQ(MyClass->GetClass()->GetSuperClass(), JavaLangObject);
   ASSERT_TRUE(MyClass->GetDescriptor() == "LMyClass;");
   EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
   EXPECT_TRUE(MyClass->HasSuperClass());
@@ -90,6 +94,9 @@
   EXPECT_EQ(0U, MyClass->NumVirtualMethods());
   EXPECT_EQ(0U, MyClass->NumInstanceFields());
   EXPECT_EQ(0U, MyClass->NumStaticFields());
+
+  EXPECT_EQ(JavaLangObject->GetClass()->GetClass(), MyClass->GetClass()->GetClass());
+
 }
 
 }  // namespace art
diff --git a/src/heap.h b/src/heap.h
index b9f7937..f7ae5a5 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -19,47 +19,30 @@
 
   ~Heap() {}
 
-  static Class* AllocClass(DexFile* dex_file) {
-    byte* raw = new byte[sizeof(Class)]();
-    Class* klass = reinterpret_cast<Class*>(raw);
-    klass->dex_file_ = dex_file;
-    return klass;
-  }
-
-  static StaticField* AllocStaticField() {
-    size_t size = sizeof(StaticField);
+  static Object* AllocRaw(size_t size, Class* klass) {
     byte* raw = new byte[size]();
-    return reinterpret_cast<StaticField*>(raw);
+    Object* object = reinterpret_cast<Object*>(raw);
+    object->klass_ = klass;
+    return object;
   }
 
-  static InstanceField* AllocInstanceField() {
-    size_t size = sizeof(InstanceField);
-    byte* raw = new byte[size]();
-    return reinterpret_cast<InstanceField*>(raw);
+  static Object* AllocObject(Class* klass) {
+    return AllocRaw(klass->object_size_, klass);
   }
 
-  static Method* AllocMethod() {
-    size_t size = sizeof(Method);
-    byte* raw = new byte[size]();
-    return reinterpret_cast<Method*>(raw);
-  }
-
-  static CharArray* AllocCharArray(size_t length) {
+  static CharArray* AllocCharArray(Class* char_array, size_t length) {
     size_t size = sizeof(Array) + length * sizeof(uint16_t);
-    byte* raw = new byte[size]();
-    return reinterpret_cast<CharArray*>(raw);
+    return reinterpret_cast<CharArray*>(AllocRaw(size, char_array));
   }
 
-  static String* AllocString() {
-    size_t size = sizeof(String);
-    byte* raw = new byte[size]();
-    return reinterpret_cast<String*>(raw);
+  static String* AllocString(Class* java_lang_String) {
+    return reinterpret_cast<String*>(AllocObject(java_lang_String));
   }
 
-  static String* AllocStringFromModifiedUtf8(const char* data) {
-    String* string = AllocString();
+  static String* AllocStringFromModifiedUtf8(Class* java_lang_String, Class* char_array, const char* data) {
+    String* string = AllocString(java_lang_String);
     uint32_t count = strlen(data);  // TODO
-    CharArray* array = AllocCharArray(count);
+    CharArray* array = AllocCharArray(char_array, count);
     string->array_ = array;
     string->count_ = count;
     return string;
diff --git a/src/object.h b/src/object.h
index d7df9dc..cd57460 100644
--- a/src/object.h
+++ b/src/object.h
@@ -190,8 +190,8 @@
 
 class Field : public Object {
  public:
-  Class* GetClass() const {
-    return klass_;
+  Class* GetDeclaringClass() const {
+    return declaring_class_;
   }
 
   const char* GetName() const {
@@ -219,7 +219,7 @@
 #undef FIELD_FIELD_SLOTS
 
   // The class in which this field is declared.
-  Class* klass_;
+  Class* declaring_class_;
 
   const char* name_;
 
@@ -315,12 +315,12 @@
     return name_;
   }
 
-  Class* GetClass() const {
-    return klass_;
+  Class* GetDeclaringClass() const {
+    return declaring_class_;
   }
 
   // const char* GetReturnTypeDescriptor() const {
-  //   return klass_->GetDexFile_->GetRaw()->dexStringByTypeIdx(proto_id_.return_type_id_);
+  //   return declaring_class_->GetDexFile_->GetRaw()->dexStringByTypeIdx(proto_id_.return_type_id_);
   // }
 
   // Returns true if the method is declared public.
@@ -400,7 +400,7 @@
 #undef METHOD_FIELD_SLOTS
 
   // the class we are a part of
-  Class* klass_;
+  Class* declaring_class_;
 
   // access flags; low 16 bits are defined by spec (could be uint16_t?)
   uint32_t access_flags_;
diff --git a/src/object_test.cc b/src/object_test.cc
index c49c4fd..b00e123 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -36,7 +36,7 @@
   scoped_ptr<ClassLinker> linker(ClassLinker::Create());
   linker->AppendToClassPath(dex_file.get());
 
-  scoped_ptr<Class> klass(Heap::AllocClass(dex_file.get()));
+  scoped_ptr<Class> klass(linker.get()->AllocClass(dex_file.get()));
   bool result = linker->LoadClass("LProtoCompare;", klass.get());
   ASSERT_TRUE(result);
 
@@ -95,10 +95,10 @@
   scoped_ptr<ClassLinker> linker2(ClassLinker::Create());
   linker2->AppendToClassPath(dex_file2.get());
 
-  scoped_ptr<Class> klass1(Heap::AllocClass(dex_file1.get()));
+  scoped_ptr<Class> klass1(linker1.get()->AllocClass(dex_file1.get()));
   bool result1 = linker1->LoadClass("LProtoCompare;", klass1.get());
   ASSERT_TRUE(result1);
-  scoped_ptr<Class> klass2(Heap::AllocClass(dex_file2.get()));
+  scoped_ptr<Class> klass2(linker2.get()->AllocClass(dex_file2.get()));
   bool result2 = linker2->LoadClass("LProtoCompare2;", klass2.get());
   ASSERT_TRUE(result2);