Convert Class::descriptor_ from StringPiece to String (as part of image loading)
Change-Id: Iab5ffa353661a7c06ee79af1f40d399a53777174
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 448a542..55aaff4 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -32,7 +32,7 @@
// 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;";
+ // 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 +40,7 @@
// 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;";
+ // 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,38 +49,47 @@
// 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;";
+ // 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;";
+ // 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);
Class* char_array_class = AllocClass(java_lang_Class);
CHECK(char_array_class != NULL);
- char_array_class->descriptor_ = "[C";
+ // char_array_class->descriptor_ = "[C"; // XXX can these be created later?
CharArray::SetArrayClass(char_array_class);
+ // Now String::Alloc* can be used
+
+ // backfill Class descriptors missing until this point
+ java_lang_Class->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/Class;");
+ java_lang_Object->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/Object;");
+ object_array_class->descriptor_ = String::AllocFromModifiedUtf8("[Ljava/lang/Object;");
+ java_lang_String->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/String;");
+ char_array_class->descriptor_ = String::AllocFromModifiedUtf8("[C");
// int[] and long[] are used for static field storage
Class* int_array_class = AllocClass(java_lang_Class);
CHECK(int_array_class != NULL);
- int_array_class->descriptor_ = "[I";
+ int_array_class->descriptor_ = String::AllocFromModifiedUtf8("[I");
IntArray::SetArrayClass(int_array_class);
Class* long_array_class = AllocClass(java_lang_Class);
CHECK(long_array_class != NULL);
- long_array_class->descriptor_ = "[J";
+ long_array_class->descriptor_ = String::AllocFromModifiedUtf8("[J");
LongArray::SetArrayClass(long_array_class);
// 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;";
+ java_lang_reflect_Field->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/reflect/Field;");
CHECK_LT(java_lang_reflect_Field->object_size_, sizeof(Field));
java_lang_reflect_Field->object_size_ = sizeof(Field);
Class* java_lang_reflect_Method = AllocClass(java_lang_Class);
- java_lang_reflect_Method->descriptor_ = "Ljava/lang/reflect/Method;";
+ java_lang_reflect_Method->descriptor_ = String::AllocFromModifiedUtf8("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);
@@ -98,9 +107,6 @@
class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
// now that these are registered, we can use AllocClass() and AllocObjectArray
- String::InitClasses(java_lang_String);
- // Now AllocString* can be used
-
// setup boot_class_path_ now that we can use AllocObjectArray to
// create DexCache instances
for (size_t i = 0; i != boot_class_path.size(); ++i) {
@@ -111,24 +117,24 @@
// 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* Class_class = FindSystemClass(java_lang_Class->GetDescriptor());
+ Class* Class_class = FindSystemClass("Ljava/lang/Class;");
CHECK_EQ(java_lang_Class, Class_class);
CHECK_LT(java_lang_Class->object_size_, sizeof(Class));
java_lang_Class->object_size_ = sizeof(Class);
- Class* Field_class = FindSystemClass(java_lang_reflect_Field->GetDescriptor());
+ Class* Field_class = FindSystemClass("Ljava/lang/reflect/Field;");
CHECK_EQ(java_lang_reflect_Field, Field_class);
CHECK_LT(java_lang_reflect_Field->object_size_, sizeof(Field));
java_lang_reflect_Field->object_size_ = sizeof(Field);
- Class* Method_class = FindSystemClass(java_lang_reflect_Method->GetDescriptor());
+ Class* Method_class = FindSystemClass("Ljava/lang/reflect/Method;");
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);
// Object and String just need more minimal setup, since they do not have extra C++ fields.
- Class* Object_class = FindSystemClass(java_lang_Object->GetDescriptor());
+ Class* Object_class = FindSystemClass("Ljava/lang/Object;");
CHECK_EQ(java_lang_Object, Object_class);
CHECK_EQ(java_lang_Object->object_size_, sizeof(Object));
- Class* String_class = FindSystemClass(java_lang_String->GetDescriptor());
+ Class* String_class = FindSystemClass("Ljava/lang/String;");
CHECK_EQ(java_lang_String, String_class);
CHECK_EQ(java_lang_String->object_size_, sizeof(String));
@@ -323,7 +329,7 @@
ObjectLock lock(klass);
klass->clinit_thread_id_ = self->GetId();
// Add the newly loaded class to the loaded classes table.
- bool success = InsertClass(klass); // TODO: just return collision
+ bool success = InsertClass(descriptor, klass); // TODO: just return collision
if (!success) {
// We may fail to insert if we raced with another thread.
klass->clinit_thread_id_ = 0;
@@ -387,8 +393,7 @@
CHECK(descriptor != NULL);
klass->klass_ = GetClassRoot(kJavaLangClass);
- klass->descriptor_.set(descriptor);
- klass->descriptor_alloc_ = NULL;
+ klass->descriptor_ = String::AllocFromModifiedUtf8(descriptor);
klass->access_flags_ = dex_class_def.access_flags_;
klass->class_loader_ = class_loader;
klass->primitive_type_ = Class::kPrimNot;
@@ -508,7 +513,7 @@
int32_t utf16_length;
scoped_array<char> utf8(dex_file.CreateMethodDescriptor(method_id.proto_idx_,
&utf16_length));
- dst->descriptor_ = String::AllocFromModifiedUtf8(utf16_length, utf8.get());
+ dst->signature_ = String::AllocFromModifiedUtf8(utf16_length, utf8.get());
}
dst->proto_idx_ = method_id.proto_idx_;
dst->code_off_ = src.code_off_;
@@ -570,15 +575,14 @@
return NULL;
}
-Class* ClassLinker::CreatePrimitiveClass(const StringPiece& descriptor) {
+Class* ClassLinker::CreatePrimitiveClass(const char* descriptor) {
Class* klass = AllocClass();
CHECK(klass != NULL);
klass->super_class_ = NULL;
klass->access_flags_ = kAccPublic | kAccFinal | kAccAbstract;
- klass->descriptor_ = descriptor;
- klass->descriptor_alloc_ = NULL;
+ klass->descriptor_ = String::AllocFromModifiedUtf8(descriptor);
klass->status_ = Class::kStatusInitialized;
- bool success = InsertClass(klass);
+ bool success = InsertClass(descriptor, klass);
CHECK(success) << "CreatePrimitiveClass(" << descriptor << ") failed";
return klass;
}
@@ -683,10 +687,7 @@
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());
+ new_class->descriptor_ = String::AllocFromModifiedUtf8(descriptor.ToString().c_str());
Class* java_lang_Object = GetClassRoot(kJavaLangObject);
new_class->super_class_ = java_lang_Object;
new_class->vtable_ = java_lang_Object->vtable_;
@@ -696,6 +697,7 @@
new_class->array_rank_ = array_rank;
new_class->status_ = Class::kStatusInitialized;
// don't need to set new_class->object_size_
+ // because Object::SizeOf delegates to Array::SizeOf
// All arrays have java/lang/Cloneable and java/io/Serializable as
@@ -726,7 +728,7 @@
new_class->access_flags_ = ((new_class->component_type_->access_flags_ &
~kAccInterface) | kAccFinal) & kAccJavaFlagsMask;
- if (InsertClass(new_class)) {
+ if (InsertClass(descriptor, new_class)) {
return new_class;
}
// Another thread must have loaded the class after we
@@ -770,19 +772,20 @@
return NULL; // Not reachable.
}
-bool ClassLinker::InsertClass(Class* klass) {
+bool ClassLinker::InsertClass(const StringPiece& descriptor, Class* klass) {
+ size_t hash = StringPieceHash()(descriptor);
MutexLock mu(classes_lock_);
- const StringPiece& key = klass->GetDescriptor();
- Table::iterator it = classes_.insert(std::make_pair(key, klass));
+ Table::iterator it = classes_.insert(std::make_pair(hash, klass));
return ((*it).second == klass);
}
Class* ClassLinker::LookupClass(const StringPiece& descriptor, ClassLoader* class_loader) {
+ size_t hash = StringPieceHash()(descriptor);
MutexLock mu(classes_lock_);
typedef Table::const_iterator It; // TODO: C++0x auto
- for (It it = classes_.find(descriptor), end = classes_.end(); it != end; ++it) {
+ for (It it = classes_.find(hash), end = classes_.end(); it != end; ++it) {
Class* klass = it->second;
- if (klass->descriptor_ == descriptor && klass->class_loader_ == class_loader) {
+ if (klass->descriptor_->Equals(descriptor) && klass->class_loader_ == class_loader) {
return klass;
}
}
@@ -974,7 +977,6 @@
CHECK(descriptor != NULL);
CHECK(klass1 != NULL);
CHECK(klass2 != NULL);
-#if 0
Class* found1 = FindClass(descriptor, klass1->GetClassLoader());
// TODO: found1 == NULL
Class* found2 = FindClass(descriptor, klass2->GetClassLoader());
@@ -988,7 +990,6 @@
return false;
}
}
-#endif
return true;
}
@@ -1033,7 +1034,7 @@
if (dex_cache == NULL) {
return;
}
- const StringPiece& descriptor = klass->GetDescriptor();
+ const std::string descriptor(klass->GetDescriptor()->ToModifiedUtf8());
const DexFile& dex_file = FindDexFile(dex_cache);
const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor);
CHECK(dex_class_def != NULL);
@@ -1140,7 +1141,7 @@
bool ClassLinker::LinkSuperClass(Class* klass) {
CHECK(!klass->IsPrimitive());
const Class* super = klass->GetSuperClass();
- if (klass->GetDescriptor() == "Ljava/lang/Object;") {
+ if (klass->GetDescriptor()->Equals("Ljava/lang/Object;")) {
if (super != NULL) {
LG << "Superclass must not be defined"; // TODO: ClassFormatError
return false;
@@ -1154,15 +1155,15 @@
}
// Verify
if (super->IsFinal()) {
- LG << "Superclass " << super->descriptor_ << " is declared final"; // TODO: IncompatibleClassChangeError
+ LG << "Superclass " << super->descriptor_->ToModifiedUtf8() << " is declared final"; // TODO: IncompatibleClassChangeError
return false;
}
if (super->IsInterface()) {
- LG << "Superclass " << super->descriptor_ << " is an interface"; // TODO: IncompatibleClassChangeError
+ LG << "Superclass " << super->descriptor_->ToModifiedUtf8() << " is an interface"; // TODO: IncompatibleClassChangeError
return false;
}
if (!klass->CanAccess(super)) {
- LG << "Superclass " << super->descriptor_ << " is inaccessible"; // TODO: IllegalAccessError
+ LG << "Superclass " << super->descriptor_->ToModifiedUtf8() << " is inaccessible"; // TODO: IllegalAccessError
return false;
}
return true;
@@ -1234,9 +1235,8 @@
klass->vtable_ = klass->vtable_->CopyOf(actual_count);
}
} else {
- CHECK(klass->GetDescriptor() == "Ljava/lang/Object;");
+ CHECK(klass->GetDescriptor()->Equals("Ljava/lang/Object;"));
uint32_t num_virtual_methods = klass->NumVirtualMethods();
- CHECK(klass->GetDescriptor() == "Ljava/lang/Object;");
if (!IsUint(16, num_virtual_methods)) {
LG << "Too many methods"; // TODO: VirtualMachineError
return false;
diff --git a/src/class_linker.h b/src/class_linker.h
index e83c850..bc7a780 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -72,7 +72,7 @@
}
PathClassLoader* AllocPathClassLoader(std::vector<const DexFile*> dex_files);
- Class* CreatePrimitiveClass(const StringPiece& descriptor);
+ Class* CreatePrimitiveClass(const char* descriptor);
Class* CreateArrayClass(const StringPiece& descriptor,
ClassLoader* class_loader);
@@ -114,7 +114,7 @@
// Inserts a class into the class table. Returns true if the class
// was inserted.
- bool InsertClass(Class* klass);
+ bool InsertClass(const StringPiece& descriptor, Class* klass);
bool InitializeSuperClass(Class* klass);
@@ -156,10 +156,10 @@
std::vector<DexCache*> dex_caches_;
- // multimap from String::descriptor_ to Class* instances. Results
- // should be compared for a matching Class::descriptor_ and
- // Class::class_loader_.
- typedef std::tr1::unordered_multimap<StringPiece, Class*> Table;
+ // multimap from a StringPiece hash code of a class descriptor to
+ // Class* instances. Results should be compared for a matching
+ // Class::descriptor_ and Class::class_loader_.
+ typedef std::tr1::unordered_multimap<size_t, Class*> Table;
Table classes_;
Mutex* classes_lock_;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index fd7fecf..42a773c 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -21,7 +21,7 @@
ASSERT_TRUE(primitive->GetClass() != NULL);
ASSERT_EQ(primitive->GetClass(), primitive->GetClass()->GetClass());
EXPECT_TRUE(primitive->GetClass()->GetSuperClass() != NULL);
- ASSERT_EQ(descriptor, primitive->GetDescriptor());
+ ASSERT_TRUE(primitive->GetDescriptor()->Equals(descriptor));
EXPECT_TRUE(primitive->GetSuperClass() == NULL);
EXPECT_FALSE(primitive->HasSuperClass());
EXPECT_TRUE(primitive->GetClassLoader() == NULL);
@@ -53,14 +53,14 @@
ASSERT_TRUE(array->GetClass() != NULL);
ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
EXPECT_TRUE(array->GetClass()->GetSuperClass() != NULL);
- ASSERT_EQ(array_descriptor, array->GetDescriptor());
+ ASSERT_TRUE(array->GetDescriptor()->Equals(array_descriptor));
EXPECT_TRUE(array->GetSuperClass() != NULL);
EXPECT_EQ(class_linker_->FindSystemClass("Ljava/lang/Object;"), array->GetSuperClass());
EXPECT_TRUE(array->HasSuperClass());
EXPECT_EQ(class_loader, array->GetClassLoader());
ASSERT_TRUE(array->GetComponentType() != NULL);
ASSERT_TRUE(array->GetComponentType()->GetDescriptor() != NULL);
- EXPECT_EQ(component_type, array->GetComponentType()->GetDescriptor());
+ EXPECT_TRUE(array->GetComponentType()->GetDescriptor()->Equals(component_type));
EXPECT_TRUE(array->GetStatus() == Class::kStatusInitialized);
EXPECT_FALSE(array->IsErroneous());
EXPECT_TRUE(array->IsVerified());
@@ -83,8 +83,8 @@
ASSERT_TRUE(descriptor != NULL);
Class* klass = class_linker_->FindSystemClass(descriptor);
ASSERT_TRUE(klass != NULL);
- EXPECT_EQ(descriptor, klass->GetDescriptor());
- if (klass->descriptor_ == "Ljava/lang/Object;") {
+ EXPECT_TRUE(klass->GetDescriptor()->Equals(descriptor));
+ if (klass->descriptor_->Equals(String::AllocFromModifiedUtf8("Ljava/lang/Object;"))) {
EXPECT_FALSE(klass->HasSuperClass());
} else {
EXPECT_TRUE(klass->HasSuperClass());
@@ -240,7 +240,7 @@
ASSERT_TRUE(JavaLangObject->GetClass() != NULL);
ASSERT_EQ(JavaLangObject->GetClass(), JavaLangObject->GetClass()->GetClass());
EXPECT_EQ(JavaLangObject, JavaLangObject->GetClass()->GetSuperClass());
- ASSERT_TRUE(JavaLangObject->GetDescriptor() == "Ljava/lang/Object;");
+ ASSERT_TRUE(JavaLangObject->GetDescriptor()->Equals("Ljava/lang/Object;"));
EXPECT_TRUE(JavaLangObject->GetSuperClass() == NULL);
EXPECT_FALSE(JavaLangObject->HasSuperClass());
EXPECT_TRUE(JavaLangObject->GetClassLoader() == NULL);
@@ -270,7 +270,7 @@
ASSERT_TRUE(MyClass->GetClass() != NULL);
ASSERT_EQ(MyClass->GetClass(), MyClass->GetClass()->GetClass());
EXPECT_EQ(JavaLangObject, MyClass->GetClass()->GetSuperClass());
- ASSERT_TRUE(MyClass->GetDescriptor() == "LMyClass;");
+ ASSERT_TRUE(MyClass->GetDescriptor()->Equals("LMyClass;"));
EXPECT_TRUE(MyClass->GetSuperClass() == JavaLangObject);
EXPECT_TRUE(MyClass->HasSuperClass());
EXPECT_EQ(class_loader, MyClass->GetClassLoader());
@@ -399,7 +399,7 @@
EXPECT_EQ(10U, statics->NumStaticFields());
Field* s0 = statics->GetStaticField(0);
- EXPECT_EQ("Ljava/lang/reflect/Field;", s0->GetClass()->descriptor_);
+ EXPECT_TRUE(s0->GetClass()->descriptor_->Equals("Ljava/lang/reflect/Field;"));
EXPECT_EQ('Z', s0->GetType());
// EXPECT_EQ(true, s0->GetBoolean()); // TODO: uncomment this
s0->SetBoolean(false);
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 63f6e8c..f55b20e 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -16,14 +16,14 @@
for (size_t i = 0; i < klass->NumDirectMethods(); ++i) {
Method* method = klass->GetDirectMethod(i);
if (!VerifyMethod(method)) {
- LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor();
+ LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor()->ToModifiedUtf8();
return false;
}
}
for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
Method* method = klass->GetVirtualMethod(i);
if (!VerifyMethod(method)) {
- LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor();
+ LOG(ERROR) << "Verifier rejected class " << klass->GetDescriptor()->ToModifiedUtf8();
return false;
}
}
diff --git a/src/heap.cc b/src/heap.cc
index de801ce..643d056 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -4,6 +4,7 @@
#include <vector>
+#include "image.h"
#include "mark_sweep.h"
#include "object.h"
#include "space.h"
@@ -76,6 +77,11 @@
// TODO: allocate the card table
+ // Make objects in boot_space live (after live_bitmap_ is set)
+ if (boot_image_file_name != NULL) {
+ RecordImageAllocations(boot_space);
+ }
+
return true;
}
@@ -92,7 +98,7 @@
}
Object* Heap::AllocObject(Class* klass, size_t num_bytes) {
- DCHECK((klass == NULL && num_bytes == sizeof(Class))
+ DCHECK(klass == NULL
|| klass->descriptor_ == NULL
|| (klass->object_size_ == (klass->IsArray() ? 0 : num_bytes)));
Object* obj = Allocate(num_bytes);
@@ -124,6 +130,18 @@
}
}
+void Heap::RecordImageAllocations(Space* space) {
+ CHECK(space != NULL);
+ CHECK(live_bitmap_ != NULL);
+ byte* current = space->GetBase() + RoundUp(sizeof(ImageHeader), 8);
+ while (current < space->GetLimit()) {
+ DCHECK(IsAligned(current, 8));
+ const Object* obj = reinterpret_cast<const Object*>(current);
+ live_bitmap_->Set(obj);
+ current += RoundUp(obj->SizeOf(), 8);
+ }
+}
+
Object* Heap::Allocate(size_t size) {
DCHECK(alloc_space_ != NULL);
Space* space = alloc_space_;
diff --git a/src/heap.h b/src/heap.h
index 99f6554..0cf0b57 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -62,6 +62,7 @@
static void RecordAllocation(Space* space, const Object* object);
static void RecordFree(Space* space, const Object* object);
+ static void RecordImageAllocations(Space* space);
static void CollectGarbageInternal();
diff --git a/src/image_test.cc b/src/image_test.cc
index 6cfa62d..c68b600 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -13,11 +13,25 @@
class ImageTest : public CommonTest {};
-TEST_F(ImageTest, WriteRead) {
- scoped_ptr<DexFile> libcore_dex_file(GetLibCoreDex());
- EXPECT_TRUE(libcore_dex_file.get() != NULL);
+std::string ReadFileToString(const char* file_name) {
+ scoped_ptr<File> file(OS::OpenFile(file_name, false));
+ CHECK(file != NULL);
- // TODO: garbage collect before writing
+ std::string contents;
+ char buf[8 * KB];
+ while (true) {
+ int64_t n = file->Read(buf, sizeof(buf));
+ CHECK_NE(-1, n);
+ if (n == 0) {
+ break;
+ }
+ contents.append(buf, n);
+ }
+ return contents;
+}
+
+TEST_F(ImageTest, WriteRead) {
+ // 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());
@@ -25,7 +39,7 @@
ImageWriter writer;
ScratchFile tmp;
- const int image_base = 0x5000000;
+ const int image_base = 0x50000000;
bool success = writer.Write(space, tmp.GetFilename(), reinterpret_cast<byte*>(image_base));
ASSERT_TRUE(success);
@@ -40,10 +54,16 @@
// tear down old runtime and make a new one
delete runtime_.release();
- java_lang_dex_file_.reset(GetLibCoreDex());
+
+ // don't reuse java_lang_dex_file_ so we make sure we don't get
+ // lucky by pointers that happen to work referencing the earlier
+ // dex.
+ delete java_lang_dex_file_.release();
+ scoped_ptr<DexFile> dex(GetLibCoreDex());
+ ASSERT_TRUE(dex != NULL);
std::vector<const DexFile*> boot_class_path;
- boot_class_path.push_back(java_lang_dex_file_.get());
+ boot_class_path.push_back(dex.get());
Runtime::Options options;
options.push_back(std::make_pair("bootclasspath", &boot_class_path));
@@ -54,6 +74,28 @@
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();
+ 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);
+ }
}
} // namespace art
diff --git a/src/image_writer.cc b/src/image_writer.cc
index b6625d0..4335a90 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -5,6 +5,7 @@
#include <sys/mman.h>
#include <vector>
+#include "dex_cache.h"
#include "file.h"
#include "globals.h"
#include "heap.h"
@@ -88,14 +89,34 @@
DCHECK(orig != NULL);
DCHECK(copy != NULL);
copy->klass_ = down_cast<Class*>(GetImageAddress(orig->klass_));
- // TODO: specical case init of pointers to malloc data (or removal of these pointers)
- if (orig->IsObjectArray()) {
+ // 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->IsObjectArray()) {
FixupObjectArray(orig->AsObjectArray<Object>(), down_cast<ObjectArray<Object>*>(copy));
} else {
FixupInstanceFields(orig, copy);
}
}
+void ImageWriter::FixupClass(Class* orig, Class* copy) {
+ FixupInstanceFields(orig, copy);
+ copy->descriptor_ = down_cast<String*>(GetImageAddress(orig->descriptor_));
+ copy->dex_cache_ = down_cast<DexCache*>(GetImageAddress(orig->dex_cache_));
+ copy->verify_error_class_ = down_cast<Class*>(GetImageAddress(orig->verify_error_class_));
+ copy->component_type_ = down_cast<Class*>(GetImageAddress(orig->component_type_));
+ copy->super_class_ = down_cast<Class*>(GetImageAddress(orig->super_class_));
+ copy->class_loader_ = down_cast<ClassLoader*>(GetImageAddress(orig->class_loader_));
+ copy->interfaces_ = down_cast<ObjectArray<Class>*>(GetImageAddress(orig->interfaces_));
+ copy->direct_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->direct_methods_));
+ copy->virtual_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->virtual_methods_));
+ copy->vtable_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->vtable_));
+ // TODO: convert iftable_ to heap allocated storage
+ copy->ifields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->ifields_));
+ copy->sfields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->sfields_));
+ copy->static_references_ = down_cast<ObjectArray<Object>*>(GetImageAddress(orig->static_references_));
+}
+
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 003c4e9..8ae8f7d 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -50,6 +50,7 @@
void CopyAndFixupObjects();
static void CopyAndFixupObjectsCallback(Object *obj, void *arg);
+ void FixupClass(Class* orig, Class* 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/jni_internal.cc b/src/jni_internal.cc
index 8e8ecd3..a55cdae 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -472,7 +472,7 @@
if (method == NULL || method->IsStatic() != is_static) {
Thread* self = Thread::Current();
- std::string class_name(c->GetDescriptor().ToString());
+ std::string class_name(c->GetDescriptor()->ToModifiedUtf8());
// TODO: try searching for the opposite kind of method from is_static
// for better diagnostics?
self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
@@ -505,7 +505,7 @@
if (field == NULL) {
Thread* self = Thread::Current();
- std::string class_name(c->GetDescriptor().ToString());
+ std::string class_name(c->GetDescriptor()->ToModifiedUtf8());
self->ThrowNewException("Ljava/lang/NoSuchFieldError;",
"no \"%s\" field \"%s\" in class \"%s\" or its superclasses", sig,
name, class_name.c_str());
@@ -1768,7 +1768,7 @@
Class* element_class = Decode<Class*>(ts, element_jclass);
std::string descriptor;
descriptor += "[";
- descriptor += element_class->GetDescriptor().ToString();
+ descriptor += element_class->GetDescriptor()->ToModifiedUtf8();
// Find the class.
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -2003,7 +2003,7 @@
}
if (method == NULL) {
Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor().ToString();
+ std::string class_name = klass->GetDescriptor()->ToModifiedUtf8();
// TODO: pretty print method names through a single routine
self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
"no method \"%s.%s%s\"",
@@ -2011,7 +2011,7 @@
return JNI_ERR;
} else if (!method->IsNative()) {
Thread* self = Thread::Current();
- std::string class_name = klass->GetDescriptor().ToString();
+ std::string class_name = klass->GetDescriptor()->ToModifiedUtf8();
// TODO: pretty print method names through a single routine
self->ThrowNewException("Ljava/lang/NoSuchMethodError;",
"method \"%s.%s%s\" is not native",
diff --git a/src/object.cc b/src/object.cc
index b9324a6..8765713 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -108,8 +108,11 @@
return false;
}
-bool Class::IsInSamePackage(const StringPiece& descriptor1,
- const StringPiece& descriptor2) {
+bool Class::IsInSamePackage(const String* descriptor_string_1,
+ const String* descriptor_string_2) {
+ const std::string descriptor1(descriptor_string_1->ToModifiedUtf8());
+ const std::string descriptor2(descriptor_string_2->ToModifiedUtf8());
+
size_t i = 0;
while (descriptor1[i] != '\0' && descriptor1[i] == descriptor2[i]) {
++i;
@@ -393,15 +396,15 @@
bool Method::HasSameNameAndDescriptor(const Method* that) const {
return (this->GetName()->Equals(that->GetName()) &&
- this->GetDescriptor()->Equals(that->GetDescriptor()));
+ this->GetSignature()->Equals(that->GetSignature()));
}
Method* Class::FindDeclaredDirectMethod(const StringPiece& name,
- const StringPiece& descriptor) {
+ const StringPiece& signature) {
for (size_t i = 0; i < NumDirectMethods(); ++i) {
Method* method = GetDirectMethod(i);
if (method->GetName()->Equals(name) &&
- method->GetDescriptor()->Equals(descriptor)) {
+ method->GetSignature()->Equals(signature)) {
return method;
}
}
@@ -409,9 +412,9 @@
}
Method* Class::FindDirectMethod(const StringPiece& name,
- const StringPiece& descriptor) {
+ const StringPiece& signature) {
for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
- Method* method = klass->FindDeclaredDirectMethod(name, descriptor);
+ Method* method = klass->FindDeclaredDirectMethod(name, signature);
if (method != NULL) {
return method;
}
@@ -420,11 +423,11 @@
}
Method* Class::FindDeclaredVirtualMethod(const StringPiece& name,
- const StringPiece& descriptor) {
+ const StringPiece& signature) {
for (size_t i = 0; i < NumVirtualMethods(); ++i) {
Method* method = GetVirtualMethod(i);
if (method->GetName()->Equals(name) &&
- method->GetDescriptor()->Equals(descriptor)) {
+ method->GetSignature()->Equals(signature)) {
return method;
}
}
@@ -519,7 +522,7 @@
// TODO: get global references for these
Class* String::java_lang_String_ = NULL;
-void String::InitClasses(Class* java_lang_String) {
+void String::InitClass(Class* java_lang_String) {
java_lang_String_ = java_lang_String;
}
diff --git a/src/object.h b/src/object.h
index 2b5a054..8efa059 100644
--- a/src/object.h
+++ b/src/object.h
@@ -367,8 +367,8 @@
return name_;
}
- const String* GetDescriptor() const {
- return descriptor_;
+ const String* GetSignature() const {
+ return signature_;
}
Class* GetDeclaringClass() const {
@@ -573,7 +573,7 @@
// the method descriptor would be
//
// (IDLjava/lang/Thread;)Ljava/lang/Object;
- String* descriptor_;
+ String* signature_;
// Method prototype descriptor string (return and argument types).
uint32_t proto_idx_;
@@ -599,16 +599,16 @@
class Array : public Object {
public:
- static size_t Size(size_t component_count,
- size_t component_size) {
+ static size_t SizeOf(size_t component_count,
+ size_t component_size) {
return sizeof(Array) + component_count * component_size;
}
static Array* Alloc(Class* array_class,
size_t component_count,
size_t component_size) {
- size_t size = Size(component_count, component_size);
- Array* array = Heap::AllocObject(array_class, size)->AsArray();
+ size_t size = SizeOf(component_count, component_size);
+ Array* array = down_cast<Array*>(Heap::AllocObject(array_class, size));
if (array != NULL) {
array->SetLength(component_count);
}
@@ -816,30 +816,15 @@
return component_type_;
}
- static size_t GetTypeSize(const StringPiece& descriptor) {
- switch (descriptor[0]) {
- case 'B': return 1; // byte
- case 'C': return 2; // char
- case 'D': return 8; // double
- case 'F': return 4; // float
- case 'I': return 4; // int
- case 'J': return 8; // long
- case 'S': return 2; // short
- case 'Z': return 1; // boolean
- case 'L': return sizeof(Object*);
- case '[': return sizeof(Array*);
- default:
- LOG(ERROR) << "Unknown type " << descriptor;
- return 0;
- }
- }
+ static size_t GetTypeSize(String* descriptor);
size_t GetComponentSize() const {
return GetTypeSize(component_type_->descriptor_);
}
- const StringPiece& GetDescriptor() const {
- DCHECK_NE(0, descriptor_.size());
+ const String* GetDescriptor() const {
+ DCHECK(descriptor_ != NULL);
+ // DCHECK_NE(0, descriptor_->GetLength()); // TODO: keep?
return descriptor_;
}
@@ -880,13 +865,11 @@
// Returns true if this class is in the same packages as that class.
bool IsInSamePackage(const Class* that) const;
- static bool IsInSamePackage(const StringPiece& descriptor1,
- const StringPiece& descriptor2);
+ static bool IsInSamePackage(const String* descriptor1,
+ const String* descriptor2);
// Returns true if this class represents an array class.
- bool IsArray() const {
- return GetDescriptor()[0] == '['; // TODO: avoid parsing the descriptor
- }
+ bool IsArray() const;
// Returns true if the class is an interface.
bool IsInterface() const {
@@ -1052,20 +1035,11 @@
bool IsSubClass(const Class* klass) const;
public: // TODO: private
- // leave space for instance data; we could access fields directly if
- // we freeze the definition of java/lang/Class
-#define CLASS_FIELD_SLOTS 1
- // Class.#0 name
- uint32_t instance_data_[CLASS_FIELD_SLOTS];
-#undef CLASS_FIELD_SLOTS
+ // descriptor for the class such as "java.lang.Class" or "[C"
+ String* name_; // TODO initialize
- // UTF-8 descriptor for the class from constant pool
- // ("Ljava/lang/Class;"), or on heap if generated ("[C")
- StringPiece descriptor_;
-
- // Proxy classes have their descriptor allocated on the native heap.
- // When this field is non-NULL it must be explicitly freed.
- std::string* descriptor_alloc_;
+ // descriptor for the class such as "Ljava/lang/Class;" or "[C"
+ String* descriptor_;
// access flags; low 16 bits are defined by VM spec
uint32_t access_flags_; // TODO: make an instance field?
@@ -1218,7 +1192,7 @@
}
inline size_t Array::SizeOf() const {
- return Size(GetLength(), klass_->GetComponentSize());
+ return SizeOf(GetLength(), klass_->GetComponentSize());
}
class DataObject : public Object {
@@ -1329,14 +1303,18 @@
return string;
}
- static void InitClasses(Class* java_lang_String);
+ static void InitClass(Class* java_lang_String);
static String* Alloc(Class* java_lang_String,
int32_t utf16_length) {
+ return Alloc(java_lang_String, CharArray::Alloc(utf16_length));
+ }
+
+ static String* Alloc(Class* java_lang_String,
+ CharArray* array) {
String* string = down_cast<String*>(java_lang_String->NewInstance());
- CharArray* array = CharArray::Alloc(utf16_length);
string->array_ = array;
- string->count_ = utf16_length;
+ string->count_ = array->GetLength();
return string;
}
@@ -1464,6 +1442,29 @@
return true;
}
+ // Create a modified UTF-8 encoded std::string from a java/lang/String object.
+ std::string ToModifiedUtf8() const {
+ std::string result;
+ for (uint32_t i = 0; i < GetLength(); i++) {
+ uint16_t ch = CharAt(i);
+ // The most common case is (ch > 0 && ch <= 0x7f).
+ if (ch == 0 || ch > 0x7f) {
+ if (ch > 0x07ff) {
+ result.push_back((ch >> 12) | 0xe0);
+ result.push_back(((ch >> 6) & 0x3f) | 0x80);
+ result.push_back((ch & 0x3f) | 0x80);
+ } else { // (ch > 0x7f || ch == 0)
+ result.push_back((ch >> 6) | 0xc0);
+ result.push_back((ch & 0x3f) | 0x80);
+ }
+ } else {
+ result.push_back(ch);
+ }
+ }
+ return result;
+ }
+
+
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
CharArray* array_;
@@ -1484,6 +1485,28 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(String);
};
+inline size_t Class::GetTypeSize(String* descriptor) {
+ switch (descriptor->CharAt(0)) {
+ case 'B': return 1; // byte
+ case 'C': return 2; // char
+ case 'D': return 8; // double
+ case 'F': return 4; // float
+ case 'I': return 4; // int
+ case 'J': return 8; // long
+ case 'S': return 2; // short
+ case 'Z': return 1; // boolean
+ case 'L': return sizeof(Object*);
+ case '[': return sizeof(Array*);
+ default:
+ LOG(ERROR) << "Unknown type " << descriptor;
+ return 0;
+ }
+}
+
+inline bool Class::IsArray() const {
+ return GetDescriptor()->CharAt(0) == '['; // TODO: avoid parsing the descriptor
+}
+
class InterfaceEntry {
public:
InterfaceEntry() : klass_(NULL), method_index_array_(NULL) {
diff --git a/src/object_test.cc b/src/object_test.cc
index 549544c..c757297 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -41,16 +41,16 @@
TEST_F(ObjectTest, IsInSamePackage) {
// Matches
- EXPECT_TRUE(Class::IsInSamePackage("Ljava/lang/Object;",
- "Ljava/lang/Class"));
- EXPECT_TRUE(Class::IsInSamePackage("LFoo;",
- "LBar;"));
+ EXPECT_TRUE(Class::IsInSamePackage(String::AllocFromModifiedUtf8("Ljava/lang/Object;"),
+ String::AllocFromModifiedUtf8("Ljava/lang/Class")));
+ EXPECT_TRUE(Class::IsInSamePackage(String::AllocFromModifiedUtf8("LFoo;"),
+ String::AllocFromModifiedUtf8("LBar;")));
// Mismatches
- EXPECT_FALSE(Class::IsInSamePackage("Ljava/lang/Object;",
- "Ljava/io/File;"));
- EXPECT_FALSE(Class::IsInSamePackage("Ljava/lang/Object;",
- "Ljava/lang/reflect/Method;"));
+ EXPECT_FALSE(Class::IsInSamePackage(String::AllocFromModifiedUtf8("Ljava/lang/Object;"),
+ String::AllocFromModifiedUtf8("Ljava/io/File;")));
+ EXPECT_FALSE(Class::IsInSamePackage(String::AllocFromModifiedUtf8("Ljava/lang/Object;"),
+ String::AllocFromModifiedUtf8("Ljava/lang/reflect/Method;")));
}
TEST_F(ObjectTest, AllocObjectArray) {
diff --git a/src/runtime_test.cc b/src/runtime_test.cc
index 6fc14b8..75c003b 100644
--- a/src/runtime_test.cc
+++ b/src/runtime_test.cc
@@ -69,7 +69,6 @@
void* test_abort = reinterpret_cast<void*>(0xb);
void* test_exit = reinterpret_cast<void*>(0xc);
void* null = reinterpret_cast<void*>(NULL);
- scoped_ptr<const DexFile> java_lang_dex_file(GetLibCoreDex());
std::vector<const DexFile*> boot_class_path;
boot_class_path.push_back(java_lang_dex_file_.get());
diff --git a/src/thread.cc b/src/thread.cc
index 44f0946..15382b9 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -176,7 +176,7 @@
// TODO: need to *call* the constructor!
UNIMPLEMENTED(WARNING) << "can't call "
- << exception_class->GetDescriptor() << ".<init> "
+ << exception_class->GetDescriptor()->ToModifiedUtf8() << ".<init> "
<< "\"" << msg << "\"";
thread->SetException(exception);
diff --git a/src/unordered_map.h b/src/unordered_map.h
index 44e5417..caa859d 100644
--- a/src/unordered_map.h
+++ b/src/unordered_map.h
@@ -35,4 +35,10 @@
#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/utils.cc b/src/utils.cc
index 419eb1c..058ca83 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -61,9 +61,9 @@
if (obj->GetClass() == NULL) {
return "(raw)";
}
- std::string result(PrettyDescriptor(obj->GetClass()->GetDescriptor()));
+ std::string result(PrettyDescriptor(obj->GetClass()->GetDescriptor()->ToModifiedUtf8()));
if (obj->IsClass()) {
- result += "<" + PrettyDescriptor(obj->AsClass()->GetDescriptor()) + ">";
+ result += "<" + PrettyDescriptor(obj->AsClass()->GetDescriptor()->ToModifiedUtf8()) + ">";
}
return result;
}