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;
}