Initialize primitive type classes during linker initialization.

Change-Id: Ib31da85afcc59c5d0a14346fb7f97043487fd662
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 3475bd1..e1e9bef 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -19,6 +19,25 @@
 
 namespace art {
 
+void ClassLinker::Init() {
+  // Allocate and partially initialize the class Class.  This object
+  // will complete its initialization when its definition is loaded.
+  java_lang_Class_ = Heap::AllocClass();
+  java_lang_Class_->super_class_ = java_lang_Class_;
+  java_lang_Class_->descriptor_ = "Ljava/lang/Class;";
+
+  // Allocate and initialize the primitive type classes.
+  primitive_byte_ = CreatePrimitiveClass(kTypeByte, "B");
+  primitive_char_ = CreatePrimitiveClass(kTypeChar, "C");
+  primitive_double_ = CreatePrimitiveClass(kTypeDouble, "D");
+  primitive_float_ = CreatePrimitiveClass(kTypeFloat, "F");
+  primitive_int_ = CreatePrimitiveClass(kTypeInt, "I");
+  primitive_long_ = CreatePrimitiveClass(kTypeLong, "J");
+  primitive_short_ = CreatePrimitiveClass(kTypeShort, "S");
+  primitive_boolean_ = CreatePrimitiveClass(kTypeBoolean, "Z");
+  primitive_void_ = CreatePrimitiveClass(kTypeVoid, "V");
+}
+
 Class* ClassLinker::FindClass(const char* descriptor,
                               Object* class_loader,
                               DexFile* dex_file) {
@@ -37,8 +56,13 @@
       }
     }
     // Load the class from the dex file.
