Initialize ClassLinker from image
Change-Id: Ibaf47b4181f7c6603a8b37e2eba8fa6509c927ed
diff --git a/src/calling_convention.cc b/src/calling_convention.cc
index d14857b..32e3ee2 100644
--- a/src/calling_convention.cc
+++ b/src/calling_convention.cc
@@ -24,7 +24,7 @@
void ManagedRuntimeCallingConvention::Next() {
CHECK(HasNext());
- if (IsCurrentUserArg() &&
+ if (IsCurrentUserArg() &&
GetMethod()->IsParamALongOrDouble(itr_args_)) {
itr_longs_and_doubles_++;
itr_slots_++;
diff --git a/src/casts.h b/src/casts.h
index a5e31c4..461df21 100644
--- a/src/casts.h
+++ b/src/casts.h
@@ -59,7 +59,7 @@
implicit_cast<From*, To>(0);
}
- //
+ //
// assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only!
return static_cast<To>(f);
}
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);
}
diff --git a/src/class_linker.h b/src/class_linker.h
index bc7a780..ad29383 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -14,6 +14,7 @@
#include "object.h"
#include "thread.h"
#include "unordered_map.h"
+#include "unordered_set.h"
#include "gtest/gtest.h"
@@ -21,11 +22,20 @@
class ClassLinker {
public:
- // Initializes the class linker.
- static ClassLinker* Create(const std::vector<DexFile*>& boot_class_path);
+ // Initializes the class linker using DexFile and an optional boot Space.
+ static ClassLinker* Create(const std::vector<DexFile*>& boot_class_path, Space* boot_space);
~ClassLinker() {
delete classes_lock_;
+ String::ResetClass();
+ BooleanArray::ResetArrayClass();
+ ByteArray::ResetArrayClass();
+ CharArray::ResetArrayClass();
+ DoubleArray::ResetArrayClass();
+ FloatArray::ResetArrayClass();
+ IntArray::ResetArrayClass();
+ LongArray::ResetArrayClass();
+ ShortArray::ResetArrayClass();
}
// Finds a class by its descriptor name.
@@ -43,17 +53,31 @@
bool EnsureInitialized(Class* c);
void RegisterDexFile(const DexFile* dex_file);
+ void RegisterDexFile(const DexFile* dex_file, DexCache* dex_cache);
- void VisitRoots(Heap::RootVistor* root_visitor, void* arg);
+ const InternTable& GetInternTable() {
+ return intern_table_;
+ }
+
+ void VisitRoots(Heap::RootVistor* root_visitor, void* arg) const;
private:
ClassLinker()
: classes_lock_(Mutex::Create("ClassLinker::Lock")),
+ class_roots_(NULL),
init_done_(false) {
}
+ // Initialize class linker from DexFile instances.
void Init(const std::vector<DexFile*>& boot_class_path_);
+ // Initialize class linker from pre-initialized space.
+ void Init(const std::vector<DexFile*>& boot_class_path_, Space* space);
+ static void InitCallback(Object *obj, void *arg);
+ struct InitCallbackState;
+
+ void FinishInit();
+
bool InitializeClass(Class* klass);
// For early bootstrapping by Init
@@ -63,12 +87,12 @@
// values that are known to the ClassLinker such as
// kObjectArrayClass and kJavaLangString etc.
Class* AllocClass();
- DexCache* AllocDexCache();
+ DexCache* AllocDexCache(const DexFile* dex_file);
Field* AllocField();
Method* AllocMethod();
template <class T>
ObjectArray<T>* AllocObjectArray(size_t length) {
- return ObjectArray<T>::Alloc(class_roots_->Get(kObjectArrayClass), length);
+ return ObjectArray<T>::Alloc(GetClassRoot(kObjectArrayClass), length);
}
PathClassLoader* AllocPathClassLoader(std::vector<const DexFile*> dex_files);
@@ -81,7 +105,8 @@
DexCache* FindDexCache(const DexFile* dex_file) const;
- void AppendToBootClassPath(DexFile* dex_file);
+ void AppendToBootClassPath(const DexFile* dex_file);
+ void AppendToBootClassPath(const DexFile* dex_file, DexCache* dex_cache);
void LoadClass(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
@@ -165,7 +190,8 @@
InternTable intern_table_;
- // indexes into class_roots_
+ // indexes into class_roots_.
+ // needs to be kept in sync with class_roots_descriptors_.
enum ClassRoot {
kJavaLangClass,
kJavaLangObject,
@@ -198,11 +224,33 @@
ObjectArray<Class>* class_roots_;
Class* GetClassRoot(ClassRoot class_root) {
+ DCHECK(class_roots_ != NULL);
Class* klass = class_roots_->Get(class_root);
DCHECK(klass != NULL);
return klass;
}
+ void SetClassRoot(ClassRoot class_root, Class* klass) {
+ DCHECK(!init_done_);
+
+ DCHECK(klass != NULL);
+ DCHECK(klass->class_loader_ == NULL);
+ DCHECK(klass->descriptor_ != NULL);
+ DCHECK(klass->descriptor_->Equals(GetClassRootDescriptor(class_root)));
+
+ DCHECK(class_roots_ != NULL);
+ DCHECK(class_roots_->Get(class_root) == NULL);
+ class_roots_->Set(class_root, klass);
+ }
+
+ static const char* class_roots_descriptors_[kClassRootsMax];
+
+ const char* GetClassRootDescriptor(ClassRoot class_root) {
+ const char* descriptor = class_roots_descriptors_[class_root];
+ CHECK(descriptor != NULL);
+ return descriptor;
+ }
+
ObjectArray<Class>* array_interfaces_;
InterfaceEntry* array_iftable_;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 42a773c..88ddd07 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -134,11 +134,15 @@
Method* method = klass->GetDirectMethod(i);
EXPECT_TRUE(method != NULL);
EXPECT_EQ(klass, method->GetDeclaringClass());
+ EXPECT_TRUE(method->GetName() != NULL);
+ EXPECT_TRUE(method->GetSignature() != NULL);
}
for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
Method* method = klass->GetVirtualMethod(i);
EXPECT_TRUE(method != NULL);
+ EXPECT_TRUE(method->GetName() != NULL);
+ EXPECT_TRUE(method->GetSignature() != NULL);
}
for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
@@ -146,6 +150,8 @@
EXPECT_TRUE(field != NULL);
EXPECT_FALSE(field->IsStatic());
EXPECT_EQ(klass, field->GetDeclaringClass());
+ EXPECT_TRUE(field->GetName() != NULL);
+ EXPECT_TRUE(field->GetDescriptor() != NULL);
}
for (size_t i = 0; i < klass->NumStaticFields(); i++) {
@@ -153,22 +159,20 @@
EXPECT_TRUE(field != NULL);
EXPECT_TRUE(field->IsStatic());
EXPECT_EQ(klass, field->GetDeclaringClass());
- }
+ EXPECT_TRUE(field->GetName() != NULL);
+ EXPECT_TRUE(field->GetDescriptor() != 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++) {
Field* 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++) {
Field* 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());
@@ -207,7 +211,7 @@
}
TEST_F(ClassLinkerTest, FindClassNested) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kNestedDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kNestedDex, "kNestedDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Class* outer = class_linker_->FindClass("LNested;", class_loader);
@@ -262,7 +266,7 @@
EXPECT_EQ(0U, JavaLangObject->NumInterfaces());
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassDex, "kMyClassDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
EXPECT_TRUE(linker->FindSystemClass("LMyClass;") == NULL);
Class* MyClass = linker->FindClass("LMyClass;", class_loader);
@@ -378,8 +382,8 @@
}
TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
- scoped_ptr<DexFile> dex_1(OpenDexFileBase64(kMyClassDex));
- scoped_ptr<DexFile> dex_2(OpenDexFileBase64(kMyClassDex));
+ scoped_ptr<DexFile> dex_1(OpenDexFileBase64(kMyClassDex, "kMyClassDex"));
+ scoped_ptr<DexFile> dex_2(OpenDexFileBase64(kMyClassDex, "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);
@@ -391,7 +395,7 @@
TEST_F(ClassLinkerTest, StaticFields) {
// TODO: uncomment expectations of initial values when InitializeClass works
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStatics));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStatics, "kStatics"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Class* statics = class_linker_->FindClass("LStatics;", class_loader);
// class_linker_->InitializeClass(statics); // TODO: uncomment this
@@ -441,7 +445,7 @@
Field* s8 = statics->GetStaticField(8);
EXPECT_EQ('L', s8->GetType());
-// EXPECT_TRUE(down_cast<String*>(s8->GetObject())->Equals("android")); // TODO: uncomment this
+// EXPECT_TRUE(s8->GetObject()->AsString()->Equals("android")); // TODO: uncomment this
s8->SetObject(String::AllocFromModifiedUtf8("robot"));
Field* s9 = statics->GetStaticField(9);
@@ -457,7 +461,7 @@
EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong());
EXPECT_EQ(0.75, s6->GetFloat());
EXPECT_EQ(16777219, s7->GetDouble());
- EXPECT_TRUE(down_cast<String*>(s8->GetObject())->Equals("robot"));
+ EXPECT_TRUE(s8->GetObject()->AsString()->Equals("robot"));
}
} // namespace art
diff --git a/src/common_test.h b/src/common_test.h
index 14a68a2..685e627 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -277,12 +277,12 @@
"AAwAAADgAAAABQAAAA4AAABwAQAABgAAAAEAAADgAQAAASAAAA0AAAAAAgAAARAAAAsAAAA4AwAA"
"AiAAABYAAACuAwAAAyAAAA0AAABXBAAAACAAAAEAAAC3BAAAABAAAAEAAAD0BAAA";
-static inline DexFile* OpenDexFileBase64(const char* base64) {
+static inline DexFile* OpenDexFileBase64(const char* base64, const std::string& location) {
CHECK(base64 != NULL);
size_t length;
byte* dex_bytes = DecodeBase64(base64, &length);
CHECK(dex_bytes != NULL);
- DexFile* dex_file = DexFile::OpenPtr(dex_bytes, length);
+ DexFile* dex_file = DexFile::OpenPtr(dex_bytes, length, location);
CHECK(dex_file != NULL);
return dex_file;
}
diff --git a/src/dex_cache.cc b/src/dex_cache.cc
index 8ab4130..3bd04eb 100644
--- a/src/dex_cache.cc
+++ b/src/dex_cache.cc
@@ -8,14 +8,16 @@
namespace art {
-void DexCache::Init(ObjectArray<String>* strings,
+void DexCache::Init(String* location,
+ ObjectArray<String>* strings,
ObjectArray<Class>* classes,
ObjectArray<Method>* methods,
ObjectArray<Field>* fields) {
- Set(kStrings, strings);
- Set(kClasses, classes);
- Set(kMethods, methods);
- Set(kFields, fields);
+ Set(kLocation, location);
+ Set(kStrings, strings);
+ Set(kClasses, classes);
+ Set(kMethods, methods);
+ Set(kFields, fields);
}
} // namespace art
diff --git a/src/dex_cache.h b/src/dex_cache.h
index 5f3c54f..534a29b 100644
--- a/src/dex_cache.h
+++ b/src/dex_cache.h
@@ -19,18 +19,24 @@
public:
enum ArrayIndexes {
- kStrings = 0,
- kClasses = 1,
- kMethods = 2,
- kFields = 3,
- kMax = 4,
+ kLocation = 0,
+ kStrings = 1,
+ kClasses = 2,
+ kMethods = 3,
+ kFields = 4,
+ kMax = 5,
};
- void Init(ObjectArray<String>* strings,
+ void Init(String* location,
+ ObjectArray<String>* strings,
ObjectArray<Class>* classes,
ObjectArray<Method>* methods,
ObjectArray<Field>* fields);
+ String* GetLocation() const {
+ return Get(kLocation)->AsString();
+ }
+
size_t NumStrings() const {
return GetStrings()->GetLength();
}
@@ -81,16 +87,16 @@
private:
ObjectArray<String>* GetStrings() const {
- return static_cast<ObjectArray<String>*>(Get(kStrings));
+ return static_cast<ObjectArray<String>*>(Get(kStrings));
}
ObjectArray<Class>* GetClasses() const {
- return static_cast<ObjectArray<Class>*>(Get(kClasses));
+ return static_cast<ObjectArray<Class>*>(Get(kClasses));
}
ObjectArray<Method>* GetMethods() const {
- return static_cast<ObjectArray<Method>*>(Get(kMethods));
+ return static_cast<ObjectArray<Method>*>(Get(kMethods));
}
ObjectArray<Field>* GetFields() const {
- return static_cast<ObjectArray<Field>*>(Get(kFields));
+ return static_cast<ObjectArray<Field>*>(Get(kFields));
}
DexCache();
};
diff --git a/src/dex_cache_test.cc b/src/dex_cache_test.cc
index cb682a0..674ec0f 100644
--- a/src/dex_cache_test.cc
+++ b/src/dex_cache_test.cc
@@ -16,16 +16,12 @@
TEST_F(DexCacheTest, Open) {
- DexCache* dex_cache = class_linker_->AllocDexCache();
+ DexCache* dex_cache = class_linker_->AllocDexCache(java_lang_dex_file_.get());
ASSERT_TRUE(dex_cache != NULL);
- dex_cache->Init(class_linker_->AllocObjectArray<String>(1),
- class_linker_->AllocObjectArray<Class>(2),
- class_linker_->AllocObjectArray<Method>(3),
- class_linker_->AllocObjectArray<Field>(4));
- EXPECT_EQ(1U, dex_cache->NumStrings());
- EXPECT_EQ(2U, dex_cache->NumClasses());
- EXPECT_EQ(3U, dex_cache->NumMethods());
- EXPECT_EQ(4U, dex_cache->NumFields());
+ EXPECT_EQ(java_lang_dex_file_->NumStringIds(), dex_cache->NumStrings());
+ EXPECT_EQ(java_lang_dex_file_->NumTypeIds(), dex_cache->NumClasses());
+ EXPECT_EQ(java_lang_dex_file_->NumMethodIds(), dex_cache->NumMethods());
+ EXPECT_EQ(java_lang_dex_file_->NumFieldIds(), dex_cache->NumFields());
}
} // namespace art
diff --git a/src/dex_file.cc b/src/dex_file.cc
index b9ae7e3..14c62f1 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -77,7 +77,7 @@
close(fd);
byte* dex_file = reinterpret_cast<byte*>(addr);
Closer* closer = new MmapCloser(addr, length);
- return Open(dex_file, length, closer);
+ return Open(dex_file, length, filename, closer);
}
static const char* kClassesDex = "classes.dex";
@@ -294,15 +294,15 @@
// NOTREACHED
}
-DexFile* DexFile::OpenPtr(byte* ptr, size_t length) {
+DexFile* DexFile::OpenPtr(byte* ptr, size_t length, const std::string& location) {
CHECK(ptr != NULL);
DexFile::Closer* closer = new PtrCloser(ptr);
- return Open(ptr, length, closer);
+ return Open(ptr, length, location, closer);
}
DexFile* DexFile::Open(const byte* dex_bytes, size_t length,
- Closer* closer) {
- scoped_ptr<DexFile> dex_file(new DexFile(dex_bytes, length, closer));
+ const std::string& location, Closer* closer) {
+ scoped_ptr<DexFile> dex_file(new DexFile(dex_bytes, length, location, closer));
if (!dex_file->Init()) {
return NULL;
} else {
diff --git a/src/dex_file.h b/src/dex_file.h
index 2de46f8..b3f9bdd 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -288,13 +288,21 @@
// Opens a .jar, .zip, or .apk file from the file system.
static DexFile* OpenZip(const std::string& filename);
- // Opens a .dex file from a new allocated pointer
- static DexFile* OpenPtr(byte* ptr, size_t length);
+ // Opens a .dex file from a new allocated pointer. location is used
+ // to identify the source, for example "/system/framework/core.jar"
+ // or "contrived-test-42". When initializing a ClassLinker from an
+ // image, the location is used to match DexCaches the image to their
+ // corresponding DexFiles.N
+ static DexFile* OpenPtr(byte* ptr, size_t length, const std::string& location);
// Closes a .dex file.
virtual ~DexFile();
- const Header& GetHeader() {
+ const std::string& GetLocation() const {
+ return location_;
+ }
+
+ const Header& GetHeader() const {
CHECK(header_ != NULL);
return *header_;
}
@@ -640,11 +648,12 @@
};
// Opens a .dex file at a the given address.
- static DexFile* Open(const byte* dex_file, size_t length, Closer* closer);
+ static DexFile* Open(const byte* dex_file, size_t length, const std::string& location, Closer* closer);
- DexFile(const byte* addr, size_t length, Closer* closer)
+ DexFile(const byte* addr, size_t length, const std::string& location, Closer* closer)
: base_(addr),
length_(length),
+ location_(location),
closer_(closer),
header_(0),
string_ids_(0),
@@ -652,7 +661,11 @@
field_ids_(0),
method_ids_(0),
proto_ids_(0),
- class_defs_(0) {}
+ class_defs_(0) {
+ CHECK(addr != NULL);
+ CHECK_GT(length, 0U);
+ CHECK(closer != NULL);
+ }
// Top-level initializer that calls other Init methods.
bool Init();
@@ -679,6 +692,12 @@
// The size of the underlying memory allocation in bytes.
size_t length_;
+ // Typically the dex file name when availble, alternatively some identifying string.
+ //
+ // The ClassLinker will use this to match DexFiles the boot class
+ // path to DexCache::GetLocation when loading from an image.
+ const std::string location_;
+
// Helper object to free the underlying allocation.
scoped_ptr<Closer> closer_;
diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc
index 616e1c4..9eb5f73 100644
--- a/src/dex_file_test.cc
+++ b/src/dex_file_test.cc
@@ -10,12 +10,12 @@
namespace art {
TEST(DexFileTest, Open) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kNestedDex));
+ scoped_ptr<const DexFile> dex(OpenDexFileBase64(kNestedDex, "kNestedDex"));
ASSERT_TRUE(dex != NULL);
}
TEST(DexFileTest, Header) {
- scoped_ptr<DexFile> raw(OpenDexFileBase64(kNestedDex));
+ scoped_ptr<const DexFile> raw(OpenDexFileBase64(kNestedDex, "kNestedDex"));
ASSERT_TRUE(raw != NULL);
const DexFile::Header& header = raw->GetHeader();
@@ -43,7 +43,7 @@
}
TEST(DexFileTest, ClassDefs) {
- scoped_ptr<DexFile> raw(OpenDexFileBase64(kNestedDex));
+ scoped_ptr<const DexFile> raw(OpenDexFileBase64(kNestedDex, "kNestedDex"));
ASSERT_TRUE(raw != NULL);
EXPECT_EQ(2U, raw->NumClassDefs());
@@ -55,7 +55,7 @@
}
TEST(DexFileTest, CreateMethodDescriptor) {
- scoped_ptr<DexFile> raw(OpenDexFileBase64(kCreateMethodDescriptorDex));
+ scoped_ptr<const DexFile> raw(OpenDexFileBase64(kCreateMethodDescriptorDex, "kCreateMethodDescriptorDex"));
ASSERT_TRUE(raw != NULL);
EXPECT_EQ(1U, raw->NumClassDefs());
diff --git a/src/exception_test.cc b/src/exception_test.cc
index e2f97c0..a9673ef 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -64,7 +64,7 @@
};
TEST_F(ExceptionTest, MyClass_F_G) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassExceptionHandleDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassExceptionHandleDex, "kMyClassExceptionHandleDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Class* klass = class_linker_->FindClass("Ljava/lang/MyClass;", class_loader);
ASSERT_TRUE(klass != NULL);
diff --git a/src/heap.cc b/src/heap.cc
index 643d056..7369804 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -15,6 +15,8 @@
std::vector<Space*> Heap::spaces_;
+Space* Heap::boot_space_ = NULL;
+
Space* Heap::alloc_space_ = NULL;
size_t Heap::maximum_size_ = 0;
@@ -79,6 +81,7 @@
// Make objects in boot_space live (after live_bitmap_ is set)
if (boot_image_file_name != NULL) {
+ boot_space_ = boot_space;
RecordImageAllocations(boot_space);
}
diff --git a/src/heap.h b/src/heap.h
index 0cf0b57..4d45366 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -47,6 +47,10 @@
return spaces_;
}
+ static Space* GetBootSpace() {
+ return boot_space_;
+ }
+
static HeapBitmap* GetLiveBits() {
return live_bitmap_;
}
@@ -72,6 +76,9 @@
static std::vector<Space*> spaces_;
+ // Space loaded from an image
+ static Space* boot_space_;
+
// default Space for allocations
static Space* alloc_space_;
diff --git a/src/image.h b/src/image.h
index c4123e8..c567880 100644
--- a/src/image.h
+++ b/src/image.h
@@ -6,6 +6,7 @@
#include <string.h>
#include "globals.h"
+#include "object.h"
namespace art {
@@ -14,7 +15,8 @@
public:
ImageHeader() {}
- ImageHeader(uint32_t base_addr) : base_addr_(base_addr) {
+ ImageHeader(uint32_t base_addr, uint32_t intern_addr)
+ : base_addr_(base_addr), intern_addr_(intern_addr) {
memcpy(magic_, kImageMagic, sizeof(kImageMagic));
memcpy(version_, kImageVersion, sizeof(kImageVersion));
}
@@ -33,13 +35,22 @@
return reinterpret_cast<byte*>(base_addr_);
}
+ ObjectArray<Object>* GetInternedArray() const {
+ return reinterpret_cast<ObjectArray<Object>*>(intern_addr_);
+ }
+
private:
static const byte kImageMagic[4];
static const byte kImageVersion[4];
byte magic_[4];
byte version_[4];
+
+ // required base address for mapping the image.
uint32_t base_addr_;
+
+ // absolute address of an Object[] of Strings to InternTable::Register
+ uint32_t intern_addr_;
};
} // namespace art
diff --git a/src/image_test.cc b/src/image_test.cc
index c68b600..8c00e89 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -31,7 +31,16 @@
}
TEST_F(ImageTest, WriteRead) {
+
+ // TODO: move the touching of classes and GC to the ImageWriter proper
+ for (size_t i = 0; i < java_lang_dex_file_->NumClassDefs(); i++) {
+ const DexFile::ClassDef class_def = java_lang_dex_file_->GetClassDef(i);
+ const char* descriptor = java_lang_dex_file_->GetClassDescriptor(class_def);
+ Class* klass = class_linker_->FindSystemClass(descriptor);
+ ASSERT_TRUE(klass != NULL) << descriptor;
+ }
// TODO: Heap::CollectGarbage before writing
+
const std::vector<Space*>& spaces = Heap::GetSpaces();
// can't currently deal with writing a space that might have pointers between spaces
ASSERT_EQ(1U, spaces.size());
@@ -52,7 +61,7 @@
ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->Length()));
}
- // tear down old runtime and make a new one
+ // tear down old runtime before making a new one, clearing out misc state
delete runtime_.release();
// don't reuse java_lang_dex_file_ so we make sure we don't get
@@ -74,27 +83,27 @@
runtime_.reset(Runtime::Create(options, false));
ASSERT_TRUE(runtime_ != NULL);
class_linker_ = runtime_->GetClassLinker();
-
- if (true) {
- const char* maps_file = "/proc/self/maps";
- std::string contents = ReadFileToString(maps_file);
- LG << maps_file << ":\n" << contents;
- }
ASSERT_EQ(2U, Heap::GetSpaces().size());
Space* boot_space = Heap::GetSpaces()[0];
ASSERT_TRUE(boot_space != NULL);
- // TODO: need to rebuild ClassLinker::classes_ and ::intern_table_
- // byte* boot_base = boot_space->GetBase();
- // byte* boot_limit = boot_space->GetLimit();
+ // enable to display maps to debug boot_base and boot_limit checking problems below
+ if (false) {
+ const char* maps_file = "/proc/self/maps";
+ std::string contents = ReadFileToString(maps_file);
+ LG << maps_file << ":\n" << contents;
+ }
+
+ byte* boot_base = boot_space->GetBase();
+ byte* boot_limit = boot_space->GetLimit();
for (size_t i = 0; i < dex->NumClassDefs(); i++) {
const DexFile::ClassDef class_def = dex->GetClassDef(i);
const char* descriptor = dex->GetClassDescriptor(class_def);
Class* klass = class_linker_->FindSystemClass(descriptor);
- EXPECT_TRUE(klass != NULL);
- // EXPECT_LT(boot_base, reinterpret_cast<byte*>(klass));
- // EXPECT_LT(reinterpret_cast<byte*>(klass), boot_limit);
+ EXPECT_TRUE(klass != NULL) << descriptor;
+ EXPECT_LT(boot_base, reinterpret_cast<byte*>(klass)) << descriptor;
+ EXPECT_LT(reinterpret_cast<byte*>(klass), boot_limit) << descriptor;
}
}
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 4335a90..1c7acff 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -6,10 +6,12 @@
#include <vector>
#include "dex_cache.h"
+#include "class_linker.h"
#include "file.h"
#include "globals.h"
#include "heap.h"
#include "image.h"
+#include "intern_table.h"
#include "logging.h"
#include "object.h"
#include "space.h"
@@ -43,6 +45,40 @@
return true;
}
+namespace {
+
+struct InternTableVisitorState {
+ int index;
+ ObjectArray<Object>* interned_array;
+};
+
+void InternTableVisitor(Object* obj, void* arg) {
+ InternTableVisitorState* state = reinterpret_cast<InternTableVisitorState*>(arg);
+ state->interned_array->Set(state->index++, obj);
+}
+
+ObjectArray<Object>* CreateInternedArray() {
+ // build a Object[] of the interned strings for reinit
+ // TODO: avoid creating this future garbage
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ const InternTable& intern_table = class_linker->GetInternTable();
+ size_t size = intern_table.Size();
+ CHECK_NE(0U, size);
+
+ Class* object_array_class = class_linker->FindSystemClass("[Ljava/lang/Object;");
+ ObjectArray<Object>* interned_array = ObjectArray<Object>::Alloc(object_array_class, size);
+
+ InternTableVisitorState state;
+ state.index = 0;
+ state.interned_array = interned_array;
+
+ intern_table.VisitRoots(InternTableVisitor, &state);
+
+ return interned_array;
+}
+
+} // namespace
+
void ImageWriter::CalculateNewObjectOffsetsCallback(Object *obj, void *arg) {
DCHECK(obj != NULL);
DCHECK(arg != NULL);
@@ -53,14 +89,24 @@
}
void ImageWriter::CalculateNewObjectOffsets() {
+ ObjectArray<Object>* interned_array = CreateInternedArray();
+
HeapBitmap* heap_bitmap = Heap::GetLiveBits();
DCHECK(heap_bitmap != NULL);
DCHECK_EQ(0U, image_top_);
- ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_));
- memcpy(image_->GetAddress(), &image_header, sizeof(image_header));
- image_top_ += RoundUp(sizeof(image_header), 8); // 64-bit-alignment
+
+ // leave space for the header, but do not write it yet, we need to
+ // know where interned_array is going to end up
+ image_top_ += RoundUp(sizeof(ImageHeader), 8); // 64-bit-alignment
+
heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this);
DCHECK_LT(image_top_, image_->GetLength());
+
+ // return to write header at start of image with future location of interned_array
+ ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_),
+ reinterpret_cast<uint32_t>(GetImageAddress(interned_array)));
+ memcpy(image_->GetAddress(), &image_header, sizeof(image_header));
+
// Note that top_ is left at end of used space
}
@@ -92,6 +138,10 @@
// TODO: special case init of pointers to malloc data (or removal of these pointers)
if (orig->IsClass()) {
FixupClass(orig->AsClass(), down_cast<Class*>(copy));
+ } else if (orig->IsMethod()) {
+ FixupMethod(orig->AsMethod(), down_cast<Method*>(copy));
+ } else if (orig->IsField()) {
+ FixupField(orig->AsField(), down_cast<Field*>(copy));
} else if (orig->IsObjectArray()) {
FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy));
} else {
@@ -117,6 +167,20 @@
copy->static_references_ = down_cast<ObjectArray<Object>*>(GetImageAddress(orig->static_references_));
}
+// TODO: remove this slow path
+void ImageWriter::FixupMethod(Method* orig, Method* copy) {
+ FixupInstanceFields(orig, copy);
+ // TODO: remove need for this by adding "signature" to java.lang.reflect.Method
+ copy->signature_ = down_cast<String*>(GetImageAddress(orig->signature_));
+ DCHECK(copy->signature_ != NULL);
+ // TODO: convert shorty_ to heap allocated storage
+}
+
+void ImageWriter::FixupField(Field* orig, Field* copy) {
+ FixupInstanceFields(orig, copy);
+ // TODO: convert descriptor_ to heap allocated storage
+}
+
void ImageWriter::FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
for (int32_t i = 0; i < orig->GetLength(); ++i) {
const Object* element = orig->Get(i);
diff --git a/src/image_writer.h b/src/image_writer.h
index 8ae8f7d..8e9ac10 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -51,6 +51,8 @@
void CopyAndFixupObjects();
static void CopyAndFixupObjectsCallback(Object *obj, void *arg);
void FixupClass(Class* orig, Class* copy);
+ void FixupMethod(Method* orig, Method* copy);
+ void FixupField(Field* orig, Field* copy);
void FixupObject(Object* orig, Object* copy);
void FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy);
void FixupInstanceFields(Object* orig, Object* copy);
diff --git a/src/intern_table.cc b/src/intern_table.cc
index 3ef5917..e070573 100644
--- a/src/intern_table.cc
+++ b/src/intern_table.cc
@@ -14,11 +14,15 @@
delete intern_table_lock_;
}
-void InternTable::VisitRoots(Heap::RootVistor* root_visitor, void* arg) {
+size_t InternTable::Size() const {
+ return intern_table_.size();
+}
+
+void InternTable::VisitRoots(Heap::RootVistor* root_visitor, void* arg) const {
MutexLock mu(intern_table_lock_);
typedef Table::const_iterator It; // TODO: C++0x auto
for (It it = intern_table_.begin(), end = intern_table_.end(); it != end; ++it) {
- root_visitor(it->second, arg);
+ root_visitor(it->second, arg);
}
}
@@ -36,9 +40,13 @@
}
}
String* new_string = String::AllocFromUtf16(utf16_length, utf16_data_out.get(), hash_code);
- intern_table_.insert(std::make_pair(hash_code, new_string));
+ Register(new_string);
return new_string;
}
}
+void InternTable::Register(String* string) {
+ intern_table_.insert(std::make_pair(string->GetHashCode(), string));
+}
+
} // namespace art
diff --git a/src/intern_table.h b/src/intern_table.h
index 0a1554d..46e0e05 100644
--- a/src/intern_table.h
+++ b/src/intern_table.h
@@ -14,8 +14,16 @@
public:
InternTable();
~InternTable();
+
+ // intern a potentially new string
String* Intern(int32_t utf16_length, const char* utf8_data);
- void VisitRoots(Heap::RootVistor* root_visitor, void* arg);
+
+ // register a String trusting that it is safe to intern.
+ // used when reinitializing InternTable from an image.
+ void Register(String* string);
+
+ size_t Size() const;
+ void VisitRoots(Heap::RootVistor* root_visitor, void* arg) const;
private:
typedef std::tr1::unordered_multimap<int32_t, String*> Table;
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 8a5155f..cb48e76 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -21,7 +21,7 @@
protected:
virtual void SetUp() {
CommonTest::SetUp();
- dex_.reset(OpenDexFileBase64(kMyClassNativesDex));
+ dex_.reset(OpenDexFileBase64(kMyClassNativesDex, "kMyClassNativesDex"));
class_loader_ = AllocPathClassLoader(dex_.get());
}
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 6c5d6f2..b9e8f19 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -456,7 +456,7 @@
#if defined(__arm__)
TEST_F(JniInternalTest, StaticMainMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMainDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kMainDex, "kMainDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -484,7 +484,7 @@
}
TEST_F(JniInternalTest, StaticNopMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -511,7 +511,7 @@
}
TEST_F(JniInternalTest, StaticIdentityByteMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -559,7 +559,7 @@
}
TEST_F(JniInternalTest, StaticIdentityIntMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -607,7 +607,7 @@
}
TEST_F(JniInternalTest, StaticIdentityDoubleMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -656,7 +656,7 @@
}
TEST_F(JniInternalTest, StaticSumIntIntMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -716,7 +716,7 @@
}
TEST_F(JniInternalTest, StaticSumIntIntIntMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -783,7 +783,7 @@
}
TEST_F(JniInternalTest, StaticSumIntIntIntIntMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -856,7 +856,7 @@
}
TEST_F(JniInternalTest, StaticSumIntIntIntIntIntMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -936,7 +936,7 @@
}
TEST_F(JniInternalTest, StaticSumDoubleDoubleMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -997,7 +997,7 @@
}
TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -1051,7 +1051,7 @@
}
TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
@@ -1110,7 +1110,7 @@
}
TEST_F(JniInternalTest, StaticSumDoubleDoubleDoubleDoubleDoubleMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStaticLeafMethodsDex, "kStaticLeafMethodsDex"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
ASSERT_TRUE(class_loader != NULL);
diff --git a/src/object.cc b/src/object.cc
index bfa200a..3200e4d 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -526,9 +526,15 @@
// TODO: get global references for these
Class* String::java_lang_String_ = NULL;
-void String::InitClass(Class* java_lang_String) {
+void String::SetClass(Class* java_lang_String) {
+ CHECK(java_lang_String_ == NULL);
+ CHECK(java_lang_String != NULL);
java_lang_String_ = java_lang_String;
}
+void String::ResetClass() {
+ CHECK(java_lang_String_ != NULL);
+ java_lang_String_ = NULL;
+}
static const char* kClassStatusNames[] = {
"Error",
diff --git a/src/object.h b/src/object.h
index ca09d07..e246dea 100644
--- a/src/object.h
+++ b/src/object.h
@@ -239,6 +239,27 @@
return down_cast<const Array*>(this);
}
+ bool IsString() const;
+
+ String* AsString() {
+ DCHECK(IsString());
+ return down_cast<String*>(this);
+ }
+
+ bool IsMethod() const;
+
+ Method* AsMethod() {
+ DCHECK(IsMethod());
+ return down_cast<Method*>(this);
+ }
+
+ bool IsField() const;
+
+ Field* AsField() {
+ DCHECK(IsField());
+ return down_cast<Field*>(this);
+ }
+
public:
Class* klass_;
@@ -285,10 +306,12 @@
class Field : public AccessibleObject {
public:
Class* GetDeclaringClass() const {
+ DCHECK(declaring_class_ != NULL);
return declaring_class_;
}
const String* GetName() const {
+ DCHECK(name_ != NULL);
return name_;
}
@@ -364,14 +387,17 @@
// Returns the method name, e.g. "<init>" or "eatLunch"
const String* GetName() const {
+ DCHECK(name_ != NULL);
return name_;
}
const String* GetSignature() const {
+ DCHECK(signature_ != NULL);
return signature_;
}
Class* GetDeclaringClass() const {
+ DCHECK(declaring_class_ != NULL);
return declaring_class_;
}
@@ -1177,7 +1203,8 @@
}
inline bool Object::IsClass() const {
- return klass_ == klass_->klass_;
+ Class* java_lang_Class = klass_->klass_;
+ return klass_ == java_lang_Class;
}
inline bool Object::IsObjectArray() const {
@@ -1188,6 +1215,18 @@
return klass_->IsArray();
}
+inline bool Object::IsField() const {
+ Class* java_lang_Class = klass_->klass_;
+ Class* java_lang_reflect_Field = java_lang_Class->GetInstanceField(0)->klass_;
+ return klass_ == java_lang_reflect_Field;
+}
+
+inline bool Object::IsMethod() const {
+ Class* java_lang_Class = klass_->klass_;
+ Class* java_lang_reflect_Method = java_lang_Class->GetDirectMethod(0)->klass_;
+ return klass_ == java_lang_reflect_Method;
+}
+
inline size_t Object::SizeOf() const {
if (IsArray()) {
return AsArray()->SizeOf();
@@ -1236,10 +1275,16 @@
}
static void SetArrayClass(Class* array_class) {
+ CHECK(array_class_ == NULL);
CHECK(array_class != NULL);
array_class_ = array_class;
}
+ static void ResetArrayClass() {
+ CHECK(array_class_ != NULL);
+ array_class_ = NULL;
+ }
+
private:
// Location of first element.
T elements_[0];
@@ -1281,7 +1326,7 @@
}
static String* AllocFromUtf16(int32_t utf16_length,
- uint16_t* utf16_data_in,
+ const uint16_t* utf16_data_in,
int32_t hash_code) {
String* string = Alloc(GetJavaLangString(),
utf16_length);
@@ -1307,7 +1352,8 @@
return string;
}
- static void InitClass(Class* java_lang_String);
+ static void SetClass(Class* java_lang_String);
+ static void ResetClass();
static String* Alloc(Class* java_lang_String,
int32_t utf16_length) {
@@ -1489,6 +1535,11 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(String);
};
+inline bool Object::IsString() const {
+ // TODO use "klass_ == String::GetJavaLangString()" instead?
+ return klass_ == klass_->descriptor_->klass_;
+}
+
inline size_t Class::GetTypeSize(String* descriptor) {
switch (descriptor->CharAt(0)) {
case 'B': return 1; // byte
diff --git a/src/object_test.cc b/src/object_test.cc
index c517459..aa3cf86 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -208,9 +208,9 @@
TEST_F(ObjectTest, DescriptorCompare) {
ClassLinker* linker = class_linker_;
- scoped_ptr<DexFile> proto1_dex_file(OpenDexFileBase64(kProtoCompareDex));
+ scoped_ptr<DexFile> proto1_dex_file(OpenDexFileBase64(kProtoCompareDex, "kProtoCompareDex"));
PathClassLoader* class_loader_1 = AllocPathClassLoader(proto1_dex_file.get());
- scoped_ptr<DexFile> proto2_dex_file(OpenDexFileBase64(kProtoCompare2Dex));
+ scoped_ptr<DexFile> proto2_dex_file(OpenDexFileBase64(kProtoCompare2Dex, "kProtoCompare2Dex"));
PathClassLoader* class_loader_2 = AllocPathClassLoader(proto2_dex_file.get());
Class* klass1 = linker->FindClass("LProtoCompare;", class_loader_1);
@@ -257,7 +257,7 @@
}
TEST_F(ObjectTest, InstanceOf) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY, "kXandY"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Class* X = class_linker_->FindClass("LX;", class_loader);
Class* Y = class_linker_->FindClass("LY;", class_loader);
@@ -284,7 +284,7 @@
}
TEST_F(ObjectTest, IsAssignableFrom) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY, "kXandY"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Class* X = class_linker_->FindClass("LX;", class_loader);
Class* Y = class_linker_->FindClass("LY;", class_loader);
@@ -296,7 +296,7 @@
}
TEST_F(ObjectTest, IsAssignableFromArray) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY));
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kXandY, "kXandY"));
PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Class* X = class_linker_->FindClass("LX;", class_loader);
Class* Y = class_linker_->FindClass("LY;", class_loader);
diff --git a/src/runtime.cc b/src/runtime.cc
index 864b257..476297b 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -352,7 +352,7 @@
Thread* current_thread = Thread::Attach(this);
thread_list_->Register(current_thread);
- class_linker_ = ClassLinker::Create(options->boot_class_path_);
+ class_linker_ = ClassLinker::Create(options->boot_class_path_, Heap::GetBootSpace());
return true;
}
diff --git a/src/space.cc b/src/space.cc
index 8048f29..c636e38 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -100,6 +100,9 @@
return false;
}
CHECK_EQ(image_header.GetBaseAddr(), map->GetAddress());
+ image_header_ = reinterpret_cast<ImageHeader*>(map->GetAddress());
+ DCHECK_EQ(0, memcmp(&image_header, image_header_, sizeof(ImageHeader)));
+
Init(map.release());
return true;
}
diff --git a/src/space.h b/src/space.h
index 57f676d..24bcefa 100644
--- a/src/space.h
+++ b/src/space.h
@@ -4,6 +4,7 @@
#define ART_SRC_SPACE_H_
#include "globals.h"
+#include "image.h"
#include "macros.h"
#include "mem_map.h"
#include "scoped_ptr.h"
@@ -47,6 +48,11 @@
return limit_ - base_;
}
+ const ImageHeader& GetImageHeader() const {
+ CHECK(image_header_ != NULL);
+ return *image_header_;
+ }
+
size_t AllocationSize(const Object* obj);
bool IsCondemned() const {
@@ -60,7 +66,7 @@
// create a Space from an existing memory mapping, taking ownership of the address space.
static Space* Create(MemMap* mem_map);
- Space() : mspace_(NULL), maximum_size_(0), base_(0), limit_(0) {}
+ Space() : mspace_(NULL), maximum_size_(0), image_header_(NULL), base_(0), limit_(0) {}
// Initializes the space and underlying storage.
bool Init(size_t initial_size, size_t maximum_size, byte* requested_base);
@@ -75,10 +81,13 @@
static void DontNeed(void* start, void* end, void* num_bytes);
- // TODO: have a Space subclass for methods that depend on mspace_ and maximum_size_
+ // TODO: have a Space subclass for non-image Spaces with mspace_ and maximum_size_
void* mspace_;
size_t maximum_size_;
+ // TODO: have a Space subclass for image Spaces with image_header_
+ ImageHeader* image_header_;
+
scoped_ptr<MemMap> mem_map_;
byte* base_;
diff --git a/src/stringpiece.h b/src/stringpiece.h
index 249b041..1338ed9 100644
--- a/src/stringpiece.h
+++ b/src/stringpiece.h
@@ -200,6 +200,21 @@
extern std::ostream& operator<<(std::ostream& o, const art::StringPiece& piece);
+// BEGIN android-added
+struct StringPieceHash {
+ size_t operator()(const art::StringPiece& string_piece) const {
+ size_t string_size = string_piece.size();
+ const char* string_data = string_piece.data();
+ // this is the java.lang.String hashcode for convenience, not interoperability
+ size_t hash = 0;
+ while (string_size--) {
+ hash = hash * 31 + *string_data++;
+ }
+ return hash;
+ }
+};
+// END android-added
+
} // namespace art
#endif // ART_SRC_STRINGPIECE_H_
diff --git a/src/unordered_map.h b/src/unordered_map.h
index caa859d..4f55d77 100644
--- a/src/unordered_map.h
+++ b/src/unordered_map.h
@@ -11,34 +11,4 @@
#include <tr1/unordered_map>
#endif
-//TODO: move out to stringpiece.h?
-namespace std {
-#ifndef __ANDROID__
-namespace tr1 {
-#endif
-template<>
-struct hash<art::StringPiece> {
- public:
- size_t operator()(const art::StringPiece& string_piece) const {
- size_t string_size = string_piece.size();
- const char* string_data = string_piece.data();
- // this is the java.lang.String hashcode for convenience, not interoperability
- size_t hash = 0;
- while (string_size--) {
- hash = hash * 31 + *string_data++;
- }
- return hash;
- }
-};
-#ifndef __ANDROID__
-} // namespace tr1
-#endif
-} // namespace std
-
-#ifdef __ANDROID__
-typedef std::hash<art::StringPiece> StringPieceHash;
-#else
-typedef std::tr1::hash<art::StringPiece> StringPieceHash;
-#endif
-
#endif // ART_SRC_CLASS_UNORDERED_MAP_H_
diff --git a/src/zip_archive.h b/src/zip_archive.h
index 8001fa3..26cb438 100644
--- a/src/zip_archive.h
+++ b/src/zip_archive.h
@@ -119,7 +119,7 @@
uint16_t num_entries_;
off_t dir_offset_;
scoped_ptr<MemMap> dir_map_;
- typedef std::tr1::unordered_map<StringPiece, const byte*> DirEntries;
+ typedef std::tr1::unordered_map<StringPiece, const byte*, StringPieceHash> DirEntries;
DirEntries dir_entries_;
friend class ZipEntry;