Working dex2oat and oatexec
adb shell dex2oatd --dex-file=/system/framework/core.jar --image=/system/framework/boot.oat --base=0x50000000 "'--method=Ljava/lang/System;logI(Ljava/lang/String;)V'" "'--method=Ljava/lang/System;log(CLjava/lang/String;Ljava/lang/Throwable;)V'"
adb shell dex2oatd --boot-dex-file=/system/framework/core.jar --boot=/system/framework/boot.oat --dex-file=/system/framework/art-test-dex-HelloWorld.jar --image=/system/framework/art-test-dex-HelloWorld.oat
adb shell oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootimage:/system/framework/boot.oat -classpath /system/framework/art-test-dex-HelloWorld.jar -Ximage:/system/framework/art-test-dex-HelloWorld.oat HelloWorld
09-05 17:58:18.912 2385 2385 I System : Hello, world!
Change-Id: I53e534068584f0c3a837313e4d517a0e4a7154fc
diff --git a/src/check_jni.cc b/src/check_jni.cc
index dc58565..0486284 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -447,7 +447,7 @@
ScopedJniThreadState ts(mEnv);
const Method* m = DecodeMethod(ts, mid);
if (*expectedType != m->GetShorty()[0]) {
- LOG(ERROR) << "JNI ERROR: expected return type '%s' calling " << PrettyMethod(m);
+ LOG(ERROR) << "JNI ERROR: expected return type '" << *expectedType << "' calling " << PrettyMethod(m);
JniAbort();
} else if (isStatic && !m->IsStatic()) {
if (isStatic) {
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 7cd320e..211b87d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -56,12 +56,14 @@
};
ClassLinker* ClassLinker::Create(const std::vector<const DexFile*>& boot_class_path,
- InternTable* intern_table, Space* space) {
+ const std::vector<const DexFile*>& class_path,
+ InternTable* intern_table, Space* space) {
+ CHECK_NE(boot_class_path.size(), 0U);
UniquePtr<ClassLinker> class_linker(new ClassLinker(intern_table));
if (space == NULL) {
- class_linker->Init(boot_class_path);
+ class_linker->Init(boot_class_path, class_path);
} else {
- class_linker->Init(boot_class_path, space);
+ class_linker->Init(boot_class_path, class_path, space);
}
// TODO: check for failure during initialization
return class_linker.release();
@@ -76,7 +78,8 @@
intern_table_(intern_table) {
}
-void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path) {
+void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path,
+ const std::vector<const DexFile*>& class_path) {
CHECK(!init_done_);
// java_lang_Class comes first, its needed for AllocClass
@@ -160,13 +163,18 @@
// now that these are registered, we can use AllocClass() and AllocObjectArray
- // setup boot_class_path_ now that we can use AllocObjectArray to
- // create DexCache instances
+ // setup boot_class_path_ and register class_path now that we can
+ // use AllocObjectArray to create DexCache instances
for (size_t i = 0; i != boot_class_path.size(); ++i) {
const DexFile* dex_file = boot_class_path[i];
CHECK(dex_file != NULL);
AppendToBootClassPath(*dex_file);
}
+ for (size_t i = 0; i != class_path.size(); ++i) {
+ const DexFile* dex_file = class_path[i];
+ CHECK(dex_file != NULL);
+ RegisterDexFile(*dex_file);
+ }
// Field and Method are necessary so that FindClass can link members
Class* java_lang_reflect_Field = AllocClass(java_lang_Class, sizeof(FieldClass));
@@ -366,16 +374,13 @@
typedef std::tr1::unordered_map<std::string, ClassRoot> Table;
Table descriptor_to_class_root;
- struct DexCacheHash {
- size_t operator()(art::DexCache* const& obj) const {
- return reinterpret_cast<size_t>(&obj);
- }
- };
typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set;
Set dex_caches;
};
-void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path, Space* space) {
+void ClassLinker::Init(const std::vector<const DexFile*>& boot_class_path,
+ const std::vector<const DexFile*>& class_path,
+ Space* space) {
CHECK(!init_done_);
HeapBitmap* heap_bitmap = Heap::GetLiveBits();
@@ -400,6 +405,7 @@
}
// reinit intern table
+ // TODO: remove interned_array, make all strings in image interned (and remove space argument)
ObjectArray<Object>* interned_array = space->GetImageHeader().GetInternedArray();
for (int32_t i = 0; i < interned_array->GetLength(); i++) {
String* string = interned_array->Get(i)->AsString();
@@ -418,14 +424,27 @@
std::string location = dex_cache->GetLocation()->ToModifiedUtf8();
location_to_dex_cache[location] = dex_cache;
}
+ CHECK_EQ(boot_class_path.size() + class_path.size(),
+ location_to_dex_cache.size());
// reinit boot_class_path with DexFile arguments and found DexCaches
for (size_t i = 0; i != boot_class_path.size(); ++i) {
const DexFile* dex_file = boot_class_path[i];
CHECK(dex_file != NULL);
DexCache* dex_cache = location_to_dex_cache[dex_file->GetLocation()];
+ CHECK(dex_cache != NULL) << dex_file->GetLocation();
AppendToBootClassPath(*dex_file, dex_cache);
}
+
+ // register class_path with DexFile arguments and found DexCaches
+ for (size_t i = 0; i != class_path.size(); ++i) {
+ const DexFile* dex_file = class_path[i];
+ CHECK(dex_file != NULL);
+ DexCache* dex_cache = location_to_dex_cache[dex_file->GetLocation()];
+ CHECK(dex_cache != NULL) << dex_file->GetLocation();
+ RegisterDexFile(*dex_file, dex_cache);
+ }
+
String::SetClass(GetClassRoot(kJavaLangString));
Field::SetClass(GetClassRoot(kJavaLangReflectField));
Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
@@ -452,10 +471,15 @@
return;
}
Class* klass = obj->AsClass();
- CHECK(klass->GetClassLoader() == NULL);
+ // 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
state->class_linker->InsertClass(descriptor, klass);
@@ -900,7 +924,7 @@
}
void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, DexCache* dex_cache) {
- CHECK(dex_cache != NULL);
+ CHECK(dex_cache != NULL) << dex_file.GetLocation();
boot_class_path_.push_back(&dex_file);
RegisterDexFile(dex_file, dex_cache);
}
@@ -910,7 +934,8 @@
}
void ClassLinker::RegisterDexFile(const DexFile& dex_file, DexCache* dex_cache) {
- CHECK(dex_cache != NULL);
+ 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);
}
@@ -921,7 +946,7 @@
return *dex_files_[i];
}
}
- CHECK(false) << "Could not find DexFile";
+ CHECK(false) << "Failed to find DexFile for DexCache " << dex_cache->GetLocation()->ToModifiedUtf8();
return *dex_files_[-1];
}
@@ -931,7 +956,7 @@
return dex_caches_[i];
}
}
- CHECK(false) << "Could not find DexCache";
+ CHECK(false) << "Failed to find DexCache for DexFile " << dex_file.GetLocation();
return NULL;
}
@@ -1544,7 +1569,7 @@
return false;
}
if (!klass->CanAccess(super)) {
- LG << "Superclass " << super->GetDescriptor()->ToModifiedUtf8() << " is inaccessible"; // TODO: IllegalAccessError
+ LG << "Superclass " << super->GetDescriptor()->ToModifiedUtf8() << " is inaccessible"; // TODO: IllegalAccessError
return false;
}
#ifndef NDEBUG
diff --git a/src/class_linker.h b/src/class_linker.h
index f63ab3c..4f4ffc7 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -26,7 +26,8 @@
public:
// Initializes the class linker using DexFile and an optional boot Space.
static ClassLinker* Create(const std::vector<const DexFile*>& boot_class_path,
- InternTable* intern_table, Space* boot_space);
+ const std::vector<const DexFile*>& class_path,
+ InternTable* intern_table, Space* boot_space);
~ClassLinker();
@@ -149,10 +150,13 @@
ClassLinker(InternTable*);
// Initialize class linker from DexFile instances.
- void Init(const std::vector<const DexFile*>& boot_class_path_);
+ void Init(const std::vector<const DexFile*>& boot_class_path_,
+ const std::vector<const DexFile*>& class_path_);
// Initialize class linker from pre-initialized space.
- void Init(const std::vector<const DexFile*>& boot_class_path_, Space* space);
+ void Init(const std::vector<const DexFile*>& boot_class_path_,
+ const std::vector<const DexFile*>& class_path_,
+ Space* space);
static void InitCallback(Object* obj, void *arg);
struct InitCallbackState;
diff --git a/src/class_loader.cc b/src/class_loader.cc
index 9769136..8f8e829 100644
--- a/src/class_loader.cc
+++ b/src/class_loader.cc
@@ -18,6 +18,7 @@
Class* PathClassLoader::dalvik_system_PathClassLoader_ = NULL;
const PathClassLoader* PathClassLoader::Alloc(std::vector<const DexFile*> dex_files) {
+ DCHECK(dalvik_system_PathClassLoader_ != NULL);
PathClassLoader* p = down_cast<PathClassLoader*>(dalvik_system_PathClassLoader_->AllocObject());
p->SetClassPath(dex_files);
return p;
diff --git a/src/common_test.h b/src/common_test.h
index 7916640..98d9127 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -85,7 +85,8 @@
setenv("ANDROID_ROOT", root.c_str(), 1);
}
- android_data_ = (is_host_ ? "/tmp/art-data-XXXXXX" : "/mnt/sdcard/art-data-XXXXXX");
+ // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of art-cache
+ android_data_ = (is_host_ ? "/tmp/art-data-XXXXXX" : "/data/art-cache/art-data-XXXXXX");
if (mkdtemp(&android_data_[0]) == NULL) {
PLOG(FATAL) << "mkdtemp(\"" << &android_data_[0] << "\") failed";
}
@@ -99,8 +100,12 @@
boot_class_path_.push_back(java_lang_dex_file_.get());
- runtime_.reset(Runtime::Create(boot_class_path_));
+ Runtime::Options options;
+ options.push_back(std::make_pair("bootclasspath", &boot_class_path_));
+ options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL)));
+ runtime_.reset(Runtime::Create(options, false));
ASSERT_TRUE(runtime_.get() != NULL);
+ runtime_->Start();
class_linker_ = runtime_->GetClassLinker();
Heap::VerifyHeap(); // Check for heap corruption before the test
@@ -167,7 +172,7 @@
return i;
}
}
- CHECK(false) << "Could not find type index for " << descriptor;
+ CHECK(false) << "Failed to find type index for " << descriptor;
return 0;
}
@@ -181,11 +186,11 @@
return i;
}
}
- CHECK(false) << "Could not find field index for " << class_descriptor << " " << field_name;
+ CHECK(false) << "Failed to find field index for " << class_descriptor << " " << field_name;
return 0;
}
- const PathClassLoader* AllocPathClassLoader(const DexFile* dex_file) {
+ const ClassLoader* AllocPathClassLoader(const DexFile* dex_file) {
CHECK(dex_file != NULL);
class_linker_->RegisterDexFile(*dex_file);
std::vector<const DexFile*> dex_files;
@@ -204,7 +209,7 @@
filename += name;
filename += ".jar";
const DexFile* dex_file = DexFile::OpenZip(filename);
- CHECK(dex_file != NULL) << "Could not open " << filename;
+ CHECK(dex_file != NULL) << "Failed to open " << filename;
return dex_file;
}
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
new file mode 100644
index 0000000..4d071a7
--- /dev/null
+++ b/src/dex2oat.cc
@@ -0,0 +1,224 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+#include <vector>
+
+#include "class_linker.h"
+#include "class_loader.h"
+#include "compiler.h"
+#include "image_writer.h"
+#include "runtime.h"
+#include "stringpiece.h"
+
+namespace art {
+
+static void usage() {
+ fprintf(stderr,
+ "Usage: dex2oat [options]...\n"
+ "\n");
+ fprintf(stderr,
+ " --dex-file=<dex-file>: specifies a .dex files to compile. At least one .dex\n"
+ " but more than one may be included. \n"
+ " Example: --dex-file=/system/framework/core.jar\n"
+ "\n");
+ fprintf(stderr,
+ " --image=<file>: specifies the required output image filename.\n"
+ " Example: --image=/system/framework/boot.oat\n"
+ "\n");
+ fprintf(stderr,
+ " --base=<hex-address>: specifies the base address when creating a boot image.\n"
+ " Example: --base=0x50000000\n"
+ "\n");
+ fprintf(stderr,
+ " --boot=<oat-file>: provide the oat file for the boot class path.\n"
+ " Example: --boot=/system/framework/boot.oat\n"
+ "\n");
+ // TODO: remove this by making boot image contain boot DexFile information?
+ fprintf(stderr,
+ " --boot-dex-file=<dex-file>: specifies a .dex file that is part of the boot\n"
+ " image specified with --boot. \n"
+ " Example: --boot-dex-file=/system/framework/core.jar\n"
+ "\n");
+ fprintf(stderr,
+ " --method may be used to limit compilation to a subset of methods.\n"
+ " Example: --method=Ljava/lang/Object;<init>()V\n"
+ "\n");
+ exit(EXIT_FAILURE);
+}
+
+static void OpenDexFiles(std::vector<const char*>& dex_filenames,
+ std::vector<const DexFile*>& dex_files) {
+ for (size_t i = 0; i < dex_filenames.size(); i++) {
+ const char* dex_filename = dex_filenames[i];
+ const DexFile* dex_file = DexFile::Open(dex_filename);
+ if (dex_file == NULL) {
+ fprintf(stderr, "could not open .dex from file %s\n", dex_filename);
+ exit(EXIT_FAILURE);
+ }
+ dex_files.push_back(dex_file);
+ }
+}
+
+int dex2oat(int argc, char** argv) {
+ // Skip over argv[0].
+ argv++;
+ argc--;
+
+ if (argc == 0) {
+ fprintf(stderr, "no arguments specified\n");
+ usage();
+ }
+
+ std::vector<const char*> dex_filenames;
+ std::vector<const char*> method_names;
+ const char* image_filename = NULL;
+ std::string boot_image_option;
+ std::vector<const char*> boot_dex_filenames;
+ uintptr_t image_base = 0;
+ for (int i = 0; i < argc; i++) {
+ const StringPiece option(argv[i]);
+ if (option.starts_with("--dex-file=")) {
+ dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
+ } else if (option.starts_with("--method=")) {
+ method_names.push_back(option.substr(strlen("--method=")).data());
+ } else if (option.starts_with("--image=")) {
+ image_filename = option.substr(strlen("--image=")).data();
+ } else if (option.starts_with("--base=")) {
+ const char* image_base_str = option.substr(strlen("--base=")).data();
+ char* end;
+ image_base = strtoul(image_base_str, &end, 16);
+ if (end == image_base_str || *end != '\0') {
+ fprintf(stderr, "could not parse hexadecimal value for option %s\n", option.data());
+ usage();
+ }
+ } else if (option.starts_with("--boot=")) {
+ const char* boot_image_filename = option.substr(strlen("--boot=")).data();
+ boot_image_option.clear();
+ boot_image_option += "-Xbootimage:";
+ boot_image_option += boot_image_filename;
+ } else if (option.starts_with("--boot-dex-file=")) {
+ boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data());
+ } else {
+ fprintf(stderr, "unknown argument %s\n", option.data());
+ usage();
+ }
+ }
+
+ if (image_filename == NULL) {
+ fprintf(stderr, "--image file name not specified\n");
+ return EXIT_FAILURE;
+ }
+
+ if (boot_image_option.empty()) {
+ if (image_base == 0) {
+ fprintf(stderr, "non-zero --base not specified\n");
+ return EXIT_FAILURE;
+ }
+ } else {
+ if (boot_dex_filenames.empty()) {
+ fprintf(stderr, "no --boot-dex-file specified with --boot\n");
+ return EXIT_FAILURE;
+ }
+ }
+
+ std::vector<const DexFile*> dex_files;
+ OpenDexFiles(dex_filenames, dex_files);
+
+ std::vector<const DexFile*> boot_dex_files;
+ OpenDexFiles(boot_dex_filenames, boot_dex_files);
+
+ Runtime::Options options;
+ if (boot_image_option.empty()) {
+ options.push_back(std::make_pair("bootclasspath", &dex_files));
+ } else {
+ options.push_back(std::make_pair("bootclasspath", &boot_dex_files));
+ options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
+ }
+ UniquePtr<Runtime> runtime(Runtime::Create(options, false));
+ if (runtime.get() == NULL) {
+ fprintf(stderr, "could not create runtime\n");
+ return EXIT_FAILURE;
+ }
+ ClassLinker* class_linker = runtime->GetClassLinker();
+
+ // If we have an existing boot image, position new space after it
+ if (!boot_image_option.empty()) {
+ Space* boot_space = Heap::GetBootSpace();
+ CHECK(boot_space != NULL);
+ image_base = RoundUp(reinterpret_cast<uintptr_t>(boot_space->GetLimit()), kPageSize);
+ }
+
+ // ClassLoader creation needs to come after Runtime::Create
+ const ClassLoader* class_loader;
+ if (boot_image_option.empty()) {
+ class_loader = NULL;
+ } else {
+ for (size_t i = 0; i < dex_files.size(); i++) {
+ class_linker->RegisterDexFile(*dex_files[i]);
+ }
+ class_loader = PathClassLoader::Alloc(dex_files);
+ }
+
+ Compiler compiler;
+ if (method_names.empty()) {
+ compiler.CompileAll(class_loader);
+ } else {
+ for (size_t i = 0; i < method_names.size(); i++) {
+ // names are actually class_descriptor + name + signature.
+ // example: Ljava/lang/Object;<init>()V
+ StringPiece method_name = method_names[i];
+ size_t end_of_class_descriptor = method_name.find(';');
+ if (end_of_class_descriptor == method_name.npos) {
+ fprintf(stderr, "could not find class descriptor in method %s\n", method_name.data());
+ return EXIT_FAILURE;
+ }
+ end_of_class_descriptor++; // want to include ;
+ std::string class_descriptor = method_name.substr(0, end_of_class_descriptor).ToString();
+ size_t end_of_name = method_name.find('(', end_of_class_descriptor);
+ if (end_of_name == method_name.npos) {
+ fprintf(stderr, "could not find start of method signature in method %s\n", method_name.data());
+ return EXIT_FAILURE;
+ }
+ std::string name = method_name.substr(end_of_class_descriptor,
+ end_of_name - end_of_class_descriptor).ToString();
+ std::string signature = method_name.substr(end_of_name).ToString();
+
+ Class* klass = class_linker->FindClass(class_descriptor, class_loader);
+ if (klass == NULL) {
+ fprintf(stderr, "could not find class for descriptor %s in method %s\n",
+ class_descriptor.c_str(), method_name.data());
+ return EXIT_FAILURE;
+ }
+ Method* method = klass->FindDirectMethod(name, signature);
+ if (method == NULL) {
+ method = klass->FindVirtualMethod(name, signature);
+ }
+ if (method == NULL) {
+ fprintf(stderr, "could not find method %s with signature %s in class %s for method argument %s\n",
+ name.c_str(),
+ signature.c_str(),
+ class_descriptor.c_str(),
+ method_name.data());
+ return EXIT_FAILURE;
+ }
+ compiler.CompileOne(method);
+ }
+ }
+
+ ImageWriter writer;
+ if (!writer.Write(image_filename, image_base)) {
+ fprintf(stderr, "could not write image %s\n", image_filename);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+} // namespace art
+
+int main(int argc, char** argv) {
+ return art::dex2oat(argc, argv);
+}
diff --git a/src/dex_cache.h b/src/dex_cache.h
index 804f680..22dae24 100644
--- a/src/dex_cache.h
+++ b/src/dex_cache.h
@@ -12,31 +12,32 @@
class Class;
class Field;
+class ImageWriter;
class Method;
class String;
union JValue;
class CodeAndDirectMethods : public IntArray {
public:
- Method* GetResolvedCode(uint32_t method_idx) const {
- return reinterpret_cast<Method*>(Get(method_idx * kMax + kCode));
+ void* GetResolvedCode(uint32_t method_idx) const {
+ return reinterpret_cast<byte*>(Get(CodeIndex(method_idx)));
}
- void* GetResolvedMethod(uint32_t method_idx) const {
- return reinterpret_cast<byte*>(Get(method_idx * kMax + kMethod));
+ Method* GetResolvedMethod(uint32_t method_idx) const {
+ return reinterpret_cast<Method*>(Get(MethodIndex(method_idx)));
}
void SetResolvedDirectMethodTrampoline(uint32_t method_idx) {
UNIMPLEMENTED(WARNING) << "need to install a trampoline to resolve the method_idx at runtime";
- Set(method_idx * kMax + kCode, 0xffffffff);
- Set(method_idx * kMax + kMethod, method_idx);
+ Set(CodeIndex(method_idx), 0xffffffff);
+ Set(MethodIndex(method_idx), method_idx);
}
void SetResolvedDirectMethod(uint32_t method_idx, Method* method) {
CHECK(method != NULL);
CHECK(method->IsDirect());
// CHECK(method->GetCode() != NULL); // TODO enable when all code is compiling
- Set(method_idx * kMax + kCode, reinterpret_cast<int32_t>(method->GetCode()));
- Set(method_idx * kMax + kMethod, reinterpret_cast<int32_t>(method));
+ Set(CodeIndex(method_idx), reinterpret_cast<int32_t>(method->GetCode()));
+ Set(MethodIndex(method_idx), reinterpret_cast<int32_t>(method));
}
static size_t LengthAsArray(size_t elements) {
@@ -45,14 +46,12 @@
// Offset of resolved method entry from start of code_and_direct_methods_
static size_t MethodOffsetInBytes(uint32_t method_idx) {
- return ((method_idx * kMax + kMethod) * sizeof(ElementType) +
- Array::DataOffset().Int32Value());
+ return (MethodIndex(method_idx) * sizeof(ElementType) + Array::DataOffset().Int32Value());
}
// Offset of resolved method's code_ from start of code_and_direct_methods_
static size_t CodeOffsetInBytes(uint32_t method_idx) {
- return ((method_idx * kMax + kCode) * sizeof(ElementType) +
- Array::DataOffset().Int32Value());
+ return (CodeIndex(method_idx) * sizeof(ElementType) + Array::DataOffset().Int32Value());
}
size_t NumCodeAndDirectMethods() const {
@@ -66,6 +65,17 @@
kMax = 2,
};
+ static size_t CodeIndex(uint32_t method_idx) {
+ return method_idx * kMax + kCode;
+ }
+ static size_t MethodIndex(uint32_t method_idx) {
+ return method_idx * kMax + kMethod;
+ }
+
+ // grant friend status to ImageWriter fixup code that needs to know internal layout
+ friend class ImageWriter;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CodeAndDirectMethods);
};
class DexCache : public ObjectArray<Object> {
@@ -197,6 +207,12 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(DexCache);
};
+struct DexCacheHash {
+ size_t operator()(art::DexCache* const& obj) const {
+ return reinterpret_cast<size_t>(&obj);
+ }
+};
+
} // namespace art
#endif // ART_SRC_DEX_CACHE_H_
diff --git a/src/dex_file.cc b/src/dex_file.cc
index ad0b3b9..b982291 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -42,6 +42,19 @@
reinterpret_cast<const DexFile::ClassDef*>(NULL));
}
+const DexFile* DexFile::Open(const std::string& filename) {
+ if (filename.size() < 4) {
+ LOG(WARNING) << "Ignoring short classpath entry '" << filename << "'";
+ return NULL;
+ }
+ std::string suffix(filename.substr(filename.size() - 4));
+ if (suffix == ".zip" || suffix == ".jar" || suffix == ".apk") {
+ return DexFile::OpenZip(filename);
+ } else {
+ return DexFile::OpenFile(filename);
+ }
+}
+
DexFile::Closer::~Closer() {}
DexFile::MmapCloser::MmapCloser(void* addr, size_t length) : addr_(addr), length_(length) {
@@ -89,7 +102,7 @@
static LockedFd* CreateAndLock(std::string& name, mode_t mode) {
int fd = open(name.c_str(), O_CREAT | O_RDWR, mode);
if (fd == -1) {
- PLOG(ERROR) << "Can't open file '" << name << "'";
+ PLOG(ERROR) << "Failed to open file '" << name << "'";
return NULL;
}
fchmod(fd, mode);
@@ -101,7 +114,7 @@
result = flock(fd, LOCK_EX);
}
if (result == -1 ) {
- PLOG(ERROR) << "Can't lock file '" << name << "'";
+ PLOG(ERROR) << "Failed to lock file '" << name << "'";
close(fd);
return NULL;
}
@@ -149,6 +162,7 @@
size_t found = adjacent_dex_filename.find_last_of(".");
if (found == std::string::npos) {
LOG(WARNING) << "No . in filename" << filename;
+ return NULL;
}
adjacent_dex_filename.replace(adjacent_dex_filename.begin() + found,
adjacent_dex_filename.end(),
@@ -168,7 +182,7 @@
char resolved[PATH_MAX];
char* absolute_path = realpath(filename.c_str(), resolved);
if (absolute_path == NULL) {
- LOG(WARNING) << "Could not create absolute path for " << filename
+ LOG(WARNING) << "Failed to create absolute path for " << filename
<< " when looking for classes.dex";
return NULL;
}
@@ -180,7 +194,7 @@
const char* data_root = getenv("ANDROID_DATA");
if (data_root == NULL) {
- data_root = "/data";
+ data_root = "/data";
}
std::string cache_path_tmp = StringPrintf("%s/art-cache/%s", data_root, cache_file.c_str());
@@ -188,12 +202,12 @@
UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(filename));
if (zip_archive.get() == NULL) {
- LOG(WARNING) << "Could not open " << filename << " when looking for classes.dex";
+ LOG(WARNING) << "Failed to open " << filename << " when looking for classes.dex";
return NULL;
}
UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex));
if (zip_entry.get() == NULL) {
- LOG(WARNING) << "Could not find classes.dex within " << filename;
+ LOG(WARNING) << "Failed to find classes.dex within " << filename;
return NULL;
}
@@ -235,7 +249,7 @@
struct stat fd_stat;
int fd_stat_result = fstat(fd->GetFd(), &fd_stat);
if (fd_stat_result == -1) {
- PLOG(ERROR) << "Can't stat open file '" << cache_path_tmp << "'";
+ PLOG(ERROR) << "Failed to stat open file '" << cache_path_tmp << "'";
return NULL;
}
struct stat file_stat;
@@ -287,7 +301,7 @@
}
int rename_result = rename(cache_path_tmp.c_str(), cache_path.c_str());
if (rename_result == -1) {
- PLOG(ERROR) << "Can't install dex cache file '" << cache_path << "'"
+ PLOG(ERROR) << "Failed to install dex cache file '" << cache_path << "'"
<< " from '" << cache_path_tmp << "'";
unlink(cache_path.c_str());
}
diff --git a/src/dex_file.h b/src/dex_file.h
index 73e6954..98e79a7 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -316,6 +316,9 @@
static ClassPathEntry FindInClassPath(const StringPiece& descriptor,
const ClassPath& class_path);
+ // Opens .dex file, guessing the format based on file extension
+ static const DexFile* Open(const std::string& filename);
+
// Opens a .dex file from the file system.
static const DexFile* OpenFile(const std::string& filename);
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 439e7ed..5283697 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -68,7 +68,7 @@
dex_.reset(OpenDexFileBase64(kMyClassExceptionHandleDex, "kMyClassExceptionHandleDex"));
ASSERT_TRUE(dex_.get() != NULL);
- const PathClassLoader* class_loader = AllocPathClassLoader(dex_.get());
+ const ClassLoader* class_loader = AllocPathClassLoader(dex_.get());
ASSERT_TRUE(class_loader != NULL);
my_klass_ = class_linker_->FindClass("Ljava/lang/MyClass;", class_loader);
ASSERT_TRUE(my_klass_ != NULL);
diff --git a/src/heap.cc b/src/heap.cc
index be3d154..86d19a8 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -37,7 +37,9 @@
MemberOffset Heap::reference_pendingNext_offset_ = MemberOffset(0);
MemberOffset Heap::finalizer_reference_zombie_offset_ = MemberOffset(0);
-bool Heap::Init(size_t initial_size, size_t maximum_size, const char* boot_image_file_name) {
+bool Heap::Init(size_t initial_size, size_t maximum_size,
+ const char* boot_image_file_name,
+ std::vector<const char*>& image_file_names) {
Space* boot_space;
byte* requested_base;
if (boot_image_file_name == NULL) {
@@ -46,14 +48,28 @@
} else {
boot_space = Space::Create(boot_image_file_name);
if (boot_space == NULL) {
+ LOG(WARNING) << "Failed to create space from " << boot_image_file_name;
return false;
}
spaces_.push_back(boot_space);
requested_base = boot_space->GetBase() + RoundUp(boot_space->Size(), kPageSize);
}
+ std::vector<Space*> image_spaces;
+ for (size_t i = 0; i < image_file_names.size(); i++) {
+ Space* space = Space::Create(image_file_names[i]);
+ if (space == NULL) {
+ LOG(WARNING) << "Failed to create space from " << image_file_names[i];
+ return false;
+ }
+ image_spaces.push_back(space);
+ spaces_.push_back(space);
+ requested_base = space->GetBase() + RoundUp(space->Size(), kPageSize);
+ }
+
Space* space = Space::Create(initial_size, maximum_size, requested_base);
if (space == NULL) {
+ LOG(WARNING) << "Failed to create alloc space";
return false;
}
@@ -68,12 +84,14 @@
// Allocate the initial live bitmap.
UniquePtr<HeapBitmap> live_bitmap(HeapBitmap::Create(base, num_bytes));
if (live_bitmap.get() == NULL) {
+ LOG(WARNING) << "Failed to create live bitmap";
return false;
}
// Allocate the initial mark bitmap.
UniquePtr<HeapBitmap> mark_bitmap(HeapBitmap::Create(base, num_bytes));
if (mark_bitmap.get() == NULL) {
+ LOG(WARNING) << "Failed to create mark bitmap";
return false;
}
@@ -93,6 +111,9 @@
boot_space_ = boot_space;
RecordImageAllocations(boot_space);
}
+ for (size_t i = 0; i < image_spaces.size(); i++) {
+ RecordImageAllocations(image_spaces[i]);
+ }
return true;
}
diff --git a/src/heap.h b/src/heap.h
index 30133b7..4922207 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -27,9 +27,12 @@
typedef void (RootVisitor)(const Object* root, void* arg);
- // Create a heap with the requested sizes. optional boot image may
+ // Create a heap with the requested sizes. The optional boot image may
// be NULL, otherwise it is an image filename created by ImageWriter.
- static bool Init(size_t starting_size, size_t maximum_size, const char* boot_image_file_name);
+ // image_file_names specifies application images to load.
+ static bool Init(size_t starting_size, size_t maximum_size,
+ const char* boot_image_file_name,
+ std::vector<const char*>& image_file_names);
static void Destroy();
@@ -149,6 +152,7 @@
static std::vector<Space*> spaces_;
// Space loaded from an image
+ // TODO: remove after intern_addr is removed
static Space* boot_space_;
// default Space for allocations
diff --git a/src/image.cc b/src/image.cc
index a41bf5ba..5bf7b10 100644
--- a/src/image.cc
+++ b/src/image.cc
@@ -4,7 +4,7 @@
namespace art {
-const byte ImageHeader::kImageMagic[] = { 'i', 'm', 'g', '\n' };
+const byte ImageHeader::kImageMagic[] = { 'o', 'a', 't', '\n' };
const byte ImageHeader::kImageVersion[] = { '0', '0', '1', '\0' };
} // namespace art
diff --git a/src/image.h b/src/image.h
index 94824d7..00f72ba 100644
--- a/src/image.h
+++ b/src/image.h
@@ -50,6 +50,7 @@
uint32_t base_addr_;
// absolute address of an Object[] of Strings to InternTable::RegisterStrong.
+ // TODO: remove after interning all Strings in image
uint32_t intern_addr_;
};
diff --git a/src/image_test.cc b/src/image_test.cc
index db09021..f07588a 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -25,15 +25,10 @@
}
// 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());
- Space* space = spaces[0];
-
ImageWriter writer;
ScratchFile tmp;
- const int image_base = 0x50000000;
- bool success = writer.Write(space, tmp.GetFilename(), reinterpret_cast<byte*>(image_base));
+ const uintptr_t image_base = 0x50000000;
+ bool success = writer.Write(tmp.GetFilename(), image_base);
ASSERT_TRUE(success);
{
@@ -42,6 +37,10 @@
ImageHeader image_header;
file->ReadFully(&image_header, sizeof(image_header));
ASSERT_TRUE(image_header.IsValid());
+
+ ASSERT_EQ(1U, Heap::GetSpaces().size());
+ Space* space = Heap::GetSpaces()[0];
+ ASSERT_TRUE(space != NULL);
ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->Length()));
}
@@ -69,7 +68,7 @@
class_linker_ = runtime_->GetClassLinker();
ASSERT_EQ(2U, Heap::GetSpaces().size());
- Space* boot_space = Heap::GetSpaces()[0];
+ Space* boot_space = Heap::GetBootSpace();
ASSERT_TRUE(boot_space != NULL);
// enable to display maps to debug boot_base and boot_limit checking problems below
@@ -87,6 +86,7 @@
EXPECT_TRUE(klass != NULL) << descriptor;
EXPECT_LT(boot_base, reinterpret_cast<byte*>(klass)) << descriptor;
EXPECT_LT(reinterpret_cast<byte*>(klass), boot_limit) << descriptor;
+ EXPECT_TRUE(klass->GetMonitor() == NULL); // address should have been removed from monitor
}
}
diff --git a/src/image_writer.cc b/src/image_writer.cc
index e0e77c7..a49b261 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -23,9 +23,16 @@
namespace art {
-bool ImageWriter::Write(Space* space, const char* filename, byte* image_base) {
- image_base_ = image_base;
- if (!Init(space)) {
+bool ImageWriter::Write(const char* filename, uintptr_t image_base) {
+ CHECK_NE(image_base, 0U);
+ image_base_ = reinterpret_cast<byte*>(image_base);
+
+ const std::vector<Space*>& spaces = Heap::GetSpaces();
+ // currently just write the last space, assuming it is the space that was being used for allocation
+ CHECK_GE(spaces.size(), 1U);
+ source_space_ = spaces[spaces.size()-1];
+
+ if (!Init()) {
return false;
}
CalculateNewObjectOffsets();
@@ -38,8 +45,8 @@
return file->WriteFully(image_->GetAddress(), image_top_);
}
-bool ImageWriter::Init(Space* space) {
- size_t size = space->Size();
+bool ImageWriter::Init() {
+ size_t size = source_space_->Size();
int prot = PROT_READ | PROT_WRITE;
size_t length = RoundUp(size, kPageSize);
image_.reset(MemMap::Map(length, prot));
@@ -88,9 +95,23 @@
DCHECK(obj != NULL);
DCHECK(arg != NULL);
ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
+ if (!image_writer->InSourceSpace(obj)) {
+ return;
+ }
image_writer->SetImageOffset(obj, image_writer->image_top_);
image_writer->image_top_ += RoundUp(obj->SizeOf(), 8); // 64-bit alignment
DCHECK_LT(image_writer->image_top_, image_writer->image_->GetLength());
+
+ // sniff out the DexCaches on this pass for use on the next pass
+ if (obj->IsClass()) {
+ Class* klass = obj->AsClass();
+ DexCache* dex_cache = klass->GetDexCache();
+ if (dex_cache != NULL) {
+ image_writer->dex_caches_.insert(dex_cache);
+ } else {
+ DCHECK(klass->IsArrayClass() || klass->IsPrimitive());
+ }
+ }
}
void ImageWriter::CalculateNewObjectOffsets() {
@@ -104,7 +125,7 @@
// know where interned_array is going to end up
image_top_ += RoundUp(sizeof(ImageHeader), 8); // 64-bit-alignment
- heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this);
+ heap_bitmap->Walk(CalculateNewObjectOffsetsCallback, this); // TODO: add Space-limited Walk
DCHECK_LT(image_top_, image_->GetLength());
// return to write header at start of image with future location of interned_array
@@ -120,7 +141,8 @@
DCHECK(heap_bitmap != NULL);
// TODO: heap validation can't handle this fix up pass
Heap::DisableObjectValidation();
- heap_bitmap->Walk(CopyAndFixupObjectsCallback, this);
+ heap_bitmap->Walk(CopyAndFixupObjectsCallback, this); // TODO: add Space-limited Walk
+ FixupDexCaches();
}
void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void *arg) {
@@ -128,7 +150,11 @@
DCHECK(arg != NULL);
const Object* obj = object;
ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
+ if (!image_writer->InSourceSpace(object)) {
+ return;
+ }
+ // see GetLocalAddress for similar computation
size_t offset = image_writer->GetImageOffset(obj);
byte* dst = image_writer->image_->GetAddress() + offset;
const byte* src = reinterpret_cast<const byte*>(obj);
@@ -136,6 +162,7 @@
DCHECK_LT(offset + n, image_writer->image_->GetLength());
memcpy(dst, src, n);
Object* copy = reinterpret_cast<Object*>(dst);
+ ResetImageOffset(copy);
image_writer->FixupObject(obj, copy);
}
@@ -178,20 +205,36 @@
FixupStaticFields(orig, copy);
}
+const void* FixupCode(const ByteArray* copy_code_array, const void* orig_code) {
+ // TODO: change to DCHECK when all code compiling
+ if (copy_code_array == NULL) {
+ return NULL;
+ }
+ const void* copy_code = copy_code_array->GetData();
+ // TODO: remember InstructionSet with each code array so we know if we need to do thumb fixup?
+ if ((reinterpret_cast<uintptr_t>(orig_code) % 2) == 1) {
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(copy_code) + 1);
+ }
+ return copy_code;
+}
+
// TODO: remove this slow path
void ImageWriter::FixupMethod(const Method* orig, Method* copy) {
FixupInstanceFields(orig, copy);
// TODO: remove need for this by adding "signature" to java.lang.reflect.Method
copy->signature_ = down_cast<String*>(GetImageAddress(orig->signature_));
DCHECK(copy->signature_ != NULL);
+ // TODO: convert shorty_ to heap allocated storage
copy->dex_cache_strings_ = down_cast<ObjectArray<String>*>(GetImageAddress(orig->dex_cache_strings_));
copy->dex_cache_resolved_types_ = down_cast<ObjectArray<Class>*>(GetImageAddress(orig->dex_cache_resolved_types_));
copy->dex_cache_resolved_methods_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->dex_cache_resolved_methods_));
copy->dex_cache_resolved_fields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->dex_cache_resolved_fields_));
copy->dex_cache_code_and_direct_methods_ = down_cast<CodeAndDirectMethods*>(GetImageAddress(orig->dex_cache_code_and_direct_methods_));
copy->dex_cache_initialized_static_storage_ = down_cast<ObjectArray<StaticStorageBase>*>(GetImageAddress(orig->dex_cache_initialized_static_storage_));
-
- // TODO: convert shorty_ to heap allocated storage
+ copy->code_array_ = down_cast<ByteArray*>(GetImageAddress(orig->code_array_));
+ copy->code_ = FixupCode(copy->code_array_, orig->code_);
+ copy->invoke_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig->invoke_stub_array_));
+ copy->invoke_stub_ = reinterpret_cast<Method::InvokeStub*>(FixupCode(copy->invoke_stub_array_, reinterpret_cast<void*>(orig->invoke_stub_)));
}
void ImageWriter::FixupField(const Field* orig, Field* copy) {
@@ -262,4 +305,34 @@
}
}
+void ImageWriter::FixupDexCaches() {
+ typedef Set::const_iterator It; // TODO: C++0x auto
+ for (It it = dex_caches_.begin(), end = dex_caches_.end(); it != end; ++it) {
+ DexCache* orig = *it;
+ DexCache* copy = down_cast<DexCache*>(GetLocalAddress(orig));
+ FixupDexCache(orig, copy);
+ }
+}
+
+void ImageWriter::FixupDexCache(const DexCache* orig, DexCache* copy) {
+ CHECK(orig != NULL);
+ CHECK(copy != NULL);
+
+ CodeAndDirectMethods* orig_cadms = orig->GetCodeAndDirectMethods();
+ CodeAndDirectMethods* copy_cadms = down_cast<CodeAndDirectMethods*>(GetLocalAddress(orig_cadms));
+ for (size_t i = 0; i < orig->NumResolvedMethods(); i++) {
+ Method* orig_method = orig->GetResolvedMethod(i);
+ // if it was resolved in the original, resolve it in the copy
+ if (orig_method != NULL
+ && InSourceSpace(orig_method)
+ && orig_method == orig_cadms->GetResolvedMethod(i)) {
+ Method* copy_method = down_cast<Method*>(GetLocalAddress(orig_method));
+ copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i),
+ reinterpret_cast<int32_t>(copy_method->code_));
+ copy_cadms->Set(CodeAndDirectMethods::MethodIndex(i),
+ reinterpret_cast<int32_t>(GetImageAddress(orig_method)));
+ }
+ }
+}
+
} // namespace art
diff --git a/src/image_writer.h b/src/image_writer.h
index b63effe..3352adb 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -8,6 +8,7 @@
#include <cstddef>
#include "UniquePtr.h"
+#include "dex_cache.h"
#include "mem_map.h"
#include "object.h"
#include "os.h"
@@ -19,33 +20,53 @@
class ImageWriter {
public:
- ImageWriter() : image_top_(0), image_base_(NULL) {};
- bool Write(Space* space, const char* filename, byte* image_base);
+ ImageWriter() : source_space_(NULL), image_top_(0), image_base_(NULL) {};
+ bool Write(const char* filename, uintptr_t image_base);
~ImageWriter() {};
private:
- bool Init(Space* space);
+ bool Init();
// we use the lock word to store the offset of the object in the image
- void SetImageOffset(Object* object, size_t offset) {
+ static void SetImageOffset(Object* object, size_t offset) {
DCHECK(object != NULL);
DCHECK(object->GetMonitor() == NULL); // should be no lock
DCHECK_NE(0U, offset);
object->SetMonitor(reinterpret_cast<Monitor*>(offset));
}
- size_t GetImageOffset(const Object* object) {
+ static size_t GetImageOffset(const Object* object) {
DCHECK(object != NULL);
size_t offset = reinterpret_cast<size_t>(object->GetMonitor());
DCHECK_NE(0U, offset);
return offset;
}
+ static void ResetImageOffset(Object* object) {
+ DCHECK(object != NULL);
+ DCHECK(object->GetMonitor() != NULL); // should be an offset
+ object->SetMonitor(reinterpret_cast<Monitor*>(0));
+ }
+
+ bool InSourceSpace(const Object* object) {
+ DCHECK(source_space_ != NULL);
+ const byte* o = reinterpret_cast<const byte*>(object);
+ return (o >= source_space_->GetBase() && o < source_space_->GetLimit());
+ }
Object* GetImageAddress(const Object* object) {
if (object == NULL) {
return NULL;
}
+ // if object outside the relocating source_space_, assume unchanged
+ if (!InSourceSpace(object)) {
+ return const_cast<Object*>(object);
+ }
return reinterpret_cast<Object*>(image_base_ + GetImageOffset(object));
}
+ Object* GetLocalAddress(const Object* object) {
+ size_t offset = GetImageOffset(object);
+ byte* dst = image_->GetAddress() + offset;
+ return reinterpret_cast<Object*>(dst);
+ }
void CalculateNewObjectOffsets();
static void CalculateNewObjectOffsetsCallback(Object* obj, void *arg);
@@ -61,6 +82,12 @@
void FixupStaticFields(const Class* orig, Class* copy);
void FixupFields(const Object* orig, Object* copy, uint32_t ref_offsets, bool is_static);
+ void FixupDexCaches();
+ void FixupDexCache(const DexCache* orig, DexCache* copy);
+
+ // Space we are writing objects from
+ const Space* source_space_;
+
// memory mapped for generating the image
UniquePtr<MemMap> image_;
@@ -69,6 +96,10 @@
// Target base address for the output image
byte* image_base_;
+
+ // DexCaches seen while scanning for fixing up CodeAndDirectMethods
+ typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set;
+ Set dex_caches_;
};
} // namespace art
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index a75a365..bd1ccec 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -207,6 +207,7 @@
// Pass everything as arguments
const Method::InvokeStub* stub = method->GetInvokeStub();
JValue result;
+
if (method->HasCode() && stub != NULL) {
(*stub)(method, receiver, self, args, &result);
} else {
@@ -2566,11 +2567,11 @@
Runtime* runtime = Runtime::Create(options, ignore_unrecognized);
if (runtime == NULL) {
return JNI_ERR;
- } else {
- *p_env = Thread::Current()->GetJniEnv();
- *p_vm = runtime->GetJavaVM();
- return JNI_OK;
}
+ runtime->Start();
+ *p_env = Thread::Current()->GetJniEnv();
+ *p_vm = runtime->GetJavaVM();
+ return JNI_OK;
}
extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize, jsize* vm_count) {
diff --git a/src/main.cc b/src/oatexec.cc
similarity index 98%
rename from src/main.cc
rename to src/oatexec.cc
index 229135c..ca976af 100644
--- a/src/main.cc
+++ b/src/oatexec.cc
@@ -29,6 +29,7 @@
fprintf(stderr, "Unable to find class Method\n");
return false;
}
+#if 0 // TODO: try restoring once iftable_ moved to managed heap
jmethodID get_modifiers = env->GetMethodID(method.get(),
"getModifiers",
"()I");
@@ -36,6 +37,7 @@
fprintf(stderr, "Unable to find reflect.Method.getModifiers\n");
return false;
}
+#endif
static const int PUBLIC = 0x0001; // java.lang.reflect.Modifiers.PUBLIC
#if 0 // CallIntMethod not yet implemented
int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
diff --git a/src/object.cc b/src/object.cc
index 5d99cb6..f92f746 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -1047,7 +1047,8 @@
}
bool String::Equals(const StringPiece& modified_utf8) const {
- // TODO: do not assume C-string representation.
+ // TODO: do not assume C-string representation. For now DCHECK.
+ DCHECK_EQ(modified_utf8.data()[modified_utf8.size()], 0);
return Equals(modified_utf8.data());
}
diff --git a/src/object.h b/src/object.h
index fa09782..9b3bf88 100644
--- a/src/object.h
+++ b/src/object.h
@@ -2494,7 +2494,6 @@
inline void Field::SetName(String* new_name) {
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Field, name_),
new_name, false);
-
}
inline uint32_t Field::GetAccessFlags() const {
@@ -2602,6 +2601,12 @@
// C++ mirror of java.lang.Throwable
class Throwable : public Object {
+ public:
+ void SetDetailMessage(String* new_detail_message) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_),
+ new_detail_message, false);
+ }
+
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
Throwable* cause_;
diff --git a/src/runtime.cc b/src/runtime.cc
index 2891e56..2c2c5e2 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -149,42 +149,35 @@
}
}
-const DexFile* Open(const std::string& filename) {
- if (filename.size() < 4) {
- LOG(WARNING) << "Ignoring short classpath entry '" << filename << "'";
- return NULL;
- }
- std::string suffix(filename.substr(filename.size() - 4));
- if (suffix == ".zip" || suffix == ".jar" || suffix == ".apk") {
- return DexFile::OpenZip(filename);
- } else {
- return DexFile::OpenFile(filename);
- }
-}
-
-void CreateBootClassPath(const char* boot_class_path_cstr,
- std::vector<const DexFile*>& boot_class_path_vector) {
- CHECK(boot_class_path_cstr != NULL);
+void CreateClassPath(const char* class_path_cstr,
+ std::vector<const DexFile*>& class_path_vector) {
+ CHECK(class_path_cstr != NULL);
std::vector<std::string> parsed;
- Split(boot_class_path_cstr, ':', parsed);
+ Split(class_path_cstr, ':', parsed);
for (size_t i = 0; i < parsed.size(); ++i) {
- const DexFile* dex_file = Open(parsed[i]);
+ const DexFile* dex_file = DexFile::Open(parsed[i]);
if (dex_file != NULL) {
- boot_class_path_vector.push_back(dex_file);
+ class_path_vector.push_back(dex_file);
}
}
}
Runtime::ParsedOptions* Runtime::ParsedOptions::Create(const Options& options, bool ignore_unrecognized) {
UniquePtr<ParsedOptions> parsed(new ParsedOptions());
- const char* boot_class_path = getenv("BOOTCLASSPATH");
+ const char* boot_class_path = NULL;
+ const char* class_path = NULL;
parsed->boot_image_ = NULL;
#ifdef NDEBUG
// -Xcheck:jni is off by default for regular builds...
parsed->check_jni_ = false;
#else
// ...but on by default in debug builds.
+#if 0 // TODO: disabled for oatexec until the shorty's used by check_jni are managed heap allocated.
+ // Instead we turn on -Xcheck_jni in common_test.
parsed->check_jni_ = true;
+#else
+ parsed->check_jni_ = false;
+#endif
#endif
parsed->heap_initial_size_ = Heap::kInitialSize;
parsed->heap_maximum_size_ = Heap::kMaximumSize;
@@ -207,12 +200,25 @@
continue;
}
// TODO: usage
- LOG(FATAL) << "Could not parse " << option;
+ LOG(FATAL) << "Failed to parse " << option;
return NULL;
}
parsed->boot_class_path_ = *v;
+ } else if (option == "-classpath" || option == "-cp") {
+ // TODO: support -Djava.class.path
+ i++;
+ if (i == options.size()) {
+ // TODO: usage
+ LOG(FATAL) << "Missing required class path value for " << option;
+ return NULL;
+ }
+ const StringPiece& value = options[i].first;
+ class_path = value.data();
} else if (option.starts_with("-Xbootimage:")) {
+ // TODO: remove when intern_addr_ is removed, just use -Ximage:
parsed->boot_image_ = option.substr(strlen("-Xbootimage:")).data();
+ } else if (option.starts_with("-Ximage:")) {
+ parsed->images_.push_back(option.substr(strlen("-Ximage:")).data());
} else if (option.starts_with("-Xcheck:jni")) {
parsed->check_jni_ = true;
} else if (option.starts_with("-Xms")) {
@@ -222,7 +228,7 @@
continue;
}
// TODO: usage
- LOG(FATAL) << "Could not parse " << option;
+ LOG(FATAL) << "Failed to parse " << option;
return NULL;
}
parsed->heap_initial_size_ = size;
@@ -233,7 +239,7 @@
continue;
}
// TODO: usage
- LOG(FATAL) << "Could not parse " << option;
+ LOG(FATAL) << "Failed to parse " << option;
return NULL;
}
parsed->heap_maximum_size_ = size;
@@ -244,7 +250,7 @@
continue;
}
// TODO: usage
- LOG(FATAL) << "Could not parse " << option;
+ LOG(FATAL) << "Failed to parse " << option;
return NULL;
}
parsed->stack_size_ = size;
@@ -273,19 +279,33 @@
}
}
- if (boot_class_path == NULL) {
- boot_class_path = "";
+ // consider it an error if both bootclasspath and -Xbootclasspath: are supplied.
+ // TODO: remove bootclasspath which is only mostly just used by tests?
+ if (!parsed->boot_class_path_.empty() && boot_class_path != NULL) {
+ // TODO: usage
+ LOG(FATAL) << "bootclasspath and -Xbootclasspath: are mutually exclusive options.";
+ return NULL;
}
- if (parsed->boot_class_path_.size() == 0) {
- CreateBootClassPath(boot_class_path, parsed->boot_class_path_);
+ if (parsed->boot_class_path_.empty()) {
+ if (boot_class_path == NULL) {
+ boot_class_path = getenv("BOOTCLASSPATH");
+ if (boot_class_path == NULL) {
+ boot_class_path = "";
+ }
+ }
+ CreateClassPath(boot_class_path, parsed->boot_class_path_);
}
- return parsed.release();
-}
-Runtime* Runtime::Create(const std::vector<const DexFile*>& boot_class_path) {
- Runtime::Options options;
- options.push_back(std::make_pair("bootclasspath", &boot_class_path));
- return Runtime::Create(options, false);
+ if (class_path == NULL) {
+ class_path = getenv("CLASSPATH");
+ if (class_path == NULL) {
+ class_path = "";
+ }
+ }
+ CHECK_EQ(parsed->class_path_.size(), 0U);
+ CreateClassPath(class_path, parsed->class_path_);
+
+ return parsed.release();
}
Runtime* Runtime::Create(const Options& options, bool ignore_unrecognized) {
@@ -299,11 +319,12 @@
return NULL;
}
instance_ = runtime.release();
+ return instance_;
+}
+void Runtime::Start() {
instance_->InitLibraries();
instance_->signal_catcher_ = new SignalCatcher;
-
- return instance_;
}
bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
@@ -311,6 +332,7 @@
UniquePtr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));
if (options.get() == NULL) {
+ LOG(WARNING) << "Failed to parse options";
return false;
}
vfprintf_ = options->hook_vfprintf_;
@@ -324,7 +346,9 @@
if (!Heap::Init(options->heap_initial_size_,
options->heap_maximum_size_,
- options->boot_image_)) {
+ options->boot_image_,
+ options->images_)) {
+ LOG(WARNING) << "Failed to create heap";
return false;
}
@@ -333,12 +357,16 @@
java_vm_ = new JavaVMExt(this, options.get());
if (!Thread::Startup()) {
+ LOG(WARNING) << "Failed to startup threads";
return false;
}
thread_list_->Register(Thread::Attach(this));
- class_linker_ = ClassLinker::Create(options->boot_class_path_, intern_table_, Heap::GetBootSpace());
+ class_linker_ = ClassLinker::Create(options->boot_class_path_,
+ options->class_path_,
+ intern_table_,
+ Heap::GetBootSpace());
return true;
}
diff --git a/src/runtime.h b/src/runtime.h
index 4e00ec1..8a6ffe3 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -40,7 +40,9 @@
static ParsedOptions* Create(const Options& options, bool ignore_unrecognized);
std::vector<const DexFile*> boot_class_path_;
+ std::vector<const DexFile*> class_path_;
const char* boot_image_;
+ std::vector<const char*> images_;
bool check_jni_;
std::string jni_trace_;
size_t heap_initial_size_;
@@ -62,7 +64,9 @@
// Creates and initializes a new runtime.
static Runtime* Create(const Options& options, bool ignore_unrecognized);
- static Runtime* Create(const std::vector<const DexFile*>& boot_class_path);
+
+ // Starts a runtime, which may cause threads to be started and code to run.
+ void Start();
static Runtime* Current() {
return instance_;
@@ -115,7 +119,8 @@
private:
static void PlatformAbort(const char*, int);
- Runtime() : stack_size_(0), thread_list_(NULL), intern_table_(NULL), class_linker_(NULL) {}
+ Runtime() : stack_size_(0), thread_list_(NULL), intern_table_(NULL), class_linker_(NULL),
+ signal_catcher_(NULL) {}
void BlockSignals();
diff --git a/src/runtime_test.cc b/src/runtime_test.cc
index 65792c9..66c181b 100644
--- a/src/runtime_test.cc
+++ b/src/runtime_test.cc
@@ -14,13 +14,22 @@
void* test_abort = reinterpret_cast<void*>(0xb);
void* test_exit = reinterpret_cast<void*>(0xc);
void* null = reinterpret_cast<void*>(NULL);
- std::vector<const DexFile*> boot_class_path;
- boot_class_path.push_back(java_lang_dex_file_.get());
+
+ std::string lib_core = GetLibCoreDexFileName();
+
+ std::string boot_class_path;
+ boot_class_path += "-Xbootclasspath:";
+ boot_class_path += lib_core;
Runtime::Options options;
- options.push_back(std::make_pair("-Xbootclasspath:class_path_foo:class_path_bar", null));
- options.push_back(std::make_pair("bootclasspath", &boot_class_path));
+ options.push_back(std::make_pair(boot_class_path.c_str(), null));
+ options.push_back(std::make_pair("-classpath", null));
+ options.push_back(std::make_pair(lib_core.c_str(), null));
+ options.push_back(std::make_pair("-cp", null));
+ options.push_back(std::make_pair(lib_core.c_str(), null));
options.push_back(std::make_pair("-Xbootimage:boot_image", null));
+ options.push_back(std::make_pair("-Ximage:image_1", null));
+ options.push_back(std::make_pair("-Ximage:image_2", null));
options.push_back(std::make_pair("-Xcheck:jni", null));
options.push_back(std::make_pair("-Xms2048", null));
options.push_back(std::make_pair("-Xmx4k", null));
@@ -34,8 +43,12 @@
UniquePtr<Runtime::ParsedOptions> parsed(Runtime::ParsedOptions::Create(options, false));
ASSERT_TRUE(parsed.get() != NULL);
- EXPECT_EQ(1U, parsed->boot_class_path_.size()); // bootclasspath overrides -Xbootclasspath
+ EXPECT_EQ(1U, parsed->boot_class_path_.size());
+ EXPECT_EQ(1U, parsed->class_path_.size());
EXPECT_STREQ("boot_image", parsed->boot_image_);
+ EXPECT_EQ(2U, parsed->images_.size());
+ EXPECT_STREQ("image_1", parsed->images_[0]);
+ EXPECT_STREQ("image_2", parsed->images_[1]);
EXPECT_EQ(true, parsed->check_jni_);
EXPECT_EQ(2048U, parsed->heap_initial_size_);
EXPECT_EQ(4 * KB, parsed->heap_maximum_size_);
diff --git a/src/space.cc b/src/space.cc
index 36eb1f6..36e3cf2 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -59,18 +59,25 @@
bool Space::Init(size_t initial_size, size_t maximum_size, byte* requested_base) {
if (!(initial_size <= maximum_size)) {
+ LOG(WARNING) << "Failed to create space with initial size > maximum size ("
+ << initial_size << ">" << maximum_size << ")";
return false;
}
size_t length = RoundUp(maximum_size, kPageSize);
int prot = PROT_READ | PROT_WRITE;
UniquePtr<MemMap> mem_map(MemMap::Map(requested_base, length, prot));
if (mem_map.get() == NULL) {
+ LOG(WARNING) << "Failed to allocate " << length << " bytes for space";
return false;
}
Init(mem_map.release());
maximum_size_ = maximum_size;
mspace_ = CreateMallocSpace(base_, initial_size, maximum_size);
- return (mspace_ != NULL);
+ if (mspace_ == NULL) {
+ LOG(WARNING) << "Failed to create mspace for space";
+ return false;
+ }
+ return true;
}
void Space::Init(MemMap* mem_map) {
@@ -83,17 +90,24 @@
bool Space::Init(const char* image_file_name) {
UniquePtr<File> file(OS::OpenFile(image_file_name, false));
if (file.get() == NULL) {
+ LOG(WARNING) << "Failed to open " << image_file_name;
return false;
}
ImageHeader image_header;
bool success = file->ReadFully(&image_header, sizeof(image_header));
if (!success || !image_header.IsValid()) {
+ LOG(WARNING) << "Invalid image header " << image_file_name;
return false;
}
UniquePtr<MemMap> map(MemMap::Map(image_header.GetBaseAddr(),
- file->Length(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED,
- file->Fd(), 0));
+ file->Length(),
+ // TODO: selectively PROT_EXEC when image contains a code space
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_FIXED,
+ file->Fd(),
+ 0));
if (map.get() == NULL) {
+ LOG(WARNING) << "Failed to map " << image_file_name;
return false;
}
CHECK_EQ(image_header.GetBaseAddr(), map->GetAddress());