Initialize ClassLinker from image
Change-Id: Ibaf47b4181f7c6603a8b37e2eba8fa6509c927ed
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 55aaff4..2e4aa9e 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -14,25 +14,59 @@
#include "object.h"
#include "dex_file.h"
#include "scoped_ptr.h"
+#include "space.h"
#include "thread.h"
#include "utils.h"
namespace art {
-ClassLinker* ClassLinker::Create(const std::vector<DexFile*>& boot_class_path) {
+const char* ClassLinker::class_roots_descriptors_[kClassRootsMax] = {
+ "Ljava/lang/Class;",
+ "Ljava/lang/Object;",
+ "[Ljava/lang/Object;",
+ "Ljava/lang/String;",
+ "Ljava/lang/reflect/Field;",
+ "Ljava/lang/reflect/Method;",
+ "Ljava/lang/ClassLoader;",
+ "Ldalvik/system/BaseDexClassLoader;",
+ "Ldalvik/system/PathClassLoader;",
+ "Z",
+ "B",
+ "C",
+ "D",
+ "F",
+ "I",
+ "J",
+ "S",
+ "V",
+ "[Z",
+ "[B",
+ "[C",
+ "[D",
+ "[F",
+ "[I",
+ "[J",
+ "[S",
+};
+
+ClassLinker* ClassLinker::Create(const std::vector<DexFile*>& boot_class_path, Space* space) {
scoped_ptr<ClassLinker> class_linker(new ClassLinker);
- class_linker->Init(boot_class_path);
+ if (space == NULL) {
+ class_linker->Init(boot_class_path);
+ } else {
+ class_linker->Init(boot_class_path, space);
+ }
// TODO: check for failure during initialization
return class_linker.release();
}
+
void ClassLinker::Init(const std::vector<DexFile*>& boot_class_path) {
CHECK(!init_done_);
// java_lang_Class comes first, its needed for AllocClass
Class* java_lang_Class = down_cast<Class*>(Heap::AllocObject(NULL, sizeof(Class)));
CHECK(java_lang_Class != NULL);
- // java_lang_Class->descriptor_ = "Ljava/lang/Class;"; // XXX bdc can these be created later?
java_lang_Class->object_size_ = sizeof(Class);
java_lang_Class->klass_ = java_lang_Class;
// AllocClass(Class*) can now be used
@@ -40,7 +74,6 @@
// java_lang_Object comes next so that object_array_class can be created
Class* java_lang_Object = AllocClass(java_lang_Class);
CHECK(java_lang_Object != NULL);
- // java_lang_Object->descriptor_ = "Ljava/lang/Object;"; // XXX bdc can these be created later?
// backfill Object as the super class of Class
java_lang_Class->super_class_ = java_lang_Object;
// mark as non-primitive for object_array_class
@@ -49,19 +82,16 @@
// object_array_class is for root_classes to provide the storage for these classes
Class* object_array_class = AllocClass(java_lang_Class);
CHECK(object_array_class != NULL);
- // object_array_class->descriptor_ = "[Ljava/lang/Object;"; // XXX bdc can these be created later?
object_array_class->component_type_ = java_lang_Object;
// 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;"; // XXX can these be created later?
CHECK_LT(java_lang_String->object_size_, sizeof(String));
java_lang_String->object_size_ = sizeof(String);
- String::InitClass(java_lang_String);
+ String::SetClass(java_lang_String);
Class* char_array_class = AllocClass(java_lang_Class);
CHECK(char_array_class != NULL);
- // char_array_class->descriptor_ = "[C"; // XXX can these be created later?
CharArray::SetArrayClass(char_array_class);
// Now String::Alloc* can be used
@@ -96,15 +126,15 @@
// 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);
- class_roots_->Set(kJavaLangObject, java_lang_Object);
- class_roots_->Set(kObjectArrayClass, object_array_class);
- class_roots_->Set(kJavaLangString, java_lang_String);
- class_roots_->Set(kCharArrayClass, char_array_class);
- class_roots_->Set(kIntArrayClass, int_array_class);
- class_roots_->Set(kLongArrayClass, long_array_class);
- class_roots_->Set(kJavaLangReflectField, java_lang_reflect_Field);
- class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
+ SetClassRoot(kJavaLangClass, java_lang_Class);
+ SetClassRoot(kJavaLangObject, java_lang_Object);
+ SetClassRoot(kObjectArrayClass, object_array_class);
+ SetClassRoot(kJavaLangString, java_lang_String);
+ SetClassRoot(kCharArrayClass, char_array_class);
+ SetClassRoot(kIntArrayClass, int_array_class);
+ SetClassRoot(kLongArrayClass, long_array_class);
+ SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field);
+ SetClassRoot(kJavaLangReflectMethod, java_lang_reflect_Method);
// now that these are registered, we can use AllocClass() and AllocObjectArray
// setup boot_class_path_ now that we can use AllocObjectArray to
@@ -143,15 +173,15 @@
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);
+ SetClassRoot(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);
+ SetClassRoot(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);
+ SetClassRoot(kDalvikSystemPathClassLoader, dalvik_system_PathClassLoader);
// Setup a single, global copy of "interfaces" and "iftable" for
// reuse across array classes
@@ -181,15 +211,15 @@
CHECK_EQ(java_io_Serializable, object_array_class->GetInterface(1));
// Setup the primitive type classes.
- class_roots_->Set(kPrimitiveBoolean, CreatePrimitiveClass("Z"));
- class_roots_->Set(kPrimitiveByte, CreatePrimitiveClass("B"));
- class_roots_->Set(kPrimitiveChar, CreatePrimitiveClass("C"));
- class_roots_->Set(kPrimitiveDouble, CreatePrimitiveClass("D"));
- class_roots_->Set(kPrimitiveFloat, CreatePrimitiveClass("F"));
- class_roots_->Set(kPrimitiveInt, CreatePrimitiveClass("I"));
- class_roots_->Set(kPrimitiveLong, CreatePrimitiveClass("J"));
- class_roots_->Set(kPrimitiveShort, CreatePrimitiveClass("S"));
- class_roots_->Set(kPrimitiveVoid, CreatePrimitiveClass("V"));
+ SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass("Z"));
+ SetClassRoot(kPrimitiveByte, CreatePrimitiveClass("B"));
+ SetClassRoot(kPrimitiveChar, CreatePrimitiveClass("C"));
+ SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass("D"));
+ SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass("F"));
+ SetClassRoot(kPrimitiveInt, CreatePrimitiveClass("I"));
+ SetClassRoot(kPrimitiveLong, CreatePrimitiveClass("J"));
+ SetClassRoot(kPrimitiveShort, CreatePrimitiveClass("S"));
+ SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass("V"));
// now we can use FindSystemClass for anything, including for "[C"
// run char[], int[] and long[] through FindClass to complete initialization
@@ -202,20 +232,29 @@
// Initialize all the other primitive array types for PrimitiveArray::Alloc.
// These are easy because everything we need has already been set up.
- class_roots_->Set(kBooleanArrayClass, FindSystemClass("[Z"));
- class_roots_->Set(kByteArrayClass, FindSystemClass("[B"));
- class_roots_->Set(kDoubleArrayClass, FindSystemClass("[D"));
- class_roots_->Set(kFloatArrayClass, FindSystemClass("[F"));
- class_roots_->Set(kShortArrayClass, FindSystemClass("[S"));
+ SetClassRoot(kBooleanArrayClass, FindSystemClass("[Z"));
+ SetClassRoot(kByteArrayClass, FindSystemClass("[B"));
+ SetClassRoot(kDoubleArrayClass, FindSystemClass("[D"));
+ SetClassRoot(kFloatArrayClass, FindSystemClass("[F"));
+ SetClassRoot(kShortArrayClass, FindSystemClass("[S"));
BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
- // ensure all class_roots_ were initialized
+ FinishInit();
+}
+
+void ClassLinker::FinishInit() {
+ // ensure all class_roots_ are initialized
for (size_t i = 0; i < kClassRootsMax; i++) {
- CHECK(GetClassRoot(static_cast<ClassRoot>(i)));
+ ClassRoot class_root = static_cast<ClassRoot>(i);
+ Class* klass = GetClassRoot(class_root);
+ CHECK(klass != NULL);
+ DCHECK(klass->IsArray() || klass->IsPrimitive() || klass->dex_cache_ != NULL);
+ // note SetClassRoot does additional validation.
+ // if possible add new checks there to catch errors early
}
// disable the slow paths in FindClass and CreatePrimitiveClass now
@@ -223,7 +262,125 @@
init_done_ = true;
}
-void ClassLinker::VisitRoots(Heap::RootVistor* root_visitor, void* arg) {
+struct ClassLinker::InitCallbackState {
+ ClassLinker* class_linker;
+
+ Class* class_roots[kClassRootsMax];
+
+ typedef std::tr1::unordered_map<std::string, ClassRoot> Table;
+ Table descriptor_to_class_root;
+
+ struct DexCacheHash {
+ size_t operator()(art::DexCache* const& obj) const {
+ return reinterpret_cast<size_t>(&obj);
+ }
+ };
+ typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set;
+ Set dex_caches;
+};
+
+void ClassLinker::Init(const std::vector<DexFile*>& boot_class_path, Space* space) {
+ CHECK(!init_done_);
+
+ HeapBitmap* heap_bitmap = Heap::GetLiveBits();
+ DCHECK(heap_bitmap != NULL);
+
+ InitCallbackState state;
+ state.class_linker = this;
+ for (size_t i = 0; i < kClassRootsMax; i++) {
+ ClassRoot class_root = static_cast<ClassRoot>(i);
+ state.descriptor_to_class_root[GetClassRootDescriptor(class_root)] = class_root;
+ }
+
+ // reinit clases_ table
+ heap_bitmap->Walk(InitCallback, &state);
+
+ // reinit class_roots_
+ Class* object_array_class = state.class_roots[kObjectArrayClass];
+ class_roots_ = ObjectArray<Class>::Alloc(object_array_class, kClassRootsMax);
+ for (size_t i = 0; i < kClassRootsMax; i++) {
+ ClassRoot class_root = static_cast<ClassRoot>(i);
+ SetClassRoot(class_root, state.class_roots[class_root]);
+ }
+
+ // reinit intern_table_
+ ObjectArray<Object>* interned_array = space->GetImageHeader().GetInternedArray();
+ for (int32_t i = 0; i < interned_array->GetLength(); i++) {
+ String* string = interned_array->Get(i)->AsString();
+ intern_table_.Register(string);
+ }
+
+ // reinit array_interfaces_ from any array class instance, they should all be ==
+ array_interfaces_ = GetClassRoot(kObjectArrayClass)->interfaces_;
+ DCHECK(array_interfaces_ == GetClassRoot(kBooleanArrayClass)->interfaces_);
+
+ // build a map from location to DexCache to match up with DexFile::GetLocation
+ std::tr1::unordered_map<std::string, DexCache*> location_to_dex_cache;
+ typedef InitCallbackState::Set::const_iterator It; // TODO: C++0x auto
+ for (It it = state.dex_caches.begin(), end = state.dex_caches.end(); it != end; ++it) {
+ DexCache* dex_cache = *it;
+ std::string location = dex_cache->GetLocation()->ToModifiedUtf8();
+ location_to_dex_cache[location] = dex_cache;
+ }
+
+ // reinit boot_class_path with DexFile arguments and found DexCaches
+ for (size_t i = 0; i != boot_class_path.size(); ++i) {
+ DexFile* dex_file = boot_class_path[i];
+ DexCache* dex_cache = location_to_dex_cache[dex_file->GetLocation()];
+ AppendToBootClassPath(dex_file, dex_cache);
+ }
+
+ String::SetClass(GetClassRoot(kJavaLangString));
+ BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
+ ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
+ CharArray::SetArrayClass(GetClassRoot(kCharArrayClass));
+ DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
+ FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
+ IntArray::SetArrayClass(GetClassRoot(kIntArrayClass));
+ LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
+ ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
+
+ FinishInit();
+}
+
+void ClassLinker::InitCallback(Object *obj, void *arg) {
+ DCHECK(obj != NULL);
+ DCHECK(arg != NULL);
+ InitCallbackState* state = reinterpret_cast<InitCallbackState*>(arg);
+
+ if (!obj->IsClass()) {
+ return;
+ }
+ Class* klass = obj->AsClass();
+ CHECK(klass->class_loader_ == NULL);
+
+ std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
+
+ // restore class to ClassLinker::classes_ table
+ state->class_linker->InsertClass(descriptor, klass);
+
+ // note DexCache to match with DexFile later
+ DexCache* dex_cache = klass->GetDexCache();
+ if (dex_cache != NULL) {
+ state->dex_caches.insert(dex_cache);
+ } else {
+ DCHECK(klass->IsArray() || klass->IsPrimitive());
+ }
+
+ // check if this is a root, if so, register it
+ typedef InitCallbackState::Table::const_iterator It; // TODO: C++0x auto
+ It it = state->descriptor_to_class_root.find(descriptor);
+ if (it != state->descriptor_to_class_root.end()) {
+ ClassRoot class_root = it->second;
+ state->class_roots[class_root] = klass;
+ }
+}
+
+// Keep in sync with InitCallback. Anything we visit, we need to
+// reinit references to when reinitializing a ClassLinker from a
+// mapped image.
+void ClassLinker::VisitRoots(Heap::RootVistor* root_visitor, void* arg) const {
+
root_visitor(class_roots_, arg);
for (size_t i = 0; i < dex_caches_.size(); i++) {
@@ -243,8 +400,14 @@
root_visitor(array_interfaces_, arg);
}
-DexCache* ClassLinker::AllocDexCache() {
- return down_cast<DexCache*>(AllocObjectArray<Object>(DexCache::kMax));
+DexCache* ClassLinker::AllocDexCache(const DexFile* dex_file) {
+ DexCache* dex_cache = down_cast<DexCache*>(AllocObjectArray<Object>(DexCache::kMax));
+ dex_cache->Init(String::AllocFromModifiedUtf8(dex_file->GetLocation().c_str()),
+ AllocObjectArray<String>(dex_file->NumStringIds()),
+ AllocObjectArray<Class>(dex_file->NumTypeIds()),
+ AllocObjectArray<Method>(dex_file->NumMethodIds()),
+ AllocObjectArray<Field>(dex_file->NumFieldIds()));
+ return dex_cache;
}
Class* ClassLinker::AllocClass(Class* java_lang_Class) {
@@ -537,21 +700,27 @@
}
}
-void ClassLinker::AppendToBootClassPath(DexFile* dex_file) {
+void ClassLinker::AppendToBootClassPath(const DexFile* dex_file) {
CHECK(dex_file != NULL);
+ AppendToBootClassPath(dex_file, AllocDexCache(dex_file));
+}
+
+void ClassLinker::AppendToBootClassPath(const DexFile* dex_file, DexCache* dex_cache) {
+ CHECK(dex_file != NULL);
+ CHECK(dex_cache != NULL);
boot_class_path_.push_back(dex_file);
- RegisterDexFile(dex_file);
+ RegisterDexFile(dex_file, dex_cache);
}
void ClassLinker::RegisterDexFile(const DexFile* dex_file) {
CHECK(dex_file != NULL);
- dex_files_.push_back(dex_file);
- DexCache* dex_cache = AllocDexCache();
+ RegisterDexFile(dex_file, AllocDexCache(dex_file));
+}
+
+void ClassLinker::RegisterDexFile(const DexFile* dex_file, DexCache* dex_cache) {
+ CHECK(dex_file != NULL);
CHECK(dex_cache != NULL);
- dex_cache->Init(AllocObjectArray<String>(dex_file->NumStringIds()),
- AllocObjectArray<Class>(dex_file->NumTypeIds()),
- AllocObjectArray<Method>(dex_file->NumMethodIds()),
- AllocObjectArray<Field>(dex_file->NumFieldIds()));
+ dex_files_.push_back(dex_file);
dex_caches_.push_back(dex_cache);
}