Improved ClassLoader support
Change-Id: I587c0fa439c64a0c947641b01c072149f480bf85
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);