Improved ClassLoader support
Change-Id: I587c0fa439c64a0c947641b01c072149f480bf85
diff --git a/build/Android.test.mk b/build/Android.test.mk
index 325f076..ba76f27 100644
--- a/build/Android.test.mk
+++ b/build/Android.test.mk
@@ -28,7 +28,7 @@
LOCAL_MODULE := $(notdir $(basename $(2:%.arm=%)))
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(2)
- LOCAL_CFLAGS := $(ART_CFLAGS)
+ LOCAL_CFLAGS := $(ART_CFLAGS) -UNDEBUG
LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
LOCAL_SHARED_LIBRARIES := libarttest libartd
ifeq ($(1),target)
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 78e2c31..0d7c1dc 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -49,13 +49,27 @@
Class* object_array_class = AllocClass(java_lang_Class);
CHECK(object_array_class != NULL);
- // string and char[] are necessary so that FindClass can assign names to members
+ // String and char[] are necessary so that FindClass can assign names to members
Class* java_lang_String = AllocClass(java_lang_Class);
CHECK(java_lang_String != NULL);
+ java_lang_String->descriptor_ = "Ljava/lang/String;";
+ CHECK_LT(java_lang_String->object_size_, sizeof(String));
java_lang_String->object_size_ = sizeof(String);
Class* char_array_class = AllocClass(java_lang_Class);
CHECK(char_array_class != NULL);
+ // Field and Method are necessary so that FindClass can link members
+ Class* java_lang_reflect_Field = AllocClass(java_lang_Class);
+ CHECK(java_lang_reflect_Field != NULL);
+ java_lang_reflect_Field->descriptor_ = "Ljava/lang/reflect/Field;";
+ CHECK_LT(java_lang_reflect_Field->object_size_, std::max(sizeof(StaticField), sizeof(InstanceField)));
+ java_lang_reflect_Field->object_size_ = std::max(sizeof(StaticField), sizeof(InstanceField));
+ Class* java_lang_reflect_Method = AllocClass(java_lang_Class);
+ java_lang_reflect_Method->descriptor_ = "Ljava/lang/reflect/Method;";
+ CHECK(java_lang_reflect_Method != NULL);
+ CHECK_LT(java_lang_reflect_Method->object_size_, sizeof(Method));
+ java_lang_reflect_Method->object_size_ = sizeof(Method);
+
// create storage for root classes, save away our work so far
class_roots_ = ObjectArray<Class>::Alloc(object_array_class, kClassRootsMax);
class_roots_->Set(kJavaLangClass, java_lang_Class);
@@ -63,48 +77,58 @@
class_roots_->Set(kObjectArrayClass, object_array_class);
class_roots_->Set(kJavaLangString, java_lang_String);
class_roots_->Set(kCharArrayClass, char_array_class);
+ class_roots_->Set(kJavaLangReflectField, java_lang_reflect_Field);
+ class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
// now that these are registered, we can use AllocClass() and AllocObjectArray
String::InitClasses(java_lang_String, char_array_class);
// Now AllocString* can be used
// setup boot_class_path_ now that we can use AllocObjectArray to
- // DexCache instances
+ // create DexCache instances
for (size_t i = 0; i != boot_class_path.size(); ++i) {
AppendToBootClassPath(boot_class_path[i]);
}
// now we can use FindSystemClass, at least for non-arrays classes.
- // run Object and Class to setup their dex_cache_ fields and register them in classes_.
+ // run Class, Field, and Method through FindSystemClass.
+ // this initializes their dex_cache_ fields and register them in classes_.
// we also override their object_size_ values to accommodate the extra C++ fields.
- Class* Object_class = FindSystemClass(java_lang_Object->GetDescriptor());
- CHECK_EQ(java_lang_Object, Object_class);
- CHECK_LE(java_lang_Object->object_size_, sizeof(Object));
- java_lang_Object->object_size_ = sizeof(Object);
Class* Class_class = FindSystemClass(java_lang_Class->GetDescriptor());
CHECK_EQ(java_lang_Class, Class_class);
- CHECK_LE(java_lang_Class->object_size_, sizeof(Class));
+ CHECK_LT(java_lang_Class->object_size_, sizeof(Class));
java_lang_Class->object_size_ = sizeof(Class);
-
- // set special sizes for these C++ extended classes (Field, Method, String).
- // we also remember them in class_roots_ to construct them within ClassLinker
- Class* java_lang_reflect_Field = FindSystemClass("Ljava/lang/reflect/Field;");
- CHECK(java_lang_reflect_Field != NULL);
- CHECK_LE(java_lang_reflect_Field->object_size_, std::max(sizeof(StaticField), sizeof(InstanceField)));
+ Class* Field_class = FindSystemClass(java_lang_reflect_Field->GetDescriptor());
+ CHECK_EQ(java_lang_reflect_Field, Field_class);
+ CHECK_LT(java_lang_reflect_Field->object_size_, std::max(sizeof(StaticField), sizeof(InstanceField)));
java_lang_reflect_Field->object_size_ = std::max(sizeof(StaticField), sizeof(InstanceField));
- class_roots_->Set(kJavaLangReflectField, java_lang_reflect_Field);
-
- Class* java_lang_reflect_Method = FindSystemClass("Ljava/lang/reflect/Method;");
- CHECK(java_lang_reflect_Method != NULL);
- CHECK_LE(java_lang_reflect_Method->object_size_, sizeof(Method));
+ Class* Method_class = FindSystemClass(java_lang_reflect_Method->GetDescriptor());
+ CHECK_EQ(java_lang_reflect_Method, Method_class);
+ CHECK_LT(java_lang_reflect_Method->object_size_, sizeof(Method));
java_lang_reflect_Method->object_size_ = sizeof(Method);
- class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
- Class* String_class = FindSystemClass("Ljava/lang/String;");
+ // Object and String just need more minimal setup, since they do not have extra C++ fields.
+ Class* Object_class = FindSystemClass(java_lang_Object->GetDescriptor());
+ CHECK_EQ(java_lang_Object, Object_class);
+ CHECK_EQ(java_lang_Object->object_size_, sizeof(Object));
+ Class* String_class = FindSystemClass(java_lang_String->GetDescriptor());
CHECK_EQ(java_lang_String, String_class);
CHECK_EQ(java_lang_String->object_size_, sizeof(String));
- java_lang_String->object_size_ = sizeof(String);
- class_roots_->Set(kJavaLangString, java_lang_String);
+
+ // Setup the ClassLoaders, adjusting the object_size_ as necessary
+ Class* java_lang_ClassLoader = FindSystemClass("Ljava/lang/ClassLoader;");
+ CHECK(java_lang_ClassLoader != NULL);
+ CHECK_LT(java_lang_ClassLoader->object_size_, sizeof(ClassLoader));
+ java_lang_ClassLoader->object_size_ = sizeof(ClassLoader);
+ class_roots_->Set(kJavaLangClassLoader, java_lang_ClassLoader);
+ Class* dalvik_system_BaseDexClassLoader = FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
+ CHECK(dalvik_system_BaseDexClassLoader != NULL);
+ CHECK_EQ(dalvik_system_BaseDexClassLoader->object_size_, sizeof(BaseDexClassLoader));
+ class_roots_->Set(kDalvikSystemBaseDexClassLoader, dalvik_system_BaseDexClassLoader);
+ Class* dalvik_system_PathClassLoader = FindSystemClass("Ldalvik/system/PathClassLoader;");
+ CHECK(dalvik_system_PathClassLoader != NULL);
+ CHECK_EQ(dalvik_system_PathClassLoader->object_size_, sizeof(PathClassLoader));
+ class_roots_->Set(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
// Setup a single, global copy of "interfaces" and "iftable" for
// reuse across array classes
@@ -154,7 +178,7 @@
// ensure all class_roots_ were initialized
for (size_t i = 0; i < kClassRootsMax; i++) {
- CHECK(class_roots_->Get(i) != NULL);
+ CHECK(GetClassRoot(static_cast<ClassRoot>(i)));
}
// disable the slow paths in FindClass and CreatePrimitiveClass now
@@ -188,27 +212,38 @@
}
Class* ClassLinker::AllocClass() {
- return AllocClass(class_roots_->Get(kJavaLangClass));
+ return AllocClass(GetClassRoot(kJavaLangClass));
}
StaticField* ClassLinker::AllocStaticField() {
- return down_cast<StaticField*>(Heap::AllocObject(class_roots_->Get(kJavaLangReflectField),
- sizeof(StaticField)));
+ return down_cast<StaticField*>(Object::Alloc(GetClassRoot(kJavaLangReflectField)));
}
InstanceField* ClassLinker::AllocInstanceField() {
- return down_cast<InstanceField*>(Heap::AllocObject(class_roots_->Get(kJavaLangReflectField),
- sizeof(InstanceField)));
+ return down_cast<InstanceField*>(Object::Alloc(GetClassRoot(kJavaLangReflectField)));
}
Method* ClassLinker::AllocMethod() {
- return down_cast<Method*>(Heap::AllocObject(class_roots_->Get(kJavaLangReflectMethod),
- sizeof(Method)));
+ return down_cast<Method*>(Object::Alloc(GetClassRoot(kJavaLangReflectMethod)));
+}
+
+// TODO remove once we can use java.lang.Class.getSystemClassLoader
+PathClassLoader* ClassLinker::AllocPathClassLoader(std::vector<const DexFile*> dex_files) {
+ PathClassLoader* cl = down_cast<PathClassLoader*>(Object::Alloc(GetClassRoot(kDalvikSystemPathClassLoader)));
+ cl->SetClassPath(dex_files);
+ return cl;
}
Class* ClassLinker::FindClass(const StringPiece& descriptor,
- Object* class_loader,
- const DexFile* dex_file) {
+ ClassLoader* class_loader) {
+ // TODO remove this contrived parent class loader check when we have a real ClassLoader.
+ if (class_loader != NULL) {
+ Class* klass = FindClass(descriptor, NULL);
+ if (klass != NULL) {
+ return klass;
+ }
+ }
+
Thread* self = Thread::Current();
DCHECK(self != NULL);
CHECK(!self->IsExceptionPending());
@@ -217,31 +252,30 @@
if (klass == NULL) {
// Class is not yet loaded.
if (descriptor[0] == '[') {
- return CreateArrayClass(descriptor, class_loader, dex_file);
+ return CreateArrayClass(descriptor, class_loader);
}
- ClassPathEntry pair;
- if (dex_file == NULL) {
- pair = FindInBootClassPath(descriptor);
- } else {
- pair.first = dex_file;
- pair.second = dex_file->FindClassDef(descriptor);
- }
+ DexFile::ClassPath& class_path = ((class_loader != NULL) ? class_loader->GetClassPath() : boot_class_path_);
+ DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_path);
if (pair.second == NULL) {
- LG << "Class " << descriptor << " not found"; // TODO: NoClassDefFoundError
+ LG << "Class " << descriptor << " not found in class loader " << class_loader; // TODO: NoClassDefFoundError
return NULL;
}
- const DexFile* dex_file = pair.first;
- const DexFile::ClassDef* dex_class_def = pair.second;
- DexCache* dex_cache = FindDexCache(dex_file);
+ const DexFile& dex_file = *pair.first;
+ const DexFile::ClassDef& dex_class_def = *pair.second;
+ DexCache* dex_cache = FindDexCache(pair.first);
// Load the class from the dex file.
if (!init_done_) {
// finish up init of hand crafted class_roots_
if (descriptor == "Ljava/lang/Object;") {
- klass = class_roots_->Get(kJavaLangObject);
+ klass = GetClassRoot(kJavaLangObject);
} else if (descriptor == "Ljava/lang/Class;") {
- klass = class_roots_->Get(kJavaLangClass);
+ klass = GetClassRoot(kJavaLangClass);
} else if (descriptor == "Ljava/lang/String;") {
- klass = class_roots_->Get(kJavaLangString);
+ klass = GetClassRoot(kJavaLangString);
+ } else if (descriptor == "Ljava/lang/reflect/Field;") {
+ klass = GetClassRoot(kJavaLangReflectField);
+ } else if (descriptor == "Ljava/lang/reflect/Method;") {
+ klass = GetClassRoot(kJavaLangReflectMethod);
} else {
klass = AllocClass();
}
@@ -249,7 +283,7 @@
klass = AllocClass();
}
klass->dex_cache_ = dex_cache;
- LoadClass(*dex_file, *dex_class_def, klass);
+ LoadClass(dex_file, dex_class_def, klass, class_loader);
// Check for a pending exception during load
if (self->IsExceptionPending()) {
// TODO: free native allocations in klass
@@ -259,7 +293,7 @@
ObjectLock lock(klass);
klass->clinit_thread_id_ = self->GetId();
// Add the newly loaded class to the loaded classes table.
- bool success = InsertClass(klass);
+ bool success = InsertClass(klass); // TODO just return collision
if (!success) {
// We may fail to insert if we raced with another thread.
klass->clinit_thread_id_ = 0;
@@ -267,13 +301,22 @@
klass = LookupClass(descriptor, class_loader);
CHECK(klass != NULL);
} else {
- // Link the class.
- if (!LinkClass(klass, dex_file)) {
+ // Finish loading (if necessary) by finding parents
+ if (!klass->IsLoaded() && !LoadSuperAndInterfaces(klass, dex_file)) {
+ // Loading failed.
+ // TODO: CHECK(self->IsExceptionPending());
+ lock.NotifyAll();
+ return NULL;
+ }
+ CHECK(klass->IsLoaded());
+ // Link the class (if necessary)
+ if (!klass->IsLinked() && !LinkClass(klass, dex_file)) {
// Linking failed.
// TODO: CHECK(self->IsExceptionPending());
lock.NotifyAll();
return NULL;
}
+ CHECK(klass->IsLinked());
}
}
}
@@ -295,26 +338,29 @@
return NULL;
}
// Return the loaded class. No exceptions should be pending.
+ CHECK(klass->IsLinked());
CHECK(!self->IsExceptionPending());
return klass;
}
void ClassLinker::LoadClass(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
- Class* klass) {
+ Class* klass,
+ ClassLoader* class_loader) {
CHECK(klass != NULL);
CHECK(klass->dex_cache_ != NULL);
+ CHECK_EQ(Class::kStatusNotReady, klass->status_);
const byte* class_data = dex_file.GetClassData(dex_class_def);
DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
CHECK(descriptor != NULL);
- klass->klass_ = class_roots_->Get(kJavaLangClass);
+ klass->klass_ = GetClassRoot(kJavaLangClass);
klass->descriptor_.set(descriptor);
klass->descriptor_alloc_ = NULL;
klass->access_flags_ = dex_class_def.access_flags_;
- klass->class_loader_ = NULL; // TODO
+ klass->class_loader_ = class_loader;
klass->primitive_type_ = Class::kPrimNot;
klass->status_ = Class::kStatusIdx;
@@ -415,7 +461,7 @@
Field* dst) {
const DexFile::FieldId& field_id = dex_file.GetFieldId(src.field_idx_);
dst->klass_ = klass;
- dst->java_name_ = ResolveString(klass, field_id.name_idx_);
+ dst->java_name_ = ResolveString(klass, field_id.name_idx_, dex_file);
dst->descriptor_.set(dex_file.dexStringByTypeIdx(field_id.type_idx_));
dst->access_flags_ = src.access_flags_;
}
@@ -426,7 +472,7 @@
Method* dst) {
const DexFile::MethodId& method_id = dex_file.GetMethodId(src.method_idx_);
dst->klass_ = klass;
- dst->java_name_ = ResolveString(klass, method_id.name_idx_);
+ dst->java_name_ = ResolveString(klass, method_id.name_idx_, dex_file);
{
int32_t utf16_length;
scoped_ptr<char> utf8(dex_file.CreateMethodDescriptor(method_id.proto_idx_,
@@ -455,17 +501,6 @@
}
}
-ClassLinker::ClassPathEntry ClassLinker::FindInBootClassPath(const StringPiece& descriptor) {
- for (size_t i = 0; i != boot_class_path_.size(); ++i) {
- const DexFile* dex_file = boot_class_path_[i];
- const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
- if (dex_class_def != NULL) {
- return ClassPathEntry(dex_file, dex_class_def);
- }
- }
- return ClassPathEntry(NULL, NULL);
-}
-
void ClassLinker::AppendToBootClassPath(DexFile* dex_file) {
CHECK(dex_file != NULL);
boot_class_path_.push_back(dex_file);
@@ -484,19 +519,17 @@
dex_caches_.push_back(dex_cache);
}
-const DexFile* ClassLinker::FindDexFile(const DexCache* dex_cache) const {
- CHECK(dex_cache != NULL);
+const DexFile& ClassLinker::FindDexFile(const DexCache* dex_cache) const {
for (size_t i = 0; i != dex_caches_.size(); ++i) {
if (dex_caches_[i] == dex_cache) {
- return dex_files_[i];
+ return *dex_files_[i];
}
}
CHECK(false) << "Could not find DexFile";
- return NULL;
+ return *dex_files_[-1];
}
DexCache* ClassLinker::FindDexCache(const DexFile* dex_file) const {
- CHECK(dex_file != NULL);
for (size_t i = 0; i != dex_files_.size(); ++i) {
if (dex_files_[i] == dex_file) {
return dex_caches_[i];
@@ -533,178 +566,166 @@
//
// Returns NULL with an exception raised on failure.
Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor,
- Object* class_loader,
- const DexFile* dex_file)
+ ClassLoader* class_loader)
{
- CHECK(descriptor[0] == '[');
+ CHECK(descriptor[0] == '[');
- // Identify the underlying element class and the array dimension depth.
- Class* component_type_ = NULL;
- int array_rank;
- if (descriptor[1] == '[') {
- // array of arrays; keep descriptor and grab stuff from parent
- Class* outer = FindClass(descriptor.substr(1), class_loader, dex_file);
- if (outer != NULL) {
- // want the base class, not "outer", in our component_type_
- component_type_ = outer->component_type_;
- array_rank = outer->array_rank_ + 1;
- } else {
- DCHECK(component_type_ == NULL); // make sure we fail
- }
+ // Identify the underlying element class and the array dimension depth.
+ Class* component_type_ = NULL;
+ int array_rank;
+ if (descriptor[1] == '[') {
+ // array of arrays; keep descriptor and grab stuff from parent
+ Class* outer = FindClass(descriptor.substr(1), class_loader);
+ if (outer != NULL) {
+ // want the base class, not "outer", in our component_type_
+ component_type_ = outer->component_type_;
+ array_rank = outer->array_rank_ + 1;
} else {
- array_rank = 1;
- if (descriptor[1] == 'L') {
- // array of objects; strip off "[" and look up descriptor.
- const StringPiece subDescriptor = descriptor.substr(1);
- component_type_ = FindClass(subDescriptor, class_loader, dex_file);
- } else {
- // array of a primitive type
- component_type_ = FindPrimitiveClass(descriptor[1]);
- }
+ DCHECK(component_type_ == NULL); // make sure we fail
}
-
- if (component_type_ == NULL) {
- // failed
- // DCHECK(Thread::Current()->IsExceptionPending()); // TODO
- return NULL;
+ } else {
+ array_rank = 1;
+ if (descriptor[1] == 'L') {
+ // array of objects; strip off "[" and look up descriptor.
+ const StringPiece subDescriptor = descriptor.substr(1);
+ component_type_ = FindClass(subDescriptor, class_loader);
+ } else {
+ // array of a primitive type
+ component_type_ = FindPrimitiveClass(descriptor[1]);
}
+ }
- // See if the component type is already loaded. Array classes are
- // always associated with the class loader of their underlying
- // element type -- an array of Strings goes with the loader for
- // java/lang/String -- so we need to look for it there. (The
- // caller should have checked for the existence of the class
- // before calling here, but they did so with *their* class loader,
- // not the component type's loader.)
- //
- // If we find it, the caller adds "loader" to the class' initiating
- // loader list, which should prevent us from going through this again.
- //
- // This call is unnecessary if "loader" and "component_type_->class_loader_"
- // are the same, because our caller (FindClass) just did the
- // lookup. (Even if we get this wrong we still have correct behavior,
- // because we effectively do this lookup again when we add the new
- // class to the hash table --- necessary because of possible races with
- // other threads.)
- if (class_loader != component_type_->class_loader_) {
- Class* new_class = LookupClass(descriptor, component_type_->class_loader_);
- if (new_class != NULL) {
- return new_class;
- }
- }
+ if (component_type_ == NULL) {
+ // failed
+ // DCHECK(Thread::Current()->IsExceptionPending()); // TODO
+ return NULL;
+ }
- // Fill out the fields in the Class.
- //
- // It is possible to execute some methods against arrays, because
- // all arrays are subclasses of java_lang_Object_, so we need to set
- // up a vtable. We can just point at the one in java_lang_Object_.
- //
- // Array classes are simple enough that we don't need to do a full
- // link step.
-
- Class* new_class = NULL;
- if (!init_done_) {
- if (descriptor == "[Ljava/lang/Object;") {
- new_class = class_roots_->Get(kObjectArrayClass);
- CHECK(new_class);
- } else if (descriptor == "[C") {
- new_class = class_roots_->Get(kCharArrayClass);
- CHECK(new_class);
- }
- }
- if (new_class == NULL) {
- new_class = AllocClass();
- if (new_class == NULL) {
- return NULL;
- }
- }
- new_class->descriptor_alloc_ = new std::string(descriptor.data(),
- descriptor.size());
- new_class->descriptor_.set(new_class->descriptor_alloc_->data(),
- new_class->descriptor_alloc_->size());
- Class* java_lang_Object = class_roots_->Get(kJavaLangObject);
- new_class->super_class_ = java_lang_Object;
- new_class->vtable_ = java_lang_Object->vtable_;
- new_class->primitive_type_ = Class::kPrimNot;
- new_class->component_type_ = component_type_;
- new_class->class_loader_ = component_type_->class_loader_;
- new_class->array_rank_ = array_rank;
- new_class->status_ = Class::kStatusInitialized;
- // don't need to set new_class->object_size_
-
-
- // All arrays have java/lang/Cloneable and java/io/Serializable as
- // interfaces. We need to set that up here, so that stuff like
- // "instanceof" works right.
- //
- // Note: The GC could run during the call to FindSystemClass,
- // so we need to make sure the class object is GC-valid while we're in
- // there. Do this by clearing the interface list so the GC will just
- // think that the entries are null.
-
-
- // Use the single, global copies of "interfaces" and "iftable"
- // (remember not to free them for arrays).
- DCHECK(array_interfaces_ != NULL);
- new_class->interfaces_ = array_interfaces_;
- new_class->iftable_count_ = 2;
- DCHECK(array_iftable_ != NULL);
- new_class->iftable_ = array_iftable_;
-
- // Inherit access flags from the component type. Arrays can't be
- // used as a superclass or interface, so we want to add "final"
- // and remove "interface".
- //
- // Don't inherit any non-standard flags (e.g., kAccFinal)
- // from component_type_. We assume that the array class does not
- // override finalize().
- new_class->access_flags_ = ((new_class->component_type_->access_flags_ &
- ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask;
-
- if (InsertClass(new_class)) {
+ // See if the component type is already loaded. Array classes are
+ // always associated with the class loader of their underlying
+ // element type -- an array of Strings goes with the loader for
+ // java/lang/String -- so we need to look for it there. (The
+ // caller should have checked for the existence of the class
+ // before calling here, but they did so with *their* class loader,
+ // not the component type's loader.)
+ //
+ // If we find it, the caller adds "loader" to the class' initiating
+ // loader list, which should prevent us from going through this again.
+ //
+ // This call is unnecessary if "loader" and "component_type_->class_loader_"
+ // are the same, because our caller (FindClass) just did the
+ // lookup. (Even if we get this wrong we still have correct behavior,
+ // because we effectively do this lookup again when we add the new
+ // class to the hash table --- necessary because of possible races with
+ // other threads.)
+ if (class_loader != component_type_->class_loader_) {
+ Class* new_class = LookupClass(descriptor, component_type_->class_loader_);
+ if (new_class != NULL) {
return new_class;
}
- // Another thread must have loaded the class after we
- // started but before we finished. Abandon what we've
- // done.
- //
- // (Yes, this happens.)
+ }
- // Grab the winning class.
- Class* other_class = LookupClass(descriptor, component_type_->class_loader_);
- DCHECK(other_class != NULL);
- return other_class;
+ // Fill out the fields in the Class.
+ //
+ // It is possible to execute some methods against arrays, because
+ // all arrays are subclasses of java_lang_Object_, so we need to set
+ // up a vtable. We can just point at the one in java_lang_Object_.
+ //
+ // Array classes are simple enough that we don't need to do a full
+ // link step.
+
+ Class* new_class = NULL;
+ if (!init_done_) {
+ if (descriptor == "[Ljava/lang/Object;") {
+ new_class = GetClassRoot(kObjectArrayClass);
+ } else if (descriptor == "[C") {
+ new_class = GetClassRoot(kCharArrayClass);
+ }
+ }
+ if (new_class == NULL) {
+ new_class = AllocClass();
+ if (new_class == NULL) {
+ return NULL;
+ }
+ }
+ new_class->descriptor_alloc_ = new std::string(descriptor.data(),
+ descriptor.size());
+ new_class->descriptor_.set(new_class->descriptor_alloc_->data(),
+ new_class->descriptor_alloc_->size());
+ Class* java_lang_Object = GetClassRoot(kJavaLangObject);
+ new_class->super_class_ = java_lang_Object;
+ new_class->vtable_ = java_lang_Object->vtable_;
+ new_class->primitive_type_ = Class::kPrimNot;
+ new_class->component_type_ = component_type_;
+ new_class->class_loader_ = component_type_->class_loader_;
+ new_class->array_rank_ = array_rank;
+ new_class->status_ = Class::kStatusInitialized;
+ // don't need to set new_class->object_size_
+
+
+ // All arrays have java/lang/Cloneable and java/io/Serializable as
+ // interfaces. We need to set that up here, so that stuff like
+ // "instanceof" works right.
+ //
+ // Note: The GC could run during the call to FindSystemClass,
+ // so we need to make sure the class object is GC-valid while we're in
+ // there. Do this by clearing the interface list so the GC will just
+ // think that the entries are null.
+
+
+ // Use the single, global copies of "interfaces" and "iftable"
+ // (remember not to free them for arrays).
+ DCHECK(array_interfaces_ != NULL);
+ new_class->interfaces_ = array_interfaces_;
+ new_class->iftable_count_ = 2;
+ DCHECK(array_iftable_ != NULL);
+ new_class->iftable_ = array_iftable_;
+
+ // Inherit access flags from the component type. Arrays can't be
+ // used as a superclass or interface, so we want to add "final"
+ // and remove "interface".
+ //
+ // Don't inherit any non-standard flags (e.g., kAccFinal)
+ // from component_type_. We assume that the array class does not
+ // override finalize().
+ new_class->access_flags_ = ((new_class->component_type_->access_flags_ &
+ ~kAccInterface) | kAccFinal) & kAccJavaFlagsMask;
+
+ if (InsertClass(new_class)) {
+ return new_class;
+ }
+ // Another thread must have loaded the class after we
+ // started but before we finished. Abandon what we've
+ // done.
+ //
+ // (Yes, this happens.)
+
+ // Grab the winning class.
+ Class* other_class = LookupClass(descriptor, component_type_->class_loader_);
+ DCHECK(other_class != NULL);
+ return other_class;
}
Class* ClassLinker::FindPrimitiveClass(char type) {
switch (type) {
case 'B':
- DCHECK(class_roots_->Get(kPrimitiveByte) != NULL);
- return class_roots_->Get(kPrimitiveByte);
+ return GetClassRoot(kPrimitiveByte);
case 'C':
- DCHECK(class_roots_->Get(kPrimitiveChar) != NULL);
- return class_roots_->Get(kPrimitiveChar);
+ return GetClassRoot(kPrimitiveChar);
case 'D':
- DCHECK(class_roots_->Get(kPrimitiveDouble) != NULL);
- return class_roots_->Get(kPrimitiveDouble);
+ return GetClassRoot(kPrimitiveDouble);
case 'F':
- DCHECK(class_roots_->Get(kPrimitiveFloat) != NULL);
- return class_roots_->Get(kPrimitiveFloat);
+ return GetClassRoot(kPrimitiveFloat);
case 'I':
- DCHECK(class_roots_->Get(kPrimitiveInt) != NULL);
- return class_roots_->Get(kPrimitiveInt);
+ return GetClassRoot(kPrimitiveInt);
case 'J':
- DCHECK(class_roots_->Get(kPrimitiveLong) != NULL);
- return class_roots_->Get(kPrimitiveLong);
+ return GetClassRoot(kPrimitiveLong);
case 'S':
- DCHECK(class_roots_->Get(kPrimitiveShort) != NULL);
- return class_roots_->Get(kPrimitiveShort);
+ return GetClassRoot(kPrimitiveShort);
case 'Z':
- DCHECK(class_roots_->Get(kPrimitiveBoolean) != NULL);
- return class_roots_->Get(kPrimitiveBoolean);
+ return GetClassRoot(kPrimitiveBoolean);
case 'V':
- DCHECK(class_roots_->Get(kPrimitiveVoid) != NULL);
- return class_roots_->Get(kPrimitiveVoid);
+ return GetClassRoot(kPrimitiveVoid);
case 'L':
case '[':
LOG(ERROR) << "Not a primitive type " << static_cast<int>(type);
@@ -717,20 +738,22 @@
bool ClassLinker::InsertClass(Class* klass) {
// TODO: acquire classes_lock_
const StringPiece& key = klass->GetDescriptor();
- bool success = classes_.insert(std::make_pair(key, klass)).second;
+ Table::iterator it = classes_.insert(std::make_pair(key, klass));
+ return ((*it).second == klass);
// TODO: release classes_lock_
- return success;
}
-Class* ClassLinker::LookupClass(const StringPiece& descriptor, Object* class_loader) {
+Class* ClassLinker::LookupClass(const StringPiece& descriptor, ClassLoader* class_loader) {
// TODO: acquire classes_lock_
- Table::iterator it = classes_.find(descriptor);
- // TODO: release classes_lock_
- if (it == classes_.end()) {
- return NULL;
- } else {
- return (*it).second;
+ typedef Table::const_iterator It; // TODO: C++0x auto
+ for (It it = classes_.find(descriptor), end = classes_.end(); it != end; ++it) {
+ Class* klass = it->second;
+ if (klass->descriptor_ == descriptor && klass->class_loader_ == class_loader) {
+ return klass;
+ }
}
+ return NULL;
+ // TODO: release classes_lock_
}
bool ClassLinker::InitializeClass(Class* klass) {
@@ -887,10 +910,10 @@
bool ClassLinker::HasSameMethodDescriptorClasses(const Method* method,
const Class* klass1,
const Class* klass2) {
- const DexFile* dex_file = FindDexFile(method->GetClass()->GetDexCache());
- const DexFile::ProtoId& proto_id = dex_file->GetProtoId(method->proto_idx_);
+ const DexFile& dex_file = FindDexFile(method->GetClass()->GetDexCache());
+ const DexFile::ProtoId& proto_id = dex_file.GetProtoId(method->proto_idx_);
DexFile::ParameterIterator *it;
- for (it = dex_file->GetParameterIterator(proto_id); it->HasNext(); it->Next()) {
+ for (it = dex_file.GetParameterIterator(proto_id); it->HasNext(); it->Next()) {
const char* descriptor = it->GetDescriptor();
if (descriptor == NULL) {
break;
@@ -903,7 +926,7 @@
}
}
// Check the return type
- const char* descriptor = dex_file->GetReturnTypeDescriptor(proto_id);
+ const char* descriptor = dex_file.GetReturnTypeDescriptor(proto_id);
if (descriptor[0] == 'L' || descriptor[0] == '[') {
if (HasSameDescriptorClasses(descriptor, klass1, klass2)) {
return false;
@@ -939,14 +962,14 @@
}
bool ClassLinker::HasSameArgumentTypes(const Method* m1, const Method* m2) const {
- const DexFile* dex1 = FindDexFile(m1->GetClass()->GetDexCache());
- const DexFile* dex2 = FindDexFile(m2->GetClass()->GetDexCache());
- const DexFile::ProtoId& proto1 = dex1->GetProtoId(m1->proto_idx_);
- const DexFile::ProtoId& proto2 = dex2->GetProtoId(m2->proto_idx_);
+ const DexFile& dex1 = FindDexFile(m1->GetClass()->GetDexCache());
+ const DexFile& dex2 = FindDexFile(m2->GetClass()->GetDexCache());
+ const DexFile::ProtoId& proto1 = dex1.GetProtoId(m1->proto_idx_);
+ const DexFile::ProtoId& proto2 = dex2.GetProtoId(m2->proto_idx_);
// TODO: compare ProtoId objects for equality and exit early
- const DexFile::TypeList* type_list1 = dex1->GetProtoParameters(proto1);
- const DexFile::TypeList* type_list2 = dex2->GetProtoParameters(proto2);
+ const DexFile::TypeList* type_list1 = dex1.GetProtoParameters(proto1);
+ const DexFile::TypeList* type_list2 = dex2.GetProtoParameters(proto2);
size_t arity1 = (type_list1 == NULL) ? 0 : type_list1->Size();
size_t arity2 = (type_list2 == NULL) ? 0 : type_list2->Size();
if (arity1 != arity2) {
@@ -956,8 +979,8 @@
for (size_t i = 0; i < arity1; ++i) {
uint32_t type_idx1 = type_list1->GetTypeItem(i).type_idx_;
uint32_t type_idx2 = type_list2->GetTypeItem(i).type_idx_;
- const char* type1 = dex1->dexStringByTypeIdx(type_idx1);
- const char* type2 = dex2->dexStringByTypeIdx(type_idx2);
+ const char* type1 = dex1.dexStringByTypeIdx(type_idx1);
+ const char* type2 = dex2.dexStringByTypeIdx(type_idx2);
if (strcmp(type1, type2) != 0) {
return false;
}
@@ -967,12 +990,12 @@
}
bool ClassLinker::HasSameReturnType(const Method* m1, const Method* m2) const {
- const DexFile* dex1 = FindDexFile(m1->GetClass()->GetDexCache());
- const DexFile* dex2 = FindDexFile(m2->GetClass()->GetDexCache());
- const DexFile::ProtoId& proto1 = dex1->GetProtoId(m1->proto_idx_);
- const DexFile::ProtoId& proto2 = dex2->GetProtoId(m2->proto_idx_);
- const char* type1 = dex1->dexStringByTypeIdx(proto1.return_type_idx_);
- const char* type2 = dex2->dexStringByTypeIdx(proto2.return_type_idx_);
+ const DexFile& dex1 = FindDexFile(m1->GetClass()->GetDexCache());
+ const DexFile& dex2 = FindDexFile(m2->GetClass()->GetDexCache());
+ const DexFile::ProtoId& proto1 = dex1.GetProtoId(m1->proto_idx_);
+ const DexFile::ProtoId& proto2 = dex2.GetProtoId(m2->proto_idx_);
+ const char* type1 = dex1.dexStringByTypeIdx(proto1.return_type_idx_);
+ const char* type2 = dex2.dexStringByTypeIdx(proto2.return_type_idx_);
return (strcmp(type1, type2) == 0);
}
@@ -1007,15 +1030,15 @@
return;
}
const StringPiece& descriptor = klass->GetDescriptor();
- const DexFile* dex_file = FindDexFile(dex_cache);
- const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor);
CHECK(dex_class_def != NULL);
- const byte* addr = dex_file->GetEncodedArray(*dex_class_def);
+ const byte* addr = dex_file.GetEncodedArray(*dex_class_def);
size_t array_size = DecodeUnsignedLeb128(&addr);
for (size_t i = 0; i < array_size; ++i) {
StaticField* field = klass->GetStaticField(i);
JValue value;
- DexFile::ValueType type = dex_file->ReadEncodedValue(&addr, &value);
+ DexFile::ValueType type = dex_file.ReadEncodedValue(&addr, &value);
switch (type) {
case DexFile::kByte:
field->SetByte(value.b);
@@ -1040,7 +1063,7 @@
break;
case DexFile::kString: {
uint32_t string_idx = value.i;
- String* resolved = ResolveString(klass, string_idx);
+ String* resolved = ResolveString(klass, string_idx, dex_file);
field->SetObject(resolved);
break;
}
@@ -1056,14 +1079,8 @@
}
}
-bool ClassLinker::LinkClass(Class* klass, const DexFile* dex_file) {
- CHECK(klass->status_ == Class::kStatusIdx ||
- klass->status_ == Class::kStatusLoaded);
- if (klass->status_ == Class::kStatusIdx) {
- if (!LinkInterfaces(klass, dex_file)) {
- return false;
- }
- }
+bool ClassLinker::LinkClass(Class* klass, const DexFile& dex_file) {
+ CHECK_EQ(Class::kStatusLoaded, klass->status_);
if (!LinkSuperClass(klass)) {
return false;
}
@@ -1074,14 +1091,13 @@
return false;
}
CreateReferenceOffsets(klass);
- CHECK_EQ(klass->status_, Class::kStatusLoaded);
+ CHECK_EQ(Class::kStatusLoaded, klass->status_);
klass->status_ = Class::kStatusResolved;
return true;
}
-bool ClassLinker::LinkInterfaces(Class* klass, const DexFile* dex_file) {
- // Mark the class as loaded.
- klass->status_ = Class::kStatusLoaded;
+bool ClassLinker::LoadSuperAndInterfaces(Class* klass, const DexFile& dex_file) {
+ CHECK_EQ(Class::kStatusIdx, klass->status_);
if (klass->super_class_idx_ != DexFile::kDexNoIndex) {
Class* super_class = ResolveClass(klass, klass->super_class_idx_, dex_file);
if (super_class == NULL) {
@@ -1105,6 +1121,8 @@
}
}
}
+ // Mark the class as loaded.
+ klass->status_ = Class::kStatusLoaded;
return true;
}
@@ -1125,15 +1143,15 @@
}
// Verify
if (super->IsFinal()) {
- LG << "Superclass is declared final"; // TODO: IncompatibleClassChangeError
+ LG << "Superclass " << super->descriptor_ << " is declared final"; // TODO: IncompatibleClassChangeError
return false;
}
if (super->IsInterface()) {
- LG << "Superclass is an interface"; // TODO: IncompatibleClassChangeError
+ LG << "Superclass " << super->descriptor_ << " is an interface"; // TODO: IncompatibleClassChangeError
return false;
}
if (!klass->CanAccess(super)) {
- LG << "Superclass is inaccessible"; // TODO: IllegalAccessError
+ LG << "Superclass " << super->descriptor_ << " is inaccessible"; // TODO: IllegalAccessError
return false;
}
return true;
@@ -1515,17 +1533,17 @@
Class* ClassLinker::ResolveClass(const Class* referrer,
uint32_t class_idx,
- const DexFile* dex_file) {
+ const DexFile& dex_file) {
DexCache* dex_cache = referrer->GetDexCache();
Class* resolved = dex_cache->GetResolvedClass(class_idx);
if (resolved != NULL) {
return resolved;
}
- const char* descriptor = dex_file->dexStringByTypeIdx(class_idx);
+ const char* descriptor = dex_file.dexStringByTypeIdx(class_idx);
if (descriptor[0] != '\0' && descriptor[1] == '\0') {
resolved = FindPrimitiveClass(descriptor[0]);
} else {
- resolved = FindClass(descriptor, referrer->GetClassLoader(), dex_file);
+ resolved = FindClass(descriptor, referrer->GetClassLoader());
}
if (resolved != NULL) {
Class* check = resolved->IsArray() ? resolved->component_type_ : resolved;
@@ -1549,11 +1567,11 @@
}
String* ClassLinker::ResolveString(const Class* referring,
- uint32_t string_idx) {
- const DexFile* dex_file = FindDexFile(referring->GetDexCache());
- const DexFile::StringId& string_id = dex_file->GetStringId(string_idx);
- int32_t utf16_length = dex_file->GetStringLength(string_id);
- const char* utf8_data = dex_file->GetStringData(string_id);
+ uint32_t string_idx,
+ const DexFile& dex_file) {
+ const DexFile::StringId& string_id = dex_file.GetStringId(string_idx);
+ int32_t utf16_length = dex_file.GetStringLength(string_id);
+ const char* utf8_data = dex_file.GetStringData(string_id);
String* new_string = String::AllocFromModifiedUtf8(utf16_length, utf8_data);
// TODO: intern the new string
referring->GetDexCache()->SetResolvedString(string_idx, new_string);
diff --git a/src/class_linker.h b/src/class_linker.h
index 87098c6..013196b 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -24,24 +24,25 @@
~ClassLinker() {}
// Finds a class by its descriptor name.
- // If dex_file is null, searches boot_class_path_.
+ // If class_loader is null, searches boot_class_path_.
Class* FindClass(const StringPiece& descriptor,
- Object* class_loader,
- const DexFile* dex_file);
+ ClassLoader* class_loader);
Class* FindSystemClass(const StringPiece& descriptor) {
- return FindClass(descriptor, NULL, NULL);
+ return FindClass(descriptor, NULL);
}
bool InitializeClass(Class* klass);
- Class* LookupClass(const StringPiece& descriptor, Object* class_loader);
+ Class* LookupClass(const StringPiece& descriptor, ClassLoader* class_loader);
Class* ResolveClass(const Class* referring,
uint32_t class_idx,
- const DexFile* dex_file);
+ const DexFile& dex_file);
- String* ResolveString(const Class* referring, uint32_t string_idx);
+ String* ResolveString(const Class* referring,
+ uint32_t string_idx,
+ const DexFile& dex_file);
void RegisterDexFile(const DexFile* dex_file);
@@ -69,28 +70,25 @@
ObjectArray<T>* AllocObjectArray(size_t length) {
return ObjectArray<T>::Alloc(class_roots_->Get(kObjectArrayClass), length);
}
+ PathClassLoader* AllocPathClassLoader(std::vector<const DexFile*> dex_files);
Class* CreatePrimitiveClass(const StringPiece& descriptor);
Class* CreateArrayClass(const StringPiece& descriptor,
- Object* class_loader,
- const DexFile* dex_file);
+ ClassLoader* class_loader);
Class* FindPrimitiveClass(char type);
- const DexFile* FindDexFile(const DexCache* dex_cache) const;
+ const DexFile& FindDexFile(const DexCache* dex_cache) const;
DexCache* FindDexCache(const DexFile* dex_file) const;
- typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry;
-
void AppendToBootClassPath(DexFile* dex_file);
- ClassPathEntry FindInBootClassPath(const StringPiece& descriptor);
-
void LoadClass(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
- Class* klass);
+ Class* klass,
+ ClassLoader* class_loader);
void LoadInterfaces(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
@@ -140,11 +138,11 @@
bool HasSameArgumentTypes(const Method* m1, const Method* m2) const;
- bool LinkClass(Class* klass, const DexFile* dex_file);
+ bool LinkClass(Class* klass, const DexFile& dex_file);
bool LinkSuperClass(Class* klass);
- bool LinkInterfaces(Class* klass, const DexFile* dex_file);
+ bool LoadSuperAndInterfaces(Class* klass, const DexFile& dex_file);
bool LinkMethods(Class* klass);
@@ -164,8 +162,11 @@
std::vector<DexCache*> dex_caches_;
+ // multimap from String::descriptor_ to Class* instances. Results
+ // should be compared for a matching Class::descriptor_ and
+ // Class::class_loader_.
// TODO: unordered_multimap
- typedef std::map<const StringPiece, Class*> Table;
+ typedef std::multimap<const StringPiece, Class*> Table;
Table classes_;
@@ -174,12 +175,17 @@
// TODO: classpath
// indexes into class_roots_
- enum ClassRoots {
+ enum ClassRoot {
kJavaLangClass,
kJavaLangObject,
+ kObjectArrayClass,
+ kJavaLangString,
+ kCharArrayClass,
kJavaLangReflectField,
kJavaLangReflectMethod,
- kJavaLangString,
+ kJavaLangClassLoader,
+ kDalvikSystemBaseDexClassLoader,
+ kDalvikSystemPathClassLoader,
kPrimitiveBoolean,
kPrimitiveChar,
kPrimitiveFloat,
@@ -189,17 +195,22 @@
kPrimitiveInt,
kPrimitiveLong,
kPrimitiveVoid,
- kObjectArrayClass,
- kCharArrayClass,
kClassRootsMax,
};
ObjectArray<Class>* class_roots_;
+ Class* GetClassRoot(ClassRoot class_root) {
+ Class* klass = class_roots_->Get(class_root);
+ DCHECK(klass != NULL);
+ return klass;
+ }
+
ObjectArray<Class>* array_interfaces_;
InterfaceEntry* array_iftable_;
bool init_done_;
+ friend class RuntimeTest;
FRIEND_TEST(ClassLinkerTest, ProtoCompare);
FRIEND_TEST(ClassLinkerTest, ProtoCompare2);
FRIEND_TEST(DexCacheTest, Open);
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 8672cf9..d521183 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -23,6 +23,7 @@
ASSERT_EQ(descriptor, primitive->GetDescriptor());
EXPECT_TRUE(primitive->GetSuperClass() == NULL);
EXPECT_FALSE(primitive->HasSuperClass());
+ EXPECT_TRUE(primitive->GetClassLoader() == NULL);
EXPECT_TRUE(primitive->GetComponentType() == NULL);
EXPECT_TRUE(primitive->GetStatus() == Class::kStatusInitialized);
EXPECT_FALSE(primitive->IsErroneous());
@@ -44,8 +45,9 @@
void AssertArrayClass(const StringPiece& array_descriptor,
int32_t array_rank,
- const StringPiece& component_type) {
- Class* array = class_linker_->FindSystemClass(array_descriptor);
+ const StringPiece& component_type,
+ ClassLoader* class_loader) {
+ Class* array = class_linker_->FindClass(array_descriptor, class_loader);
ASSERT_TRUE(array != NULL);
ASSERT_TRUE(array->GetClass() != NULL);
ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
@@ -54,6 +56,7 @@
EXPECT_TRUE(array->GetSuperClass() != NULL);
EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Object;"), array->GetSuperClass());
EXPECT_TRUE(array->HasSuperClass());
+ EXPECT_EQ(class_loader, array->GetClassLoader());
ASSERT_TRUE(array->GetComponentType() != NULL);
ASSERT_TRUE(array->GetComponentType()->GetDescriptor() != NULL);
EXPECT_EQ(component_type, array->GetComponentType()->GetDescriptor());
@@ -75,18 +78,18 @@
EXPECT_EQ(2U, array->NumInterfaces());
}
- void AssertDexFileClass(const DexFile* dex, const char* descriptor) {
+ void AssertDexFileClass(ClassLoader* class_loader, const char* descriptor) {
ASSERT_TRUE(descriptor != NULL);
- Class* klass = class_linker_->FindClass(descriptor, NULL, dex);
+ Class* klass = class_linker_->FindSystemClass(descriptor);
ASSERT_TRUE(klass != NULL);
EXPECT_EQ(descriptor, klass->GetDescriptor());
if (klass->descriptor_ == "Ljava/lang/Object;") {
- EXPECT_FALSE(klass->HasSuperClass());
+ EXPECT_FALSE(klass->HasSuperClass());
} else {
- EXPECT_TRUE(klass->HasSuperClass());
- EXPECT_TRUE(klass->GetSuperClass() != NULL);
+ EXPECT_TRUE(klass->HasSuperClass());
+ EXPECT_TRUE(klass->GetSuperClass() != NULL);
}
- // EXPECT_TRUE(klass->GetClassLoader() != NULL); // TODO needs class loader
+ EXPECT_EQ(class_loader, klass->GetClassLoader());
EXPECT_TRUE(klass->GetDexCache() != NULL);
EXPECT_TRUE(klass->GetComponentType() == NULL);
EXPECT_TRUE(klass->GetComponentType() == NULL);
@@ -98,78 +101,78 @@
EXPECT_TRUE(klass->IsInSamePackage(klass));
EXPECT_TRUE(Class::IsInSamePackage(klass->GetDescriptor(), klass->GetDescriptor()));
if (klass->IsInterface()) {
- EXPECT_TRUE(klass->IsAbstract());
- if (klass->NumDirectMethods() == 1) {
- EXPECT_PRED2(String::EqualsUtf8, klass->GetDirectMethod(0)->GetName(), "<clinit>");
- } else {
- EXPECT_EQ(0U, klass->NumDirectMethods());
- }
+ EXPECT_TRUE(klass->IsAbstract());
+ if (klass->NumDirectMethods() == 1) {
+ EXPECT_PRED2(String::EqualsUtf8, klass->GetDirectMethod(0)->GetName(), "<clinit>");
+ } else {
+ EXPECT_EQ(0U, klass->NumDirectMethods());
+ }
} else {
- if (!klass->IsSynthetic()) {
- EXPECT_NE(0U, klass->NumDirectMethods());
- }
+ if (!klass->IsSynthetic()) {
+ EXPECT_NE(0U, klass->NumDirectMethods());
+ }
}
if (klass->IsAbstract()) {
- EXPECT_FALSE(klass->IsFinal());
+ EXPECT_FALSE(klass->IsFinal());
} else {
- EXPECT_FALSE(klass->IsAnnotation());
+ EXPECT_FALSE(klass->IsAnnotation());
}
if (klass->IsFinal()) {
- EXPECT_FALSE(klass->IsAbstract());
- EXPECT_FALSE(klass->IsAnnotation());
+ EXPECT_FALSE(klass->IsAbstract());
+ EXPECT_FALSE(klass->IsAnnotation());
}
if (klass->IsAnnotation()) {
- EXPECT_FALSE(klass->IsFinal());
- EXPECT_TRUE(klass->IsAbstract());
+ EXPECT_FALSE(klass->IsFinal());
+ EXPECT_TRUE(klass->IsAbstract());
}
EXPECT_FALSE(klass->IsPrimitive());
EXPECT_TRUE(klass->CanAccess(klass));
for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
- Method* method = klass->GetDirectMethod(i);
- EXPECT_TRUE(method != NULL);
+ Method* method = klass->GetDirectMethod(i);
+ EXPECT_TRUE(method != NULL);
}
for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
- Method* method = klass->GetVirtualMethod(i);
- EXPECT_TRUE(method != NULL);
+ Method* method = klass->GetVirtualMethod(i);
+ EXPECT_TRUE(method != NULL);
}
for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
- InstanceField* field = klass->GetInstanceField(i);
- EXPECT_TRUE(field != NULL);
+ InstanceField* field = klass->GetInstanceField(i);
+ EXPECT_TRUE(field != NULL);
}
for (size_t i = 0; i < klass->NumStaticFields(); i++) {
- StaticField* field = klass->GetStaticField(i);
- EXPECT_TRUE(field != NULL);
+ StaticField* field = klass->GetStaticField(i);
+ EXPECT_TRUE(field != NULL);
}
// Confirm that all instances fields are packed together at the start
EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields());
for (size_t i = 0; i < klass->NumReferenceInstanceFields(); i++) {
- InstanceField* field = klass->GetInstanceField(i);
- ASSERT_TRUE(field != NULL);
- ASSERT_TRUE(field->GetDescriptor() != NULL);
- Class* fieldType = class_linker_->FindClass(field->GetDescriptor(), NULL, dex);
- ASSERT_TRUE(fieldType != NULL);
- EXPECT_FALSE(fieldType->IsPrimitive());
+ InstanceField* field = klass->GetInstanceField(i);
+ ASSERT_TRUE(field != NULL);
+ ASSERT_TRUE(field->GetDescriptor() != NULL);
+ Class* field_type = class_linker_->FindClass(field->GetDescriptor(), class_loader);
+ ASSERT_TRUE(field_type != NULL);
+ EXPECT_FALSE(field_type->IsPrimitive());
}
for (size_t i = klass->NumReferenceInstanceFields(); i < klass->NumInstanceFields(); i++) {
- InstanceField* field = klass->GetInstanceField(i);
- ASSERT_TRUE(field != NULL);
- ASSERT_TRUE(field->GetDescriptor() != NULL);
- Class* fieldType = class_linker_->FindClass(field->GetDescriptor(), NULL, dex);
- ASSERT_TRUE(fieldType != NULL);
- EXPECT_TRUE(fieldType->IsPrimitive());
+ InstanceField* field = klass->GetInstanceField(i);
+ ASSERT_TRUE(field != NULL);
+ ASSERT_TRUE(field->GetDescriptor() != NULL);
+ Class* field_type = class_linker_->FindClass(field->GetDescriptor(), class_loader);
+ ASSERT_TRUE(field_type != NULL);
+ EXPECT_TRUE(field_type->IsPrimitive());
}
size_t total_num_reference_instance_fields = 0;
Class* k = klass;
while (k != NULL) {
- total_num_reference_instance_fields += k->NumReferenceInstanceFields();
- k = k->GetSuperClass();
+ total_num_reference_instance_fields += k->NumReferenceInstanceFields();
+ k = k->GetSuperClass();
}
EXPECT_EQ(klass->GetReferenceOffsets() == 0,
total_num_reference_instance_fields == 0);
@@ -179,13 +182,12 @@
EXPECT_TRUE(root != NULL);
}
- void AssertDexFile(const DexFile* dex) {
+ void AssertDexFile(const DexFile* dex, ClassLoader* class_loader) {
ASSERT_TRUE(dex != NULL);
- class_linker_->RegisterDexFile(dex);
for (size_t i = 0; i < dex->NumClassDefs(); i++) {
const DexFile::ClassDef class_def = dex->GetClassDef(i);
const char* descriptor = dex->GetClassDescriptor(class_def);
- AssertDexFileClass(dex, descriptor);
+ AssertDexFileClass(class_loader, descriptor);
}
class_linker_->VisitRoots(TestRootVisitor, NULL);
}
@@ -199,15 +201,15 @@
}
TEST_F(ClassLinkerTest, FindClassNested) {
- scoped_ptr<DexFile> nested_dex(OpenDexFileBase64(kNestedDex));
- class_linker_->RegisterDexFile(nested_dex.get());
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kNestedDex));
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* outer = class_linker_->FindClass("LNested;", NULL, nested_dex.get());
+ Class* outer = class_linker_->FindClass("LNested;", class_loader);
ASSERT_TRUE(outer != NULL);
EXPECT_EQ(0U, outer->NumVirtualMethods());
EXPECT_EQ(1U, outer->NumDirectMethods());
- Class* inner = class_linker_->FindClass("LNested$Inner;", NULL, nested_dex.get());
+ Class* inner = class_linker_->FindClass("LNested$Inner;", class_loader);
ASSERT_TRUE(inner != NULL);
EXPECT_EQ(0U, inner->NumVirtualMethods());
EXPECT_EQ(1U, inner->NumDirectMethods());
@@ -235,6 +237,7 @@
ASSERT_TRUE(JavaLangObject->GetDescriptor() == "Ljava/lang/Object;");
EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
EXPECT_FALSE(JavaLangObject->HasSuperClass());
+ EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
EXPECT_TRUE(JavaLangObject->GetComponentType() == NULL);
EXPECT_FALSE(JavaLangObject->IsErroneous());
EXPECT_FALSE(JavaLangObject->IsVerified());
@@ -254,9 +257,9 @@
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassDex));
- linker->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
EXPECT_TRUE(linker->FindSystemClass("LMyClass;") == NULL);
- Class* MyClass = linker->FindClass("LMyClass;", NULL, dex.get());
+ Class* MyClass = linker->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(MyClass != NULL);
ASSERT_TRUE(MyClass->GetClass() != NULL);
ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
@@ -264,6 +267,7 @@
ASSERT_TRUE(MyClass->GetDescriptor() == "LMyClass;");
EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
EXPECT_TRUE(MyClass->HasSuperClass());
+ EXPECT_EQ(class_loader, MyClass->GetClassLoader());
EXPECT_TRUE(MyClass->GetComponentType() == NULL);
EXPECT_TRUE(MyClass->GetStatus() == Class::kStatusResolved);
EXPECT_FALSE(MyClass->IsErroneous());
@@ -285,11 +289,11 @@
EXPECT_EQ(JavaLangObject->GetClass()->GetClass(), MyClass->GetClass()->GetClass());
// created by class_linker
- AssertArrayClass("[C", 1, "C");
- AssertArrayClass("[Ljava/lang/Object;", 1, "Ljava/lang/Object;");
+ AssertArrayClass("[C", 1, "C", NULL);
+ AssertArrayClass("[Ljava/lang/Object;", 1, "Ljava/lang/Object;", NULL);
// synthesized on the fly
- AssertArrayClass("[[C", 2, "C");
- AssertArrayClass("[[[LMyClass;", 3, "LMyClass;");
+ AssertArrayClass("[[C", 2, "C", NULL);
+ AssertArrayClass("[[[LMyClass;", 3, "LMyClass;", class_loader);
// or not available at all
AssertNonExistantClass("[[[[LNonExistantClass;");
}
@@ -297,10 +301,10 @@
TEST_F(ClassLinkerTest, ProtoCompare) {
ClassLinker* linker = class_linker_;
- scoped_ptr<DexFile> proto_dex_file(OpenDexFileBase64(kProtoCompareDex));
- linker->RegisterDexFile(proto_dex_file.get());
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kProtoCompareDex));
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = linker->FindClass("LProtoCompare;", NULL, proto_dex_file.get());
+ Class* klass = linker->FindClass("LProtoCompare;", class_loader);
ASSERT_TRUE(klass != NULL);
ASSERT_EQ(4U, klass->NumVirtualMethods());
@@ -352,13 +356,13 @@
ClassLinker* linker = class_linker_;
scoped_ptr<DexFile> proto1_dex_file(OpenDexFileBase64(kProtoCompareDex));
- linker->RegisterDexFile(proto1_dex_file.get());
+ PathClassLoader* class_loader_1 = AllocPathClassLoader(proto1_dex_file.get());
scoped_ptr<DexFile> proto2_dex_file(OpenDexFileBase64(kProtoCompare2Dex));
- linker->RegisterDexFile(proto2_dex_file.get());
+ PathClassLoader* class_loader_2 = AllocPathClassLoader(proto2_dex_file.get());
- Class* klass1 = linker->FindClass("LProtoCompare;", NULL, proto1_dex_file.get());
+ Class* klass1 = linker->FindClass("LProtoCompare;", class_loader_1);
ASSERT_TRUE(klass1 != NULL);
- Class* klass2 = linker->FindClass("LProtoCompare2;", NULL, proto2_dex_file.get());
+ Class* klass2 = linker->FindClass("LProtoCompare2;", class_loader_2);
ASSERT_TRUE(klass2 != NULL);
Method* m1_1 = klass1->GetVirtualMethod(0);
@@ -393,9 +397,10 @@
}
TEST_F(ClassLinkerTest, LibCore) {
+ UseLibCoreDex();
scoped_ptr<DexFile> libcore_dex_file(GetLibCoreDex());
- EXPECT_TRUE(libcore_dex_file.get() != NULL); // Passes on host only until we have DexFile::OpenJar
- AssertDexFile(libcore_dex_file.get());
+ EXPECT_TRUE(libcore_dex_file.get() != NULL);
+ AssertDexFile(libcore_dex_file.get(), NULL);
}
// C++ fields must exactly match the fields in the Java classes. If this fails,
@@ -403,18 +408,18 @@
// ClassLinker::LinkInstanceFields.
TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) {
UseLibCoreDex();
- Class* string = class_linker_->FindClass( "Ljava/lang/String;", NULL, java_lang_dex_file_.get());
+ Class* string = class_linker_->FindSystemClass( "Ljava/lang/String;");
ASSERT_EQ(4U, string->NumInstanceFields());
EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(0)->GetName(), "value");
EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(1)->GetName(), "hashCode");
EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(2)->GetName(), "offset");
EXPECT_PRED2(String::EqualsUtf8, string->GetInstanceField(3)->GetName(), "count");
- Class* accessible_object = class_linker_->FindClass("Ljava/lang/reflect/AccessibleObject;", NULL, java_lang_dex_file_.get());
+ Class* accessible_object = class_linker_->FindSystemClass("Ljava/lang/reflect/AccessibleObject;");
ASSERT_EQ(1U, accessible_object->NumInstanceFields());
EXPECT_PRED2(String::EqualsUtf8, accessible_object->GetInstanceField(0)->GetName(), "flag");
- Class* field = class_linker_->FindClass("Ljava/lang/reflect/Field;", NULL, java_lang_dex_file_.get());
+ Class* field = class_linker_->FindSystemClass("Ljava/lang/reflect/Field;");
ASSERT_EQ(6U, field->NumInstanceFields());
EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(0)->GetName(), "declaringClass");
EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(1)->GetName(), "genericType");
@@ -423,7 +428,7 @@
EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(4)->GetName(), "slot");
EXPECT_PRED2(String::EqualsUtf8, field->GetInstanceField(5)->GetName(), "genericTypesAreInitialized");
- Class* method = class_linker_->FindClass("Ljava/lang/reflect/Method;", NULL, java_lang_dex_file_.get());
+ Class* method = class_linker_->FindSystemClass("Ljava/lang/reflect/Method;");
ASSERT_EQ(11U, method->NumInstanceFields());
EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 0)->GetName(), "declaringClass");
EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 1)->GetName(), "exceptionTypes");
@@ -436,6 +441,28 @@
EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 8)->GetName(), "parameterTypes");
EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField( 9)->GetName(), "genericTypesAreInitialized");
EXPECT_PRED2(String::EqualsUtf8, method->GetInstanceField(10)->GetName(), "slot");
+
+ Class* class_loader = class_linker_->FindSystemClass("Ljava/lang/ClassLoader;");
+ ASSERT_EQ(2U, class_loader->NumInstanceFields());
+ EXPECT_PRED2(String::EqualsUtf8, class_loader->GetInstanceField(0)->GetName(), "packages");
+ EXPECT_PRED2(String::EqualsUtf8, class_loader->GetInstanceField(1)->GetName(), "parent");
+
+ Class* dex_base_class_loader = class_linker_->FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
+ ASSERT_EQ(2U, dex_base_class_loader->NumInstanceFields());
+ EXPECT_PRED2(String::EqualsUtf8, dex_base_class_loader->GetInstanceField(0)->GetName(), "originalPath");
+ EXPECT_PRED2(String::EqualsUtf8, dex_base_class_loader->GetInstanceField(1)->GetName(), "pathList");
+}
+
+TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
+ scoped_ptr<DexFile> dex_1(OpenDexFileBase64(kMyClassDex));
+ scoped_ptr<DexFile> dex_2(OpenDexFileBase64(kMyClassDex));
+ PathClassLoader* class_loader_1 = AllocPathClassLoader(dex_1.get());
+ PathClassLoader* class_loader_2 = AllocPathClassLoader(dex_2.get());
+ Class* MyClass_1 = class_linker_->FindClass("LMyClass;", class_loader_1);
+ Class* MyClass_2 = class_linker_->FindClass("LMyClass;", class_loader_2);
+ EXPECT_TRUE(MyClass_1 != NULL);
+ EXPECT_TRUE(MyClass_2 != NULL);
+ EXPECT_NE(MyClass_1, MyClass_2);
}
} // namespace art
diff --git a/src/common_test.h b/src/common_test.h
index 685a06c..13f92d1 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -36,33 +36,57 @@
// }
//
// package java.lang;
+// public class ClassLoader {
+// Object packages;
+// ClassLoader parent;
+// }
+//
+// package dalvik.system;
+// public class BaseDexClassLoader extends ClassLoader {
+// String originalPath;
+// Object pathList;
+// }
+//
+// package dalvik.system;
+// public class PathClassLoader extends BaseDexClassLoader {}
+//
+// package java.lang;
// public interface Cloneable {}
//
// package java.io;
// public interface Serializable {}
static const char kJavaLangDex[] =
- "ZGV4CjAzNQDgopvWPbyCTsLOzSYO4VPqS6aRqcz6ZQu0BAAAcAAAAHhWNBIAAAAAAAAAACAEAAAW"
- "AAAAcAAAAAoAAADIAAAAAQAAAPAAAAAEAAAA/AAAAAUAAAAcAQAABwAAAEQBAACQAgAAJAIAAJgC"
- "AACgAgAArAIAALwCAADIAgAAywIAAOMCAAD2AgAADQMAACEDAAA1AwAAUAMAAGwDAAB5AwAAhgMA"
- "AJkDAACmAwAAqQMAAK0DAAC0AwAAvgMAAMYDAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAA"
- "CwAAABAAAAARAAAAEAAAAAgAAAAAAAAABQAAABIAAAAFAAAAEwAAAAUAAAAUAAAABQAJABUAAAAC"
- "AAAAAAAAAAQAAAAAAAAABQAAAAAAAAAGAAAAAAAAAAcAAAAAAAAABAAAAAEAAAD/////AAAAAA0A"
- "AAAAAAAA5gMAAAAAAAABAAAAAQYAAAQAAAAAAAAADgAAAAAAAAAAAAAAAAAAAAIAAAABAAAABAAA"
- "AAAAAAABAAAAAAAAAPADAAAAAAAAAwAAAAEGAAAEAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAFAAAA"
- "AQAAAAQAAAAAAAAADwAAAAAAAAD6AwAAAAAAAAYAAAABAAAABAAAAAAAAAADAAAAAAAAAAwEAAAA"
- "AAAABwAAAAEAAAAEAAAAAAAAAAwAAAAAAAAAFgQAAAAAAAABAAEAAAAAAM0DAAABAAAADgAAAAEA"
- "AQABAAAA0gMAAAQAAABwEAEAAAAOAAEAAQABAAAA1wMAAAQAAABwEAEAAAAOAAEAAQABAAAA3AMA"
- "AAQAAABwEAEAAAAOAAEAAQABAAAA4QMAAAQAAABwEAEAAAAOAAY8aW5pdD4ACkNsYXNzLmphdmEA"
- "DkNsb25lYWJsZS5qYXZhAApGaWVsZC5qYXZhAAFJABZMamF2YS9pby9TZXJpYWxpemFibGU7ABFM"
- "amF2YS9sYW5nL0NsYXNzOwAVTGphdmEvbGFuZy9DbG9uZWFibGU7ABJMamF2YS9sYW5nL09iamVj"
- "dDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAZTGphdmEvbGFuZy9yZWZsZWN0L0ZpZWxkOwAaTGphdmEv"
- "bGFuZy9yZWZsZWN0L01ldGhvZDsAC01ldGhvZC5qYXZhAAtPYmplY3QuamF2YQARU2VyaWFsaXph"
- "YmxlLmphdmEAC1N0cmluZy5qYXZhAAFWAAJbQwAFY291bnQACGhhc2hDb2RlAAZvZmZzZXQABXZh"
- "bHVlAAMABw4ABQAHDgAFAAcOAAUABw4ABQAHDgAAAAEAAYGABKQEAAABAACBgAS4BAAEAQAAAAEA"
- "AQABAAKBgATQBAAAAQADgYAE6AQAAAEABIGABIAFDAAAAAAAAAABAAAAAAAAAAEAAAAWAAAAcAAA"
- "AAIAAAAKAAAAyAAAAAMAAAABAAAA8AAAAAQAAAAEAAAA/AAAAAUAAAAFAAAAHAEAAAYAAAAHAAAA"
- "RAEAAAEgAAAFAAAAJAIAAAIgAAAWAAAAmAIAAAMgAAAFAAAAzQMAAAAgAAAFAAAA5gMAAAAQAAAB"
- "AAAAIAQAAA==";
+ "ZGV4CjAzNQCf+7APoNCFqeL/QKrA9vK3fihkWcSko9nIBgAAcAAAAHhWNBIAAAAAAAAAADQGAAAg"
+ "AAAAcAAAAA0AAADwAAAAAQAAACQBAAAIAAAAMAEAAAgAAABwAQAACgAAALABAADYAwAA8AIAAKwD"
+ "AAC0AwAAzQMAANkDAADrAwAA+wMAAAcEAAAKBAAALgQAAE8EAABnBAAAegQAAJMEAACqBAAAvgQA"
+ "ANIEAADtBAAACQUAABYFAAAjBQAAOQUAAEwFAABZBQAAXAUAAGAFAABnBQAAcQUAAHkFAACHBQAA"
+ "kQUAAJkFAACjBQAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAAAAW"
+ "AAAAFwAAABYAAAALAAAAAAAAAAEACAAbAAAAAQAHAB4AAAAFAAcAHAAAAAUABQAdAAAACAAAABgA"
+ "AAAIAAAAGQAAAAgAAAAaAAAACAAMAB8AAAABAAAAAAAAAAIAAAAAAAAABAAAAAAAAAAFAAAAAAAA"
+ "AAcAAAAAAAAACAAAAAAAAAAJAAAAAAAAAAoAAAAAAAAABwAAAAEAAAD/////AAAAABIAAAAAAAAA"
+ "0gUAAAAAAAAFAAAAAQAAAAcAAAAAAAAAAwAAAAAAAADcBQAAAAAAAAEAAAABAAAABQAAAAAAAAAB"
+ "AAAAAAAAAOoFAAAAAAAAAgAAAAEAAAABAAAAAAAAABMAAAAAAAAA+AUAAAAAAAADAAAAAQYAAAcA"
+ "AAAAAAAAFAAAAAAAAAAAAAAAAAAAAAQAAAABAAAABwAAAAAAAAACAAAAAAAAAAIGAAAAAAAABgAA"
+ "AAEGAAAHAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAIAAAAAQAAAAcAAAAAAAAAFQAAAAAAAAAMBgAA"
+ "AAAAAAkAAAABAAAABwAAAAAAAAAFAAAAAAAAAB4GAAAAAAAACgAAAAEAAAAHAAAAAAAAABEAAAAA"
+ "AAAAKAYAAAAAAAABAAEAAAAAAKoFAAABAAAADgAAAAEAAQABAAAArwUAAAQAAABwEAQAAAAOAAEA"
+ "AQABAAAAtAUAAAQAAABwEAMAAAAOAAEAAQABAAAAuQUAAAQAAABwEAAAAAAOAAEAAQABAAAAvgUA"
+ "AAQAAABwEAQAAAAOAAEAAQABAAAAwwUAAAQAAABwEAQAAAAOAAEAAQABAAAAyAUAAAQAAABwEAQA"
+ "AAAOAAEAAQABAAAAzQUAAAQAAABwEAQAAAAOAAY8aW5pdD4AF0Jhc2VEZXhDbGFzc0xvYWRlci5q"
+ "YXZhAApDbGFzcy5qYXZhABBDbGFzc0xvYWRlci5qYXZhAA5DbG9uZWFibGUuamF2YQAKRmllbGQu"
+ "amF2YQABSQAiTGRhbHZpay9zeXN0ZW0vQmFzZURleENsYXNzTG9hZGVyOwAfTGRhbHZpay9zeXN0"
+ "ZW0vUGF0aENsYXNzTG9hZGVyOwAWTGphdmEvaW8vU2VyaWFsaXphYmxlOwARTGphdmEvbGFuZy9D"
+ "bGFzczsAF0xqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7ABVMamF2YS9sYW5nL0Nsb25lYWJsZTsAEkxq"
+ "YXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABlMamF2YS9sYW5nL3JlZmxlY3Qv"
+ "RmllbGQ7ABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwALTWV0aG9kLmphdmEAC09iamVjdC5q"
+ "YXZhABRQYXRoQ2xhc3NMb2FkZXIuamF2YQARU2VyaWFsaXphYmxlLmphdmEAC1N0cmluZy5qYXZh"
+ "AAFWAAJbQwAFY291bnQACGhhc2hDb2RlAAZvZmZzZXQADG9yaWdpbmFsUGF0aAAIcGFja2FnZXMA"
+ "BnBhcmVudAAIcGF0aExpc3QABXZhbHVlAAMABw4ABQAHDgAFAAcOAAUABw4ABQAHDgAFAAcOAAUA"
+ "Bw4ABQAHDgAAAAEABIGABPAFAAIBAAIAAQADgYAEhAYAAgEAAAABAACBgAScBgAAAQABgYAEtAYA"
+ "AAEAAoGABMwGAAQBAAQAAQABAAEABYGABOQGAAABAAaBgAT8BgAAAQAHgYAElAcAAAwAAAAAAAAA"
+ "AQAAAAAAAAABAAAAIAAAAHAAAAACAAAADQAAAPAAAAADAAAAAQAAACQBAAAEAAAACAAAADABAAAF"
+ "AAAACAAAAHABAAAGAAAACgAAALABAAABIAAACAAAAPACAAACIAAAIAAAAKwDAAADIAAACAAAAKoF"
+ "AAAAIAAACAAAANIFAAAAEAAAAQAAADQGAAA=";
// package java.lang;
// public class Object {}
@@ -288,6 +312,13 @@
class_linker_ = runtime_->GetClassLinker();
}
+ PathClassLoader* AllocPathClassLoader(const DexFile* dex_file) {
+ class_linker_->RegisterDexFile(dex_file);
+ std::vector<const DexFile*> dex_files;
+ dex_files.push_back(dex_file);
+ return class_linker_->AllocPathClassLoader(dex_files);
+ }
+
bool is_host_;
scoped_ptr_malloc<char> android_data_;
std::string art_cache_;
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 0cf98b1..35e98db 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -25,6 +25,18 @@
const byte DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
const byte DexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' };
+DexFile::ClassPathEntry DexFile::FindInClassPath(const StringPiece& descriptor,
+ ClassPath& class_path) {
+ for (size_t i = 0; i != class_path.size(); ++i) {
+ const DexFile* dex_file = class_path[i];
+ const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+ if (dex_class_def != NULL) {
+ return ClassPathEntry(dex_file, dex_class_def);
+ }
+ }
+ return ClassPathEntry(NULL, NULL);
+}
+
DexFile::Closer::~Closer() {}
DexFile::MmapCloser::MmapCloser(void* addr, size_t length) : addr_(addr), length_(length) {
diff --git a/src/dex_file.h b/src/dex_file.h
index 6cc7b10..b4c6c47 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -4,6 +4,7 @@
#define ART_SRC_DEX_FILE_H_
#include <map>
+#include <vector>
#include "globals.h"
#include "leb128.h"
@@ -203,6 +204,13 @@
uint32_t code_off_;
};
+ typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry;
+ typedef std::vector<const DexFile*> ClassPath;
+
+ // Search a collection of DexFiles for a descriptor
+ static ClassPathEntry FindInClassPath(const StringPiece& descriptor,
+ ClassPath& class_path);
+
// Opens a .dex file from the file system.
static DexFile* OpenFile(const std::string& filename);
diff --git a/src/heap.cc b/src/heap.cc
index bc54a82..86942fa 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -68,6 +68,9 @@
}
Object* Heap::AllocObject(Class* klass, size_t num_bytes) {
+ DCHECK((klass == NULL && num_bytes == sizeof(Class))
+ || klass->descriptor_ == NULL
+ || (klass->object_size_ == (klass->IsArray() ? 0 : num_bytes)));
Object* obj = Allocate(num_bytes);
if (obj != NULL) {
obj->klass_ = klass;
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 3041927..79806f6 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -204,9 +204,9 @@
TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- class_linker_->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+ Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
Method* method = klass->FindVirtualMethod("foo", "()V");
@@ -233,9 +233,9 @@
TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- class_linker_->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+ Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
Method* method = klass->FindVirtualMethod("fooI", "(I)I");
@@ -264,9 +264,9 @@
TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- class_linker_->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+ Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
Method* method = klass->FindVirtualMethod("fooII", "(II)I");
@@ -298,9 +298,9 @@
TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- class_linker_->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+ Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
Method* method = klass->FindVirtualMethod("fooDD", "(DD)D");
@@ -331,9 +331,9 @@
TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- class_linker_->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+ Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
Method* method = klass->FindVirtualMethod(
@@ -392,9 +392,9 @@
TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- class_linker_->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+ Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
Method* method = klass->FindDirectMethod(
@@ -450,9 +450,9 @@
TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- class_linker_->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+ Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
Method* method = klass->FindDirectMethod(
@@ -514,9 +514,9 @@
}
TEST_F(JniCompilerTest, SuspendCountAcknolewdgement) {
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- class_linker_->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+ Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
Method* method = klass->FindVirtualMethod("fooI", "(I)I");
@@ -559,9 +559,9 @@
}
TEST_F(JniCompilerTest, ExceptionHandling) {
scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- class_linker_->RegisterDexFile(dex.get());
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
- Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
+ Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
Method* method = klass->FindVirtualMethod("foo", "()V");
diff --git a/src/object.h b/src/object.h
index 3a9888e..d0f4a63 100644
--- a/src/object.h
+++ b/src/object.h
@@ -262,10 +262,11 @@
}
char GetType() const { // TODO: return type
- return descriptor_[0];
+ return GetDescriptor()[0];
}
const StringPiece& GetDescriptor() const {
+ DCHECK_NE(0, descriptor_.size());
return descriptor_;
}
@@ -648,13 +649,72 @@
ObjectArray();
};
+// ClassLoader objects.
+class ClassLoader : public Object {
+ public:
+ std::vector<const DexFile*>& GetClassPath() {
+ return class_path_;
+ }
+ void SetClassPath(std::vector<const DexFile*>& class_path) {
+ DCHECK_EQ(0U, class_path_.size());
+ class_path_ = class_path;
+ }
+
+ private:
+ // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+ Object* packages_;
+ ClassLoader* parent_;
+
+ // TODO remove once we can create a real PathClassLoader
+ std::vector<const DexFile*> class_path_;
+
+ ClassLoader();
+};
+
+class BaseDexClassLoader : public ClassLoader {
+ private:
+ // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
+ String* original_path_;
+ Object* path_list_;
+ BaseDexClassLoader();
+};
+
+class PathClassLoader : public BaseDexClassLoader {
+ private:
+ PathClassLoader();
+};
+
// Class objects.
class Class : public Object {
public:
+
+ // Class Status
+ //
+ // kStatusNotReady: If a Class cannot be found in the class table by
+ // FindClass, it allocates an new one with AllocClass in the
+ // kStatusNotReady and calls LoadClass. Note if it does find a
+ // class, it may not be kStatusResolved and it will try to push it
+ // forward toward kStatusResolved.
+ //
+ // 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_idx_ and interfaces_idx_. 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_.
+ //
+ // kStatusResolved: Still holding the lock on Class, the ClassLinker
+ // will use LinkClass to link all members, creating Field and Method
+ // objects, setting up the vtable, etc. On success, the class is
+ // marked kStatusResolved.
+
enum Status {
kStatusError = -1,
kStatusNotReady = 0,
- kStatusIdx = 1, // loaded, DEX idx in super or ifaces
+ kStatusIdx = 1, // loaded, DEX idx in super_class_idx_ and interfaces_idx_
kStatusLoaded = 2, // DEX idx values resolved
kStatusResolved = 3, // part of linking
kStatusVerifying = 4, // in the process of being verified
@@ -679,7 +739,7 @@
return super_class_ != NULL;
}
- Object* GetClassLoader() const {
+ ClassLoader* GetClassLoader() const {
return class_loader_;
}
@@ -688,11 +748,11 @@
}
Class* GetComponentType() const {
- DCHECK(IsArray());
return component_type_;
}
const StringPiece& GetDescriptor() const {
+ DCHECK_NE(0, descriptor_.size());
return descriptor_;
}
@@ -732,7 +792,7 @@
// Returns true if this class represents an array class.
bool IsArray() const {
- return descriptor_[0] == '['; // TODO: avoid parsing the descriptor
+ return GetDescriptor()[0] == '['; // TODO: avoid parsing the descriptor
}
// Returns true if the class is an interface.
@@ -933,7 +993,7 @@
uint32_t super_class_idx_;
// defining class loader, or NULL for the "bootstrap" system loader
- Object* class_loader_; // TODO: make an instance field
+ ClassLoader* class_loader_; // TODO: make an instance field
// initiating class loader list
// NOTE: for classes with low serialNumber, these are unused, and the
@@ -1136,23 +1196,52 @@
static uint16_t GetUtf16FromUtf8(const char** utf8_data_in) {
uint8_t one = *(*utf8_data_in)++;
if ((one & 0x80) == 0) {
- /* one-byte encoding */
+ // one-byte encoding
return one;
}
- /* two- or three-byte encoding */
+ // two- or three-byte encoding
uint8_t two = *(*utf8_data_in)++;
if ((one & 0x20) == 0) {
- /* two-byte encoding */
+ // two-byte encoding
return ((one & 0x1f) << 6) |
(two & 0x3f);
}
- /* three-byte encoding */
+ // three-byte encoding
uint8_t three = *(*utf8_data_in)++;
return ((one & 0x0f) << 12) |
((two & 0x3f) << 6) |
(three & 0x3f);
}
+ // Like "strlen", but for strings encoded with "modified" UTF-8.
+ //
+ // The value returned is the number of characters, which may or may not
+ // be the same as the number of bytes.
+ //
+ // (If this needs optimizing, try: mask against 0xa0, shift right 5,
+ // get increment {1-3} from table of 8 values.)
+ static size_t ModifiedUtf8Len(const char* utf8) {
+ size_t len = 0;
+ int ic;
+ while ((ic = *utf8++) != '\0') {
+ len++;
+ if ((ic & 0x80) == 0) {
+ // one-byte encoding
+ continue;
+ }
+ // two- or three-byte encoding
+ utf8++;
+ if ((ic & 0x20) == 0) {
+ // two-byte encoding
+ continue;
+ }
+ // three-byte encoding
+ utf8++;
+ }
+ return len;
+ }
+
+
// The java/lang/String.computeHashCode() algorithm
static int32_t ComputeUtf16Hash(const uint16_t* string_data, size_t string_length) {
int32_t hash = 0;