diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/class_linker.cc | 64 | ||||
-rw-r--r-- | runtime/class_linker.h | 4 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc | 3 | ||||
-rw-r--r-- | runtime/gc/heap.cc | 25 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 67 | ||||
-rw-r--r-- | runtime/gc/space/image_space.h | 2 | ||||
-rw-r--r-- | runtime/parsed_options.cc | 6 | ||||
-rw-r--r-- | runtime/parsed_options.h | 1 | ||||
-rw-r--r-- | runtime/runtime.cc | 44 | ||||
-rw-r--r-- | runtime/runtime.h | 7 |
10 files changed, 173 insertions, 50 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index f68e27443f..dcf8f5f42e 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 edcddcefd1..14a9e4ad1b 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -61,8 +61,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 9a22c154f5..49df62db47 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 898c258c8b..82d58307e1 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 -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- @@ -598,6 +604,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 1d10af2e63..0139eccef0 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 6be3b8f3df..28ebca6e94 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 5e61696d2a..7ac5bceda2 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -225,6 +225,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. @@ -439,6 +440,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:")) { @@ -796,6 +801,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 c0f00e1c79..c1474656f2 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 f6b3247fa4..3e03c1a16b 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), @@ -399,10 +400,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(); @@ -538,6 +547,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); @@ -562,6 +589,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_; @@ -681,10 +709,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 259691adc1..b0a88d5684 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_; |