Working ClassLoader
Change-Id: Ia1122165e47f846a1d4506111849f830d9f14c1b
diff --git a/Android.mk b/Android.mk
index 97bf41a..9a53fd0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -166,7 +166,7 @@
# oatdump targets
.PHONY: dump-oat
-dump-oat: dump-oat-core dump-oat-boot dump-oat-Calculator
+dump-oat: dump-oat-core dump-oat-boot # dump-oat-Calculator # TODO: restore when oatdump can dump an oat without an image
.PHONY: dump-oat-core
dump-oat-core: $(TARGET_CORE_OAT) $(OATDUMP)
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 605c48b..a45c644 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -27,6 +27,7 @@
art_cflags := \
-O2 \
+ -O0 \
-ggdb3 \
-Wall \
-Werror \
@@ -178,6 +179,7 @@
TEST_COMMON_SRC_FILES := \
src/class_linker_test.cc \
+ src/compiler_test.cc \
src/dex_cache_test.cc \
src/dex_file_test.cc \
src/dex_instruction_visitor_test.cc \
@@ -198,8 +200,7 @@
src/runtime_test.cc \
src/space_test.cc \
src/utils_test.cc \
- src/zip_archive_test.cc \
- src/compiler_test.cc
+ src/zip_archive_test.cc
TEST_TARGET_SRC_FILES := \
$(TEST_COMMON_SRC_FILES)
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index b3dee96..6dfbf99 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -40,7 +40,7 @@
# TODO: change DEX2OATD (and perhaps $(2) boot oat) to order-only prerequisite when output is stable
$(patsubst %.apk,%.oat,$(patsubst %.jar,%.oat,$(1))): $(1) $(2) $(DEX2OAT)
@echo "target dex2oat: $$@ ($$<)"
- $(hide) $(DEX2OAT) -Xms16m -Xmx16m --boot-image=$(patsubst %.oat,%.art,$(2)) $(addprefix --dex-file=,$$<) --oat=$$@ --image=$$(patsubst %.oat,%.art,$$@) --host-prefix=$(PRODUCT_OUT)
+ $(hide) $(DEX2OAT) -Xms16m -Xmx16m --boot-image=$(patsubst %.oat,%.art,$(2)) $(addprefix --dex-file=,$$<) --oat=$$@ --host-prefix=$(PRODUCT_OUT)
endef
########################################################################
@@ -64,7 +64,7 @@
test-art-target-oat-$(1): test-art-target-sync
adb shell touch /sdcard/test-art-target-oat-$(1)
adb shell rm /sdcard/test-art-target-oat-$(1)
- adb shell sh -c "oatexecd -Ximage:/system/framework/core.art -classpath /system/framework/art-test-dex-$(1).jar -Ximage:/system/framework/art-test-dex-$(1).art $(1) $(2) && touch /sdcard/test-art-target-oat-$(1)"
+ adb shell sh -c "oatexecd -Ximage:/system/framework/core.art -classpath /system/framework/art-test-dex-$(1).jar $(1) $(2) && touch /sdcard/test-art-target-oat-$(1)"
$(hide) (adb pull /sdcard/test-art-target-oat-$(1) /tmp/ && echo test-art-target-oat-$(1) PASSED) || (echo test-art-target-oat-$(1) FAILED && exit 1)
$(hide) rm /tmp/test-art-target-oat-$(1)
diff --git a/oat_process/app_main.cpp b/oat_process/app_main.cpp
index e769907..53321f1 100644
--- a/oat_process/app_main.cpp
+++ b/oat_process/app_main.cpp
@@ -82,52 +82,6 @@
free(slashClassName);
mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
-
- // TODO: remove this ClassLoader code
- jclass ApplicationLoaders = env->FindClass("android/app/ApplicationLoaders");
- jmethodID getDefault = env->GetStaticMethodID(ApplicationLoaders,
- "getDefault",
- "()Landroid/app/ApplicationLoaders;");
- jfieldID mLoaders = env->GetFieldID(ApplicationLoaders, "mLoaders", "Ljava/util/Map;");
- jclass BootClassLoader = env->FindClass("java/lang/BootClassLoader");
- jmethodID getInstance = env->GetStaticMethodID(BootClassLoader,
- "getInstance",
- "()Ljava/lang/BootClassLoader;");
- jclass ClassLoader = env->FindClass("java/lang/ClassLoader");
- jfieldID parent = env->GetFieldID(ClassLoader, "parent", "Ljava/lang/ClassLoader;");
- jclass Map = env->FindClass("java/util/Map");
- jmethodID put = env->GetMethodID(Map,
- "put",
- "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
- jclass BaseDexClassLoader = env->FindClass("dalvik/system/BaseDexClassLoader");
- jfieldID originalPath = env->GetFieldID(BaseDexClassLoader, "originalPath", "Ljava/lang/String;");
- jfieldID pathList = env->GetFieldID(BaseDexClassLoader, "pathList", "Ldalvik/system/DexPathList;");
- jclass DexPathList = env->FindClass("dalvik/system/DexPathList");
- jmethodID init = env->GetMethodID(DexPathList,
- "<init>",
- "(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V");
-
- // Set the parent of our pre-existing ClassLoader to the non-null BootClassLoader.getInstance()
- const art::ClassLoader* class_loader_object = art::Thread::Current()->GetClassLoaderOverride();
- jobject class_loader = art::AddLocalReference<jobject>(env, class_loader_object);
- jobject boot_class_loader = env->CallStaticObjectMethod(BootClassLoader, getInstance);
- env->SetObjectField(class_loader, parent, boot_class_loader);
-
- // Create a DexPathList
- jstring dex_path = env->NewStringUTF("/system/app/Calculator.apk");
- jstring library_path = env->NewStringUTF("/data/data/com.android.calculator2/lib");
- jobject dex_path_list = env->NewObject(DexPathList, init,
- boot_class_loader, dex_path, library_path, NULL);
-
- // Set DexPathList into our pre-existing ClassLoader
- env->SetObjectField(class_loader, pathList, dex_path_list);
- env->SetObjectField(class_loader, originalPath, dex_path);
-
- // Stash our pre-existing ClassLoader into ApplicationLoaders.getDefault().mLoaders
- // under the expected name.
- jobject application_loaders = env->CallStaticObjectMethod(ApplicationLoaders, getDefault);
- jobject loaders = env->GetObjectField(application_loaders, mLoaders);
- env->CallObjectMethod(loaders, put, dex_path, class_loader);
}
virtual void onStarted()
@@ -209,14 +163,12 @@
}
}
- // TODO: remove Calculator special case
- int oatArgc = argc + 2;
+ // TODO: remove when we default the boot image
+ int oatArgc = argc + 1;
const char* oatArgv[oatArgc];
if (strcmp(argv[0], "-Ximage:/system/framework/boot.art") != 0) {
- LOG(INFO) << "Adding oat arguments";
+ LOG(INFO) << "Adding image arguments";
oatArgv[0] = "-Ximage:/system/framework/boot.art";
- oatArgv[1] = "-Ximage:/system/app/Calculator.art";
- setenv("CLASSPATH", "/system/app/Calculator.apk", 1);
memcpy(oatArgv + (oatArgc - argc), argv, argc * sizeof(*argv));
argv = oatArgv;
argc = oatArgc;
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 8ca633b..3f30b9e 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -436,10 +436,9 @@
java_lang_ref_WeakReference->GetAccessFlags() |
kAccClassIsReference | kAccClassIsWeakReference);
- // Setup the ClassLoaders, adjusting the object_size_ as necessary
+ // Setup the ClassLoaders, verifying the object_size_
Class* java_lang_ClassLoader = FindSystemClass("Ljava/lang/ClassLoader;");
- CHECK_LT(java_lang_ClassLoader->GetObjectSize(), sizeof(ClassLoader));
- java_lang_ClassLoader->SetObjectSize(sizeof(ClassLoader));
+ CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), sizeof(ClassLoader));
SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader);
Class* dalvik_system_BaseDexClassLoader = FindSystemClass("Ldalvik/system/BaseDexClassLoader;");
@@ -539,6 +538,7 @@
}
OatFile* ClassLinker::OpenOat(const Space* space) {
+ MutexLock mu(lock_);
const Runtime* runtime = Runtime::Current();
if (runtime->IsVerboseStartup()) {
LOG(INFO) << "ClassLinker::OpenOat entering";
@@ -568,6 +568,37 @@
return oat_file;
}
+const OatFile* ClassLinker::FindOatFile(const DexFile& dex_file) {
+ MutexLock mu(lock_);
+ std::string dex_file_location = dex_file.GetLocation();
+ std::string location(dex_file_location);
+ CHECK(StringPiece(location).ends_with(".dex")
+ || StringPiece(location).ends_with(".zip")
+ || StringPiece(location).ends_with(".jar")
+ || StringPiece(location).ends_with(".apk"));
+ location.erase(location.size()-3);
+ location += "oat";
+ // TODO: check if dex_file matches an OatDexFile location and checksum
+ return FindOatFile(location);
+}
+
+const OatFile* ClassLinker::FindOatFile(const std::string& location) {
+ for (size_t i = 0; i < oat_files_.size(); i++) {
+ const OatFile* oat_file = oat_files_[i];
+ DCHECK(oat_file != NULL);
+ if (oat_file->GetLocation() == location) {
+ return oat_file;
+ }
+ }
+
+ const OatFile* oat_file = OatFile::Open(location, "", NULL);
+ if (oat_file == NULL) {
+ LOG(ERROR) << "Failed to open oat file " << location;
+ return NULL;
+ }
+ return oat_file;
+}
+
void ClassLinker::InitFromImage() {
const Runtime* runtime = Runtime::Current();
if (runtime->IsVerboseStartup()) {
@@ -599,8 +630,8 @@
<< " referenced from oat file as " << dex_file_location;
}
- const OatFile::OatDexFile& oat_dex_file = oat_file->GetOatDexFile(dex_file_location);
- CHECK_EQ(dex_file->GetHeader().checksum_, oat_dex_file.GetDexFileChecksum());
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location);
+ CHECK_EQ(dex_file->GetHeader().checksum_, oat_dex_file->GetDexFileChecksum());
RegisterDexFile(*dex_file, dex_cache);
}
@@ -653,21 +684,13 @@
class_linker->intern_table_->RegisterStrong(obj->AsString());
return;
}
- if (!obj->IsClass()) {
+ if (obj->IsClass()) {
+ // restore class to ClassLinker::classes_ table
+ Class* klass = obj->AsClass();
+ std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
+ class_linker->InsertClass(descriptor, klass);
return;
}
- Class* klass = obj->AsClass();
- // TODO: restore ClassLoader's list of DexFiles after image load
- // CHECK(klass->GetClassLoader() == NULL);
- const ClassLoader* class_loader = klass->GetClassLoader();
- if (class_loader != NULL) {
- // TODO: replace this hack with something based on command line arguments
- Thread::Current()->SetClassLoaderOverride(class_loader);
- }
-
- std::string descriptor = klass->GetDescriptor()->ToModifiedUtf8();
- // restore class to ClassLinker::classes_ table
- class_linker->InsertClass(descriptor, klass);
}
// Keep in sync with InitCallback. Anything we visit, we need to
@@ -759,100 +782,10 @@
length);
}
-Class* ClassLinker::FindClass(const StringPiece& descriptor,
- const ClassLoader* class_loader) {
- // TODO: remove this contrived parent class loader check when we have a real ClassLoader.
- if (class_loader != NULL) {
- Class* klass = FindClass(descriptor, NULL);
- if (klass != NULL) {
- return klass;
- }
- Thread::Current()->ClearException();
- }
-
+Class* EnsureResolved(Class* klass) {
+ DCHECK(klass != NULL);
+ // Wait for the class if it has not already been linked.
Thread* self = Thread::Current();
- DCHECK(self != NULL);
- CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
- // Find the class in the loaded classes table.
- Class* klass = LookupClass(descriptor, class_loader);
- if (klass == NULL) {
- // Class is not yet loaded.
- if (descriptor[0] == '[' && descriptor[1] != '\0') {
- return CreateArrayClass(descriptor, class_loader);
- }
- const DexFile::ClassPath& class_path = ((class_loader != NULL)
- ? ClassLoader::GetClassPath(class_loader)
- : boot_class_path_);
- DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_path);
- if (pair.second == NULL) {
- std::string name(PrintableString(descriptor));
- ThrowNoClassDefFoundError("Class %s not found in class loader %p", name.c_str(), class_loader);
- return NULL;
- }
- const DexFile& dex_file = *pair.first;
- const DexFile::ClassDef& dex_class_def = *pair.second;
- DexCache* dex_cache = FindDexCache(dex_file);
- // Load the class from the dex file.
- if (!init_done_) {
- // finish up init of hand crafted class_roots_
- if (descriptor == "Ljava/lang/Object;") {
- klass = GetClassRoot(kJavaLangObject);
- } else if (descriptor == "Ljava/lang/Class;") {
- klass = GetClassRoot(kJavaLangClass);
- } else if (descriptor == "Ljava/lang/String;") {
- klass = GetClassRoot(kJavaLangString);
- } else if (descriptor == "Ljava/lang/reflect/Constructor;") {
- klass = GetClassRoot(kJavaLangReflectConstructor);
- } else if (descriptor == "Ljava/lang/reflect/Field;") {
- klass = GetClassRoot(kJavaLangReflectField);
- } else if (descriptor == "Ljava/lang/reflect/Method;") {
- klass = GetClassRoot(kJavaLangReflectMethod);
- } else {
- klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
- }
- } else {
- klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
- }
- if (!klass->IsResolved()) {
- klass->SetDexCache(dex_cache);
- LoadClass(dex_file, dex_class_def, klass, class_loader);
- // Check for a pending exception during load
- if (self->IsExceptionPending()) {
- return NULL;
- }
- ObjectLock lock(klass);
- klass->SetClinitThreadId(self->GetTid());
- // Add the newly loaded class to the loaded classes table.
- bool success = InsertClass(descriptor, klass); // TODO: just return collision
- if (!success) {
- // We may fail to insert if we raced with another thread.
- klass->SetClinitThreadId(0);
- klass = LookupClass(descriptor, class_loader);
- CHECK(klass != NULL);
- return klass;
- } else {
- // Finish loading (if necessary) by finding parents
- CHECK(!klass->IsLoaded());
- if (!LoadSuperAndInterfaces(klass, dex_file)) {
- // Loading failed.
- CHECK(self->IsExceptionPending());
- lock.NotifyAll();
- return NULL;
- }
- CHECK(klass->IsLoaded());
- // Link the class (if necessary)
- CHECK(!klass->IsResolved());
- if (!LinkClass(klass)) {
- // Linking failed.
- CHECK(self->IsExceptionPending());
- lock.NotifyAll();
- return NULL;
- }
- CHECK(klass->IsResolved());
- }
- }
- }
- // Link the class if it has not already been linked.
if (!klass->IsResolved() && !klass->IsErroneous()) {
ObjectLock lock(klass);
// Check for circular dependencies between classes.
@@ -871,8 +804,134 @@
return NULL;
}
// Return the loaded class. No exceptions should be pending.
- CHECK(klass->IsResolved()) << descriptor;
- CHECK(!self->IsExceptionPending()) << descriptor << " " << PrettyTypeOf(self->GetException());
+ CHECK(klass->IsResolved()) << PrettyClass(klass);
+ CHECK(!self->IsExceptionPending())
+ << PrettyClass(klass) << " " << PrettyTypeOf(self->GetException());
+ return klass;
+}
+
+Class* ClassLinker::FindClass(const std::string& descriptor,
+ const ClassLoader* class_loader) {
+ CHECK_NE(descriptor.size(), 0U);
+ Thread* self = Thread::Current();
+ DCHECK(self != NULL);
+ CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
+ // Find the class in the loaded classes table.
+ Class* klass = LookupClass(descriptor, class_loader);
+ if (klass != NULL) {
+ return EnsureResolved(klass);
+ }
+ if (descriptor.size() == 1) {
+ // only the descriptors of primitive types should be 1 character long
+ return FindPrimitiveClass(descriptor[0]);
+ }
+ // Class is not yet loaded.
+ if (descriptor[0] == '[') {
+ return CreateArrayClass(descriptor, class_loader);
+ }
+ if (class_loader == NULL) {
+ DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_);
+ if (pair.second == NULL) {
+ std::string name(PrintableString(descriptor));
+ ThrowNoClassDefFoundError("Class %s not found in boot class loader", name.c_str());
+ return NULL;
+ }
+ return DefineClass(descriptor, NULL, *pair.first, *pair.second);
+ }
+
+ if (ClassLoader::UseCompileTimeClassPath()) {
+ const std::vector<const DexFile*>& class_path
+ = ClassLoader::GetCompileTimeClassPath(class_loader);
+ DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_path);
+ if (pair.second == NULL) {
+ return FindSystemClass(descriptor);
+ }
+ return DefineClass(descriptor, class_loader, *pair.first, *pair.second);
+ }
+
+ std::string class_name_string = DescriptorToDot(descriptor);
+ ScopedThreadStateChange(self, Thread::kNative);
+ JNIEnv* env = self->GetJniEnv();
+ jclass c = AddLocalReference<jclass>(env, GetClassRoot(kJavaLangClassLoader));
+ CHECK(c != NULL);
+ // TODO: cache method?
+ jmethodID mid = env->GetMethodID(c, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+ CHECK(mid != NULL);
+ jobject class_name_object = env->NewStringUTF(class_name_string.c_str());
+ if (class_name_string == NULL) {
+ return NULL;
+ }
+ jobject class_loader_object = AddLocalReference<jobject>(env, class_loader);
+ jobject result = env->CallObjectMethod(class_loader_object, mid, class_name_object);
+ Class* klass_result = Decode<Class*>(env, result);
+ env->DeleteLocalRef(result);
+ env->DeleteLocalRef(class_name_object);
+ env->DeleteLocalRef(c);
+ return klass_result;
+}
+
+Class* ClassLinker::DefineClass(const std::string& descriptor,
+ const ClassLoader* class_loader,
+ const DexFile& dex_file,
+ const DexFile::ClassDef& dex_class_def) {
+ Class* klass;
+ // Load the class from the dex file.
+ if (!init_done_) {
+ // finish up init of hand crafted class_roots_
+ if (descriptor == "Ljava/lang/Object;") {
+ klass = GetClassRoot(kJavaLangObject);
+ } else if (descriptor == "Ljava/lang/Class;") {
+ klass = GetClassRoot(kJavaLangClass);
+ } else if (descriptor == "Ljava/lang/String;") {
+ klass = GetClassRoot(kJavaLangString);
+ } else if (descriptor == "Ljava/lang/reflect/Constructor;") {
+ klass = GetClassRoot(kJavaLangReflectConstructor);
+ } else if (descriptor == "Ljava/lang/reflect/Field;") {
+ klass = GetClassRoot(kJavaLangReflectField);
+ } else if (descriptor == "Ljava/lang/reflect/Method;") {
+ klass = GetClassRoot(kJavaLangReflectMethod);
+ } else {
+ klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
+ }
+ } else {
+ klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
+ }
+ klass->SetDexCache(FindDexCache(dex_file));
+ LoadClass(dex_file, dex_class_def, klass, class_loader);
+ // Check for a pending exception during load
+ Thread* self = Thread::Current();
+ if (self->IsExceptionPending()) {
+ return NULL;
+ }
+ ObjectLock lock(klass);
+ klass->SetClinitThreadId(self->GetTid());
+ // Add the newly loaded class to the loaded classes table.
+ bool success = InsertClass(descriptor, klass); // TODO: just return collision
+ if (!success) {
+ // We may fail to insert if we raced with another thread.
+ klass->SetClinitThreadId(0);
+ klass = LookupClass(descriptor, class_loader);
+ CHECK(klass != NULL);
+ return klass;
+ }
+ // Finish loading (if necessary) by finding parents
+ CHECK(!klass->IsLoaded());
+ if (!LoadSuperAndInterfaces(klass, dex_file)) {
+ // Loading failed.
+ CHECK(self->IsExceptionPending());
+ lock.NotifyAll();
+ return NULL;
+ }
+ CHECK(klass->IsLoaded());
+ // Link the class (if necessary)
+ CHECK(!klass->IsResolved());
+ if (!LinkClass(klass)) {
+ // Linking failed.
+ CHECK(self->IsExceptionPending());
+ lock.NotifyAll();
+ return NULL;
+ }
+ CHECK(klass->IsResolved());
return klass;
}
@@ -991,18 +1050,36 @@
}
}
+ UniquePtr<const OatFile::OatClass> oat_class;
+ if (Runtime::Current()->IsStarted() && !ClassLoader::UseCompileTimeClassPath()) {
+ const OatFile* oat_file = FindOatFile(dex_file);
+ if (oat_file != NULL) {
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+ if (oat_dex_file != NULL) {
+ uint32_t class_def_index;
+ bool found = dex_file.FindClassDefIndex(descriptor, class_def_index);
+ CHECK(found) << descriptor;
+ oat_class.reset(oat_dex_file->GetOatClass(class_def_index));
+ }
+ }
+ }
+ size_t method_index = 0;
+
// Load direct methods.
if (num_direct_methods != 0) {
// TODO: append direct methods to class object
klass->SetDirectMethods(AllocObjectArray<Method>(num_direct_methods));
uint32_t last_idx = 0;
- for (size_t i = 0; i < num_direct_methods; ++i) {
+ for (size_t i = 0; i < num_direct_methods; ++i, ++method_index) {
DexFile::Method dex_method;
dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
Method* meth = AllocMethod();
klass->SetDirectMethod(i, meth);
LoadMethod(dex_file, dex_method, klass, meth);
- // TODO: register maps
+ if (oat_class.get() != NULL) {
+ const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
+ oat_method.LinkMethod(meth);
+ }
}
}
@@ -1011,13 +1088,16 @@
// TODO: append virtual methods to class object
klass->SetVirtualMethods(AllocObjectArray<Method>(num_virtual_methods));
uint32_t last_idx = 0;
- for (size_t i = 0; i < num_virtual_methods; ++i) {
+ for (size_t i = 0; i < num_virtual_methods; ++i, ++method_index) {
DexFile::Method dex_method;
dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
Method* meth = AllocMethod();
klass->SetVirtualMethod(i, meth);
LoadMethod(dex_file, dex_method, klass, meth);
- // TODO: register maps
+ if (oat_class.get() != NULL) {
+ const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
+ oat_method.LinkMethod(meth);
+ }
}
}
}
@@ -1130,18 +1210,42 @@
RegisterDexFile(dex_file, dex_cache);
}
-void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
- RegisterDexFile(dex_file, AllocDexCache(dex_file));
+bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) const {
+ lock_.AssertHeld();
+ for (size_t i = 0; i != dex_files_.size(); ++i) {
+ if (dex_files_[i] == &dex_file) {
+ return true;
+ }
+ }
+ return false;
}
-void ClassLinker::RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache) {
+bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const {
MutexLock mu(lock_);
+ return IsDexFileRegistered(dex_file);
+}
+
+void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, DexCache* dex_cache) {
+ lock_.AssertHeld();
CHECK(dex_cache != NULL) << dex_file.GetLocation();
CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()));
dex_files_.push_back(&dex_file);
dex_caches_.push_back(dex_cache);
}
+void ClassLinker::RegisterDexFile(const DexFile& dex_file) {
+ MutexLock mu(lock_);
+ if (IsDexFileRegisteredLocked(dex_file)) {
+ return;
+ }
+ RegisterDexFileLocked(dex_file, AllocDexCache(dex_file));
+}
+
+void ClassLinker::RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache) {
+ MutexLock mu(lock_);
+ RegisterDexFileLocked(dex_file, dex_cache);
+}
+
const DexFile& ClassLinker::FindDexFile(const DexCache* dex_cache) const {
MutexLock mu(lock_);
for (size_t i = 0; i != dex_caches_.size(); ++i) {
@@ -1191,7 +1295,7 @@
// array class; that always comes from the base element class.
//
// Returns NULL with an exception raised on failure.
-Class* ClassLinker::CreateArrayClass(const StringPiece& descriptor,
+Class* ClassLinker::CreateArrayClass(const std::string& descriptor,
const ClassLoader* class_loader) {
CHECK_EQ('[', descriptor[0]);
@@ -1259,7 +1363,7 @@
if (new_class->GetDescriptor() != NULL) {
DCHECK(new_class->GetDescriptor()->Equals(descriptor));
} else {
- new_class->SetDescriptor(intern_table_->InternStrong(descriptor.ToString().c_str()));
+ new_class->SetDescriptor(intern_table_->InternStrong(descriptor.c_str()));
}
Class* java_lang_Object = GetClassRoot(kJavaLangObject);
new_class->SetSuperClass(java_lang_Object);
@@ -1339,14 +1443,14 @@
return NULL;
}
-bool ClassLinker::InsertClass(const StringPiece& descriptor, Class* klass) {
+bool ClassLinker::InsertClass(const std::string& descriptor, Class* klass) {
size_t hash = StringPieceHash()(descriptor);
MutexLock mu(lock_);
Table::iterator it = classes_.insert(std::make_pair(hash, klass));
return ((*it).second == klass);
}
-Class* ClassLinker::LookupClass(const StringPiece& descriptor, const ClassLoader* class_loader) {
+Class* ClassLinker::LookupClass(const std::string& descriptor, const ClassLoader* class_loader) {
size_t hash = StringPieceHash()(descriptor);
MutexLock mu(lock_);
typedef Table::const_iterator It; // TODO: C++0x auto
@@ -2290,12 +2394,7 @@
Class* resolved = dex_cache->GetResolvedType(type_idx);
if (resolved == NULL) {
const char* descriptor = dex_file.dexStringByTypeIdx(type_idx);
- if (descriptor[1] == '\0') {
- // only the descriptors of primitive types should be 1 character long
- resolved = FindPrimitiveClass(descriptor[0]);
- } else {
- resolved = FindClass(descriptor, class_loader);
- }
+ resolved = FindClass(descriptor, class_loader);
if (resolved != NULL) {
Class* check = resolved;
while (check->IsArrayClass()) {
diff --git a/src/class_linker.h b/src/class_linker.h
index 6d17a10..67bb35c 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -50,23 +50,38 @@
// Finds a class by its descriptor, loading it if necessary.
// If class_loader is null, searches boot_class_path_.
- Class* FindClass(const StringPiece& descriptor, const ClassLoader* class_loader);
+ Class* FindClass(const std::string& descriptor, const ClassLoader* class_loader);
+
+ Class* FindSystemClass(const std::string& descriptor) {
+ return FindClass(descriptor, NULL);
+ }
+
+ // Define a new a class based on a ClassDef from a DexFile
+ Class* DefineClass(const std::string& descriptor, const ClassLoader* class_loader,
+ const DexFile& dex_file, const DexFile::ClassDef& dex_class_def);
// Finds a class by its descriptor, returning NULL if it isn't wasn't loaded
// by the given 'class_loader'.
- Class* LookupClass(const StringPiece& descriptor, const ClassLoader* class_loader);
+ Class* LookupClass(const std::string& descriptor, const ClassLoader* class_loader);
Class* FindPrimitiveClass(char type);
- Class* FindSystemClass(const StringPiece& descriptor) {
- return FindClass(descriptor, NULL);
- }
-
void DumpAllClasses(int flags) const;
size_t NumLoadedClasses() const;
// Resolve a String with the given index from the DexFile, storing the
+ // result in the DexCache. The referrer is used to identify the
+ // target DexCache and ClassLoader to use for resolution.
+ String* ResolveString(uint32_t string_idx, const Method* referrer) {
+ Class* declaring_class = referrer->GetDeclaringClass();
+ DexCache* dex_cache = declaring_class->GetDexCache();
+ // TODO: we could check for a dex cache hit here
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ return ResolveString(dex_file, string_idx, dex_cache);
+ }
+
+ // Resolve a String with the given index from the DexFile, storing the
// result in the DexCache.
String* ResolveString(const DexFile& dex_file, uint32_t string_idx, DexCache* dex_cache);
@@ -175,6 +190,8 @@
const DexFile& FindDexFile(const DexCache* dex_cache) const;
DexCache* FindDexCache(const DexFile& dex_file) const;
+ bool IsDexFileRegistered(const DexFile& dex_file) const;
+ const OatFile* FindOatFile(const std::string& location);
// TODO: replace this with multiple methods that allocate the correct managed type.
template <class T>
@@ -228,7 +245,7 @@
Class::PrimitiveType type);
- Class* CreateArrayClass(const StringPiece& descriptor,
+ Class* CreateArrayClass(const std::string& descriptor,
const ClassLoader* class_loader);
void AppendToBootClassPath(const DexFile& dex_file);
@@ -261,7 +278,13 @@
// Inserts a class into the class table. Returns true if the class
// was inserted.
- bool InsertClass(const StringPiece& descriptor, Class* klass);
+ bool InsertClass(const std::string& descriptor, Class* klass);
+
+ void RegisterDexFileLocked(const DexFile& dex_file, DexCache* dex_cache);
+ bool IsDexFileRegisteredLocked(const DexFile& dex_file) const;
+
+ // Find, possibily opening, an OatFile corresponding to a DexFile
+ const OatFile* FindOatFile(const DexFile& dex_file);
bool InitializeClass(Class* klass, bool can_run_clinit);
bool WaitForInitializeClass(Class* klass, Thread* self, ObjectLock& lock);
@@ -314,7 +337,7 @@
std::vector<const DexFile*> dex_files_;
std::vector<DexCache*> dex_caches_;
- // multimap from a StringPiece hash code of a class descriptor to
+ // multimap from a string 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;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 264b669..8ad2a20 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -15,7 +15,7 @@
class ClassLinkerTest : public CommonTest {
protected:
- void AssertNonExistentClass(const StringPiece& descriptor) {
+ void AssertNonExistentClass(const std::string& descriptor) {
EXPECT_TRUE(class_linker_->FindSystemClass(descriptor) == NULL);
Thread* self = Thread::Current();
EXPECT_TRUE(self->IsExceptionPending());
@@ -25,11 +25,11 @@
EXPECT_TRUE(exception->InstanceOf(exception_class));
}
- void AssertPrimitiveClass(const StringPiece& descriptor) {
+ void AssertPrimitiveClass(const std::string& descriptor) {
AssertPrimitiveClass(descriptor, class_linker_->FindSystemClass(descriptor));
}
- void AssertPrimitiveClass(const StringPiece& descriptor, const Class* primitive) {
+ void AssertPrimitiveClass(const std::string& descriptor, const Class* primitive) {
ASSERT_TRUE(primitive != NULL);
ASSERT_TRUE(primitive->GetClass() != NULL);
ASSERT_EQ(primitive->GetClass(), primitive->GetClass()->GetClass());
@@ -62,8 +62,8 @@
EXPECT_TRUE(primitive->GetIfTable() == NULL);
}
- void AssertArrayClass(const StringPiece& array_descriptor,
- const StringPiece& component_type,
+ void AssertArrayClass(const std::string& array_descriptor,
+ const std::string& component_type,
const ClassLoader* class_loader) {
Class* array = class_linker_->FindClass(array_descriptor, class_loader);
EXPECT_TRUE(array->GetComponentType()->GetDescriptor()->Equals(component_type));
@@ -71,7 +71,7 @@
AssertArrayClass(array_descriptor, array);
}
- void AssertArrayClass(const StringPiece& array_descriptor, Class* array) {
+ void AssertArrayClass(const std::string& array_descriptor, Class* array) {
ASSERT_TRUE(array != NULL);
ASSERT_TRUE(array->GetClass() != NULL);
ASSERT_EQ(array->GetClass(), array->GetClass()->GetClass());
@@ -142,7 +142,7 @@
EXPECT_TRUE(field->GetType() != NULL);
}
- void AssertClass(const StringPiece& descriptor, Class* klass) {
+ void AssertClass(const std::string& descriptor, Class* klass) {
EXPECT_TRUE(klass->GetDescriptor()->Equals(descriptor));
if (klass->GetDescriptor()->Equals(String::AllocFromModifiedUtf8("Ljava/lang/Object;"))) {
EXPECT_FALSE(klass->HasSuperClass());
@@ -259,7 +259,7 @@
total_num_reference_instance_fields == 0);
}
- void AssertDexFileClass(ClassLoader* class_loader, const StringPiece& descriptor) {
+ void AssertDexFileClass(ClassLoader* class_loader, const std::string& descriptor) {
ASSERT_TRUE(descriptor != NULL);
Class* klass = class_linker_->FindSystemClass(descriptor);
ASSERT_TRUE(klass != NULL);
@@ -668,11 +668,11 @@
}
TEST_F(ClassLinkerTest, FindClass_Primitives) {
- StringPiece expected = "BCDFIJSZV";
+ const std::string expected("BCDFIJSZV");
for (int ch = 0; ch < 255; ch++) {
char* s = reinterpret_cast<char*>(&ch);
- StringPiece descriptor(s, 1);
- if (expected.find(ch) == StringPiece::npos) {
+ const std::string descriptor(s, 1);
+ if (expected.find(ch) == std::string::npos) {
AssertNonExistentClass(descriptor);
} else {
AssertPrimitiveClass(descriptor);
@@ -932,7 +932,7 @@
// case 2, get the initialized storage from StaticsFromCode.getS0
const ClassLoader* class_loader = LoadDex("StaticsFromCode");
- const DexFile* dex_file = ClassLoader::GetClassPath(class_loader)[0];
+ const DexFile* dex_file = ClassLoader::GetCompileTimeClassPath(class_loader)[0];
CHECK(dex_file != NULL);
Class* klass = class_linker_->FindClass("LStaticsFromCode;", class_loader);
diff --git a/src/class_loader.cc b/src/class_loader.cc
index 8f8e829..94a212f 100644
--- a/src/class_loader.cc
+++ b/src/class_loader.cc
@@ -7,20 +7,35 @@
namespace art {
-const std::vector<const DexFile*>& ClassLoader::GetClassPath(const ClassLoader* class_loader) {
+bool ClassLoader::use_compile_time_class_path = false;
+ClassLoader::Table ClassLoader::compile_time_class_paths_;
+
+const std::vector<const DexFile*>& ClassLoader::GetCompileTimeClassPath(const ClassLoader* class_loader) {
+ Runtime* runtime = Runtime::Current();
if (class_loader == NULL) {
- return Runtime::Current()->GetClassLinker()->GetBootClassPath();
+ return runtime->GetClassLinker()->GetBootClassPath();
}
- return class_loader->class_path_;
+ CHECK(ClassLoader::UseCompileTimeClassPath());
+ Table::const_iterator it = compile_time_class_paths_.find(class_loader);
+ CHECK(it != compile_time_class_paths_.end());
+ return it->second;
+}
+
+void ClassLoader::SetCompileTimeClassPath(const ClassLoader* class_loader,
+ std::vector<const DexFile*>& class_path) {
+ CHECK(!Runtime::Current()->IsStarted());
+ use_compile_time_class_path = true;
+ compile_time_class_paths_[class_loader] = class_path;
}
// TODO: get global references for these
Class* PathClassLoader::dalvik_system_PathClassLoader_ = NULL;
-const PathClassLoader* PathClassLoader::Alloc(std::vector<const DexFile*> dex_files) {
+const PathClassLoader* PathClassLoader::AllocCompileTime(std::vector<const DexFile*>& dex_files) {
+ CHECK(!Runtime::Current()->IsStarted());
DCHECK(dalvik_system_PathClassLoader_ != NULL);
PathClassLoader* p = down_cast<PathClassLoader*>(dalvik_system_PathClassLoader_->AllocObject());
- p->SetClassPath(dex_files);
+ SetCompileTimeClassPath(p, dex_files);
return p;
}
diff --git a/src/class_loader.h b/src/class_loader.h
index 80444f5..8fe6a09 100644
--- a/src/class_loader.h
+++ b/src/class_loader.h
@@ -7,19 +7,17 @@
#include "dex_file.h"
#include "object.h"
+#include "unordered_map.h"
namespace art {
// C++ mirror of java.lang.ClassLoader
-// TODO: add MANAGED when class_path_ removed
-class ClassLoader : public Object {
+class MANAGED ClassLoader : public Object {
public:
- static const std::vector<const DexFile*>& GetClassPath(const ClassLoader* class_loader);
-
- void SetClassPath(std::vector<const DexFile*>& class_path) {
- DCHECK_EQ(class_path_.size(), 0U);
- // TODO: use setter
- class_path_ = class_path;
+ static const std::vector<const DexFile*>& GetCompileTimeClassPath(const ClassLoader* class_loader);
+ static void SetCompileTimeClassPath(const ClassLoader* class_loader, std::vector<const DexFile*>& class_path);
+ static bool UseCompileTimeClassPath() {
+ return use_compile_time_class_path;
}
private:
@@ -27,8 +25,10 @@
Object* packages_;
ClassLoader* parent_;
- // TODO: remove once we can create a real PathClassLoader
- std::vector<const DexFile*> class_path_;
+ typedef std::tr1::unordered_map<const ClassLoader*, std::vector<const DexFile*>, ObjectIdentityHash> Table;
+ static Table compile_time_class_paths_;
+
+ static bool use_compile_time_class_path;
friend struct ClassLoaderOffsets; // for verifying offset information
DISALLOW_IMPLICIT_CONSTRUCTORS(ClassLoader);
@@ -50,7 +50,7 @@
// TODO: add MANAGED when class_path_ removed
class PathClassLoader : public BaseDexClassLoader {
public:
- static const PathClassLoader* Alloc(std::vector<const DexFile*> dex_files);
+ static const PathClassLoader* AllocCompileTime(std::vector<const DexFile*>& dex_files);
static void SetClass(Class* dalvik_system_PathClassLoader);
static void ResetClass();
private:
diff --git a/src/common_test.h b/src/common_test.h
index 950020d..024cde9 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -210,7 +210,7 @@
runtime_->CreateCalleeSaveMethod(instruction_set, type), type);
}
}
- compiler_.reset(new Compiler(instruction_set));
+ compiler_.reset(new Compiler(instruction_set, false));
Heap::VerifyHeap(); // Check for heap corruption before the test
}
@@ -301,7 +301,7 @@
class_linker_->RegisterDexFile(*dex_file);
std::vector<const DexFile*> dex_files;
dex_files.push_back(dex_file);
- return PathClassLoader::Alloc(dex_files);
+ return PathClassLoader::AllocCompileTime(dex_files);
}
const DexFile* OpenTestDexFile(const char* name) {
@@ -326,12 +326,24 @@
class_linker_->RegisterDexFile(*dex_file);
std::vector<const DexFile*> class_path;
class_path.push_back(dex_file);
- const ClassLoader* class_loader = PathClassLoader::Alloc(class_path);
+ const ClassLoader* class_loader = PathClassLoader::AllocCompileTime(class_path);
CHECK(class_loader != NULL);
Thread::Current()->SetClassLoaderOverride(class_loader);
return class_loader;
}
+ void CompileClass(const ClassLoader* class_loader, const char* class_name) {
+ std::string class_descriptor = DotToDescriptor(class_name);
+ Class* klass = class_linker_->FindClass(class_descriptor, class_loader);
+ CHECK(klass != NULL) << "Class not found " << class_name;
+ for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
+ CompileMethod(klass->GetDirectMethod(i));
+ }
+ for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
+ CompileMethod(klass->GetVirtualMethod(i));
+ }
+ }
+
void CompileMethod(Method* method) {
CHECK(method != NULL);
compiler_->CompileOne(method);
diff --git a/src/compiler.cc b/src/compiler.cc
index 3b98ea0..b62c40b 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -31,8 +31,11 @@
ByteArray* X86CreateResolutionTrampoline(Runtime::TrampolineType type);
}
-Compiler::Compiler(InstructionSet instruction_set)
- : instruction_set_(instruction_set), jni_compiler_(instruction_set), verbose_(false) {
+Compiler::Compiler(InstructionSet instruction_set, bool image)
+ : instruction_set_(instruction_set),
+ jni_compiler_(instruction_set),
+ image_(image),
+ verbose_(false) {
CHECK(!Runtime::Current()->IsStarted());
}
@@ -82,7 +85,8 @@
}
void Compiler::Resolve(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(class_loader);
+ const std::vector<const DexFile*>& class_path
+ = ClassLoader::GetCompileTimeClassPath(class_loader);
for (size_t i = 0; i != class_path.size(); ++i) {
const DexFile* dex_file = class_path[i];
CHECK(dex_file != NULL);
@@ -92,11 +96,13 @@
void Compiler::ResolveDexFile(const ClassLoader* class_loader, const DexFile& dex_file) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ DexCache* dex_cache = class_linker->FindDexCache(dex_file);
// Strings are easy, they always are simply resolved to literals in the same file
- DexCache* dex_cache = class_linker->FindDexCache(dex_file);
- for (size_t string_idx = 0; string_idx < dex_cache->NumStrings(); string_idx++) {
- class_linker->ResolveString(dex_file, string_idx, dex_cache);
+ if (IsImage()) { // Only resolve when we'll have an image, so compiler won't choose fast path
+ for (size_t string_idx = 0; string_idx < dex_cache->NumStrings(); string_idx++) {
+ class_linker->ResolveString(dex_file, string_idx, dex_cache);
+ }
}
// Class derived values are more complicated, they require the linker and loader.
@@ -188,7 +194,8 @@
}
void Compiler::Verify(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(class_loader);
+ const std::vector<const DexFile*>& class_path
+ = ClassLoader::GetCompileTimeClassPath(class_loader);
for (size_t i = 0; i != class_path.size(); ++i) {
const DexFile* dex_file = class_path[i];
CHECK(dex_file != NULL);
@@ -227,7 +234,8 @@
}
void Compiler::InitializeClassesWithoutClinit(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(class_loader);
+ const std::vector<const DexFile*>& class_path
+ = ClassLoader::GetCompileTimeClassPath(class_loader);
for (size_t i = 0; i != class_path.size(); ++i) {
const DexFile* dex_file = class_path[i];
CHECK(dex_file != NULL);
@@ -260,7 +268,8 @@
}
void Compiler::Compile(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(class_loader);
+ const std::vector<const DexFile*>& class_path
+ = ClassLoader::GetCompileTimeClassPath(class_loader);
for (size_t i = 0; i != class_path.size(); ++i) {
const DexFile* dex_file = class_path[i];
CHECK(dex_file != NULL);
@@ -323,7 +332,7 @@
}
const CompiledMethod* Compiler::GetCompiledMethod(const Method* method) const {
- MethodTable::const_iterator it = compiled_methods_.find(method);
+ MethodTable::const_iterator it = compiled_methods_.find(method);
if (it == compiled_methods_.end()) {
return NULL;
}
@@ -341,7 +350,8 @@
}
void Compiler::SetCodeAndDirectMethods(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(class_loader);
+ const std::vector<const DexFile*>& class_path
+ = ClassLoader::GetCompileTimeClassPath(class_loader);
for (size_t i = 0; i != class_path.size(); ++i) {
const DexFile* dex_file = class_path[i];
CHECK(dex_file != NULL);
diff --git a/src/compiler.h b/src/compiler.h
index 6059a2a..0fc68df 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -16,7 +16,9 @@
class Compiler {
public:
- explicit Compiler(InstructionSet instruction_set);
+ // Create a compiler targeting the requested "instruction_set".
+ // "image" should be true if image specific optimizations should be enabled.
+ explicit Compiler(InstructionSet instruction_set, bool image);
~Compiler();
@@ -26,14 +28,18 @@
// Compile a single Method
void CompileOne(const Method* method);
- void SetVerbose(bool verbose) {
- verbose_ = verbose;
- }
-
InstructionSet GetInstructionSet() const {
return instruction_set_;
}
+ bool IsImage() const {
+ return image_;
+ }
+
+ void SetVerbose(bool verbose) {
+ verbose_ = verbose;
+ }
+
bool IsVerbose() const {
return verbose_;
}
@@ -81,6 +87,8 @@
typedef std::tr1::unordered_map<const Method*, CompiledInvokeStub*, ObjectIdentityHash> InvokeStubTable;
InvokeStubTable compiled_invoke_stubs_;
+ bool image_;
+
bool verbose_;
DISALLOW_COPY_AND_ASSIGN(Compiler);
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index f261406..1066783 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -39,7 +39,8 @@
}
void MakeAllExecutable(const ClassLoader* class_loader) {
- const std::vector<const DexFile*>& class_path = ClassLoader::GetClassPath(class_loader);
+ const std::vector<const DexFile*>& class_path
+ = ClassLoader::GetCompileTimeClassPath(class_loader);
for (size_t i = 0; i != class_path.size(); ++i) {
const DexFile* dex_file = class_path[i];
CHECK(dex_file != NULL);
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index 3c373d5..977abc8 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -14,7 +14,11 @@
* limitations under the License.
*/
+#include "class_loader.h"
+#include "class_linker.h"
+#include "dex_file.h"
#include "logging.h"
+#include "runtime.h"
#include "ScopedUtfChars.h"
#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
@@ -80,20 +84,61 @@
if (env->ExceptionOccurred()) {
return 0;
}
- UNIMPLEMENTED(WARNING) << sourceName.c_str();
- return 0;
+ const DexFile* dex_file = DexFile::Open(sourceName.c_str(), "");
+ if (dex_file == NULL) {
+ jniThrowExceptionFmt(env, "java/io/IOException", "unable to open DEX file: %s",
+ sourceName.c_str());
+ return NULL;
+ }
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
+}
+
+static const DexFile* toDexFile(JNIEnv* env, int dex_file_address) {
+ const DexFile* dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(dex_file_address));
+ if ((dex_file == NULL)) {
+ jniThrowNullPointerException(env, "dex_file == null");
+ }
+ return dex_file;
}
void DexFile_closeDexFile(JNIEnv* env, jclass, jint cookie) {
- UNIMPLEMENTED(WARNING);
+ const DexFile* dex_file = toDexFile(env, cookie);
+ if (dex_file == NULL) {
+ return;
+ }
+ if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
+ return;
+ }
+ delete dex_file;
}
jclass DexFile_defineClass(JNIEnv* env, jclass, jstring javaName, jobject javaLoader, jint cookie) {
- UNIMPLEMENTED(ERROR);
- return NULL;
+ const DexFile* dex_file = toDexFile(env, cookie);
+ if (dex_file == NULL) {
+ return NULL;
+ }
+ String* name = Decode<String*>(env, javaName);
+ const char* class_name = name->ToModifiedUtf8().c_str();
+ const std::string descriptor = DotToDescriptor(class_name);
+ const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
+ if (dex_class_def == NULL) {
+ jniThrowExceptionFmt(env, "Ljava/lang/NoClassDefFoundError;", "Class %s not found", class_name);
+ return NULL;
+ }
+
+ Object* class_loader_object = Decode<Object*>(env, javaLoader);
+ ClassLoader* class_loader = down_cast<ClassLoader*>(class_loader_object);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ class_linker->RegisterDexFile(*dex_file);
+ Class* result = class_linker->DefineClass(descriptor, class_loader, *dex_file, *dex_class_def);
+ return AddLocalReference<jclass>(env, result);
}
jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jint cookie) {
+ const DexFile* dex_file = toDexFile(env, cookie);
+ if (dex_file == NULL) {
+ return NULL;
+ }
UNIMPLEMENTED(ERROR);
return NULL;
}
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index d5db436..b6a12835 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -124,8 +124,8 @@
return EXIT_FAILURE;
}
- if (image_filename == NULL) {
- fprintf(stderr, "--image file name not specified\n");
+ if (image_filename == NULL && boot_image_option.empty()) {
+ fprintf(stderr, "Either --image or --boot-image must be specified\n");
return EXIT_FAILURE;
}
@@ -190,7 +190,7 @@
for (size_t i = 0; i < dex_files.size(); i++) {
class_linker->RegisterDexFile(*dex_files[i]);
}
- class_loader = PathClassLoader::Alloc(dex_files);
+ class_loader = PathClassLoader::AllocCompileTime(dex_files);
}
// if we loaded an existing image, we will reuse values from the image roots.
@@ -212,7 +212,7 @@
runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2, type), type);
}
}
- Compiler compiler(kThumb2);
+ Compiler compiler(kThumb2, image_filename != NULL);
if (method_names.empty()) {
compiler.CompileAll(class_loader);
} else {
@@ -263,6 +263,11 @@
return EXIT_FAILURE;
}
+ if (image_filename == NULL) {
+ return EXIT_SUCCESS;
+ }
+ CHECK(compiler.IsImage());
+
ImageWriter image_writer;
if (!image_writer.Write(image_filename, image_base, oat_filename, host_prefix)) {
fprintf(stderr, "Failed to create image file %s\n", image_filename);
diff --git a/src/dex_cache.cc b/src/dex_cache.cc
index d24c436..4eb18a5 100644
--- a/src/dex_cache.cc
+++ b/src/dex_cache.cc
@@ -30,6 +30,15 @@
Set(kResolvedFields, resolved_fields);
Set(kCodeAndDirectMethods, code_and_direct_methods);
Set(kInitializedStaticStorage, initialized_static_storage);
+
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsStarted()) {
+ Runtime::TrampolineType unknown_method_resolution_type = Runtime::GetTrampolineType(NULL);
+ ByteArray* res_trampoline = runtime->GetResolutionStubArray(unknown_method_resolution_type);
+ for (size_t i = 0; i < NumResolvedMethods(); i++) {
+ code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline);
+ }
+ }
}
} // namespace art
diff --git a/src/dex_file.h b/src/dex_file.h
index 45cd33e..468ce4d 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -437,8 +437,13 @@
}
// Returns the prototype of a method id.
- const char* GetMethodPrototype(const MethodId& method_id) const {
- return dexStringById(method_id.proto_idx_);
+ const ProtoId& GetMethodPrototype(const MethodId& method_id) const {
+ return GetProtoId(method_id.proto_idx_);
+ }
+
+ // Returns the signature of a method id.
+ const std::string GetMethodSignature(const MethodId& method_id) const {
+ return CreateMethodDescriptor(method_id.proto_idx_, NULL);
}
// Returns the name of a method id.
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 2908d58..d84e4cb 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -4934,11 +4934,11 @@
if (res_method == NULL) {
const DexFile::MethodId& method_id = dex_file->GetMethodId(dec_insn->vB_);
const char* method_name = dex_file->GetMethodName(method_id);
- const char* method_proto = dex_file->GetMethodPrototype(method_id);
+ std::string method_signature = dex_file->GetMethodSignature(method_id);
const char* class_descriptor = dex_file->GetMethodClassDescriptor(method_id);
LOG(ERROR) << "VFY: unable to resolve method " << dec_insn->vB_ << ": "
- << class_descriptor << "." << method_name << " " << method_proto;
+ << class_descriptor << "." << method_name << " " << method_signature;
return NULL;
}
diff --git a/src/dex_verifier_test.cc b/src/dex_verifier_test.cc
index 39e14c4..89482bd 100644
--- a/src/dex_verifier_test.cc
+++ b/src/dex_verifier_test.cc
@@ -13,7 +13,7 @@
class DexVerifierTest : public CommonTest {
protected:
- void VerifyClass(ClassLoader* class_loader, const StringPiece& descriptor) {
+ void VerifyClass(ClassLoader* class_loader, const std::string& descriptor) {
ASSERT_TRUE(descriptor != NULL);
Class* klass = class_linker_->FindSystemClass(descriptor);
diff --git a/src/image.h b/src/image.h
index 86b71e1..76db7e5 100644
--- a/src/image.h
+++ b/src/image.h
@@ -81,10 +81,14 @@
};
Object* GetImageRoot(ImageRoot image_root) const {
- return reinterpret_cast<ObjectArray<Object>*>(image_roots_)->Get(image_root);
+ return GetImageRoots()->Get(image_root);
}
private:
+ ObjectArray<Object>* GetImageRoots() const {
+ return reinterpret_cast<ObjectArray<Object>*>(image_roots_);
+ }
+
static const byte kImageMagic[4];
static const byte kImageVersion[4];
@@ -107,6 +111,7 @@
uint32_t image_roots_;
friend class ImageWriter;
+ friend class ImageDump; // For GetImageRoots()
};
} // namespace art
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 39f3e64..f3ecda0 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -25,6 +25,8 @@
bool ImageWriter::Write(const char* image_filename, uintptr_t image_base,
const std::string& oat_filename, const std::string& strip_location_prefix) {
+ CHECK(image_filename != NULL);
+
CHECK_NE(image_base, 0U);
image_base_ = reinterpret_cast<byte*>(image_base);
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 9ca4034..277284a 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -2771,7 +2771,7 @@
version = (*jni_on_load)(this, NULL);
}
- self->SetClassLoaderOverride(old_class_loader);;
+ self->SetClassLoaderOverride(old_class_loader);
if (version != JNI_VERSION_1_2 &&
version != JNI_VERSION_1_4 &&
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 95ef64c..8a4aa9a 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -123,12 +123,21 @@
return mem_map_->GetLimit();
}
-const OatFile::OatDexFile& OatFile::GetOatDexFile(const std::string& dex_file_location) {
+const OatFile::OatDexFile* OatFile::GetOatDexFile(const std::string& dex_file_location) const {
Table::const_iterator it = oat_dex_files_.find(dex_file_location);
if (it == oat_dex_files_.end()) {
- LOG(FATAL) << "Failed to find OatDexFile for DexFile " << dex_file_location;
+ LOG(WARNING) << "Failed to find OatDexFile for DexFile " << dex_file_location;
+ return NULL;
}
- return *it->second;
+ return it->second;
+}
+
+std::vector<const OatFile::OatDexFile*> OatFile::GetOatDexFiles() const {
+ std::vector<const OatFile::OatDexFile*> result;
+ for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it ) {
+ result.push_back(it->second);
+ }
+ return result;
}
OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
@@ -142,11 +151,11 @@
OatFile::OatDexFile::~OatDexFile() {}
-const OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
+const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
uint32_t methods_offset = classes_pointer_[class_def_index];
const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
CHECK_LT(methods_pointer, oat_file_->GetLimit());
- return OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
+ return new OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
}
OatFile::OatClass::OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer)
@@ -186,7 +195,7 @@
OatFile::OatMethod::~OatMethod() {}
-void OatFile::OatMethod::LinkMethod(Method* method) {
+void OatFile::OatMethod::LinkMethod(Method* method) const {
CHECK(method != NULL);
method->SetCode(code_);
method->SetFrameSizeInBytes(frame_size_in_bytes_);
diff --git a/src/oat_file.h b/src/oat_file.h
index 0472c16..9f95b3b 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -47,7 +47,7 @@
~OatMethod();
// Link Method using the contents of this OatMethod
- void LinkMethod(Method* method);
+ void LinkMethod(Method* method) const;
const void* code_;
size_t frame_size_in_bytes_;
@@ -65,7 +65,7 @@
// defintion. direct methods come first, followed by virtual
// methods. note that runtime created methods such as miranda
// methods are not included.
- const OatMethod GetOatMethod(uint32_t method_idx) const;
+ const OatMethod GetOatMethod(uint32_t method_index) const;
~OatClass();
private:
@@ -89,7 +89,11 @@
class OatDexFile {
public:
- const OatClass GetOatClass(uint32_t class_def_index) const;
+ const OatClass* GetOatClass(uint32_t class_def_index) const;
+
+ const std::string& GetDexFileLocation() const {
+ return dex_file_location_;
+ }
uint32_t GetDexFileChecksum() const {
return dex_file_checksum_;
@@ -111,7 +115,8 @@
DISALLOW_COPY_AND_ASSIGN(OatDexFile);
};
- const OatDexFile& GetOatDexFile(const std::string& dex_file_location);
+ const OatDexFile* GetOatDexFile(const std::string& dex_file_location) const;
+ std::vector<const OatDexFile*> GetOatDexFiles() const;
size_t GetSize() const {
return GetLimit() - GetBase();
@@ -137,6 +142,7 @@
friend class OatClass;
friend class OatDexFile;
+ friend class OatDump; // For GetBase and GetLimit
DISALLOW_COPY_AND_ASSIGN(OatFile);
};
diff --git a/src/oat_test.cc b/src/oat_test.cc
index 3137728..392a822 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -14,7 +14,7 @@
const ClassLoader* class_loader = NULL;
if (compile) {
- compiler_.reset(new Compiler(kThumb2));
+ compiler_.reset(new Compiler(kThumb2, false));
compiler_->CompileAll(class_loader);
}
@@ -33,7 +33,7 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
const DexFile& dex_file = *java_lang_dex_file_.get();
- const OatFile::OatDexFile& oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
+ const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
for (size_t i = 0; i < dex_file.NumClassDefs(); i++) {
const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
const byte* class_data = dex_file.GetClassData(class_def);
@@ -41,14 +41,14 @@
size_t num_virtual_methods = header.virtual_methods_size_;
const char* descriptor = dex_file.GetClassDescriptor(class_def);
- const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(i);
+ UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(i));
Class* klass = class_linker->FindClass(descriptor, class_loader);
size_t method_index = 0;
for (size_t i = 0; i < klass->NumDirectMethods(); i++, method_index++) {
Method* method = klass->GetDirectMethod(i);
- const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+ const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
if (compiled_method == NULL) {
@@ -75,7 +75,7 @@
}
for (size_t i = 0; i < num_virtual_methods; i++, method_index++) {
Method* method = klass->GetVirtualMethod(i);
- const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+ const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
if (compiled_method == NULL) {
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 0722520..99c9361 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -13,7 +13,7 @@
bool OatWriter::Create(const std::string& filename,
const ClassLoader* class_loader,
const Compiler& compiler) {
- const std::vector<const DexFile*>& dex_files = ClassLoader::GetClassPath(class_loader);
+ const std::vector<const DexFile*>& dex_files = ClassLoader::GetCompileTimeClassPath(class_loader);
OatWriter oat_writer(dex_files, class_loader, compiler);
return oat_writer.Write(filename);
}
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 8113c2b..4d99647 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -26,7 +26,11 @@
" Example: adb shell oatdump --image=/system/framework/boot.art\n"
"\n");
fprintf(stderr,
- " --image=<file.art>: specifies the required input image filename.\n"
+ " --oat=<file.oat>: specifies an input oat filename.\n"
+ " Example: --image=/system/framework/boot.oat\n"
+ "\n");
+ fprintf(stderr,
+ " --image=<file.art>: specifies an input image filename.\n"
" Example: --image=/system/framework/boot.art\n"
"\n");
fprintf(stderr,
@@ -52,15 +56,168 @@
"kStaticResolutionStubArray",
"kUnknownMethodResolutionStubArray",
"kCalleeSaveMethod",
+ "kRefsOnlySaveMethod",
+ "kRefsAndArgsSaveMethod",
"kOatLocation",
"kDexCaches",
"kClassRoots",
};
class OatDump {
+ public:
+ static void Dump(const std::string& oat_filename,
+ const std::string& host_prefix,
+ std::ostream& os,
+ const OatFile& oat_file) {
+ const OatHeader& oat_header = oat_file.GetOatHeader();
+
+ os << "MAGIC:\n";
+ os << oat_header.GetMagic() << "\n\n";
+
+ os << "CHECKSUM:\n";
+ os << StringPrintf("%08x\n\n", oat_header.GetChecksum());
+
+ os << "DEX FILE COUNT:\n";
+ os << oat_header.GetDexFileCount() << "\n\n";
+
+ os << "EXECUTABLE OFFSET:\n";
+ os << StringPrintf("%08x\n\n", oat_header.GetExecutableOffset());
+
+ os << "BASE:\n";
+ os << oat_file.GetBase() << "\n\n";
+
+ os << "LIMIT:\n";
+ os << oat_file.GetLimit() << "\n\n";
+
+ os << std::flush;
+
+ std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file.GetOatDexFiles() ;
+ for (size_t i = 0; i < oat_dex_files.size(); i++) {
+ const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
+ CHECK(oat_dex_file != NULL);
+ DumpOatDexFile(host_prefix, os, oat_file, *oat_dex_file);
+ }
+ }
+
+ private:
+ static void DumpOatDexFile(const std::string& host_prefix,
+ std::ostream& os,
+ const OatFile& oat_file,
+ const OatFile::OatDexFile& oat_dex_file) {
+ os << "OAT DEX FILE:\n";
+ std::string dex_file_location = oat_dex_file.GetDexFileLocation();
+ os << "location: " << dex_file_location;
+ if (!host_prefix.empty()) {
+ dex_file_location = host_prefix + dex_file_location;
+ os << " (" << dex_file_location << ")\n";
+ }
+ os << StringPrintf("checksum: %08x\n", oat_dex_file.GetDexFileChecksum());
+ const DexFile* dex_file = DexFile::Open(dex_file_location, "");
+ if (dex_file == NULL) {
+ os << "NOT FOUND\n\n";
+ return;
+ }
+ for (size_t class_def_index = 0; class_def_index < dex_file->NumClassDefs(); class_def_index++) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+ const char* descriptor = dex_file->GetClassDescriptor(class_def);
+ os << StringPrintf("%d: %s (type_ide=%d)\n", class_def_index, descriptor, class_def.class_idx_);
+ UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file.GetOatClass(class_def_index));
+ CHECK(oat_class.get() != NULL);
+ DumpOatClass(os, oat_file, *oat_class.get(), *dex_file, class_def);
+ }
+
+ os << std::flush;
+ }
+
+ static void DumpOatClass(std::ostream& os,
+ const OatFile& oat_file,
+ const OatFile::OatClass& oat_class,
+ const DexFile& dex_file,
+ const DexFile::ClassDef& class_def) {
+ const byte* class_data = dex_file.GetClassData(class_def);
+ DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
+ size_t num_static_fields = header.static_fields_size_;
+ size_t num_instance_fields = header.instance_fields_size_;
+ size_t num_direct_methods = header.direct_methods_size_;
+ size_t num_virtual_methods = header.virtual_methods_size_;
+ uint32_t method_index = 0;
+
+ // just skipping through the fields to advance class_data
+ if (num_static_fields != 0) {
+ uint32_t last_idx = 0;
+ for (size_t i = 0; i < num_static_fields; ++i) {
+ DexFile::Field dex_field;
+ dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
+ }
+ }
+ if (num_instance_fields != 0) {
+ uint32_t last_idx = 0;
+ for (size_t i = 0; i < num_instance_fields; ++i) {
+ DexFile::Field dex_field;
+ dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
+ }
+ }
+
+ if (num_direct_methods != 0) {
+ uint32_t last_idx = 0;
+ for (size_t i = 0; i < num_direct_methods; ++i, method_index++) {
+ DexFile::Method dex_method;
+ dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
+ const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+ DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, dex_method);
+ }
+ }
+ if (num_virtual_methods != 0) {
+ uint32_t last_idx = 0;
+ for (size_t i = 0; i < num_virtual_methods; ++i, method_index++) {
+ DexFile::Method dex_method;
+ dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
+ const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+ DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, dex_method);
+ }
+ }
+ os << std::flush;
+ }
+ static void DumpOatMethod(std::ostream& os,
+ uint32_t method_index,
+ const OatFile& oat_file,
+ const OatFile::OatMethod& oat_method,
+ const DexFile& dex_file,
+ const DexFile::Method& dex_method) {
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method.method_idx_);
+ const char* name = dex_file.GetMethodName(method_id);
+ std::string signature = dex_file.GetMethodSignature(method_id);
+ os << StringPrintf("\t%d: %s %s (method_idx=%d)\n",
+ method_index, name, signature.c_str(), dex_method.method_idx_);
+ os << StringPrintf("\t\tcode: %p (offset=%08x)\n",
+ oat_method.code_,
+ reinterpret_cast<const byte*>(oat_method.code_) - oat_file.GetBase());
+ os << StringPrintf("\t\tframe_size_in_bytes: %d\n",
+ oat_method.frame_size_in_bytes_);
+ os << StringPrintf("\t\treturn_pc_offset_in_bytes: %d\n",
+ oat_method.return_pc_offset_in_bytes_);
+ os << StringPrintf("\t\tcore_spill_mask: %08x\n",
+ oat_method.core_spill_mask_);
+ os << StringPrintf("\t\tfp_spill_mask: %08x\n",
+ oat_method.fp_spill_mask_);
+ os << StringPrintf("\t\tmapping_table: %p (offset=%08x)\n",
+ oat_method.mapping_table_,
+ reinterpret_cast<const byte*>(oat_method.mapping_table_) - oat_file.GetBase());
+ os << StringPrintf("\t\tvmap_table: %p (offset=%08x)\n",
+ oat_method.vmap_table_,
+ reinterpret_cast<const byte*>(oat_method.vmap_table_) - oat_file.GetBase());
+ os << StringPrintf("\t\tinvoke_stub: %p (offset=%08x)\n",
+ oat_method.invoke_stub_,
+ reinterpret_cast<const byte*>(oat_method.invoke_stub_) - oat_file.GetBase());
+ }
+
+};
+
+class ImageDump {
public:
static void Dump(const std::string& image_filename,
+ const std::string& host_prefix,
std::ostream& os,
Space& image_space,
const ImageHeader& image_header) {
@@ -70,10 +227,17 @@
os << "IMAGE BASE:\n";
os << reinterpret_cast<void*>(image_header.GetImageBaseAddr()) << "\n\n";
+ os << "OAT CHECKSUM:\n";
+ os << StringPrintf("%08x\n\n", image_header.GetOatChecksum());
+
os << "OAT BASE:\n";
os << reinterpret_cast<void*>(image_header.GetOatBaseAddr()) << "\n\n";
+ os << "OAT LIMIT:\n";
+ os << reinterpret_cast<void*>(image_header.GetOatLimitAddr()) << "\n\n";
+
os << "ROOTS:\n";
+ os << reinterpret_cast<void*>(image_header.GetImageRoots()) << "\n";
CHECK_EQ(arraysize(image_roots_descriptions_), size_t(ImageHeader::kImageRootsMax));
for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
@@ -93,10 +257,10 @@
os << "\n";
os << "OBJECTS:\n" << std::flush;
- OatDump state(image_space, os);
+ ImageDump state(image_space, os);
HeapBitmap* heap_bitmap = Heap::GetLiveBits();
DCHECK(heap_bitmap != NULL);
- heap_bitmap->Walk(OatDump::Callback, &state);
+ heap_bitmap->Walk(ImageDump::Callback, &state);
os << "\n";
os << "STATS:\n" << std::flush;
@@ -107,22 +271,41 @@
size_t alignment_bytes = RoundUp(header_bytes, kObjectAlignment) - header_bytes;
state.stats_.alignment_bytes += alignment_bytes;
state.stats_.Dump(os);
+ os << "\n";
os << std::flush;
+
+ os << "OAT LOCATION:\n" << std::flush;
+ Object* oat_location_object = image_header.GetImageRoot(ImageHeader::kOatLocation);
+ std::string oat_location = oat_location_object->AsString()->ToModifiedUtf8();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ os << oat_location;
+ if (!host_prefix.empty()) {
+ oat_location = host_prefix + oat_location;
+ os << " (" << oat_location << ")\n";
+ }
+ const OatFile* oat_file = class_linker->FindOatFile(oat_location);
+ if (oat_file == NULL) {
+ os << "NOT FOUND\n";
+ os << std::flush;
+ return;
+ }
+ os << "\n";
+ os << std::flush;
+
+ OatDump::Dump(oat_location, host_prefix, os, *oat_file);
}
private:
- OatDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space), os_(os) {
- }
+ ImageDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space), os_(os) {}
- ~OatDump() {
- }
+ ~ImageDump() {}
static void Callback(Object* obj, void* arg) {
DCHECK(obj != NULL);
DCHECK(arg != NULL);
- OatDump* state = reinterpret_cast<OatDump*>(arg);
+ ImageDump* state = reinterpret_cast<ImageDump*>(arg);
if (!state->InDumpSpace(obj)) {
return;
}
@@ -319,7 +502,6 @@
/ static_cast<double>(dex_instruction_bytes));
os << "\n";
os << std::flush;
-
}
} stats_;
@@ -327,7 +509,7 @@
const Space& dump_space_;
std::ostream& os_;
- DISALLOW_COPY_AND_ASSIGN(OatDump);
+ DISALLOW_COPY_AND_ASSIGN(ImageDump);
};
int oatdump(int argc, char** argv) {
@@ -336,10 +518,11 @@
argc--;
if (argc == 0) {
- fprintf(stderr, "no arguments specified\n");
+ fprintf(stderr, "No arguments specified\n");
usage();
}
+ const char* oat_filename = NULL;
const char* image_filename = NULL;
const char* boot_image_filename = NULL;
std::string host_prefix;
@@ -348,7 +531,9 @@
for (int i = 0; i < argc; i++) {
const StringPiece option(argv[i]);
- if (option.starts_with("--image=")) {
+ if (option.starts_with("--oat=")) {
+ oat_filename = option.substr(strlen("--oat=")).data();
+ } else if (option.starts_with("--image=")) {
image_filename = option.substr(strlen("--image=")).data();
} else if (option.starts_with("--boot-image=")) {
boot_image_filename = option.substr(strlen("--boot-image=")).data();
@@ -358,21 +543,36 @@
const char* filename = option.substr(strlen("--output=")).data();
out.reset(new std::ofstream(filename));
if (!out->good()) {
- fprintf(stderr, "failed to open output filename %s\n", filename);
+ fprintf(stderr, "Failed to open output filename %s\n", filename);
usage();
}
os = out.get();
} else {
- fprintf(stderr, "unknown argument %s\n", option.data());
+ fprintf(stderr, "Unknown argument %s\n", option.data());
usage();
}
}
- if (image_filename == NULL) {
- fprintf(stderr, "--image file name not specified\n");
+ if (image_filename == NULL && oat_filename == NULL) {
+ fprintf(stderr, "Either --image or --oat must be specified\n");
return EXIT_FAILURE;
}
+ if (image_filename != NULL && oat_filename != NULL) {
+ fprintf(stderr, "Either --image or --oat must be specified but not both\n");
+ return EXIT_FAILURE;
+ }
+
+ if (oat_filename != NULL) {
+ const OatFile* oat_file = OatFile::Open(oat_filename, "", NULL);
+ if (oat_file == NULL) {
+ fprintf(stderr, "Failed to open oat file from %s\n", oat_filename);
+ return EXIT_FAILURE;
+ }
+ OatDump::Dump(oat_filename, host_prefix, *os, *oat_file);
+ return EXIT_SUCCESS;
+ }
+
Runtime::Options options;
std::string image_option;
std::string oat_option;
@@ -383,9 +583,11 @@
boot_image_option += boot_image_filename;
options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
}
- image_option += "-Ximage:";
- image_option += image_filename;
- options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
+ if (image_filename != NULL) {
+ image_option += "-Ximage:";
+ image_option += image_filename;
+ options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
+ }
if (!host_prefix.empty()) {
options.push_back(std::make_pair("host-prefix", host_prefix.c_str()));
@@ -393,7 +595,7 @@
UniquePtr<Runtime> runtime(Runtime::Create(options, false));
if (runtime.get() == NULL) {
- fprintf(stderr, "could not create runtime\n");
+ fprintf(stderr, "Failed to create runtime\n");
return EXIT_FAILURE;
}
@@ -401,10 +603,10 @@
CHECK(image_space != NULL);
const ImageHeader& image_header = image_space->GetImageHeader();
if (!image_header.IsValid()) {
- fprintf(stderr, "invalid image header %s\n", image_filename);
+ fprintf(stderr, "Invalid image header %s\n", image_filename);
return EXIT_FAILURE;
}
- OatDump::Dump(image_filename, *os, *image_space, image_header);
+ ImageDump::Dump(image_filename, host_prefix, *os, *image_space, image_header);
return EXIT_SUCCESS;
}
diff --git a/src/object.cc b/src/object.cc
index 58ffa6b..33cd802 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -309,7 +309,7 @@
}
++p; // Either the ';' or the primitive type.
- StringPiece descriptor(start, (p - start));
+ std::string descriptor(start, (p - start));
return class_linker->FindClass(descriptor, cl);
} else if (*p == 'L') {
const char* start = p;
@@ -318,7 +318,7 @@
}
++p;
StringPiece descriptor(start, (p - start));
- return class_linker->FindClass(descriptor, cl);
+ return class_linker->FindClass(descriptor.ToString(), cl);
} else {
return class_linker->FindPrimitiveClass(*p++);
}
diff --git a/src/object_test.cc b/src/object_test.cc
index 6b1f818..1c317e6 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -178,7 +178,7 @@
TEST_F(ObjectTest, StaticFieldFromCode) {
// pretend we are trying to access 'Static.s0' from StaticsFromCode.<clinit>
const ClassLoader* class_loader = LoadDex("StaticsFromCode");
- const DexFile* dex_file = ClassLoader::GetClassPath(class_loader)[0];
+ const DexFile* dex_file = ClassLoader::GetCompileTimeClassPath(class_loader)[0];
CHECK(dex_file != NULL);
Class* klass = class_linker_->FindClass("LStaticsFromCode;", class_loader);
diff --git a/src/runtime.cc b/src/runtime.cc
index 64df1d3..c733bfe 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -7,8 +7,10 @@
#include <limits>
#include <vector>
+#include "ScopedLocalRef.h"
#include "UniquePtr.h"
#include "class_linker.h"
+#include "class_loader.h"
#include "heap.h"
#include "image.h"
#include "intern_table.h"
@@ -307,6 +309,29 @@
return instance_;
}
+void CreateSystemClassLoader() {
+ if (ClassLoader::UseCompileTimeClassPath()) {
+ return;
+ }
+
+ Thread* self = Thread::Current();
+
+ // Must be in the kNative state for calling native methods.
+ CHECK_EQ(self->GetState(), Thread::kNative);
+
+ JNIEnv* env = self->GetJniEnv();
+ ScopedLocalRef<jclass> c(env, env->FindClass("java/lang/ClassLoader"));
+ CHECK(c.get() != NULL);
+ jmethodID mid = env->GetStaticMethodID(c.get(),
+ "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
+ CHECK(mid != NULL);
+ ScopedLocalRef<jobject> result(env, env->CallStaticObjectMethod(c.get(), mid));
+ CHECK(result.get() != NULL);
+
+ ClassLoader* class_loader = Decode<ClassLoader*>(env, result.get());
+ Thread::Current()->SetClassLoaderOverride(class_loader);
+}
+
void Runtime::Start() {
if (IsVerboseStartup()) {
LOG(INFO) << "Runtime::Start entering";
@@ -327,6 +352,8 @@
StartDaemonThreads();
+ CreateSystemClassLoader();
+
Thread::Current()->GetJniEnv()->locals.AssertEmpty();
if (IsVerboseStartup()) {
@@ -338,6 +365,10 @@
signal_catcher_ = new SignalCatcher;
Thread* self = Thread::Current();
+
+ // Must be in the kNative state for calling native methods.
+ CHECK_EQ(self->GetState(), Thread::kNative);
+
JNIEnv* env = self->GetJniEnv();
ScopedLocalRef<jclass> c(env, env->FindClass("java/lang/Daemons"));
CHECK(c.get() != NULL);
@@ -408,7 +439,7 @@
JNIEnv* env = self->GetJniEnv();
// Must be in the kNative state for calling native methods (JNI_OnLoad code).
- ScopedThreadStateChange tsc(self, Thread::kNative);
+ CHECK_EQ(self->GetState(), Thread::kNative);
// First set up JniConstants, which is used by both the runtime's built-in native
// methods and libcore.
@@ -581,8 +612,9 @@
}
void Runtime::SetJniStubArray(ByteArray* jni_stub_array) {
- CHECK(jni_stub_array != NULL);
- CHECK(jni_stub_array_ == NULL || jni_stub_array_ == jni_stub_array);
+ CHECK(jni_stub_array != NULL) << " jni_stub_array=" << jni_stub_array;
+ CHECK(jni_stub_array_ == NULL || jni_stub_array_ == jni_stub_array)
+ << "jni_stub_array_=" << jni_stub_array_ << " jni_stub_array=" << jni_stub_array;
jni_stub_array_ = jni_stub_array;
}
diff --git a/src/runtime.h b/src/runtime.h
index bb6bfda..65a54e9 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -25,6 +25,7 @@
template<class T> class PrimitiveArray;
typedef PrimitiveArray<int8_t> ByteArray;
class ClassLinker;
+class ClassLoader;
class DexFile;
class Heap;
class InternTable;
@@ -245,6 +246,9 @@
Method* callee_save_method_[kLastCalleeSaveType];
+ // As returned by ClassLoader.getSystemClassLoader()
+ ClassLoader* system_class_loader_;
+
bool started_;
// Hooks supported by JNI_CreateJavaVM
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index c7a04ec..23bb2f5 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -669,6 +669,17 @@
return InitializeStaticStorage(type_idx, referrer, self);
}
+String* ResolveStringFromCode(const Method* referrer, uint32_t string_idx) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ return class_linker->ResolveString(string_idx, referrer);
+}
+
+extern "C" String* artResolveStringFromCode(Method* referrer, int32_t string_idx,
+ Thread* self, Method** sp) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ return ResolveStringFromCode(referrer, string_idx);
+}
+
extern "C" int artUnlockObjectFromCode(Object* obj, Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
DCHECK(obj != NULL); // Assumed to have been checked before entry
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 2d34f9b..9c7fc3e 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -44,6 +44,7 @@
extern "C" void* art_get_obj_static_from_code(uint32_t, void*);
extern "C" void art_handle_fill_data_from_code(void*, void*);
extern "C" void* art_initialize_static_storage_from_code(uint32_t, void*);
+ extern "C" void* art_resolve_string_from_code(void*, uint32_t);
extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
extern "C" int art_set32_static_from_code(uint32_t, void*, int32_t);
extern "C" int art_set64_static_from_code(uint32_t, void*, int64_t);
diff --git a/src/runtime_support_asm.S b/src/runtime_support_asm.S
index 38eaf82..f1a6d63 100644
--- a/src/runtime_support_asm.S
+++ b/src/runtime_support_asm.S
@@ -256,7 +256,7 @@
SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
mov r2, r9 @ pass Thread::Current
mov r3, sp @ pass SP
- @ ClassLinker::InitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
+ @ artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
bl artInitializeStaticStorageFromCode
RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
cmp r0, #0 @ success if result is non-null
@@ -373,6 +373,24 @@
bxeq lr @ return on success
DELIVER_PENDING_EXCEPTION
+ .global art_resolve_string_from_code
+ .extern artResolveStringFromCode
+ /*
+ * Entry from managed code to resolve a string, this stub will
+ * allocate a String and deliver an exception on error. On
+ * success the String is returned.
+ */
+ art_resolve_string_from_code:
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
+ mov r2, r9 @ pass Thread::Current
+ mov r3, sp @ pass SP
+ @ artResolveStringFromCode(Method* referrer, uint32_t type_idx, Thread*, SP)
+ bl artResolveStringFromCode
+ RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+ cmp r0, #0 @ success if result is non-null
+ bxne lr @ return on success
+ DELIVER_PENDING_EXCEPTION
+
.global art_alloc_object_from_code
.extern artAllocObjectFromCode
/*
diff --git a/src/thread.cc b/src/thread.cc
index 400da0c..4dcef55 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -61,12 +61,6 @@
static Method* gThreadGroup_removeThread = NULL;
static Method* gUncaughtExceptionHandler_uncaughtException = NULL;
-// TODO: flesh out and move to appropriate location
-String* ResolveStringFromCode(Method* method, int32_t string_idx) {
- UNIMPLEMENTED(FATAL) << "Resolve string; handle OOM";
- return NULL; // Must return valid string or if exception, doesn't return
-}
-
// TODO: move to appropriate location
static void ObjectInitFromCode(Object* o) {
Class* c = o->GetClass();
@@ -118,6 +112,7 @@
pGetObjStatic = art_get_obj_static_from_code;
pHandleFillArrayDataFromCode = art_handle_fill_data_from_code;
pInitializeStaticStorage = art_initialize_static_storage_from_code;
+ pResolveStringFromCode = art_resolve_string_from_code;
pInvokeInterfaceTrampoline = art_invoke_interface_trampoline;
pSet32Static = art_set32_static_from_code;
pSet64Static = art_set64_static_from_code;
@@ -144,7 +139,6 @@
pInstanceofNonTrivialFromCode = Class::IsAssignableFromCode;
pObjectInit = ObjectInitFromCode;
pResolveMethodFromCode = ResolveMethodFromCode;
- pResolveStringFromCode = ResolveStringFromCode;
pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
pUnresolvedDirectMethodTrampolineFromCode = UnresolvedDirectMethodTrampolineFromCode;
}
diff --git a/src/thread.h b/src/thread.h
index 52e01f2..884aa64 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -82,7 +82,7 @@
};
// Space to throw a StackOverflowError in.
- static const size_t kStackOverflowReservedBytes = 3 * KB;
+ static const size_t kStackOverflowReservedBytes = 4 * KB;
static const size_t kDefaultStackSize = 64 * KB;
@@ -139,7 +139,7 @@
void (*pLockObjectFromCode)(void*);
void (*pObjectInit)(Object*);
void (*pResolveMethodFromCode)(Method*, uint32_t);
- String* (*pResolveStringFromCode)(Method*, int32_t);
+ void* (*pResolveStringFromCode)(void*, uint32_t);
int (*pSet32Static)(uint32_t, void*, int32_t);
int (*pSet64Static)(uint32_t, void*, int64_t);
int (*pSetObjStatic)(uint32_t, void*, void*);
diff --git a/src/utils.cc b/src/utils.cc
index 48ae2ae..86fa312 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -198,6 +198,14 @@
return descriptor;
}
+std::string DescriptorToDot(const std::string& descriptor) {
+ DCHECK_EQ(descriptor[0], 'L');
+ DCHECK_EQ(descriptor[descriptor.size()-1], ';');
+ std::string dot = descriptor.substr(1, descriptor.size()-2);
+ std::replace(dot.begin(), dot.end(), '/', '.');
+ return dot;
+}
+
std::string JniShortName(const Method* m) {
Class* declaring_class = m->GetDeclaringClass();
diff --git a/src/utils.h b/src/utils.h
index 5470f7f..4f58c52 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -176,6 +176,9 @@
// Turn "java.lang.String" into "Ljava/lang/String;".
std::string DotToDescriptor(const char* class_name);
+// Turn "Ljava/lang/String;" into "java.lang.String".
+std::string DescriptorToDot(const std::string& descriptor);
+
// Tests whether 's' is a valid class name.
// name_or_descriptor
// true => "java/lang/String"
diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build
index 2a09167..6ee341b 100644
--- a/test/003-omnibus-opcodes/build
+++ b/test/003-omnibus-opcodes/build
@@ -29,5 +29,4 @@
--boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
--oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
--host-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build
index 10c1c06..88201a2 100644
--- a/test/023-many-interfaces/build
+++ b/test/023-many-interfaces/build
@@ -31,5 +31,4 @@
--boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
--oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
--host-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/056-const-string-jumbo/build b/test/056-const-string-jumbo/build
index 22c9646..fbd4116 100644
--- a/test/056-const-string-jumbo/build
+++ b/test/056-const-string-jumbo/build
@@ -50,5 +50,4 @@
--boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
--oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
--host-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/085-old-style-inner-class/build b/test/085-old-style-inner-class/build
index db6a5dd..a08c98b 100644
--- a/test/085-old-style-inner-class/build
+++ b/test/085-old-style-inner-class/build
@@ -32,5 +32,4 @@
--boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
--oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
--host-prefix=${ANDROID_PRODUCT_OUT}
diff --git a/test/etc/default-build b/test/etc/default-build
index a2e9066..c3cdd79 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -32,7 +32,6 @@
--boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.jar \
--oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.oat \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME.art \
--host-prefix=${ANDROID_PRODUCT_OUT}
if [ -r src-ex ]; then
@@ -52,6 +51,5 @@
--boot-image=${ANDROID_PRODUCT_OUT}/system/framework/core.art \
--dex-file=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME-ex.jar \
--oat=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME-ex.oat \
- --image=${ANDROID_PRODUCT_OUT}/system/framework/$TEST_NAME-ex.art \
--host-prefix=${ANDROID_PRODUCT_OUT}
fi
diff --git a/test/etc/push-and-run-test-jar b/test/etc/push-and-run-test-jar
index 8bbf8d8..79b0605 100755
--- a/test/etc/push-and-run-test-jar
+++ b/test/etc/push-and-run-test-jar
@@ -136,7 +136,7 @@
else
cmdline="cd /data; oatexecd \
-Ximage:/system/framework/core.art \
- -Ximage:/system/framework/$TEST_NAME.art \
+ -cp /system/framework/$TEST_NAME.jar \
Main"
#cmdline="cd /data; dalvikvm $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG \
# $GC_OPTS -cp test.jar -Xint:${INTERP} -ea Main"