-    klass = dex_file->LoadClass(descriptor);
-    if (klass == NULL) {
+    if (!strcmp(descriptor, "Ljava/lang/Class;")) {
+      klass = java_lang_Class_;
+    } else {
+      klass = Heap::AllocClass();
+    }
+    bool is_loaded = dex_file->LoadClass(descriptor, klass);
+    if (!is_loaded) {
       // TODO: this occurs only when a dex file is provided.
       LG << "Class not found";  // TODO: NoClassDefFoundError
       return NULL;
@@ -106,9 +130,49 @@
   class_path_.push_back(dex_file);
 }
 
+Class* ClassLinker::CreatePrimitiveClass(JType type, const char* descriptor) {
+  Class* klass = Heap::AllocClass();
+  CHECK(klass != NULL);
+  klass->super_class_ = java_lang_Class_;
+  klass->access_flags_ = kAccPublic | kAccFinal | kAccAbstract;
+  klass->descriptor_ = descriptor;
+  klass->status_ = Class::kStatusInitialized;
+  return klass;
+}
 
-Class* ClassLinker::FindPrimitiveClass(const char* descriptor) {
-  return NULL;  // TODO
+Class* ClassLinker::FindPrimitiveClass(JType type) {
+  switch (type) {
+    case kTypeByte:
+      CHECK(primitive_byte_ != NULL);
+      return primitive_byte_;
+    case kTypeChar:
+      CHECK(primitive_char_ != NULL);
+      return primitive_char_;
+    case kTypeDouble:
+      CHECK(primitive_double_ != NULL);
+      return primitive_double_;
+    case kTypeFloat:
+      CHECK(primitive_float_ != NULL);
+      return primitive_float_;
+    case kTypeInt:
+      CHECK(primitive_int_ != NULL);
+      return primitive_int_;
+    case kTypeLong:
+      CHECK(primitive_long_ != NULL);
+      return primitive_long_;
+    case kTypeShort:
+      CHECK(primitive_short_ != NULL);
+      return primitive_short_;
+    case kTypeBoolean:
+      CHECK(primitive_boolean_ != NULL);
+      return primitive_boolean_;
+    case kTypeVoid:
+      CHECK(primitive_void_ != NULL);
+      return primitive_void_;
+    default:
+      LOG(FATAL) << "Unknown primitive type " << static_cast<int>(type);
+  };
+  return NULL;  // Not reachable.
 }
 
 bool ClassLinker::InsertClass(Class* klass) {
@@ -445,9 +509,10 @@
   // TODO: store interfaces_idx in the Class object
   // TODO: move this outside of link interfaces
   if (klass->interface_count_ > 0) {
+    size_t length = klass->interface_count_ * sizeof(klass->interfaces_[0]);
     interfaces_idx.reset(new uint32_t[klass->interface_count_]);
-    memcpy(interfaces_idx.get(), klass->interfaces_, klass->interface_count_);
-    memset(klass->interfaces_, 0, klass->interface_count_);
+    memcpy(interfaces_idx.get(), klass->interfaces_, length);
+    memset(klass->interfaces_, 0xFF, length);
   }
   // Mark the class as loaded.
   klass->status_ = Class::kStatusLoaded;
@@ -517,7 +582,7 @@
       LG << "Too many methods on interface";  // TODO: VirtualMachineError
       return false;
     }
-    for (size_t i = 0; i < count; ++count) {
+    for (size_t i = 0; i < count; ++i) {
       klass->GetVirtualMethod(i)->method_index_ = i;
     }
   } else {
@@ -580,7 +645,7 @@
     if (actual_count < max_count) {
       Method** new_vtable = new Method*[actual_count];
       memcpy(new_vtable, klass->vtable_, actual_count * sizeof(Method*));
-      delete klass->vtable_;
+      delete[] klass->vtable_;
       klass->vtable_ = new_vtable;
       LG << "shrunk vtable: "
          << "was " << max_count << ", "
@@ -666,7 +731,7 @@
       int k;  // must be signed
       for (k = klass->vtable_count_ - 1; k >= 0; --k) {
         if (interface_method->HasSameNameAndPrototype(klass->vtable_[k])) {
-          if (klass->vtable_[k]->IsPublic()) {
+          if (!klass->vtable_[k]->IsPublic()) {
             LG << "Implementation not public";
             return false;
           }
@@ -916,7 +981,8 @@
   }
   const char* descriptor = dex_file->GetRaw()->dexStringByTypeIdx(class_idx);
   if (descriptor[0] != '\0' && descriptor[1] == '\0') {
-    resolved = FindPrimitiveClass(descriptor);
+    JType type = static_cast<JType>(descriptor[0]);
+    resolved = FindPrimitiveClass(type);
   } else {
     resolved = FindClass(descriptor, referrer->GetClassLoader(), NULL);
   }
diff --git a/src/class_linker.h b/src/class_linker.h
index fec3cb1..89fd8f7 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -18,12 +18,19 @@
   ClassLinker() {}
   ~ClassLinker() {}
 
+  // Initializes the class linker.
+  void Init();
+
   // Finds a class by its descriptor name.
   Class* FindClass(const char* descriptor,
                    Object* class_loader,
                    DexFile* dex_file);
 
-  Class* FindPrimitiveClass(const char* descriptor);
+  Class* FindSystemClass(const char* descriptor) {
+    return FindClass(descriptor, NULL, NULL);
+  }
+
+  Class* FindPrimitiveClass(JType type);
 
   bool InitializeClass(Class* klass);
 
@@ -38,6 +45,8 @@
   void AppendToClassPath(DexFile* dex_file);
 
  private:
+  Class* CreatePrimitiveClass(JType type, const char* descriptor);
+
   // Inserts a class into the class table.  Returns true if the class
   // was inserted.
   bool InsertClass(Class* klass);
@@ -85,6 +94,18 @@
 
   // TODO: classpath
 
+  Class* primitive_boolean_;
+  Class* primitive_char_;
+  Class* primitive_float_;
+  Class* primitive_double_;
+  Class* primitive_byte_;
+  Class* primitive_short_;
+  Class* primitive_int_;
+  Class* primitive_long_;
+  Class* primitive_void_;
+
+  Class* java_lang_Class_;
+
   DISALLOW_COPY_AND_ASSIGN(ClassLinker);
 };
 
diff --git a/src/dex_file.cc b/src/dex_file.cc
index fcde266..c9604a1 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -49,27 +49,23 @@
   fields_ = new Field*[num_fields_]();
 }
 
-Class* DexFile::LoadClass(const char* descriptor) {
+bool DexFile::LoadClass(const char* descriptor, Class* klass) {
   const RawDexFile::ClassDef* class_def = raw_->FindClassDef(descriptor);
   if (class_def == NULL) {
-    return NULL;
+    return false;
   } else {
-    return LoadClass(*class_def);
+    return LoadClass(*class_def, klass);
   }
 }
 
-Class* DexFile::LoadClass(const RawDexFile::ClassDef& class_def) {
+bool DexFile::LoadClass(const RawDexFile::ClassDef& class_def, Class* klass) {
+  CHECK(klass != NULL);
   const byte* class_data = raw_->GetClassData(class_def);
   RawDexFile::ClassDataHeader header = raw_->ReadClassDataHeader(&class_data);
 
   const char* descriptor = raw_->GetClassDescriptor(class_def);
   CHECK(descriptor != NULL);
 
-  // Allocate storage for the new class object.
-  size_t size = Class::Size(header.static_fields_size_);
-  Class* klass = Heap::AllocClass(size);
-  CHECK(klass != NULL);  // TODO: throw an OOME
-
   klass->klass_ = NULL;  // TODO
   klass->descriptor_.set(descriptor);
   klass->descriptor_alloc_ = NULL;
@@ -94,6 +90,8 @@
 
   // Load static fields.
   if (klass->num_sfields_ != 0) {
+    // TODO: allocate on the object heap.
+    klass->sfields_ = new StaticField[klass->NumStaticFields()]();
     uint32_t last_idx = 0;
     for (size_t i = 0; i < klass->num_sfields_; ++i) {
       RawDexFile::Field raw_field;
@@ -104,7 +102,7 @@
 
   // Load instance fields.
   if (klass->NumInstanceFields() != 0) {
-    // TODO: append instance fields to class object
+    // TODO: allocate on the object heap.
     klass->ifields_ = new InstanceField[klass->NumInstanceFields()]();
     uint32_t last_idx = 0;
     for (size_t i = 0; i < klass->NumInstanceFields(); ++i) {
@@ -148,7 +146,8 @@
   const RawDexFile::TypeList* list = raw_->GetInterfacesList(class_def);
   if (list != NULL) {
     klass->interface_count_ = list->Size();
-    klass->interfaces_ = new Class*[list->Size()];
+    // TODO: allocate the interfaces array on the object heap.
+    klass->interfaces_ = new Class*[list->Size()]();
     for (size_t i = 0; i < list->Size(); ++i) {
       const RawDexFile::TypeItem& type_item = list->GetTypeItem(i);
       klass->interfaces_[i] = reinterpret_cast<Class*>(type_item.type_idx_);
diff --git a/src/dex_file.h b/src/dex_file.h
index ae5101a..8463672 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -40,9 +40,9 @@
     return num_methods_;
   }
 
-  Class* LoadClass(const char* descriptor);
+  bool LoadClass(const char* descriptor, Class* klass);
 
-  Class* LoadClass(const RawDexFile::ClassDef& class_def);
+  bool LoadClass(const RawDexFile::ClassDef& class_def, Class* klass);
 
   bool HasClass(const char* descriptor) {
     return raw_->FindClassDef(descriptor) != NULL;
@@ -53,18 +53,22 @@
   }
 
   String* GetResolvedString(uint32_t string_idx) const {
+    CHECK_LT(string_idx, num_strings_);
     return strings_[string_idx];
   }
 
   void SetResolvedString(String* resolved, uint32_t string_idx) {
+    CHECK_LT(string_idx, num_strings_);
     strings_[string_idx] = resolved;
   }
 
   Class* GetResolvedClass(uint32_t class_idx) const {
+    CHECK_LT(class_idx, num_classes_);
     return classes_[class_idx];
   }
 
   void SetResolvedClass(Class* resolved, uint32_t class_idx) {
+    CHECK_LT(class_idx, num_classes_);
     classes_[class_idx] = resolved;
   }
 
diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc
index ea42519..ccac396 100644
--- a/src/dex_file_test.cc
+++ b/src/dex_file_test.cc
@@ -40,16 +40,18 @@
   scoped_ptr<DexFile> dex(DexFile::OpenBase64(kNestedDex));
   ASSERT_TRUE(dex != NULL);
 
-  Class* klass = dex->LoadClass("NoSuchClass");
-  ASSERT_TRUE(klass == NULL);
+  scoped_ptr<Class> klass(reinterpret_cast<Class*>(new byte[sizeof(Class)]));
+  bool result = dex->LoadClass("NoSuchClass", klass.get());
+  ASSERT_FALSE(result);
 }
 
 TEST(DexFile, Load) {
   scoped_ptr<DexFile> dex(DexFile::OpenBase64(kNestedDex));
   ASSERT_TRUE(dex != NULL);
 
-  Class* klass = dex->LoadClass("LNested;");
-  ASSERT_TRUE(klass != NULL);
+  scoped_ptr<Class> klass(reinterpret_cast<Class*>(new byte[sizeof(Class)]));
+  bool result = dex->LoadClass("LNested;", klass.get());
+  ASSERT_TRUE(result);
 
   uint32_t vmeth = klass->NumVirtualMethods();
   EXPECT_EQ(vmeth, 0U);
diff --git a/src/heap.h b/src/heap.h
index c04a60f..d6b1649 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -11,8 +11,8 @@
 
 class Heap {
  public:
-  static Class* AllocClass(size_t size) {
-    byte* raw = new byte[size]();
+  static Class* AllocClass() {
+    byte* raw = new byte[sizeof(Class)]();
     return reinterpret_cast<Class*>(raw);
   }
 
diff --git a/src/object.cc b/src/object.cc
index a380b5a..7c28d76 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -57,7 +57,7 @@
 uint32_t Method::NumArgRegisters() {
   CHECK(shorty_ != NULL);
   uint32_t num_registers = 0;
-  for (size_t i = 1; shorty_[i] != '\0'; ++i) {
+  for (int i = 1; i < shorty_.length(); ++i) {
     char ch = shorty_[i];
     if (ch == 'D' || ch == 'J') {
       num_registers += 2;
diff --git a/src/object.h b/src/object.h
index 8252de1..2b75ff7 100644
--- a/src/object.h
+++ b/src/object.h
@@ -33,6 +33,20 @@
   Object* l;
 };
 
+enum JType {
+  kTypeByte = 'B',
+  kTypeChar = 'C',
+  kTypeDouble = 'D',
+  kTypeFloat = 'F',
+  kTypeInt = 'I',
+  kTypeLong = 'J',
+  kTypeShort = 'S',
+  kTypeBoolean = 'Z',
+  kTypeClass = 'L',
+  kTypeArray= '[',
+  kTypeVoid = 'V',
+};
+
 static const uint32_t kAccPublic = 0x0001; // class, field, method, ic
 static const uint32_t kAccPrivate = 0x0002; // field, method, ic
 static const uint32_t kAccProtected = 0x0004; // field, method, ic
@@ -275,7 +289,7 @@
   }
 
   void SetObject(Object* l) {
-    CHECK_EQ(GetType(), 'L');
+    CHECK(GetType() == 'L' || GetType() == '[');
     value_.l = l;
     // TODO: write barrier
   }
@@ -513,9 +527,9 @@
 
   // Returns the size in bytes of a class object instance with the
   // given number of static fields.
-  static size_t Size(size_t num_sfields) {
-    return OFFSETOF_MEMBER(Class, sfields_) + sizeof(StaticField) * num_sfields;
-  }
+  // static size_t Size(size_t num_sfields) {
+  //   return OFFSETOF_MEMBER(Class, sfields_) + sizeof(StaticField) * num_sfields;
+  // }
 
   // Returns the number of static, private, and constructor methods.
   size_t NumDirectMethods() const {
@@ -690,7 +704,7 @@
 
   // Static fields
   size_t num_sfields_;
-  StaticField sfields_[];  // MUST be last item
+  StaticField* sfields_;
 };
 
 class DataObject : public Object {
diff --git a/src/object_test.cc b/src/object_test.cc
index 7cbf086..6ce3570 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -53,8 +53,9 @@
   scoped_ptr<DexFile> dex_file(DexFile::OpenBase64(kProtoCompareDex));
   ASSERT_TRUE(dex_file != NULL);
 
-  Class* klass = dex_file->LoadClass("LProtoCompare;");
-  ASSERT_TRUE(klass != NULL);
+  scoped_ptr<Class> klass(reinterpret_cast<Class*>(new byte[sizeof(Class)]));
+  bool result = dex_file->LoadClass("LProtoCompare;", klass.get());
+  ASSERT_TRUE(result);
 
   ASSERT_EQ(4U, klass->NumVirtualMethods());
 
@@ -130,10 +131,12 @@
   scoped_ptr<DexFile> dex_file2(DexFile::OpenBase64(kProtoCompare2Dex));
   ASSERT_TRUE(dex_file2 != NULL);
 
-  Class* klass1 = dex_file1->LoadClass("LProtoCompare;");
-  ASSERT_TRUE(klass1 != NULL);
-  Class* klass2 = dex_file2->LoadClass("LProtoCompare2;");
-  ASSERT_TRUE(klass2 != NULL);
+  scoped_ptr<Class> klass1(reinterpret_cast<Class*>(new byte[sizeof(Class)]));
+  bool result1 = dex_file1->LoadClass("LProtoCompare;", klass1.get());
+  ASSERT_TRUE(result1);
+  scoped_ptr<Class> klass2(reinterpret_cast<Class*>(new byte[sizeof(Class)]));
+  bool result2 = dex_file2->LoadClass("LProtoCompare2;", klass2.get());
+  ASSERT_TRUE(result2);
 
   Method* m1_1 = klass1->GetVirtualMethod(0);
   ASSERT_STREQ("m1", m1_1->GetName().data());
diff --git a/src/raw_dex_file.h b/src/raw_dex_file.h
index afd65c2..db3d8a2 100644
--- a/src/raw_dex_file.h
+++ b/src/raw_dex_file.h
@@ -269,19 +269,23 @@
   // TODO: return a stream
   const byte* GetClassData(const ClassDef& class_def) const {
     if (class_def.class_data_off_ == 0) {
-      LG << "class_def.class_data_off_ == 0";
       return NULL;
+    } else {
+      return base_ + class_def.class_data_off_;
     }
-    return base_ + class_def.class_data_off_;
   }
 
   // Decodes the header section from the raw class data bytes.
   ClassDataHeader ReadClassDataHeader(const byte** class_data) {
+    CHECK(class_data != NULL);
     ClassDataHeader header;
-    header.static_fields_size_ = DecodeUnsignedLeb128(class_data);
-    header.instance_fields_size_ = DecodeUnsignedLeb128(class_data);
-    header.direct_methods_size_ = DecodeUnsignedLeb128(class_data);
-    header.virtual_methods_size_ = DecodeUnsignedLeb128(class_data);
+    memset(&header, 0, sizeof(ClassDataHeader));
+    if (*class_data != NULL) {
+      header.static_fields_size_ = DecodeUnsignedLeb128(class_data);
+      header.instance_fields_size_ = DecodeUnsignedLeb128(class_data);
+      header.direct_methods_size_ = DecodeUnsignedLeb128(class_data);
+      header.virtual_methods_size_ = DecodeUnsignedLeb128(class_data);
+    }
     return header;
   }