summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Light <allight@google.com>2014-08-19 14:23:13 -0700
committerAlex Light <allight@google.com>2014-08-25 10:36:26 -0700
commit64ad14dbe2225441fb7734bf6d89358d96692eea (patch)
tree8992ebe906a4a0040502132aa9c77628a0a5ced6
parent688d4a42ff5ab3bcb28d516afcb80b79c392e8e4 (diff)
downloadart-64ad14dbe2225441fb7734bf6d89358d96692eea.zip
art-64ad14dbe2225441fb7734bf6d89358d96692eea.tar.gz
art-64ad14dbe2225441fb7734bf6d89358d96692eea.tar.bz2
Support running without a boot image.
Bug: 17000769 Change-Id: I6404d5050c8a2f4ee6e70d58532eb25ee9de248e
-rw-r--r--runtime/class_linker.cc64
-rw-r--r--runtime/class_linker.h4
-rw-r--r--runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc3
-rw-r--r--runtime/gc/heap.cc25
-rw-r--r--runtime/gc/space/image_space.cc67
-rw-r--r--runtime/gc/space/image_space.h2
-rw-r--r--runtime/parsed_options.cc6
-rw-r--r--runtime/parsed_options.h1
-rw-r--r--runtime/runtime.cc44
-rw-r--r--runtime/runtime.h7
-rw-r--r--test/118-noimage-dex2oat/expected.txt6
-rw-r--r--test/118-noimage-dex2oat/info.txt1
-rw-r--r--test/118-noimage-dex2oat/noimage-dex2oat.cc45
-rw-r--r--test/118-noimage-dex2oat/run41
-rw-r--r--test/118-noimage-dex2oat/src/Main.java38
-rw-r--r--test/Android.libarttest.mk3
16 files changed, 306 insertions, 51 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 8fc1d07..ab4bf41 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -195,10 +195,13 @@ ClassLinker::ClassLinker(InternTable* intern_table)
// To set a value for generic JNI. May be necessary in compiler tests.
extern "C" void art_quick_generic_jni_trampoline(mirror::ArtMethod*);
+extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*);
+extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*);
+extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*);
-void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class_path) {
+void ClassLinker::InitWithoutImage(const std::vector<const DexFile*>& boot_class_path) {
VLOG(startup) << "ClassLinker::Init";
- CHECK(Runtime::Current()->IsCompiler());
+ CHECK(!Runtime::Current()->GetHeap()->HasImageSpace()) << "Runtime has image. We should use it.";
CHECK(!init_done_);
@@ -370,6 +373,12 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class
// Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that
// we do not need friend classes or a publicly exposed setter.
quick_generic_jni_trampoline_ = reinterpret_cast<void*>(art_quick_generic_jni_trampoline);
+ if (!runtime->IsCompiler()) {
+ // We need to set up the generic trampolines since we don't have an image.
+ quick_resolution_trampoline_ = reinterpret_cast<void*>(art_quick_resolution_trampoline);
+ quick_imt_conflict_trampoline_ = reinterpret_cast<void*>(art_quick_imt_conflict_trampoline);
+ quick_to_interpreter_bridge_trampoline_ = reinterpret_cast<void*>(art_quick_to_interpreter_bridge);
+ }
// Object, String and DexCache need to be rerun through FindSystemClass to finish init
java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self);
@@ -589,6 +598,13 @@ bool ClassLinker::GenerateOatFile(const char* dex_filename,
gc::Heap* heap = Runtime::Current()->GetHeap();
std::string boot_image_option("--boot-image=");
+ if (heap->GetImageSpace() == nullptr) {
+ // TODO If we get a dex2dex compiler working we could maybe use that, OTOH since we are likely
+ // out of space anyway it might not matter.
+ *error_msg = StringPrintf("Cannot create oat file for '%s' because we are running "
+ "without an image.", dex_filename);
+ return false;
+ }
boot_image_option += heap->GetImageSpace()->GetImageLocation();
std::string dex_file_option("--dex-file=");
@@ -879,16 +895,17 @@ bool ClassLinker::OpenDexFilesFromOat(const char* dex_location, const char* oat_
oat_location = cache_location.c_str();
}
+ bool has_flock = true;
// Definitely need to lock now.
if (!scoped_flock.HasFile()) {
std::string error_msg;
if (!scoped_flock.Init(oat_location, &error_msg)) {
error_msgs->push_back(error_msg);
- return false;
+ has_flock = false;
}
}
- if (Runtime::Current()->IsDex2OatEnabled()) {
+ if (Runtime::Current()->IsDex2OatEnabled() && has_flock && scoped_flock.HasFile()) {
// Create the oat file.
open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()->Fd(),
oat_location, error_msgs));
@@ -1003,6 +1020,9 @@ bool ClassLinker::VerifyOatImageChecksum(const OatFile* oat_file,
const InstructionSet instruction_set) {
Runtime* runtime = Runtime::Current();
const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+ if (image_space == nullptr) {
+ return false;
+ }
uint32_t image_oat_checksum = 0;
if (instruction_set == kRuntimeISA) {
const ImageHeader& image_header = image_space->GetImageHeader();
@@ -1020,6 +1040,10 @@ bool ClassLinker::VerifyOatChecksums(const OatFile* oat_file,
std::string* error_msg) {
Runtime* runtime = Runtime::Current();
const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+ if (image_space == nullptr) {
+ *error_msg = "No image space for verification against";
+ return false;
+ }
// If the requested instruction set is the same as the current runtime,
// we can use the checksums directly. If it isn't, we'll have to read the
@@ -1270,13 +1294,15 @@ const OatFile* ClassLinker::OpenOatFileFromDexLocation(const std::string& dex_lo
std::string error_msg;
if (runtime->CanRelocate()) {
// Run relocation
- const std::string& image_location =
- Runtime::Current()->GetHeap()->GetImageSpace()->GetImageLocation();
- if (odex_checksum_verified && should_patch_system) {
- ret = PatchAndRetrieveOat(odex_filename, cache_filename, image_location, isa, &error_msg);
- } else if (cache_checksum_verified && should_patch_cache) {
- CHECK(have_dalvik_cache);
- ret = PatchAndRetrieveOat(cache_filename, cache_filename, image_location, isa, &error_msg);
+ gc::space::ImageSpace* space = Runtime::Current()->GetHeap()->GetImageSpace();
+ if (space != nullptr) {
+ const std::string& image_location = space->GetImageLocation();
+ if (odex_checksum_verified && should_patch_system) {
+ ret = PatchAndRetrieveOat(odex_filename, cache_filename, image_location, isa, &error_msg);
+ } else if (cache_checksum_verified && should_patch_cache) {
+ CHECK(have_dalvik_cache);
+ ret = PatchAndRetrieveOat(cache_filename, cache_filename, image_location, isa, &error_msg);
+ }
}
}
if (ret == nullptr && have_dalvik_cache && OS::FileExists(cache_filename.c_str())) {
@@ -1340,6 +1366,12 @@ const OatFile* ClassLinker::PatchAndRetrieveOat(const std::string& input_oat,
const std::string& image_location,
InstructionSet isa,
std::string* error_msg) {
+ if (!Runtime::Current()->GetHeap()->HasImageSpace()) {
+ // We don't have an image space so there is no point in trying to patchoat.
+ LOG(WARNING) << "Patching of oat file '" << input_oat << "' not attempted because we are "
+ << "running without an image. Attempting to use oat file for interpretation.";
+ return GetInterpretedOnlyOat(input_oat, isa, error_msg);
+ }
if (!Runtime::Current()->IsDex2OatEnabled()) {
// We don't have dex2oat so we can assume we don't have patchoat either. We should just use the
// input_oat but make sure we only do interpretation on it's dex files.
@@ -1402,6 +1434,7 @@ int32_t ClassLinker::GetRequiredDelta(const OatFile* oat_file, InstructionSet is
Runtime* runtime = Runtime::Current();
int32_t real_patch_delta;
const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+ CHECK(image_space != nullptr);
if (isa == Runtime::Current()->GetInstructionSet()) {
const ImageHeader& image_header = image_space->GetImageHeader();
real_patch_delta = image_header.GetPatchDelta();
@@ -1423,6 +1456,10 @@ bool ClassLinker::CheckOatFile(const OatFile* oat_file, InstructionSet isa,
void* real_image_oat_offset;
int32_t real_patch_delta;
const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+ if (image_space == nullptr) {
+ *error_msg = "No image space present";
+ return false;
+ }
if (isa == Runtime::Current()->GetInstructionSet()) {
const ImageHeader& image_header = image_space->GetImageHeader();
real_image_checksum = image_header.GetOatChecksum();
@@ -2275,8 +2312,11 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) {
}
Runtime* runtime = Runtime::Current();
if (!runtime->IsStarted() || runtime->UseCompileTimeClassPath()) {
- return; // OAT file unavailable.
+ if (runtime->IsCompiler() || runtime->GetHeap()->HasImageSpace()) {
+ return; // OAT file unavailable.
+ }
}
+
const DexFile& dex_file = klass->GetDexFile();
const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
CHECK(dex_class_def != nullptr);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 5694149..71ce468 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -60,8 +60,8 @@ class ClassLinker {
explicit ClassLinker(InternTable* intern_table);
~ClassLinker();
- // Initialize class linker by bootstraping from dex files
- void InitFromCompiler(const std::vector<const DexFile*>& boot_class_path)
+ // Initialize class linker by bootstraping from dex files.
+ void InitWithoutImage(const std::vector<const DexFile*>& boot_class_path)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Initialize class linker from one or more images.
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index 9a22c15..49df62d 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -38,7 +38,8 @@ extern "C" const void* artInstrumentationMethodEntryFromCode(mirror::ArtMethod*
} else {
result = instrumentation->GetQuickCodeFor(method);
}
- DCHECK(result != Runtime::Current()->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline());
+ DCHECK((result != Runtime::Current()->GetClassLinker()->GetQuickToInterpreterBridgeTrampoline())
+ || !Runtime::Current()->GetHeap()->HasImageSpace());
bool interpreter_entry = (result == GetQuickToInterpreterBridge());
instrumentation->PushInstrumentationStackFrame(self, method->IsStatic() ? nullptr : this_object,
method, lr, interpreter_entry);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index f0b7685..cd1cdd3 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -202,15 +202,21 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
// Requested begin for the alloc space, to follow the mapped image and oat files
byte* requested_alloc_space_begin = nullptr;
if (!image_file_name.empty()) {
+ std::string error_msg;
space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name.c_str(),
- image_instruction_set);
- CHECK(image_space != nullptr) << "Failed to create space for " << image_file_name;
- AddSpace(image_space);
- // Oat files referenced by image files immediately follow them in memory, ensure alloc space
- // isn't going to get in the middle
- byte* oat_file_end_addr = image_space->GetImageHeader().GetOatFileEnd();
- CHECK_GT(oat_file_end_addr, image_space->End());
- requested_alloc_space_begin = AlignUp(oat_file_end_addr, kPageSize);
+ image_instruction_set,
+ &error_msg);
+ if (image_space != nullptr) {
+ AddSpace(image_space);
+ // Oat files referenced by image files immediately follow them in memory, ensure alloc space
+ // isn't going to get in the middle
+ byte* oat_file_end_addr = image_space->GetImageHeader().GetOatFileEnd();
+ CHECK_GT(oat_file_end_addr, image_space->End());
+ requested_alloc_space_begin = AlignUp(oat_file_end_addr, kPageSize);
+ } else {
+ LOG(WARNING) << "Could not create image space with image file '" << image_file_name << "'. "
+ << "Attempting to fall back to imageless running. Error was: " << error_msg;
+ }
}
/*
requested_alloc_space_begin -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
@@ -579,6 +585,9 @@ void Heap::DumpObject(std::ostream& stream, mirror::Object* obj) {
}
bool Heap::IsCompilingBoot() const {
+ if (!Runtime::Current()->IsCompiler()) {
+ return false;
+ }
for (const auto& space : continuous_spaces_) {
if (space->IsImageSpace() || space->IsZygoteSpace()) {
return false;
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 1d10af2..0139ecc 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -283,8 +283,8 @@ static bool ChecksumsMatch(const char* image_a, const char* image_b) {
}
ImageSpace* ImageSpace::Create(const char* image_location,
- const InstructionSet image_isa) {
- std::string error_msg;
+ const InstructionSet image_isa,
+ std::string* error_msg) {
std::string system_filename;
bool has_system = false;
std::string cache_filename;
@@ -296,14 +296,18 @@ ImageSpace* ImageSpace::Create(const char* image_location,
ImageSpace* space;
bool relocate = Runtime::Current()->ShouldRelocate();
+ bool can_compile = Runtime::Current()->IsImageDex2OatEnabled();
if (found_image) {
const std::string* image_filename;
bool is_system = false;
bool relocated_version_used = false;
if (relocate) {
- CHECK(dalvik_cache_exists) << "Requiring relocation for image " << image_location << " "
- << "at " << system_filename << " but we do not have any "
- << "dalvik_cache to find/place it in.";
+ if (!dalvik_cache_exists) {
+ *error_msg = StringPrintf("Requiring relocation for image '%s' at '%s' but we do not have "
+ "any dalvik_cache to find/place it in.",
+ image_location, system_filename.c_str());
+ return nullptr;
+ }
if (has_system) {
if (has_cache && ChecksumsMatch(system_filename.c_str(), cache_filename.c_str())) {
// We already have a relocated version
@@ -311,14 +315,20 @@ ImageSpace* ImageSpace::Create(const char* image_location,
relocated_version_used = true;
} else {
// We cannot have a relocated version, Relocate the system one and use it.
- if (RelocateImage(image_location, cache_filename.c_str(), image_isa,
- &error_msg)) {
+ if (can_compile && RelocateImage(image_location, cache_filename.c_str(), image_isa,
+ error_msg)) {
relocated_version_used = true;
image_filename = &cache_filename;
} else {
- LOG(FATAL) << "Unable to relocate image " << image_location << " "
- << "from " << system_filename << " to " << cache_filename << ": "
- << error_msg;
+ std::string reason;
+ if (can_compile) {
+ reason = StringPrintf(": %s", error_msg->c_str());
+ } else {
+ reason = " because image dex2oat is disabled.";
+ }
+ *error_msg = StringPrintf("Unable to relocate image '%s' from '%s' to '%s'%s",
+ image_location, system_filename.c_str(),
+ cache_filename.c_str(), reason.c_str());
return nullptr;
}
}
@@ -351,7 +361,7 @@ ImageSpace* ImageSpace::Create(const char* image_location,
// descriptor (and the associated exclusive lock) to be released when
// we leave Create.
ScopedFlock image_lock;
- image_lock.Init(image_filename->c_str(), &error_msg);
+ image_lock.Init(image_filename->c_str(), error_msg);
LOG(INFO) << "Using image file " << image_filename->c_str() << " for image location "
<< image_location;
// If we are in /system we can assume the image is good. We can also
@@ -359,7 +369,7 @@ ImageSpace* ImageSpace::Create(const char* image_location,
// matches) since this is only different by the offset. We need this to
// make sure that host tests continue to work.
space = ImageSpace::Init(image_filename->c_str(), image_location,
- !(is_system || relocated_version_used), &error_msg);
+ !(is_system || relocated_version_used), error_msg);
}
if (space != nullptr) {
return space;
@@ -374,29 +384,38 @@ ImageSpace* ImageSpace::Create(const char* image_location,
<< "but image failed to load: " << error_msg;
return nullptr;
} else if (is_system) {
- LOG(FATAL) << "Failed to load /system image '" << *image_filename << "': " << error_msg;
+ *error_msg = StringPrintf("Failed to load /system image '%s': %s",
+ image_filename->c_str(), error_msg->c_str());
return nullptr;
} else {
- LOG(WARNING) << error_msg;
+ LOG(WARNING) << *error_msg;
}
}
- CHECK(dalvik_cache_exists) << "No place to put generated image.";
- CHECK(GenerateImage(cache_filename, &error_msg))
- << "Failed to generate image '" << cache_filename << "': " << error_msg;
- {
+ if (!can_compile) {
+ *error_msg = "Not attempting to compile image because -Xnoimage-dex2oat";
+ return nullptr;
+ } else if (!dalvik_cache_exists) {
+ *error_msg = StringPrintf("No place to put generated image.");
+ return nullptr;
+ } else if (!GenerateImage(cache_filename, error_msg)) {
+ *error_msg = StringPrintf("Failed to generate image '%s': %s",
+ cache_filename.c_str(), error_msg->c_str());
+ return nullptr;
+ } else {
// Note that we must not use the file descriptor associated with
// ScopedFlock::GetFile to Init the image file. We want the file
// descriptor (and the associated exclusive lock) to be released when
// we leave Create.
ScopedFlock image_lock;
- image_lock.Init(cache_filename.c_str(), &error_msg);
- space = ImageSpace::Init(cache_filename.c_str(), image_location, true, &error_msg);
- }
- if (space == nullptr) {
- LOG(FATAL) << "Failed to load generated image '" << cache_filename << "': " << error_msg;
+ image_lock.Init(cache_filename.c_str(), error_msg);
+ space = ImageSpace::Init(cache_filename.c_str(), image_location, true, error_msg);
+ if (space == nullptr) {
+ *error_msg = StringPrintf("Failed to load generated image '%s': %s",
+ cache_filename.c_str(), error_msg->c_str());
+ }
+ return space;
}
- return space;
}
void ImageSpace::VerifyImageAllocations() {
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 6be3b8f..28ebca6 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -43,7 +43,7 @@ class ImageSpace : public MemMapSpace {
// creation of the alloc space. The ReleaseOatFile will later be
// used to transfer ownership of the OatFile to the ClassLinker when
// it is initialized.
- static ImageSpace* Create(const char* image, InstructionSet image_isa)
+ static ImageSpace* Create(const char* image, InstructionSet image_isa, std::string* error_msg)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Reads the image header from the specified image location for the
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 26360d7..9ed5e7b 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -224,6 +224,7 @@ bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognize
is_zygote_ = false;
must_relocate_ = kDefaultMustRelocate;
dex2oat_enabled_ = true;
+ image_dex2oat_enabled_ = true;
if (kPoisonHeapReferences) {
// kPoisonHeapReferences currently works only with the interpreter only.
// TODO: make it work with the compiler.
@@ -434,6 +435,10 @@ bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognize
dex2oat_enabled_ = false;
} else if (option == "-Xdex2oat") {
dex2oat_enabled_ = true;
+ } else if (option == "-Xnoimage-dex2oat") {
+ image_dex2oat_enabled_ = false;
+ } else if (option == "-Ximage-dex2oat") {
+ image_dex2oat_enabled_ = true;
} else if (option == "-Xint") {
interpreter_only_ = true;
} else if (StartsWith(option, "-Xgc:")) {
@@ -790,6 +795,7 @@ void ParsedOptions::Usage(const char* fmt, ...) {
UsageMessage(stream, " -Xpatchoat:filename\n");
UsageMessage(stream, " -X[no]relocate\n");
UsageMessage(stream, " -X[no]dex2oat (Whether to invoke dex2oat on the application)\n");
+ UsageMessage(stream, " -X[no]image-dex2oat (Whether to create and use a boot image)\n");
UsageMessage(stream, "\n");
UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n");
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 1afd610..ba1b848 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -51,6 +51,7 @@ class ParsedOptions {
bool is_zygote_;
bool must_relocate_;
bool dex2oat_enabled_;
+ bool image_dex2oat_enabled_;
std::string patchoat_executable_;
bool interpreter_only_;
bool is_explicit_gc_disabled_;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index ba53c43..233c9d4 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -102,6 +102,7 @@ Runtime::Runtime()
is_concurrent_gc_enabled_(true),
is_explicit_gc_disabled_(false),
dex2oat_enabled_(true),
+ image_dex2oat_enabled_(true),
default_stack_size_(0),
heap_(nullptr),
max_spins_before_thin_lock_inflation_(Monitor::kDefaultMaxSpinsBeforeThinLockInflation),
@@ -396,10 +397,18 @@ bool Runtime::Start() {
// Restore main thread state to kNative as expected by native code.
Thread* self = Thread::Current();
+
self->TransitionFromRunnableToSuspended(kNative);
started_ = true;
+ if (!IsImageDex2OatEnabled() || !Runtime::Current()->GetHeap()->HasImageSpace()) {
+ ScopedObjectAccess soa(Thread::Current());
+ StackHandleScope<1> hs(soa.Self());
+ auto klass(hs.NewHandle<mirror::Class>(mirror::Class::GetJavaLangClass()));
+ class_linker_->EnsureInitialized(klass, true, true);
+ }
+
// InitNativeMethods needs to be after started_ so that the classes
// it touches will have methods linked to the oat file if necessary.
InitNativeMethods();
@@ -535,6 +544,24 @@ void Runtime::StartDaemonThreads() {
VLOG(startup) << "Runtime::StartDaemonThreads exiting";
}
+static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames,
+ std::vector<const DexFile*>& dex_files) {
+ size_t failure_count = 0;
+ for (size_t i = 0; i < dex_filenames.size(); i++) {
+ const char* dex_filename = dex_filenames[i].c_str();
+ std::string error_msg;
+ if (!OS::FileExists(dex_filename)) {
+ LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
+ continue;
+ }
+ if (!DexFile::Open(dex_filename, dex_filename, &error_msg, &dex_files)) {
+ LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
+ ++failure_count;
+ }
+ }
+ return failure_count;
+}
+
bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
@@ -559,6 +586,7 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized)
is_zygote_ = options->is_zygote_;
is_explicit_gc_disabled_ = options->is_explicit_gc_disabled_;
dex2oat_enabled_ = options->dex2oat_enabled_;
+ image_dex2oat_enabled_ = options->image_dex2oat_enabled_;
vfprintf_ = options->hook_vfprintf_;
exit_ = options->hook_exit_;
@@ -677,10 +705,24 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized)
if (kIsDebugBuild) {
GetHeap()->GetImageSpace()->VerifyImageAllocations();
}
+ } else if (!IsCompiler() || !image_dex2oat_enabled_) {
+ std::vector<std::string> dex_filenames;
+ Split(boot_class_path_string_, ':', dex_filenames);
+ std::vector<const DexFile*> boot_class_path;
+ OpenDexFiles(dex_filenames, boot_class_path);
+ class_linker_->InitWithoutImage(boot_class_path);
+ // TODO: Should we move the following to InitWithoutImage?
+ SetInstructionSet(kRuntimeISA);
+ for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+ Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+ if (!HasCalleeSaveMethod(type)) {
+ SetCalleeSaveMethod(CreateCalleeSaveMethod(type), type);
+ }
+ }
} else {
CHECK(options->boot_class_path_ != NULL);
CHECK_NE(options->boot_class_path_->size(), 0U);
- class_linker_->InitFromCompiler(*options->boot_class_path_);
+ class_linker_->InitWithoutImage(*options->boot_class_path_);
}
CHECK(class_linker_ != NULL);
verifier::MethodVerifier::Init();
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 34ccdcb..784241e 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -107,7 +107,11 @@ class Runtime {
}
bool IsDex2OatEnabled() const {
- return dex2oat_enabled_;
+ return dex2oat_enabled_ && IsImageDex2OatEnabled();
+ }
+
+ bool IsImageDex2OatEnabled() const {
+ return image_dex2oat_enabled_;
}
CompilerCallbacks* GetCompilerCallbacks() {
@@ -509,6 +513,7 @@ class Runtime {
bool is_concurrent_gc_enabled_;
bool is_explicit_gc_disabled_;
bool dex2oat_enabled_;
+ bool image_dex2oat_enabled_;
std::string compiler_executable_;
std::string patchoat_executable_;
diff --git a/test/118-noimage-dex2oat/expected.txt b/test/118-noimage-dex2oat/expected.txt
new file mode 100644
index 0000000..472a5f2
--- /dev/null
+++ b/test/118-noimage-dex2oat/expected.txt
@@ -0,0 +1,6 @@
+Run -Xnoimage-dex2oat
+Has image is false, is image dex2oat enabled is false.
+Run -Ximage-dex2oat
+Has image is true, is image dex2oat enabled is true.
+Run default
+Has image is true, is image dex2oat enabled is true.
diff --git a/test/118-noimage-dex2oat/info.txt b/test/118-noimage-dex2oat/info.txt
new file mode 100644
index 0000000..fc102ac
--- /dev/null
+++ b/test/118-noimage-dex2oat/info.txt
@@ -0,0 +1 @@
+Test that disables dex2oat'ing the image.
diff --git a/test/118-noimage-dex2oat/noimage-dex2oat.cc b/test/118-noimage-dex2oat/noimage-dex2oat.cc
new file mode 100644
index 0000000..4a3d33c
--- /dev/null
+++ b/test/118-noimage-dex2oat/noimage-dex2oat.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "class_linker.h"
+#include "dex_file-inl.h"
+#include "mirror/class-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread.h"
+
+namespace art {
+
+class NoDex2OatTest {
+ public:
+ static bool hasOat(jclass cls) {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+ const DexFile& dex_file = klass->GetDexFile();
+ const OatFile* oat_file =
+ Runtime::Current()->GetClassLinker()->FindOpenedOatFileForDexFile(dex_file);
+ return oat_file != nullptr;
+ }
+};
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasImage(JNIEnv*, jclass cls) {
+ return Runtime::Current()->GetHeap()->HasImageSpace();
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isImageDex2OatEnabled(JNIEnv*, jclass cls) {
+ return Runtime::Current()->IsImageDex2OatEnabled();
+}
+
+} // namespace art
diff --git a/test/118-noimage-dex2oat/run b/test/118-noimage-dex2oat/run
new file mode 100644
index 0000000..911abdf
--- /dev/null
+++ b/test/118-noimage-dex2oat/run
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Force relocation otherwise we will just use the already created core.oat/art pair.
+flags="${@/--no-relocate/--relocate}"
+
+# Use the non-prebuild script.
+RUN="${RUN/push-and-run-prebuilt-test-jar/push-and-run-test-jar}"
+
+if [ $(basename $RUN) == 'host-run-test-jar' ]; then
+ BPATH="--runtime-option -Xbootclasspath:$ANDROID_HOST_OUT/../common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/javalib.jar"
+ # Remove prebuild from the flags, this test is for testing not having oat files.
+ flags="${flags/--prebuild/}"
+else
+ BPATH="--runtime-option -Xbootclasspath:/system/framework/core-libart.jar"
+fi
+
+# Make sure we can run without an oat file,
+echo "Run -Xnoimage-dex2oat"
+${RUN} ${flags} ${BPATH} --runtime-option -Xnoimage-dex2oat --runtime-option -Xnodex2oat
+
+# Make sure we can run with the oat file.
+echo "Run -Ximage-dex2oat"
+${RUN} ${flags} ${BPATH} --runtime-option -Ximage-dex2oat
+
+# Make sure we can run with the default settings.
+echo "Run default"
+${RUN} ${flags} ${BPATH}
diff --git a/test/118-noimage-dex2oat/src/Main.java b/test/118-noimage-dex2oat/src/Main.java
new file mode 100644
index 0000000..11c736a
--- /dev/null
+++ b/test/118-noimage-dex2oat/src/Main.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ boolean hasImage = hasImage();
+ System.out.println(
+ "Has image is " + hasImage + ", is image dex2oat enabled is "
+ + isImageDex2OatEnabled() + ".");
+
+ if (hasImage && !isImageDex2OatEnabled()) {
+ throw new Error("Image with dex2oat disabled runs with an oat file");
+ } else if (!hasImage && isImageDex2OatEnabled()) {
+ throw new Error("Image with dex2oat enabled runs without an oat file");
+ }
+ }
+
+ static {
+ System.loadLibrary("arttest");
+ }
+
+ private native static boolean hasImage();
+
+ private native static boolean isImageDex2OatEnabled();
+}
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index caaf649..2d139a6 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -25,7 +25,8 @@ LIBARTTEST_COMMON_SRC_FILES := \
004-StackWalk/stack_walk_jni.cc \
004-UnsafeTest/unsafe_test.cc \
116-nodex2oat/nodex2oat.cc \
- 117-nopatchoat/nopatchoat.cc
+ 117-nopatchoat/nopatchoat.cc \
+ 118-noimage-dex2oat/noimage-dex2oat.cc
ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
ifdef TARGET_2ND_ARCH