summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Geoffray <ngeoffray@google.com>2014-07-22 10:48:00 +0100
committerNicolas Geoffray <ngeoffray@google.com>2014-08-13 18:01:51 +0100
commit4fcdc94d22a4608e355aa8df36240181149d10e8 (patch)
treecb600df7e9b585720c03a08b10509151aa96d5dd
parentb66252112d45fd24eab85122fa8902afd1324542 (diff)
downloadart-4fcdc94d22a4608e355aa8df36240181149d10e8.tar.gz
art-4fcdc94d22a4608e355aa8df36240181149d10e8.tar.bz2
art-4fcdc94d22a4608e355aa8df36240181149d10e8.zip
Execute an application even when dex2oat crashes.
Bug: 17000769 Change-Id: Iffeb582862a5e794b6c7364c7ec2368cfd0f2214
-rw-r--r--runtime/class_linker.cc111
-rw-r--r--runtime/class_linker.h8
-rw-r--r--runtime/native/dalvik_system_DexFile.cc4
-rw-r--r--runtime/oat_file.h12
-rw-r--r--runtime/parsed_options.cc14
-rw-r--r--runtime/parsed_options.h1
-rw-r--r--runtime/runtime.cc2
-rw-r--r--runtime/runtime.h5
-rw-r--r--test/116-nodex2oat/expected.txt6
-rw-r--r--test/116-nodex2oat/info.txt1
-rw-r--r--test/116-nodex2oat/nodex2oat.cc45
-rwxr-xr-xtest/116-nodex2oat/run30
-rw-r--r--test/116-nodex2oat/src/Main.java36
-rw-r--r--test/Android.libarttest.mk3
14 files changed, 232 insertions, 46 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ee6fa66907..d52992c5f2 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -887,12 +887,18 @@ bool ClassLinker::OpenDexFilesFromOat(const char* dex_location, const char* oat_
}
}
- // Create the oat file.
- open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()->Fd(),
- oat_location, error_msgs));
+ if (Runtime::Current()->IsDex2OatEnabled()) {
+ // Create the oat file.
+ open_oat_file.reset(CreateOatFileForDexLocation(dex_location, scoped_flock.GetFile()->Fd(),
+ oat_location, error_msgs));
+ }
// Failed, bail.
if (open_oat_file.get() == nullptr) {
+ std::string error_msg;
+ // dex2oat was disabled or crashed. Add the dex file in the list of dex_files to make progress.
+ DexFile::Open(dex_location, dex_location, &error_msg, dex_files);
+ error_msgs->push_back(error_msg);
return false;
}
@@ -2016,15 +2022,21 @@ uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
return mirror::Class::ComputeClassSize(false, 0, num_32, num_64, num_ref);
}
-OatFile::OatClass ClassLinker::GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) {
+bool ClassLinker::FindOatClass(const DexFile& dex_file,
+ uint16_t class_def_idx,
+ OatFile::OatClass* oat_class) {
+ DCHECK(oat_class != nullptr);
DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16);
const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
- CHECK(oat_file != NULL) << dex_file.GetLocation();
+ if (oat_file == nullptr) {
+ return false;
+ }
uint dex_location_checksum = dex_file.GetLocationChecksum();
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
&dex_location_checksum);
CHECK(oat_dex_file != NULL) << dex_file.GetLocation();
- return oat_dex_file->GetOatClass(class_def_idx);
+ *oat_class = oat_dex_file->GetOatClass(class_def_idx);
+ return true;
}
static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx,
@@ -2061,7 +2073,8 @@ static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16
return 0;
}
-const OatFile::OatMethod ClassLinker::GetOatMethodFor(mirror::ArtMethod* method) {
+bool ClassLinker::FindOatMethodFor(mirror::ArtMethod* method, OatFile::OatMethod* oat_method) {
+ DCHECK(oat_method != nullptr);
// Although we overwrite the trampoline of non-static methods, we may get here via the resolution
// method for direct methods (or virtual methods made direct).
mirror::Class* declaring_class = method->GetDeclaringClass();
@@ -2088,10 +2101,15 @@ const OatFile::OatMethod ClassLinker::GetOatMethodFor(mirror::ArtMethod* method)
GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(),
method->GetDeclaringClass()->GetDexClassDefIndex(),
method->GetDexMethodIndex()));
- const OatFile::OatClass oat_class = GetOatClass(*declaring_class->GetDexCache()->GetDexFile(),
- declaring_class->GetDexClassDefIndex());
+ OatFile::OatClass oat_class;
+ if (!FindOatClass(*declaring_class->GetDexCache()->GetDexFile(),
+ declaring_class->GetDexClassDefIndex(),
+ &oat_class)) {
+ return false;
+ }
- return oat_class.GetOatMethod(oat_method_index);
+ *oat_method = oat_class.GetOatMethod(oat_method_index);
+ return true;
}
// Special case to get oat code without overwriting a trampoline.
@@ -2100,7 +2118,12 @@ const void* ClassLinker::GetQuickOatCodeFor(mirror::ArtMethod* method) {
if (method->IsProxyMethod()) {
return GetQuickProxyInvokeHandler();
}
- const void* result = GetOatMethodFor(method).GetQuickCode();
+ OatFile::OatMethod oat_method;
+ const void* result = nullptr;
+ if (FindOatMethodFor(method, &oat_method)) {
+ result = oat_method.GetQuickCode();
+ }
+
if (result == nullptr) {
if (method->IsNative()) {
// No code and native? Use generic trampoline.
@@ -2123,10 +2146,16 @@ const void* ClassLinker::GetPortableOatCodeFor(mirror::ArtMethod* method,
if (method->IsProxyMethod()) {
return GetPortableProxyInvokeHandler();
}
- const OatFile::OatMethod oat_method = GetOatMethodFor(method);
- const void* result = oat_method.GetPortableCode();
+ OatFile::OatMethod oat_method;
+ const void* result = nullptr;
+ const void* quick_code = nullptr;
+ if (FindOatMethodFor(method, &oat_method)) {
+ result = oat_method.GetPortableCode();
+ quick_code = oat_method.GetQuickCode();
+ }
+
if (result == nullptr) {
- if (oat_method.GetQuickCode() == nullptr) {
+ if (quick_code == nullptr) {
// No code? You must mean to go into the interpreter.
result = GetPortableToInterpreterBridge();
} else {
@@ -2141,14 +2170,20 @@ const void* ClassLinker::GetPortableOatCodeFor(mirror::ArtMethod* method,
const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx,
uint32_t method_idx) {
- const OatFile::OatClass oat_class = GetOatClass(dex_file, class_def_idx);
+ OatFile::OatClass oat_class;
+ if (!FindOatClass(dex_file, class_def_idx, &oat_class)) {
+ return nullptr;
+ }
uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx);
return oat_class.GetOatMethod(oat_method_idx).GetQuickCode();
}
const void* ClassLinker::GetPortableOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx,
uint32_t method_idx) {
- const OatFile::OatClass oat_class = GetOatClass(dex_file, class_def_idx);
+ OatFile::OatClass oat_class;
+ if (!FindOatClass(dex_file, class_def_idx, &oat_class)) {
+ return nullptr;
+ }
uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx);
return oat_class.GetOatMethod(oat_method_idx).GetPortableCode();
}
@@ -2191,7 +2226,6 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) {
const byte* class_data = dex_file.GetClassData(*dex_class_def);
// There should always be class data if there were direct methods.
CHECK(class_data != nullptr) << PrettyDescriptor(klass);
- const OatFile::OatClass oat_class = GetOatClass(dex_file, klass->GetDexClassDefIndex());
ClassDataItemIterator it(dex_file, class_data);
// Skip fields
while (it.HasNextStaticField()) {
@@ -2200,6 +2234,8 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) {
while (it.HasNextInstanceField()) {
it.Next();
}
+ OatFile::OatClass oat_class;
+ bool has_oat_class = FindOatClass(dex_file, klass->GetDexClassDefIndex(), &oat_class);
// Link the code of methods skipped by LinkCode.
for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) {
mirror::ArtMethod* method = klass->GetDirectMethod(method_index);
@@ -2207,8 +2243,13 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) {
// Only update static methods.
continue;
}
- const void* portable_code = oat_class.GetOatMethod(method_index).GetPortableCode();
- const void* quick_code = oat_class.GetOatMethod(method_index).GetQuickCode();
+ const void* portable_code = nullptr;
+ const void* quick_code = nullptr;
+ if (has_oat_class) {
+ OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+ portable_code = oat_method.GetPortableCode();
+ quick_code = oat_method.GetQuickCode();
+ }
const bool enter_interpreter = NeedsInterpreter(method, quick_code, portable_code);
bool have_portable_code = false;
if (enter_interpreter) {
@@ -2240,16 +2281,21 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) {
void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,
const DexFile& dex_file, uint32_t dex_method_index,
uint32_t method_index) {
+ if (Runtime::Current()->IsCompiler()) {
+ // The following code only applies to a non-compiler runtime.
+ return;
+ }
// Method shouldn't have already been linked.
DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
DCHECK(method->GetEntryPointFromPortableCompiledCode() == nullptr);
- // Every kind of method should at least get an invoke stub from the oat_method.
- // non-abstract methods also get their code pointers.
- const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
- oat_method.LinkMethod(method.Get());
+ if (oat_class != nullptr) {
+ // Every kind of method should at least get an invoke stub from the oat_method.
+ // non-abstract methods also get their code pointers.
+ const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index);
+ oat_method.LinkMethod(method.Get());
+ }
// Install entry point from interpreter.
- Runtime* runtime = Runtime::Current();
bool enter_interpreter = NeedsInterpreter(method.Get(),
method->GetEntryPointFromQuickCompiledCode(),
method->GetEntryPointFromPortableCompiledCode());
@@ -2303,6 +2349,7 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method, const OatFile::OatC
}
// Allow instrumentation its chance to hijack code.
+ Runtime* runtime = Runtime::Current();
runtime->GetInstrumentation()->UpdateMethodsCode(method.Get(),
method->GetEntryPointFromQuickCompiledCode(),
method->GetEntryPointFromPortableCompiledCode(),
@@ -2339,8 +2386,10 @@ void ClassLinker::LoadClass(const DexFile& dex_file,
return; // no fields or methods - for example a marker interface
}
- if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) {
- const OatFile::OatClass oat_class = GetOatClass(dex_file, klass->GetDexClassDefIndex());
+ OatFile::OatClass oat_class;
+ if (Runtime::Current()->IsStarted()
+ && !Runtime::Current()->UseCompileTimeClassPath()
+ && FindOatClass(dex_file, klass->GetDexClassDefIndex(), &oat_class)) {
LoadClassMembers(dex_file, class_data, klass, class_loader, &oat_class);
} else {
LoadClassMembers(dex_file, class_data, klass, class_loader, nullptr);
@@ -2423,9 +2472,7 @@ void ClassLinker::LoadClassMembers(const DexFile& dex_file,
return;
}
klass->SetDirectMethod(i, method.Get());
- if (oat_class != nullptr) {
- LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
- }
+ LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
method->SetMethodIndex(class_def_method_index);
class_def_method_index++;
}
@@ -2438,9 +2485,7 @@ void ClassLinker::LoadClassMembers(const DexFile& dex_file,
}
klass->SetVirtualMethod(i, method.Get());
DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
- if (oat_class != nullptr) {
- LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
- }
+ LinkCode(method, oat_class, dex_file, it.GetMemberIndex(), class_def_method_index);
class_def_method_index++;
}
DCHECK(!it.HasNext());
@@ -3221,7 +3266,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class
const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
// Make this work with gtests, which do not set up the image properly.
// TODO: we should clean up gtests to set up the image path properly.
- if (Runtime::Current()->IsCompiler() && (oat_file == NULL)) {
+ if (Runtime::Current()->IsCompiler() || (oat_file == NULL)) {
return false;
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 8c0904203b..6fc0f0e2f2 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -392,7 +392,7 @@ class ClassLinker {
}
private:
- const OatFile::OatMethod GetOatMethodFor(mirror::ArtMethod* method)
+ bool FindOatMethodFor(mirror::ArtMethod* method, OatFile::OatMethod* oat_method)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
OatFile& GetImageOatFile(gc::space::ImageSpace* space)
@@ -461,8 +461,9 @@ class ClassLinker {
void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Finds the associated oat class for a dex_file and descriptor
- OatFile::OatClass GetOatClass(const DexFile& dex_file, uint16_t class_def_idx)
+ // Finds the associated oat class for a dex_file and descriptor. Returns whether the class
+ // was found, and sets the data in oat_class.
+ bool FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, OatFile::OatClass* oat_class)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
@@ -742,6 +743,7 @@ class ClassLinker {
friend class ImageWriter; // for GetClassRoots
friend class ImageDumper; // for FindOpenedOatFileFromOatLocation
friend class ElfPatcher; // for FindOpenedOatFileForDexFile & FindOpenedOatFileFromOatLocation
+ friend class NoDex2OatTest; // for FindOpenedOatFileForDexFile
FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors);
FRIEND_TEST(mirror::DexCacheTest, Open);
FRIEND_TEST(ExceptionTest, FindExceptionHandler);
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index c3304e6670..f199c99599 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -114,7 +114,9 @@ static jlong DexFile_openDexFileNative(JNIEnv* env, jclass, jstring javaSourceNa
bool success = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,
dex_files.get());
- if (success) {
+ if (success || !dex_files->empty()) {
+ // In the case of non-success, we have not found or could not generate the oat file.
+ // But we may still have found a dex file that we can use.
return static_cast<jlong>(reinterpret_cast<uintptr_t>(dex_files.release()));
} else {
// The vector should be empty after a failed loading attempt.
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 9710a2addd..810eccb2d1 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -133,6 +133,8 @@ class OatFile {
const uint32_t code_offset,
const uint32_t gc_map_offset);
+ OatMethod() {}
+
private:
template<class T>
T GetOatPointer(uint32_t offset) const {
@@ -166,6 +168,8 @@ class OatFile {
// methods are not included.
const OatMethod GetOatMethod(uint32_t method_index) const;
+ OatClass() {}
+
private:
OatClass(const OatFile* oat_file,
mirror::Class::Status status,
@@ -174,13 +178,13 @@ class OatFile {
const uint32_t* bitmap_pointer,
const OatMethodOffsets* methods_pointer);
- const OatFile* const oat_file_;
+ const OatFile* oat_file_;
- const mirror::Class::Status status_;
+ mirror::Class::Status status_;
- const OatClassType type_;
+ OatClassType type_;
- const uint32_t* const bitmap_;
+ const uint32_t* bitmap_;
const OatMethodOffsets* methods_pointer_;
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 12f9f33f5f..3ef7a17615 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -223,6 +223,7 @@ bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognize
compiler_callbacks_ = nullptr;
is_zygote_ = false;
must_relocate_ = kDefaultMustRelocate;
+ dex2oat_enabled_ = true;
if (kPoisonHeapReferences) {
// kPoisonHeapReferences currently works only with the interpreter only.
// TODO: make it work with the compiler.
@@ -421,6 +422,10 @@ bool ParsedOptions::Parse(const RuntimeOptions& options, bool ignore_unrecognize
must_relocate_ = true;
} else if (option == "-Xnorelocate") {
must_relocate_ = false;
+ } else if (option == "-Xnodex2oat") {
+ dex2oat_enabled_ = false;
+ } else if (option == "-Xdex2oat") {
+ dex2oat_enabled_ = true;
} else if (option == "-Xint") {
interpreter_only_ = true;
} else if (StartsWith(option, "-Xgc:")) {
@@ -710,7 +715,7 @@ void ParsedOptions::Usage(const char* fmt, ...) {
UsageMessage(stream, "The following standard options are supported:\n");
UsageMessage(stream, " -classpath classpath (-cp classpath)\n");
UsageMessage(stream, " -Dproperty=value\n");
- UsageMessage(stream, " -verbose:tag ('gc', 'jni', or 'class')\n");
+ UsageMessage(stream, " -verbose:tag ('gc', 'jni', or 'class')\n");
UsageMessage(stream, " -showversion\n");
UsageMessage(stream, " -help\n");
UsageMessage(stream, " -agentlib:jdwp=options\n");
@@ -720,9 +725,9 @@ void ParsedOptions::Usage(const char* fmt, ...) {
UsageMessage(stream, " -Xrunjdwp:<options>\n");
UsageMessage(stream, " -Xbootclasspath:bootclasspath\n");
UsageMessage(stream, " -Xcheck:tag (e.g. 'jni')\n");
- UsageMessage(stream, " -XmsN (min heap, must be multiple of 1K, >= 1MB)\n");
- UsageMessage(stream, " -XmxN (max heap, must be multiple of 1K, >= 2MB)\n");
- UsageMessage(stream, " -XssN (stack size)\n");
+ UsageMessage(stream, " -XmsN (min heap, must be multiple of 1K, >= 1MB)\n");
+ UsageMessage(stream, " -XmxN (max heap, must be multiple of 1K, >= 2MB)\n");
+ UsageMessage(stream, " -XssN (stack size)\n");
UsageMessage(stream, " -Xint\n");
UsageMessage(stream, "\n");
@@ -776,6 +781,7 @@ void ParsedOptions::Usage(const char* fmt, ...) {
UsageMessage(stream, " -Ximage-compiler-option dex2oat-option\n");
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, "\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 c328ca7ef5..aa2c55713e 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -50,6 +50,7 @@ class ParsedOptions {
CompilerCallbacks* compiler_callbacks_;
bool is_zygote_;
bool must_relocate_;
+ bool 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 d677729b7e..d3957c1e9f 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -101,6 +101,7 @@ Runtime::Runtime()
must_relocate_(false),
is_concurrent_gc_enabled_(true),
is_explicit_gc_disabled_(false),
+ dex2oat_enabled_(true),
default_stack_size_(0),
heap_(nullptr),
max_spins_before_thin_lock_inflation_(Monitor::kDefaultMaxSpinsBeforeThinLockInflation),
@@ -556,6 +557,7 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized)
must_relocate_ = options->must_relocate_;
is_zygote_ = options->is_zygote_;
is_explicit_gc_disabled_ = options->is_explicit_gc_disabled_;
+ dex2oat_enabled_ = options->dex2oat_enabled_;
vfprintf_ = options->hook_vfprintf_;
exit_ = options->hook_exit_;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index a85c2e4eda..e76280ae95 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -105,6 +105,10 @@ class Runtime {
return must_relocate_;
}
+ bool IsDex2OatEnabled() const {
+ return dex2oat_enabled_;
+ }
+
CompilerCallbacks* GetCompilerCallbacks() {
return compiler_callbacks_;
}
@@ -503,6 +507,7 @@ class Runtime {
bool must_relocate_;
bool is_concurrent_gc_enabled_;
bool is_explicit_gc_disabled_;
+ bool dex2oat_enabled_;
std::string compiler_executable_;
std::string patchoat_executable_;
diff --git a/test/116-nodex2oat/expected.txt b/test/116-nodex2oat/expected.txt
new file mode 100644
index 0000000000..05b1c2f387
--- /dev/null
+++ b/test/116-nodex2oat/expected.txt
@@ -0,0 +1,6 @@
+Run -Xnodex2oat
+Has oat is false, is dex2oat enabled is false.
+Run -Xdex2oat
+Has oat is true, is dex2oat enabled is true.
+Run default
+Has oat is true, is dex2oat enabled is true.
diff --git a/test/116-nodex2oat/info.txt b/test/116-nodex2oat/info.txt
new file mode 100644
index 0000000000..f063d9f12e
--- /dev/null
+++ b/test/116-nodex2oat/info.txt
@@ -0,0 +1 @@
+Test that disables dex2oat'ing the application.
diff --git a/test/116-nodex2oat/nodex2oat.cc b/test/116-nodex2oat/nodex2oat.cc
new file mode 100644
index 0000000000..4326db0e54
--- /dev/null
+++ b/test/116-nodex2oat/nodex2oat.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_hasOat(JNIEnv*, jclass cls) {
+ return NoDex2OatTest::hasOat(cls);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isDex2OatEnabled(JNIEnv*, jclass cls) {
+ return Runtime::Current()->IsDex2OatEnabled();
+}
+
+} // namespace art
diff --git a/test/116-nodex2oat/run b/test/116-nodex2oat/run
new file mode 100755
index 0000000000..5ffeecdbb1
--- /dev/null
+++ b/test/116-nodex2oat/run
@@ -0,0 +1,30 @@
+#!/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.
+
+# Remove prebuild from the flags, this test is for testing not having oat files.
+flags="${@/--prebuild/}"
+
+# Make sure we can run without an oat file,
+echo "Run -Xnodex2oat"
+${RUN} ${flags} --runtime-option -Xnodex2oat
+
+# Make sure we can run with the oat file.
+echo "Run -Xdex2oat"
+${RUN} ${flags} --runtime-option -Xdex2oat
+
+# Make sure we can run with the default settings.
+echo "Run default"
+${RUN} ${flags}
diff --git a/test/116-nodex2oat/src/Main.java b/test/116-nodex2oat/src/Main.java
new file mode 100644
index 0000000000..37ac9d5b78
--- /dev/null
+++ b/test/116-nodex2oat/src/Main.java
@@ -0,0 +1,36 @@
+/*
+ * 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) {
+ System.out.println(
+ "Has oat is " + hasOat() + ", is dex2oat enabled is " + isDex2OatEnabled() + ".");
+
+ if (hasOat() && !isDex2OatEnabled()) {
+ throw new Error("Application with dex2oat disabled runs with an oat file");
+ } else if (!hasOat() && isDex2OatEnabled()) {
+ throw new Error("Application with dex2oat enabled runs without an oat file");
+ }
+ }
+
+ static {
+ System.loadLibrary("arttest");
+ }
+
+ private native static boolean hasOat();
+
+ private native static boolean isDex2OatEnabled();
+}
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index f3563a4af0..3871b28ec1 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -23,7 +23,8 @@ LIBARTTEST_COMMON_SRC_FILES := \
004-SignalTest/signaltest.cc \
004-ReferenceMap/stack_walk_refmap_jni.cc \
004-StackWalk/stack_walk_jni.cc \
- 004-UnsafeTest/unsafe_test.cc
+ 004-UnsafeTest/unsafe_test.cc \
+ 116-nodex2oat/nodex2oat.cc
ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
ifdef TARGET_2ND_ARCH