Merge "Re-enable tests with the optimizing compiler."
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 21ba962..5cfdbfd 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -121,10 +121,10 @@
   ART_HOST_CLANG := true
 endif
 
-# Clang on the target: only enabled for ARM64. Target builds use GCC by default.
+# Clang on the target. Target builds use GCC by default.
 ART_TARGET_CLANG :=
 ART_TARGET_CLANG_arm :=
-ART_TARGET_CLANG_arm64 := true
+ART_TARGET_CLANG_arm64 :=
 ART_TARGET_CLANG_mips :=
 ART_TARGET_CLANG_x86 :=
 ART_TARGET_CLANG_x86_64 :=
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 69d6c5a..45bdbcb 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -45,21 +45,21 @@
   $(ART_TARGET_NATIVETEST_OUT),art/build/Android.gtest.mk,ART_GTEST_$(dir)_DEX)))
 
 # Dex file dependencies for each gtest.
-ART_GTEST_class_linker_test_DEPS := Interfaces MyClass Nested Statics StaticsFromCode
-ART_GTEST_compiler_driver_test_DEPS := AbstractMethod
-ART_GTEST_dex_file_test_DEPS := GetMethodSignature
-ART_GTEST_exception_test_DEPS := ExceptionHandle
-ART_GTEST_jni_compiler_test_DEPS := MyClassNatives
-ART_GTEST_jni_internal_test_DEPS := AllFields StaticLeafMethods
-ART_GTEST_object_test_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
-ART_GTEST_proxy_test_DEPS := Interfaces
-ART_GTEST_reflection_test_DEPS := Main NonStaticLeafMethods StaticLeafMethods
-ART_GTEST_stub_test_DEPS := AllFields
-ART_GTEST_transaction_test_DEPS := Transaction
+ART_GTEST_class_linker_test_DEX_DEPS := Interfaces MyClass Nested Statics StaticsFromCode
+ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod
+ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature
+ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
+ART_GTEST_jni_compiler_test_DEX_DEPS := MyClassNatives
+ART_GTEST_jni_internal_test_DEX_DEPS := AllFields StaticLeafMethods
+ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY
+ART_GTEST_proxy_test_DEX_DEPS := Interfaces
+ART_GTEST_reflection_test_DEX_DEPS := Main NonStaticLeafMethods StaticLeafMethods
+ART_GTEST_stub_test_DEX_DEPS := AllFields
+ART_GTEST_transaction_test_DEX_DEPS := Transaction
 
 # The elf writer test has dependencies on core.oat.
-ART_GTEST_elf_writer_test_DEPS := $(HOST_CORE_OAT_OUT) $(2ND_HOST_CORE_OAT_OUT) \
-  $(TARGET_CORE_OAT_OUT) $(2ND_TARGET_CORE_OAT_OUT)
+ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_OAT_OUT) $(2ND_HOST_CORE_OAT_OUT)
+ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_OAT_OUT) $(2ND_TARGET_CORE_OAT_OUT)
 
 # The path for which all the source files are relative, not actually the current directory.
 LOCAL_PATH := art
@@ -194,7 +194,8 @@
   # Add the test dependencies to test-art-target-sync, which will be a prerequisite for the test
   # to ensure files are pushed to the device.
   TEST_ART_TARGET_SYNC_DEPS += \
-    $(foreach file,$(ART_GTEST_$(1)_DEPS),$(ART_GTEST_$(file)_DEX)) \
+    $$(ART_GTEST_$(1)_TARGET_DEPS) \
+    $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_GTEST_$(file)_DEX)) \
     $$(ART_TARGET_NATIVETEST_OUT)/$$(TARGET_$(2)ARCH)/$(1) \
     $$($(2)TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
 
@@ -230,7 +231,7 @@
 
 
 .PHONY: $$(gtest_rule)
-$$(gtest_rule): $$(gtest_exe) $(foreach file,$(ART_GTEST_$(1)_DEPS),$(ART_GTEST_$(file)_DEX-host)) $$(gtest_deps)
+$$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_HOST_DEPS) $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_GTEST_$(file)_DEX-host)) $$(gtest_deps)
 	$(hide) ($$(call ART_TEST_SKIP,$$@) && $$< && $$(call ART_TEST_PASSED,$$@)) \
 	  || $$(call ART_TEST_FAILED,$$@)
 
@@ -239,7 +240,7 @@
   ART_TEST_HOST_GTEST_$(1)_RULES += $$(gtest_rule)
 
 .PHONY: valgrind-$$(gtest_rule)
-valgrind-$$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_DEPS) $$(gtest_deps)
+valgrind-$$(gtest_rule): $$(gtest_exe) $$(ART_GTEST_$(1)_HOST_DEPS) $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_GTEST_$(file)_DEX-host)) $$(gtest_deps)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
 	  valgrind --leak-check=full --error-exitcode=1 $$< && $$(call ART_TEST_PASSED,$$@) \
 	    || $$(call ART_TEST_FAILED,$$@)
@@ -444,17 +445,19 @@
 ART_TEST_TARGET_GTEST$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
 ART_TEST_TARGET_GTEST_RULES :=
-ART_GTEST_class_linker_test_DEPS :=
-ART_GTEST_compiler_driver_test_DEPS :=
-ART_GTEST_dex_file_test_DEPS :=
-ART_GTEST_exception_test_DEPS :=
-ART_GTEST_jni_compiler_test_DEPS :=
-ART_GTEST_jni_internal_test_DEPS :=
-ART_GTEST_object_test_DEPS :=
-ART_GTEST_proxy_test_DEPS :=
-ART_GTEST_reflection_test_DEPS :=
-ART_GTEST_stub_test_DEPS :=
-ART_GTEST_transaction_test_DEPS :=
+ART_GTEST_class_linker_test_DEX_DEPS :=
+ART_GTEST_compiler_driver_test_DEX_DEPS :=
+ART_GTEST_dex_file_test_DEX_DEPS :=
+ART_GTEST_exception_test_DEX_DEPS :=
+ART_GTEST_elf_writer_test_HOST_DEPS :=
+ART_GTEST_elf_writer_test_TARGET_DEPS :=
+ART_GTEST_jni_compiler_test_DEX_DEPS :=
+ART_GTEST_jni_internal_test_DEX_DEPS :=
+ART_GTEST_object_test_DEX_DEPS :=
+ART_GTEST_proxy_test_DEX_DEPS :=
+ART_GTEST_reflection_test_DEX_DEPS :=
+ART_GTEST_stub_test_DEX_DEPS :=
+ART_GTEST_transaction_test_DEX_DEPS :=
 $(foreach dir,$(GTEST_DEX_DIRECTORIES), $(eval ART_GTEST_TEST_$(dir)_DEX :=))
 GTEST_DEX_DIRECTORIES :=
 LOCAL_PATH :=
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index e8bbaef..d52ec0a 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -129,11 +129,7 @@
   runtime_.reset();
   java_lang_dex_file_ = NULL;
 
-  std::string error_msg;
-  std::unique_ptr<const DexFile> dex(DexFile::Open(GetLibCoreDexFileName().c_str(),
-                                             GetLibCoreDexFileName().c_str(),
-                                             &error_msg));
-  ASSERT_TRUE(dex.get() != nullptr) << error_msg;
+  std::unique_ptr<const DexFile> dex(LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str()));
 
   // Remove the reservation of the memory for use to load the image.
   UnreserveImageSpace();
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 2d55140..de2960c 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -478,11 +478,8 @@
         continue;
       }
       std::string error_msg;
-      const DexFile* dex_file = DexFile::Open(parsed[i].c_str(), parsed[i].c_str(), &error_msg);
-      if (dex_file == nullptr) {
+      if (!DexFile::Open(parsed[i].c_str(), parsed[i].c_str(), &error_msg, &dex_files)) {
         LOG(WARNING) << "Failed to open dex file '" << parsed[i] << "': " << error_msg;
-      } else {
-        dex_files.push_back(dex_file);
       }
     }
   }
@@ -536,12 +533,9 @@
       LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
       continue;
     }
-    const DexFile* dex_file = DexFile::Open(dex_filename, dex_location, &error_msg);
-    if (dex_file == nullptr) {
+    if (!DexFile::Open(dex_filename, dex_location, &error_msg, &dex_files)) {
       LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
       ++failure_count;
-    } else {
-      dex_files.push_back(dex_file);
     }
     ATRACE_END();
   }
@@ -1319,13 +1313,11 @@
             << error_msg;
         return EXIT_FAILURE;
       }
-      const DexFile* dex_file = DexFile::Open(*zip_archive.get(), zip_location, &error_msg);
-      if (dex_file == nullptr) {
+      if (!DexFile::OpenFromZip(*zip_archive.get(), zip_location, &error_msg, &dex_files)) {
         LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location
             << "': " << error_msg;
         return EXIT_FAILURE;
       }
-      dex_files.push_back(dex_file);
       ATRACE_END();
     } else {
       size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, dex_files);
diff --git a/runtime/arch/arm64/memcmp.S b/runtime/arch/arm64/memcmp.S
index 3d08ecd..d73fb67 100644
--- a/runtime/arch/arm64/memcmp.S
+++ b/runtime/arch/arm64/memcmp.S
@@ -1,29 +1,18 @@
-/* Copyright (c) 2014, Linaro Limited
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or without
-   modification, are permitted provided that the following conditions are met:
-       * Redistributions of source code must retain the above copyright
-         notice, this list of conditions and the following disclaimer.
-       * Redistributions in binary form must reproduce the above copyright
-         notice, this list of conditions and the following disclaimer in the
-         documentation and/or other materials provided with the distribution.
-       * Neither the name of the Linaro nor the
-         names of its contributors may be used to endorse or promote products
-         derived from this software without specific prior written permission.
-
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-   HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
+/*
+ * 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.
+ */
 
 /* Assumptions:
  *
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 22b8cca..a31c08b 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -258,7 +258,7 @@
           "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
           "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
           "memory");  // clobber.
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) && !defined(__APPLE__)
     // Note: Uses the native convention
     // TODO: Set the thread?
     __asm__ __volatile__(
@@ -483,7 +483,7 @@
           "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
           "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
           "memory");  // clobber.
-#elif defined(__x86_64__)
+#elif defined(__x86_64__) && !defined(__APPLE__)
     // Note: Uses the native convention
     // TODO: Set the thread?
     __asm__ __volatile__(
@@ -518,7 +518,7 @@
   // Method with 32b arg0, 64b arg1
   size_t Invoke3UWithReferrer(size_t arg0, uint64_t arg1, uintptr_t code, Thread* self,
                               mirror::ArtMethod* referrer) {
-#if defined(__x86_64__) || defined(__aarch64__)
+#if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
     // Just pass through.
     return Invoke3WithReferrer(arg0, arg1, 0U, code, self, referrer);
 #else
@@ -533,7 +533,7 @@
   // Method with 32b arg0, 32b arg1, 64b arg2
   size_t Invoke3UUWithReferrer(uint32_t arg0, uint32_t arg1, uint64_t arg2, uintptr_t code,
                                Thread* self, mirror::ArtMethod* referrer) {
-#if defined(__x86_64__) || defined(__aarch64__)
+#if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
     // Just pass through.
     return Invoke3WithReferrer(arg0, arg1, arg2, code, self, referrer);
 #else
@@ -547,12 +547,12 @@
 };
 
 
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_memcpy(void);
 #endif
 
 TEST_F(StubTest, Memcpy) {
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || (defined(__x86_64__) && !defined(__APPLE__))
   Thread* self = Thread::Current();
 
   uint32_t orig[20];
@@ -588,12 +588,12 @@
 #endif
 }
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_lock_object(void);
 #endif
 
 TEST_F(StubTest, LockObject) {
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   static constexpr size_t kThinLockLoops = 100;
 
   Thread* self = Thread::Current();
@@ -664,14 +664,14 @@
 };
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_lock_object(void);
 extern "C" void art_quick_unlock_object(void);
 #endif
 
 // NO_THREAD_SAFETY_ANALYSIS as we do not want to grab exclusive mutator lock for MonitorInfo.
 static void TestUnlockObject(StubTest* test) NO_THREAD_SAFETY_ANALYSIS {
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   static constexpr size_t kThinLockLoops = 100;
 
   Thread* self = Thread::Current();
@@ -817,12 +817,12 @@
   TestUnlockObject(this);
 }
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_check_cast(void);
 #endif
 
 TEST_F(StubTest, CheckCast) {
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   Thread* self = Thread::Current();
   // Find some classes.
   ScopedObjectAccess soa(self);
@@ -867,7 +867,7 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_aput_obj_with_null_and_bound_check(void);
 // Do not check non-checked ones, we'd need handlers and stuff...
 #endif
@@ -875,7 +875,7 @@
 TEST_F(StubTest, APutObj) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   Thread* self = Thread::Current();
   // Create an object
   ScopedObjectAccess soa(self);
@@ -1003,7 +1003,7 @@
 TEST_F(StubTest, AllocObject) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   // TODO: Check the "Unresolved" allocation stubs
 
   Thread* self = Thread::Current();
@@ -1125,7 +1125,7 @@
 TEST_F(StubTest, AllocObjectArray) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   // TODO: Check the "Unresolved" allocation stubs
 
   Thread* self = Thread::Current();
@@ -1204,14 +1204,14 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_string_compareto(void);
 #endif
 
 TEST_F(StubTest, StringCompareTo) {
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   // TODO: Check the "Unresolved" allocation stubs
 
   Thread* self = Thread::Current();
@@ -1301,7 +1301,7 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_set32_static(void);
 extern "C" void art_quick_get32_static(void);
 #endif
@@ -1309,7 +1309,7 @@
 static void GetSet32Static(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   constexpr size_t num_values = 7;
   uint32_t values[num_values] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF };
 
@@ -1337,7 +1337,7 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_set32_instance(void);
 extern "C" void art_quick_get32_instance(void);
 #endif
@@ -1345,7 +1345,7 @@
 static void GetSet32Instance(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f,
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   constexpr size_t num_values = 7;
   uint32_t values[num_values] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF };
 
@@ -1379,7 +1379,7 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_set_obj_static(void);
 extern "C" void art_quick_get_obj_static(void);
 
@@ -1406,7 +1406,7 @@
 static void GetSetObjStatic(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
                             mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   set_and_check_static((*f)->GetDexFieldIndex(), nullptr, self, referrer, test);
 
   // Allocate a string object for simplicity.
@@ -1422,7 +1422,7 @@
 }
 
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_set_obj_instance(void);
 extern "C" void art_quick_get_obj_instance(void);
 
@@ -1453,7 +1453,7 @@
 static void GetSetObjInstance(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f,
                               Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   set_and_check_instance(f, obj->Get(), nullptr, self, referrer, test);
 
   // Allocate a string object for simplicity.
@@ -1471,7 +1471,7 @@
 
 // TODO: Complete these tests for 32b architectures.
 
-#if defined(__x86_64__) || defined(__aarch64__)
+#if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
 extern "C" void art_quick_set64_static(void);
 extern "C" void art_quick_get64_static(void);
 #endif
@@ -1479,7 +1479,7 @@
 static void GetSet64Static(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f, Thread* self,
                            mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if defined(__x86_64__) || defined(__aarch64__)
+#if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
   constexpr size_t num_values = 8;
   uint64_t values[num_values] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF, 0xFFFFFFFFFFFF };
 
@@ -1506,7 +1506,7 @@
 }
 
 
-#if defined(__x86_64__) || defined(__aarch64__)
+#if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
 extern "C" void art_quick_set64_instance(void);
 extern "C" void art_quick_get64_instance(void);
 #endif
@@ -1514,7 +1514,7 @@
 static void GetSet64Instance(Handle<mirror::Object>* obj, Handle<mirror::ArtField>* f,
                              Thread* self, mirror::ArtMethod* referrer, StubTest* test)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if defined(__x86_64__) || defined(__aarch64__)
+#if (defined(__x86_64__) && !defined(__APPLE__)) || defined(__aarch64__)
   constexpr size_t num_values = 8;
   uint64_t values[num_values] = { 0, 1, 2, 255, 32768, 1000000, 0xFFFFFFFF, 0xFFFFFFFFFFFF };
 
@@ -1678,12 +1678,12 @@
   TestFields(self, this, Primitive::Type::kPrimLong);
 }
 
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
 extern "C" void art_quick_imt_conflict_trampoline(void);
 #endif
 
 TEST_F(StubTest, IMT) {
-#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || (defined(__x86_64__) && !defined(__APPLE__))
   TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
 
   Thread* self = Thread::Current();
diff --git a/runtime/arch/x86_64/asm_support_x86_64.S b/runtime/arch/x86_64/asm_support_x86_64.S
index 34c8b82..70c71c2 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.S
+++ b/runtime/arch/x86_64/asm_support_x86_64.S
@@ -19,7 +19,7 @@
 
 #include "asm_support_x86_64.h"
 
-#if defined(__clang__) && (__clang_major__ < 4) && (__clang_minor__ < 5)
+#if defined(__APPLE__) || (defined(__clang__) && (__clang_major__ < 4) && (__clang_minor__ < 5))
     // Clang's as(1) doesn't let you name macro parameters prior to 3.5.
     #define MACRO0(macro_name) .macro macro_name
     #define MACRO1(macro_name, macro_arg1) .macro macro_name
@@ -27,13 +27,12 @@
     #define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name
     #define END_MACRO .endmacro
 
-    // Clang's as(1) uses $0, $1, and so on for macro arguments prior to 3.5.
+    // Clang's as(1) uses $0, $1, and so on for macro arguments.
+    #define RAW_VAR(name,index) $index
     #define VAR(name,index) SYMBOL($index)
-    #define PLT_VAR(name, index) SYMBOL($index)@PLT
+    #define PLT_VAR(name, index) PLT_SYMBOL($index)
     #define REG_VAR(name,index) %$index
     #define CALL_MACRO(name,index) $index
-    #define FUNCTION_TYPE(name,index) .type $index, @function
-    #define SIZE(name,index) .size $index, .-$index
 
     //  The use of $x for arguments mean that literals need to be represented with $$x in macros.
     #define LITERAL(value) $value
@@ -52,17 +51,27 @@
     // no special meaning to $, so literals are still just $x. The use of altmacro means % is a
     // special character meaning care needs to be taken when passing registers as macro arguments.
     .altmacro
+    #define RAW_VAR(name,index) name&
     #define VAR(name,index) name&
     #define PLT_VAR(name, index) name&@PLT
     #define REG_VAR(name,index) %name
     #define CALL_MACRO(name,index) name&
-    #define FUNCTION_TYPE(name,index) .type name&, @function
-    #define SIZE(name,index) .size name, .-name
 
     #define LITERAL(value) $value
     #define MACRO_LITERAL(value) $value
 #endif
 
+#if defined(__APPLE__)
+    #define FUNCTION_TYPE(name,index)
+    #define SIZE(name,index)
+#elif defined(__clang__) && (__clang_major__ < 4) && (__clang_minor__ < 5)
+    #define FUNCTION_TYPE(name,index) .type $index, @function
+    #define SIZE(name,index) .size $index, .-$index
+#else
+    #define FUNCTION_TYPE(name,index) .type name&, @function
+    #define SIZE(name,index) .size name, .-name
+#endif
+
     // CFI support.
 #if !defined(__APPLE__)
     #define CFI_STARTPROC .cfi_startproc
@@ -86,9 +95,14 @@
     // Symbols.
 #if !defined(__APPLE__)
     #define SYMBOL(name) name
-    #define PLT_SYMBOL(name) name ## @PLT
+    #if defined(__clang__) && (__clang_major__ < 4) && (__clang_minor__ < 5)
+        // TODO: Disabled for old clang 3.3, this leads to text relocations and there should be a
+        // better fix.
+        #define PLT_SYMBOL(name) name // ## @PLT
+    #else
+        #define PLT_SYMBOL(name) name ## @PLT
+    #endif
 #else
-    // Mac OS' symbols have an _ prefix.
     #define SYMBOL(name) _ ## name
     #define PLT_SYMBOL(name) _ ## name
 #endif
@@ -103,8 +117,10 @@
     .globl VAR(c_name, 0)
     ALIGN_FUNCTION_ENTRY
 VAR(c_name, 0):
+#if !defined(__APPLE__)
     // Have a local entrypoint that's not globl
 VAR(c_name, 0)_local:
+#endif
     CFI_STARTPROC
     // Ensure we get a sane starting CFA.
     CFI_DEF_CFA(rsp, 8)
diff --git a/runtime/arch/x86_64/context_x86_64.cc b/runtime/arch/x86_64/context_x86_64.cc
index 0ccbd27..e1f47ee 100644
--- a/runtime/arch/x86_64/context_x86_64.cc
+++ b/runtime/arch/x86_64/context_x86_64.cc
@@ -59,8 +59,8 @@
     size_t j = 2;  // Offset j to skip return address spill.
     for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) {
       if (((frame_info.FpSpillMask() >> i) & 1) != 0) {
-        fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j,
-                                        frame_info.FrameSizeInBytes());
+        fprs_[i] = reinterpret_cast<uint64_t*>(
+            fr.CalleeSaveAddress(spill_count + fp_spill_count - j, frame_info.FrameSizeInBytes()));
         j++;
       }
     }
@@ -93,7 +93,7 @@
 
 bool X86_64Context::SetFPR(uint32_t reg, uintptr_t value) {
   CHECK_LT(reg, static_cast<uint32_t>(kNumberOfFloatRegisters));
-  CHECK_NE(fprs_[reg], &gZero);
+  CHECK_NE(fprs_[reg], reinterpret_cast<const uint64_t*>(&gZero));
   if (fprs_[reg] != nullptr) {
     *fprs_[reg] = value;
     return true;
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index 92aabee..b6f51f7 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -112,6 +112,9 @@
 
 void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
                      PortableEntryPoints* ppoints, QuickEntryPoints* qpoints) {
+#if defined(__APPLE__)
+  UNIMPLEMENTED(FATAL);
+#else
   // Interpreter
   ipoints->pInterpreterToInterpreterBridge = artInterpreterToInterpreterBridge;
   ipoints->pInterpreterToCompiledCodeBridge = artInterpreterToCompiledCodeBridge;
@@ -216,6 +219,7 @@
   qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method;
   qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception;
   qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow;
+#endif  // __APPLE__
 };
 
 }  // namespace art
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index c9220c8..668fb88 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -23,6 +23,10 @@
      * Runtime::CreateCalleeSaveMethod(kSaveAll)
      */
 MACRO0(SETUP_SAVE_ALL_CALLEE_SAVE_FRAME)
+#if defined(__APPLE__)
+    int3
+    int3
+#else
     // R10 := Runtime::Current()
     movq _ZN3art7Runtime9instance_E@GOTPCREL(%rip), %r10
     movq (%r10), %r10
@@ -45,6 +49,7 @@
 #if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 6*8 + 8 + 8)
 #error "SAVE_ALL_CALLEE_SAVE_FRAME(X86_64) size not as expected."
 #endif
+#endif  // __APPLE__
 END_MACRO
 
     /*
@@ -52,6 +57,10 @@
      * Runtime::CreateCalleeSaveMethod(kRefsOnly)
      */
 MACRO0(SETUP_REF_ONLY_CALLEE_SAVE_FRAME)
+#if defined(__APPLE__)
+    int3
+    int3
+#else
     // R10 := Runtime::Current()
     movq _ZN3art7Runtime9instance_E@GOTPCREL(%rip), %r10
     movq (%r10), %r10
@@ -74,6 +83,7 @@
 #if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 6*8 + 8 + 8)
 #error "REFS_ONLY_CALLEE_SAVE_FRAME(X86_64) size not as expected."
 #endif
+#endif  // __APPLE__
 END_MACRO
 
 MACRO0(RESTORE_REF_ONLY_CALLEE_SAVE_FRAME)
@@ -93,6 +103,10 @@
      * Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
      */
 MACRO0(SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME)
+#if defined(__APPLE__)
+    int3
+    int3
+#else
     // R10 := Runtime::Current()
     movq _ZN3art7Runtime9instance_E@GOTPCREL(%rip), %r10
     movq (%r10), %r10
@@ -130,6 +144,7 @@
 #if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 11*8 + 80 + 8)
 #error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(X86_64) size not as expected."
 #endif
+#endif  // __APPLE__
 END_MACRO
 
 MACRO0(RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME)
@@ -366,6 +381,10 @@
      *   r9 = char* shorty
      */
 DEFINE_FUNCTION art_quick_invoke_stub
+#if defined(__APPLE__)
+    int3
+    int3
+#else
     // Set up argument XMM registers.
     leaq 1(%r9), %r10             // R10 := shorty + 1  ; ie skip return arg character.
     leaq 4(%rsi), %r11            // R11 := arg_array + 4 ; ie skip this pointer.
@@ -431,6 +450,7 @@
 .Lreturn_float_quick:
     movss %xmm0, (%r8)           // Store the floating point result.
     ret
+#endif  // __APPLE__
 END_FUNCTION art_quick_invoke_stub
 
     /*
@@ -445,6 +465,10 @@
      *   r9 = char* shorty
      */
 DEFINE_FUNCTION art_quick_invoke_static_stub
+#if defined(__APPLE__)
+    int3
+    int3
+#else
     // Set up argument XMM registers.
     leaq 1(%r9), %r10             // R10 := shorty + 1  ; ie skip return arg character
     movq %rsi, %r11               // R11 := arg_array
@@ -509,6 +533,7 @@
 .Lreturn_float_quick2:
     movss %xmm0, (%r8)           // Store the floating point result.
     ret
+#endif  // __APPLE__
 END_FUNCTION art_quick_invoke_static_stub
 
 MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
@@ -559,6 +584,45 @@
     END_FUNCTION VAR(c_name, 0)
 END_MACRO
 
+MACRO3(ONE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
+    DEFINE_FUNCTION VAR(c_name, 0)
+    movl 8(%rsp), %esi                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // arg0 is in rdi
+    movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
+    movq %rsp, %rcx                    // pass SP
+    call PLT_VAR(cxx_name, 1)          // cxx_name(arg0, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    CALL_MACRO(return_macro, 2)
+    END_FUNCTION VAR(c_name, 0)
+END_MACRO
+
+MACRO3(TWO_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
+    DEFINE_FUNCTION VAR(c_name, 0)
+    movl 8(%rsp), %edx                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // arg0 and arg1 are in rdi/rsi
+    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
+    movq %rsp, %r8                     // pass SP
+    call PLT_VAR(cxx_name, 1)          // (arg0, arg1, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    CALL_MACRO(return_macro, 2)
+    END_FUNCTION VAR(c_name, 0)
+END_MACRO
+
+MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
+    DEFINE_FUNCTION VAR(c_name, 0)
+    movl 8(%rsp), %ecx                 // pass referrer
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
+                                       // arg0, arg1, and arg2 are in rdi/rsi/rdx
+    movq %gs:THREAD_SELF_OFFSET, %r8    // pass Thread::Current()
+    movq %rsp, %r9                     // pass SP
+    call PLT_VAR(cxx_name, 1)          // cxx_name(arg0, arg1, arg2, referrer, Thread*, SP)
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
+    CALL_MACRO(return_macro, 2)        // return or deliver exception
+    END_FUNCTION VAR(c_name, 0)
+END_MACRO
+
 MACRO0(RETURN_IF_RESULT_IS_NON_ZERO)
     testq %rax, %rax               // rax == 0 ?
     jz  1f                         // if rax == 0 goto 1
@@ -783,14 +847,23 @@
      * rdi(edi) = array, rsi(esi) = index, rdx(edx) = value
      */
 DEFINE_FUNCTION art_quick_aput_obj_with_null_and_bound_check
+#if defined(__APPLE__)
+    int3
+    int3
+#else
     testl %edi, %edi
 //  testq %rdi, %rdi
     jnz art_quick_aput_obj_with_bound_check_local
     jmp art_quick_throw_null_pointer_exception_local
+#endif  // __APPLE__
 END_FUNCTION art_quick_aput_obj_with_null_and_bound_check
 
 
 DEFINE_FUNCTION art_quick_aput_obj_with_bound_check
+#if defined(__APPLE__)
+    int3
+    int3
+#else
     movl ARRAY_LENGTH_OFFSET(%edi), %ecx
 //  movl ARRAY_LENGTH_OFFSET(%rdi), %ecx      // This zero-extends, so value(%rcx)=value(%ecx)
     cmpl %ecx, %esi
@@ -800,6 +873,7 @@
     mov %ecx, %esi
 //  mov %rcx, %rsi
     jmp art_quick_throw_array_bounds_local
+#endif  // __APPLE__
 END_FUNCTION art_quick_aput_obj_with_bound_check
 
 
@@ -894,47 +968,6 @@
 UNIMPLEMENTED art_quick_lshr
 UNIMPLEMENTED art_quick_lushr
 
-
-MACRO3(ONE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
-    DEFINE_FUNCTION VAR(c_name, 0)
-    movl 8(%rsp), %esi                 // pass referrer
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-                                       // arg0 is in rdi
-    movq %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
-    movq %rsp, %rcx                    // pass SP
-    call PLT_VAR(cxx_name, 1)          // cxx_name(arg0, referrer, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
-    CALL_MACRO(return_macro, 2)
-    END_FUNCTION VAR(c_name, 0)
-END_MACRO
-
-MACRO3(TWO_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
-    DEFINE_FUNCTION VAR(c_name, 0)
-    movl 8(%rsp), %edx                 // pass referrer
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-                                       // arg0 and arg1 are in rdi/rsi
-    movq %gs:THREAD_SELF_OFFSET, %rcx  // pass Thread::Current()
-    movq %rsp, %r8                     // pass SP
-    call PLT_VAR(cxx_name, 1)          // (arg0, arg1, referrer, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
-    CALL_MACRO(return_macro, 2)
-    END_FUNCTION VAR(c_name, 0)
-END_MACRO
-
-MACRO3(THREE_ARG_REF_DOWNCALL, c_name, cxx_name, return_macro)
-    DEFINE_FUNCTION VAR(c_name, 0)
-    movl 8(%rsp), %ecx                 // pass referrer
-    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-                                       // arg0, arg1, and arg2 are in rdi/rsi/rdx
-    movq %gs:THREAD_SELF_OFFSET, %r8    // pass Thread::Current()
-    movq %rsp, %r9                     // pass SP
-    call PLT_VAR(cxx_name, 1)          // cxx_name(arg0, arg1, arg2, referrer, Thread*, SP)
-    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME // restore frame up to return address
-    CALL_MACRO(return_macro, 2)        // return or deliver exception
-    END_FUNCTION VAR(c_name, 0)
-END_MACRO
-
-
 THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_EAX_ZERO
 THREE_ARG_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCode, RETURN_IF_EAX_ZERO
 THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_EAX_ZERO
@@ -1006,10 +1039,15 @@
      * rax is a hidden argument that holds the target method's dex method index.
      */
 DEFINE_FUNCTION art_quick_imt_conflict_trampoline
+#if defined(__APPLE__)
+    int3
+    int3
+#else
     movl 8(%rsp), %edi            // load caller Method*
     movl METHOD_DEX_CACHE_METHODS_OFFSET(%rdi), %edi  // load dex_cache_resolved_methods
     movl OBJECT_ARRAY_DATA_OFFSET(%rdi, %rax, 4), %edi  // load the target method
     jmp art_quick_invoke_interface_trampoline_local
+#endif  // __APPLE__
 END_FUNCTION art_quick_imt_conflict_trampoline
 
 DEFINE_FUNCTION art_quick_resolution_trampoline
@@ -1294,6 +1332,10 @@
      * Routine that intercepts method calls and returns.
      */
 DEFINE_FUNCTION art_quick_instrumentation_entry
+#if defined(__APPLE__)
+    int3
+    int3
+#else
     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
 
     movq %rdi, %r12               // Preserve method pointer in a callee-save.
@@ -1313,6 +1355,7 @@
     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
 
     jmp *%rax                     // Tail call to intended method.
+#endif  // __APPLE__
 END_FUNCTION art_quick_instrumentation_entry
 
 DEFINE_FUNCTION art_quick_instrumentation_exit
diff --git a/runtime/arch/x86_64/thread_x86_64.cc b/runtime/arch/x86_64/thread_x86_64.cc
index b7a5c43..6dff2b4 100644
--- a/runtime/arch/x86_64/thread_x86_64.cc
+++ b/runtime/arch/x86_64/thread_x86_64.cc
@@ -21,18 +21,28 @@
 #include "thread-inl.h"
 #include "thread_list.h"
 
+#if defined(__linux__)
 #include <asm/prctl.h>
 #include <sys/prctl.h>
 #include <sys/syscall.h>
+#endif
 
 namespace art {
 
+#if defined(__linux__)
 static void arch_prctl(int code, void* val) {
   syscall(__NR_arch_prctl, code, val);
 }
+#endif
+
 void Thread::InitCpu() {
   MutexLock mu(nullptr, *Locks::modify_ldt_lock_);
+
+#if defined(__linux__)
   arch_prctl(ARCH_SET_GS, this);
+#else
+  UNIMPLEMENTED(FATAL) << "Need to set GS";
+#endif
 
   // Allow easy indirection back to Thread*.
   tlsPtr_.self = this;
diff --git a/runtime/base/scoped_flock.cc b/runtime/base/scoped_flock.cc
index c0bce84..351de3d 100644
--- a/runtime/base/scoped_flock.cc
+++ b/runtime/base/scoped_flock.cc
@@ -63,6 +63,10 @@
   return file_.get();
 }
 
+bool ScopedFlock::HasFile() {
+  return file_.get() != nullptr;
+}
+
 ScopedFlock::ScopedFlock() { }
 
 ScopedFlock::~ScopedFlock() {
diff --git a/runtime/base/scoped_flock.h b/runtime/base/scoped_flock.h
index 26b4eb0..f8ed805 100644
--- a/runtime/base/scoped_flock.h
+++ b/runtime/base/scoped_flock.h
@@ -40,6 +40,10 @@
 
   // Returns the (locked) file associated with this instance.
   File* GetFile();
+
+  // Returns whether a file is held.
+  bool HasFile();
+
   ~ScopedFlock();
  private:
   std::unique_ptr<File> file_;
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index a816489..fefb907 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -1757,9 +1757,7 @@
     CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
     if (address == nullptr) {
       JniAbortF(__FUNCTION__, "non-nullable address is NULL");
-    }
-    if (capacity < 0) {
-      JniAbortF(__FUNCTION__, "capacity must be non-negative: %" PRId64, capacity);
+      return nullptr;
     }
     return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
   }
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 61f94d4..60453c3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -634,15 +634,22 @@
 const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
   const char* dex_location = dex_file.GetLocation().c_str();
   uint32_t dex_location_checksum = dex_file.GetLocationChecksum();
-  return FindOpenedOatFileFromDexLocation(dex_location, &dex_location_checksum);
+  return FindOpenedOatFile(nullptr, dex_location, &dex_location_checksum);
 }
 
-const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(
-    const char* dex_location, const uint32_t* const dex_location_checksum) {
+const OatFile* ClassLinker::FindOpenedOatFile(const char* oat_location, const char* dex_location,
+                                              const uint32_t* const dex_location_checksum) {
   ReaderMutexLock mu(Thread::Current(), dex_lock_);
   for (size_t i = 0; i < oat_files_.size(); i++) {
     const OatFile* oat_file = oat_files_[i];
     DCHECK(oat_file != NULL);
+
+    if (oat_location != nullptr) {
+      if (oat_file->GetLocation() != oat_location) {
+        continue;
+      }
+    }
+
     const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
                                                                       dex_location_checksum,
                                                                       false);
@@ -653,10 +660,229 @@
   return NULL;
 }
 
-const DexFile* ClassLinker::FindDexFileInOatLocation(const char* dex_location,
-                                                     uint32_t dex_location_checksum,
-                                                     const char* oat_location,
-                                                     std::string* error_msg) {
+static std::string GetMultiDexClassesDexName(size_t number, const char* dex_location) {
+  if (number == 0) {
+    return dex_location;
+  } else {
+    return StringPrintf("%s" kMultiDexSeparatorString "classes%zu.dex", dex_location, number + 1);
+  }
+}
+
+static bool LoadMultiDexFilesFromOatFile(const OatFile* oat_file, const char* dex_location,
+                                         bool generated,
+                                         std::vector<std::string>* error_msgs,
+                                         std::vector<const DexFile*>* dex_files) {
+  if (oat_file == nullptr) {
+    return false;
+  }
+
+  size_t old_size = dex_files->size();  // To rollback on error.
+
+  bool success = true;
+  for (size_t i = 0; success; ++i) {
+    std::string next_name_str = GetMultiDexClassesDexName(i, dex_location);
+    const char* next_name = next_name_str.c_str();
+
+    uint32_t dex_location_checksum;
+    uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
+    std::string error_msg;
+    if (!DexFile::GetChecksum(next_name, dex_location_checksum_pointer, &error_msg)) {
+      DCHECK_EQ(false, i == 0 && generated);
+      dex_location_checksum_pointer = nullptr;
+    }
+
+    const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(next_name, nullptr, false);
+
+    if (oat_dex_file == nullptr) {
+      if (i == 0 && generated) {
+        std::string error_msg;
+        error_msg = StringPrintf("\nFailed to find dex file '%s' (checksum 0x%x) in generated out "
+                                 " file'%s'", dex_location, dex_location_checksum,
+                                 oat_file->GetLocation().c_str());
+        error_msgs->push_back(error_msg);
+      }
+      break;  // Not found, done.
+    }
+
+    // Checksum test. Test must succeed when generated.
+    success = !generated;
+    if (dex_location_checksum_pointer != nullptr) {
+      success = dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum();
+    }
+
+    if (success) {
+      const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
+      if (dex_file == nullptr) {
+        success = false;
+        error_msgs->push_back(error_msg);
+      } else {
+        dex_files->push_back(dex_file);
+      }
+    }
+
+    // When we generated the file, we expect success, or something is terribly wrong.
+    CHECK_EQ(false, generated && !success)
+        << "dex_location=" << next_name << " oat_location=" << oat_file->GetLocation().c_str()
+        << std::hex << " dex_location_checksum=" << dex_location_checksum
+        << " OatDexFile::GetLocationChecksum()=" << oat_dex_file->GetDexFileLocationChecksum();
+  }
+
+  if (dex_files->size() == old_size) {
+    success = false;  // We did not even find classes.dex
+  }
+
+  if (success) {
+    return true;
+  } else {
+    // Free all the dex files we have loaded.
+    auto it = dex_files->begin() + old_size;
+    auto it_end = dex_files->end();
+    for (; it != it_end; it++) {
+      delete *it;
+    }
+    dex_files->erase(dex_files->begin() + old_size, it_end);
+
+    return false;
+  }
+}
+
+// Multidex files make it possible that some, but not all, dex files can be broken/outdated. This
+// complicates the loading process, as we should not use an iterative loading process, because that
+// would register the oat file and dex files that come before the broken one. Instead, check all
+// multidex ahead of time.
+bool ClassLinker::OpenDexFilesFromOat(const char* dex_location, const char* oat_location,
+                                      std::vector<std::string>* error_msgs,
+                                      std::vector<const DexFile*>* dex_files) {
+  // 1) Check whether we have an open oat file.
+  // This requires a dex checksum, use the "primary" one.
+  uint32_t dex_location_checksum;
+  uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
+  bool have_checksum = true;
+  std::string checksum_error_msg;
+  if (!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
+    dex_location_checksum_pointer = nullptr;
+    have_checksum = false;
+  }
+
+  bool needs_registering = false;
+
+  std::unique_ptr<const OatFile> open_oat_file(FindOpenedOatFile(oat_location, dex_location,
+                                                                 dex_location_checksum_pointer));
+
+  // 2) If we do not have an open one, maybe there's one on disk already.
+
+  // In case the oat file is not open, we play a locking game here so
+  // that if two different processes race to load and register or generate
+  // (or worse, one tries to open a partial generated file) we will be okay.
+  // This is actually common with apps that use DexClassLoader to work
+  // around the dex method reference limit and that have a background
+  // service running in a separate process.
+  ScopedFlock scoped_flock;
+
+  if (open_oat_file.get() == nullptr) {
+    if (oat_location != nullptr) {
+      // Can only do this if we have a checksum, else error.
+      if (!have_checksum) {
+        error_msgs->push_back(checksum_error_msg);
+        return false;
+      }
+
+      std::string error_msg;
+
+      // We are loading or creating one in the future. Time to set up the file lock.
+      if (!scoped_flock.Init(oat_location, &error_msg)) {
+        error_msgs->push_back(error_msg);
+        return false;
+      }
+
+      open_oat_file.reset(FindOatFileInOatLocationForDexFile(dex_location, dex_location_checksum,
+                                                             oat_location, &error_msg));
+
+      if (open_oat_file.get() == nullptr) {
+        std::string compound_msg = StringPrintf("Failed to find dex file '%s' in oat location '%s': %s",
+                                                dex_location, oat_location, error_msg.c_str());
+        VLOG(class_linker) << compound_msg;
+        error_msgs->push_back(compound_msg);
+      }
+    } else {
+      // TODO: What to lock here?
+      open_oat_file.reset(FindOatFileContainingDexFileFromDexLocation(dex_location,
+                                                                      dex_location_checksum_pointer,
+                                                                      kRuntimeISA, error_msgs));
+    }
+    needs_registering = true;
+  }
+
+  // 3) If we have an oat file, check all contained multidex files for our dex_location.
+  // Note: LoadMultiDexFilesFromOatFile will check for nullptr in the first argument.
+  bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, false, error_msgs,
+                                              dex_files);
+  if (success) {
+    const OatFile* oat_file = open_oat_file.release();  // Avoid deleting it.
+    if (needs_registering) {
+      // We opened the oat file, so we must register it.
+      RegisterOatFile(oat_file);
+    }
+    return true;
+  } else {
+    if (needs_registering) {
+      // We opened it, delete it.
+      open_oat_file.reset();
+    } else {
+      open_oat_file.release();  // Do not delete open oat files.
+    }
+  }
+
+  // 4) If it's not the case (either no oat file or mismatches), regenerate and load.
+
+  // Need a checksum, fail else.
+  if (!have_checksum) {
+    error_msgs->push_back(checksum_error_msg);
+    return false;
+  }
+
+  // Look in cache location if no oat_location is given.
+  std::string cache_location;
+  if (oat_location == nullptr) {
+    // Use the dalvik cache.
+    const std::string dalvik_cache(GetDalvikCacheOrDie(GetInstructionSetString(kRuntimeISA)));
+    cache_location = GetDalvikCacheFilenameOrDie(dex_location, dalvik_cache.c_str());
+    oat_location = cache_location.c_str();
+  }
+
+  // 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;
+    }
+  }
+
+  // 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) {
+    return false;
+  }
+
+  // Try to load again, but stronger checks.
+  success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, true, error_msgs,
+                                         dex_files);
+  if (success) {
+    RegisterOatFile(open_oat_file.release());
+    return true;
+  } else {
+    return false;
+  }
+}
+
+const OatFile* ClassLinker::FindOatFileInOatLocationForDexFile(const char* dex_location,
+                                                               uint32_t dex_location_checksum,
+                                                               const char* oat_location,
+                                                               std::string* error_msg) {
   std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL,
                                             !Runtime::Current()->IsCompiler(),
                                             error_msg));
@@ -699,44 +925,21 @@
                               actual_dex_checksum);
     return nullptr;
   }
-  const DexFile* dex_file = oat_dex_file->OpenDexFile(error_msg);
-  if (dex_file != nullptr) {
-    RegisterOatFile(oat_file.release());
-  }
-  return dex_file;
-}
-
-const DexFile* ClassLinker::FindOrCreateOatFileForDexLocation(
-    const char* dex_location,
-    uint32_t dex_location_checksum,
-    const char* oat_location,
-    std::vector<std::string>* error_msgs) {
-  // We play a locking game here so that if two different processes
-  // race to generate (or worse, one tries to open a partial generated
-  // file) we will be okay. This is actually common with apps that use
-  // DexClassLoader to work around the dex method reference limit and
-  // that have a background service running in a separate process.
-  ScopedFlock scoped_flock;
-  std::string error_msg;
-  if (!scoped_flock.Init(oat_location, &error_msg)) {
-    error_msgs->push_back(error_msg);
+  std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(error_msg));
+  if (dex_file.get() != nullptr) {
+    return oat_file.release();
+  } else {
     return nullptr;
   }
+}
 
-  // Check if we already have an up-to-date output file
-  const DexFile* dex_file = FindDexFileInOatLocation(dex_location, dex_location_checksum,
-                                                     oat_location, &error_msg);
-  if (dex_file != nullptr) {
-    return dex_file;
-  }
-  std::string compound_msg = StringPrintf("Failed to find dex file '%s' in oat location '%s': %s",
-                                          dex_location, oat_location, error_msg.c_str());
-  VLOG(class_linker) << compound_msg;
-  error_msgs->push_back(compound_msg);
-
+const OatFile* ClassLinker::CreateOatFileForDexLocation(const char* dex_location,
+                                                        int fd, const char* oat_location,
+                                                        std::vector<std::string>* error_msgs) {
   // Generate the output oat file for the dex file
   VLOG(class_linker) << "Generating oat file " << oat_location << " for " << dex_location;
-  if (!GenerateOatFile(dex_location, scoped_flock.GetFile()->Fd(), oat_location, &error_msg)) {
+  std::string error_msg;
+  if (!GenerateOatFile(dex_location, fd, oat_location, &error_msg)) {
     CHECK(!error_msg.empty());
     error_msgs->push_back(error_msg);
     return nullptr;
@@ -745,27 +948,13 @@
                                             !Runtime::Current()->IsCompiler(),
                                             &error_msg));
   if (oat_file.get() == nullptr) {
-    compound_msg = StringPrintf("\nFailed to open generated oat file '%s': %s",
-                                oat_location, error_msg.c_str());
+    std::string compound_msg = StringPrintf("\nFailed to open generated oat file '%s': %s",
+                                            oat_location, error_msg.c_str());
     error_msgs->push_back(compound_msg);
     return nullptr;
   }
-  const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
-                                                                    &dex_location_checksum);
-  if (oat_dex_file == nullptr) {
-    error_msg = StringPrintf("\nFailed to find dex file '%s' (checksum 0x%x) in generated out file "
-                             "'%s'", dex_location, dex_location_checksum, oat_location);
-    error_msgs->push_back(error_msg);
-    return nullptr;
-  }
-  const DexFile* result = oat_dex_file->OpenDexFile(&error_msg);
-  CHECK(result != nullptr) << error_msgs << ", " << error_msg;
-  CHECK_EQ(dex_location_checksum, result->GetLocationChecksum())
-          << "dex_location=" << dex_location << " oat_location=" << oat_location << std::hex
-          << " dex_location_checksum=" << dex_location_checksum
-          << " DexFile::GetLocationChecksum()=" << result->GetLocationChecksum();
-  RegisterOatFile(oat_file.release());
-  return result;
+
+  return oat_file.release();
 }
 
 bool ClassLinker::VerifyOatFileChecksums(const OatFile* oat_file,
@@ -832,17 +1021,17 @@
   return false;
 }
 
-const DexFile* ClassLinker::VerifyAndOpenDexFileFromOatFile(const std::string& oat_file_location,
-                                                            const char* dex_location,
-                                                            std::string* error_msg,
-                                                            bool* open_failed) {
+const OatFile* ClassLinker::LoadOatFileAndVerifyDexFile(const std::string& oat_file_location,
+                                                        const char* dex_location,
+                                                        std::string* error_msg,
+                                                        bool* open_failed) {
   std::unique_ptr<const OatFile> oat_file(FindOatFileFromOatLocation(oat_file_location, error_msg));
   if (oat_file.get() == nullptr) {
     *open_failed = true;
     return nullptr;
   }
   *open_failed = false;
-  const DexFile* dex_file = nullptr;
+  std::unique_ptr<const DexFile> dex_file;
   uint32_t dex_location_checksum;
   if (!DexFile::GetChecksum(dex_location, &dex_location_checksum, error_msg)) {
     // If no classes.dex found in dex_location, it has been stripped or is corrupt, assume oat is
@@ -855,49 +1044,38 @@
                                 error_msg->c_str());
       return nullptr;
     }
-    dex_file = oat_dex_file->OpenDexFile(error_msg);
+    dex_file.reset(oat_dex_file->OpenDexFile(error_msg));
   } else {
     bool verified = VerifyOatFileChecksums(oat_file.get(), dex_location, dex_location_checksum,
                                            kRuntimeISA, error_msg);
     if (!verified) {
       return nullptr;
     }
-    dex_file = oat_file->GetOatDexFile(dex_location,
-                                       &dex_location_checksum)->OpenDexFile(error_msg);
+    dex_file.reset(oat_file->GetOatDexFile(dex_location,
+                                           &dex_location_checksum)->OpenDexFile(error_msg));
   }
-  if (dex_file != nullptr) {
-    RegisterOatFile(oat_file.release());
+
+  if (dex_file.get() != nullptr) {
+    return oat_file.release();
+  } else {
+    return nullptr;
   }
-  return dex_file;
 }
 
-const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(
+const OatFile* ClassLinker::FindOatFileContainingDexFileFromDexLocation(
     const char* dex_location,
     const uint32_t* const dex_location_checksum,
     InstructionSet isa,
     std::vector<std::string>* error_msgs) {
-  const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location,
-                                                                  dex_location_checksum);
-  if (open_oat_file != nullptr) {
-    const OatFile::OatDexFile* oat_dex_file = open_oat_file->GetOatDexFile(dex_location,
-                                                                           dex_location_checksum);
-    std::string error_msg;
-    const DexFile* ret = oat_dex_file->OpenDexFile(&error_msg);
-    if (ret == nullptr) {
-      error_msgs->push_back(error_msg);
-    }
-    return ret;
-  }
-
   // Look for an existing file next to dex. for example, for
   // /foo/bar/baz.jar, look for /foo/bar/<isa>/baz.odex.
   std::string odex_filename(DexFilenameToOdexFilename(dex_location, isa));
   bool open_failed;
   std::string error_msg;
-  const DexFile* dex_file = VerifyAndOpenDexFileFromOatFile(odex_filename, dex_location,
-                                                            &error_msg, &open_failed);
-  if (dex_file != nullptr) {
-    return dex_file;
+  const OatFile* oat_file = LoadOatFileAndVerifyDexFile(odex_filename, dex_location, &error_msg,
+                                                        &open_failed);
+  if (oat_file != nullptr) {
+    return oat_file;
   }
   if (dex_location_checksum == nullptr) {
     error_msgs->push_back(StringPrintf("Failed to open oat file from %s and no classes.dex found in"
@@ -910,10 +1088,10 @@
   const std::string dalvik_cache(GetDalvikCacheOrDie(GetInstructionSetString(kRuntimeISA)));
   std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location,
                                                          dalvik_cache.c_str()));
-  dex_file = VerifyAndOpenDexFileFromOatFile(cache_location, dex_location, &cache_error_msg,
-                                             &open_failed);
-  if (dex_file != nullptr) {
-    return dex_file;
+  oat_file = LoadOatFileAndVerifyDexFile(cache_location, dex_location, &cache_error_msg,
+                                         &open_failed);
+  if (oat_file != nullptr) {
+    return oat_file;
   }
   if (!open_failed && TEMP_FAILURE_RETRY(unlink(cache_location.c_str())) != 0) {
     PLOG(FATAL) << "Failed to remove obsolete oat file from " << cache_location;
@@ -924,9 +1102,7 @@
   VLOG(class_linker) << compound_msg;
   error_msgs->push_back(compound_msg);
 
-  // Try to generate oat file if it wasn't found or was obsolete.
-  return FindOrCreateOatFileForDexLocation(dex_location, *dex_location_checksum,
-                                           cache_location.c_str(), error_msgs);
+  return nullptr;
 }
 
 const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& oat_location) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 7d7bf15..60dad7b 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -273,23 +273,12 @@
                                             std::string* error_msg)
       LOCKS_EXCLUDED(dex_lock_);
 
-  // Finds the oat file for a dex location, generating the oat file if
-  // it is missing or out of date. Returns the DexFile from within the
-  // created oat file.
-  const DexFile* FindOrCreateOatFileForDexLocation(const char* dex_location,
-                                                   uint32_t dex_location_checksum,
-                                                   const char* oat_location,
-                                                   std::vector<std::string>* error_msgs)
+  // Find or create the oat file holding dex_location. Then load all corresponding dex files
+  // (if multidex) into the given vector.
+  bool OpenDexFilesFromOat(const char* dex_location, const char* oat_location,
+                           std::vector<std::string>* error_msgs,
+                           std::vector<const DexFile*>* dex_files)
       LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
-  // Find a DexFile within an OatFile given a DexFile location. Note
-  // that this returns null if the location checksum of the DexFile
-  // does not match the OatFile.
-  const DexFile* FindDexFileInOatFileFromDexLocation(const char* location,
-                                                     const uint32_t* const location_checksum,
-                                                     InstructionSet isa,
-                                                     std::vector<std::string>* error_msgs)
-      LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
-
 
   // Returns true if oat file contains the dex file with the given location and checksum.
   static bool VerifyOatFileChecksums(const OatFile* oat_file,
@@ -545,21 +534,47 @@
   const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  const OatFile* FindOpenedOatFileFromDexLocation(const char* dex_location,
-                                                  const uint32_t* const dex_location_checksum)
+
+  // Find an opened oat file that contains dex_location. If oat_location is not nullptr, the file
+  // must have that location, else any oat location is accepted.
+  const OatFile* FindOpenedOatFile(const char* oat_location, const char* dex_location,
+                                   const uint32_t* const dex_location_checksum)
       LOCKS_EXCLUDED(dex_lock_);
   const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
       LOCKS_EXCLUDED(dex_lock_);
-  const DexFile* FindDexFileInOatLocation(const char* dex_location,
-                                          uint32_t dex_location_checksum,
-                                          const char* oat_location,
-                                          std::string* error_msg)
+
+  // Note: will not register the oat file.
+  const OatFile* FindOatFileInOatLocationForDexFile(const char* dex_location,
+                                                    uint32_t dex_location_checksum,
+                                                    const char* oat_location,
+                                                    std::string* error_msg)
       LOCKS_EXCLUDED(dex_lock_);
 
-  const DexFile* VerifyAndOpenDexFileFromOatFile(const std::string& oat_file_location,
-                                                 const char* dex_location,
-                                                 std::string* error_msg,
-                                                 bool* open_failed)
+  // Creates the oat file from the dex_location to the oat_location. Needs a file descriptor for
+  // the file to be written, which is assumed to be under a lock.
+  const OatFile* CreateOatFileForDexLocation(const char* dex_location,
+                                             int fd, const char* oat_location,
+                                             std::vector<std::string>* error_msgs)
+      LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
+
+  // Finds an OatFile that contains a DexFile for the given a DexFile location.
+  //
+  // Note 1: this will not check open oat files, which are assumed to be stale when this is run.
+  // Note 2: Does not register the oat file. It is the caller's job to register if the file is to
+  //         be kept.
+  const OatFile* FindOatFileContainingDexFileFromDexLocation(const char* location,
+                                                             const uint32_t* const location_checksum,
+                                                             InstructionSet isa,
+                                                             std::vector<std::string>* error_msgs)
+      LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
+
+  // Find a verify an oat file with the given dex file. Will return nullptr when the oat file
+  // was not found or the dex file could not be verified.
+  // Note: Does not register the oat file.
+  const OatFile* LoadOatFileAndVerifyDexFile(const std::string& oat_file_location,
+                                             const char* dex_location,
+                                             std::string* error_msg,
+                                             bool* open_failed)
       LOCKS_EXCLUDED(dex_lock_);
 
   mirror::ArtMethod* CreateProxyConstructor(Thread* self, Handle<mirror::Class> klass,
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 044d08b..fdbc9c2 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -114,32 +114,42 @@
  public:
   static void SetEnvironmentVariables(std::string& android_data) {
     if (IsHost()) {
-      // $ANDROID_ROOT is set on the device, but not on the host.
-      // We need to set this so that icu4c can find its locale data.
-      std::string root;
-      const char* android_build_top = getenv("ANDROID_BUILD_TOP");
-      if (android_build_top != nullptr) {
-        root += android_build_top;
-      } else {
-        // Not set by build server, so default to current directory
-        char* cwd = getcwd(nullptr, 0);
-        setenv("ANDROID_BUILD_TOP", cwd, 1);
-        root += cwd;
-        free(cwd);
-      }
+      // $ANDROID_ROOT is set on the device, but not necessarily on the host.
+      // But it needs to be set so that icu4c can find its locale data.
+      const char* android_root_from_env = getenv("ANDROID_ROOT");
+      if (android_root_from_env == nullptr) {
+        // Use ANDROID_HOST_OUT for ANDROID_ROOT if it is set.
+        const char* android_host_out = getenv("ANDROID_HOST_OUT");
+        if (android_host_out != nullptr) {
+          setenv("ANDROID_ROOT", android_host_out, 1);
+        } else {
+          // Build it from ANDROID_BUILD_TOP or cwd
+          std::string root;
+          const char* android_build_top = getenv("ANDROID_BUILD_TOP");
+          if (android_build_top != nullptr) {
+            root += android_build_top;
+          } else {
+            // Not set by build server, so default to current directory
+            char* cwd = getcwd(nullptr, 0);
+            setenv("ANDROID_BUILD_TOP", cwd, 1);
+            root += cwd;
+            free(cwd);
+          }
 #if defined(__linux__)
-      root += "/out/host/linux-x86";
+          root += "/out/host/linux-x86";
 #elif defined(__APPLE__)
-      root += "/out/host/darwin-x86";
+          root += "/out/host/darwin-x86";
 #else
 #error unsupported OS
 #endif
-      setenv("ANDROID_ROOT", root.c_str(), 1);
+          setenv("ANDROID_ROOT", root.c_str(), 1);
+        }
+      }
       setenv("LD_LIBRARY_PATH", ":", 0);  // Required by java.lang.System.<clinit>.
 
       // Not set by build server, so default
       if (getenv("ANDROID_HOST_OUT") == nullptr) {
-        setenv("ANDROID_HOST_OUT", root.c_str(), 1);
+        setenv("ANDROID_HOST_OUT", getenv("ANDROID_ROOT"), 1);
       }
     }
 
@@ -156,6 +166,18 @@
     return !kIsTargetBuild;
   }
 
+  const DexFile* LoadExpectSingleDexFile(const char* location) {
+    std::vector<const DexFile*> dex_files;
+    std::string error_msg;
+    if (!DexFile::Open(location, location, &error_msg, &dex_files)) {
+      LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n";
+      return nullptr;
+    } else {
+      CHECK_EQ(1U, dex_files.size()) << "Expected only one dex file in " << location;
+      return dex_files[0];
+    }
+  }
+
   virtual void SetUp() {
     SetEnvironmentVariables(android_data_);
     dalvik_cache_.append(android_data_.c_str());
@@ -164,12 +186,7 @@
     ASSERT_EQ(mkdir_result, 0);
 
     std::string error_msg;
-    java_lang_dex_file_ = DexFile::Open(GetLibCoreDexFileName().c_str(),
-                                        GetLibCoreDexFileName().c_str(), &error_msg);
-    if (java_lang_dex_file_ == nullptr) {
-      LOG(FATAL) << "Could not open .dex file '" << GetLibCoreDexFileName() << "': "
-          << error_msg << "\n";
-    }
+    java_lang_dex_file_ = LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str());
     boot_class_path_.push_back(java_lang_dex_file_);
 
     std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB));
@@ -233,7 +250,7 @@
     // There's a function to clear the array, but it's not public...
     typedef void (*IcuCleanupFn)();
     void* sym = dlsym(RTLD_DEFAULT, "u_cleanup_" U_ICU_VERSION_SHORT);
-    CHECK(sym != nullptr);
+    CHECK(sym != nullptr) << dlerror();
     IcuCleanupFn icu_cleanup_fn = reinterpret_cast<IcuCleanupFn>(sym);
     (*icu_cleanup_fn)();
 
@@ -264,7 +281,8 @@
     return GetAndroidRoot();
   }
 
-  const DexFile* OpenTestDexFile(const char* name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  std::vector<const DexFile*> OpenTestDexFiles(const char* name)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     CHECK(name != nullptr);
     std::string filename;
     if (IsHost()) {
@@ -277,26 +295,36 @@
     filename += name;
     filename += ".jar";
     std::string error_msg;
-    const DexFile* dex_file = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg);
-    CHECK(dex_file != nullptr) << "Failed to open '" << filename << "': " << error_msg;
-    CHECK_EQ(PROT_READ, dex_file->GetPermissions());
-    CHECK(dex_file->IsReadOnly());
-    opened_dex_files_.push_back(dex_file);
-    return dex_file;
+    std::vector<const DexFile*> dex_files;
+    bool success = DexFile::Open(filename.c_str(), filename.c_str(), &error_msg, &dex_files);
+    CHECK(success) << "Failed to open '" << filename << "': " << error_msg;
+    for (const DexFile* dex_file : dex_files) {
+      CHECK_EQ(PROT_READ, dex_file->GetPermissions());
+      CHECK(dex_file->IsReadOnly());
+    }
+    opened_dex_files_.insert(opened_dex_files_.end(), dex_files.begin(), dex_files.end());
+    return dex_files;
+  }
+
+  const DexFile* OpenTestDexFile(const char* name)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    std::vector<const DexFile*> vector = OpenTestDexFiles(name);
+    EXPECT_EQ(1U, vector.size());
+    return vector[0];
   }
 
   jobject LoadDex(const char* dex_name) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    const DexFile* dex_file = OpenTestDexFile(dex_name);
-    CHECK(dex_file != nullptr);
-    class_linker_->RegisterDexFile(*dex_file);
-    std::vector<const DexFile*> class_path;
-    class_path.push_back(dex_file);
+    std::vector<const DexFile*> dex_files = OpenTestDexFiles(dex_name);
+    CHECK_NE(0U, dex_files.size());
+    for (const DexFile* dex_file : dex_files) {
+      class_linker_->RegisterDexFile(*dex_file);
+    }
     ScopedObjectAccessUnchecked soa(Thread::Current());
     ScopedLocalRef<jobject> class_loader_local(soa.Env(),
         soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
     jobject class_loader = soa.Env()->NewGlobalRef(class_loader_local.get());
     soa.Self()->SetClassLoaderOverride(soa.Decode<mirror::ClassLoader*>(class_loader_local.get()));
-    Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path);
+    Runtime::Current()->SetCompileTimeClassPath(class_loader, dex_files);
     return class_loader;
   }
 
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 10f34d9..d368e41 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -87,7 +87,21 @@
 bool DexFile::GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg) {
   CHECK(checksum != NULL);
   uint32_t magic;
-  ScopedFd fd(OpenAndReadMagic(filename, &magic, error_msg));
+
+  // Strip ":...", which is the location
+  const char* zip_entry_name = kClassesDex;
+  const char* file_part = filename;
+  std::unique_ptr<const char> file_part_ptr;
+
+
+  if (IsMultiDexLocation(filename)) {
+    std::pair<const char*, const char*> pair = SplitMultiDexLocation(filename);
+    file_part_ptr.reset(pair.first);
+    file_part = pair.first;
+    zip_entry_name = pair.second;
+  }
+
+  ScopedFd fd(OpenAndReadMagic(file_part, &magic, error_msg));
   if (fd.get() == -1) {
     DCHECK(!error_msg->empty());
     return false;
@@ -95,13 +109,13 @@
   if (IsZipMagic(magic)) {
     std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd.release(), filename, error_msg));
     if (zip_archive.get() == NULL) {
-      *error_msg = StringPrintf("Failed to open zip archive '%s'", filename);
+      *error_msg = StringPrintf("Failed to open zip archive '%s'", file_part);
       return false;
     }
-    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex, error_msg));
+    std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name, error_msg));
     if (zip_entry.get() == NULL) {
-      *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
-                                kClassesDex, error_msg->c_str());
+      *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", file_part,
+                                zip_entry_name, error_msg->c_str());
       return false;
     }
     *checksum = zip_entry->GetCrc32();
@@ -119,20 +133,26 @@
   return false;
 }
 
-const DexFile* DexFile::Open(const char* filename,
-                             const char* location,
-                             std::string* error_msg) {
+bool DexFile::Open(const char* filename, const char* location, std::string* error_msg,
+                   std::vector<const DexFile*>* dex_files) {
   uint32_t magic;
   ScopedFd fd(OpenAndReadMagic(filename, &magic, error_msg));
   if (fd.get() == -1) {
     DCHECK(!error_msg->empty());
-    return NULL;
+    return false;
   }
   if (IsZipMagic(magic)) {
-    return DexFile::OpenZip(fd.release(), location, error_msg);
+    return DexFile::OpenZip(fd.release(), location, error_msg, dex_files);
   }
   if (IsDexMagic(magic)) {
-    return DexFile::OpenFile(fd.release(), location, true, error_msg);
+    std::unique_ptr<const DexFile> dex_file(DexFile::OpenFile(fd.release(), location, true,
+                                                              error_msg));
+    if (dex_file.get() != nullptr) {
+      dex_files->push_back(dex_file.release());
+      return true;
+    } else {
+      return false;
+    }
   }
   *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
   return nullptr;
@@ -217,13 +237,14 @@
 
 const char* DexFile::kClassesDex = "classes.dex";
 
-const DexFile* DexFile::OpenZip(int fd, const std::string& location, std::string* error_msg) {
+bool DexFile::OpenZip(int fd, const std::string& location, std::string* error_msg,
+                      std::vector<const  DexFile*>* dex_files) {
   std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
   if (zip_archive.get() == nullptr) {
     DCHECK(!error_msg->empty());
-    return nullptr;
+    return false;
   }
-  return DexFile::Open(*zip_archive, location, error_msg);
+  return DexFile::OpenFromZip(*zip_archive, location, error_msg, dex_files);
 }
 
 const DexFile* DexFile::OpenMemory(const std::string& location,
@@ -238,17 +259,20 @@
                     error_msg);
 }
 
-const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location,
-                             std::string* error_msg) {
+const DexFile* DexFile::Open(const ZipArchive& zip_archive, const char* entry_name,
+                             const std::string& location, std::string* error_msg,
+                             ZipOpenErrorCode* error_code) {
   CHECK(!location.empty());
-  std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex, error_msg));
+  std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
   if (zip_entry.get() == NULL) {
+    *error_code = ZipOpenErrorCode::kEntryNotFound;
     return nullptr;
   }
-  std::unique_ptr<MemMap> map(zip_entry->ExtractToMemMap(location.c_str(), kClassesDex, error_msg));
+  std::unique_ptr<MemMap> map(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
   if (map.get() == NULL) {
-    *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", kClassesDex, location.c_str(),
+    *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
                               error_msg->c_str());
+    *error_code = ZipOpenErrorCode::kExtractToMemoryError;
     return nullptr;
   }
   std::unique_ptr<const DexFile> dex_file(OpenMemory(location, zip_entry->GetCrc32(), map.release(),
@@ -256,20 +280,63 @@
   if (dex_file.get() == nullptr) {
     *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
                               error_msg->c_str());
+    *error_code = ZipOpenErrorCode::kDexFileError;
     return nullptr;
   }
   if (!dex_file->DisableWrite()) {
     *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
+    *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
     return nullptr;
   }
   CHECK(dex_file->IsReadOnly()) << location;
   if (!DexFileVerifier::Verify(dex_file.get(), dex_file->Begin(), dex_file->Size(),
                                location.c_str(), error_msg)) {
+    *error_code = ZipOpenErrorCode::kVerifyError;
     return nullptr;
   }
+  *error_code = ZipOpenErrorCode::kNoError;
   return dex_file.release();
 }
 
+bool DexFile::OpenFromZip(const ZipArchive& zip_archive, const std::string& location,
+                          std::string* error_msg, std::vector<const DexFile*>* dex_files) {
+  ZipOpenErrorCode error_code;
+  std::unique_ptr<const DexFile> dex_file(Open(zip_archive, kClassesDex, location, error_msg,
+                                               &error_code));
+  if (dex_file.get() == nullptr) {
+    return false;
+  } else {
+    // Had at least classes.dex.
+    dex_files->push_back(dex_file.release());
+
+    // Now try some more.
+    size_t i = 2;
+
+    // We could try to avoid std::string allocations by working on a char array directly. As we
+    // do not expect a lot of iterations, this seems too involved and brittle.
+
+    while (i < 100) {
+      std::string name = StringPrintf("classes%zu.dex", i);
+      std::string fake_location = location + ":" + name;
+      std::unique_ptr<const DexFile> next_dex_file(Open(zip_archive, name.c_str(), fake_location,
+                                                        error_msg, &error_code));
+      if (next_dex_file.get() == nullptr) {
+        if (error_code != ZipOpenErrorCode::kEntryNotFound) {
+          LOG(WARNING) << error_msg;
+        }
+        break;
+      } else {
+        dex_files->push_back(next_dex_file.release());
+      }
+
+      i++;
+    }
+
+    return true;
+  }
+}
+
+
 const DexFile* DexFile::OpenMemory(const byte* base,
                                    size_t size,
                                    const std::string& location,
@@ -865,6 +932,25 @@
   }
 }
 
+bool DexFile::IsMultiDexLocation(const char* location) {
+  return strrchr(location, kMultiDexSeparator) != nullptr;
+}
+
+std::pair<const char*, const char*> DexFile::SplitMultiDexLocation(
+    const char* location) {
+  const char* colon_ptr = strrchr(location, kMultiDexSeparator);
+
+  // Check it's synthetic.
+  CHECK_NE(colon_ptr, static_cast<const char*>(nullptr));
+
+  size_t colon_index = colon_ptr - location;
+  char* tmp = new char[colon_index + 1];
+  strncpy(tmp, location, colon_index);
+  tmp[colon_index] = 0;
+
+  return std::make_pair(tmp, colon_ptr + 1);
+}
+
 std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
   os << StringPrintf("[DexFile: %s dex-checksum=%08x location-checksum=%08x %p-%p]",
                      dex_file.GetLocation().c_str(),
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 8270a2b..04f1cc1 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -63,6 +63,13 @@
   // The value of an invalid index.
   static const uint16_t kDexNoIndex16 = 0xFFFF;
 
+  // The separator charactor in MultiDex locations.
+  static constexpr char kMultiDexSeparator = ':';
+
+  // A string version of the previous. This is a define so that we can merge string literals in the
+  // preprocessor.
+  #define kMultiDexSeparatorString ":"
+
   // Raw header_item.
   struct Header {
     uint8_t magic_[8];
@@ -352,8 +359,9 @@
   // Return true if the checksum could be found, false otherwise.
   static bool GetChecksum(const char* filename, uint32_t* checksum, std::string* error_msg);
 
-  // Opens .dex file, guessing the container format based on file extension
-  static const DexFile* Open(const char* filename, const char* location, std::string* error_msg);
+  // Opens .dex files found in the container, guessing the container format based on file extension.
+  static bool Open(const char* filename, const char* location, std::string* error_msg,
+                   std::vector<const DexFile*>* dex_files);
 
   // Opens .dex file, backed by existing memory
   static const DexFile* Open(const uint8_t* base, size_t size,
@@ -363,9 +371,9 @@
     return OpenMemory(base, size, location, location_checksum, NULL, error_msg);
   }
 
-  // Opens .dex file from the classes.dex in a zip archive
-  static const DexFile* Open(const ZipArchive& zip_archive, const std::string& location,
-                             std::string* error_msg);
+  // Open all classesXXX.dex files from a zip archive.
+  static bool OpenFromZip(const ZipArchive& zip_archive, const std::string& location,
+                          std::string* error_msg, std::vector<const DexFile*>* dex_files);
 
   // Closes a .dex file.
   virtual ~DexFile();
@@ -823,8 +831,24 @@
   // Opens a .dex file
   static const DexFile* OpenFile(int fd, const char* location, bool verify, std::string* error_msg);
 
-  // Opens a dex file from within a .jar, .zip, or .apk file
-  static const DexFile* OpenZip(int fd, const std::string& location, std::string* error_msg);
+  // Opens dex files from within a .jar, .zip, or .apk file
+  static bool OpenZip(int fd, const std::string& location, std::string* error_msg,
+                      std::vector<const DexFile*>* dex_files);
+
+  enum class ZipOpenErrorCode {  // private
+    kNoError,
+    kEntryNotFound,
+    kExtractToMemoryError,
+    kDexFileError,
+    kMakeReadOnlyError,
+    kVerifyError
+  };
+
+  // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-nullptr
+  // return.
+  static const DexFile* Open(const ZipArchive& zip_archive, const char* entry_name,
+                             const std::string& location, std::string* error_msg,
+                             ZipOpenErrorCode* error_code);
 
   // Opens a .dex file at the given address backed by a MemMap
   static const DexFile* OpenMemory(const std::string& location,
@@ -855,6 +879,18 @@
       DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb,
       void* context, const byte* stream, LocalInfo* local_in_reg) const;
 
+  // Check whether a location denotes a multidex dex file. This is a very simple check: returns
+  // whether the string contains the separator character.
+  static bool IsMultiDexLocation(const char* location);
+
+  // Splits a multidex location at the last separator character. The second component is a pointer
+  // to the character after the separator. The first is a copy of the substring up to the separator.
+  //
+  // Note: It's the caller's job to free the first component of the returned pair.
+  // Bug 15313523: gcc/libc++ don't allow a unique_ptr for the first component
+  static std::pair<const char*, const char*> SplitMultiDexLocation(const char* location);
+
+
   // The base address of the memory mapping.
   const byte* const begin_;
 
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index a814c34..c1e00fc 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -146,8 +146,11 @@
   // read dex file
   ScopedObjectAccess soa(Thread::Current());
   std::string error_msg;
-  const DexFile* dex_file = DexFile::Open(location, location, &error_msg);
-  CHECK(dex_file != nullptr) << error_msg;
+  std::vector<const DexFile*> tmp;
+  bool success = DexFile::Open(location, location, &error_msg, &tmp);
+  CHECK(success) << error_msg;
+  EXPECT_EQ(1U, tmp.size());
+  const DexFile* dex_file = tmp[0];
   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
   EXPECT_TRUE(dex_file->IsReadOnly());
   return dex_file;
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index d0ce00f..93faeae 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -115,7 +115,14 @@
 
   // read dex file
   ScopedObjectAccess soa(Thread::Current());
-  return DexFile::Open(location, location, error_msg);
+  std::vector<const DexFile*> tmp;
+  bool success = DexFile::Open(location, location, error_msg, &tmp);
+  CHECK(success) << error_msg;
+  EXPECT_EQ(1U, tmp.size());
+  const DexFile* dex_file = tmp[0];
+  EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
+  EXPECT_TRUE(dex_file->IsReadOnly());
+  return dex_file;
 }
 
 
@@ -170,7 +177,15 @@
 
   // read dex file
   ScopedObjectAccess soa(Thread::Current());
-  return DexFile::Open(location, location, error_msg);
+  std::vector<const DexFile*> tmp;
+  if (!DexFile::Open(location, location, error_msg, &tmp)) {
+    return nullptr;
+  }
+  EXPECT_EQ(1U, tmp.size());
+  const DexFile* dex_file = tmp[0];
+  EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
+  EXPECT_TRUE(dex_file->IsReadOnly());
+  return dex_file;
 }
 
 static bool ModifyAndLoad(const char* location, size_t offset, uint8_t new_val,
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index 5e2d89e..0d00cc3 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -21,26 +21,15 @@
 namespace art {
 
 class DexMethodIteratorTest : public CommonRuntimeTest {
- public:
-  const DexFile* OpenDexFile(const std::string& partial_filename) {
-    std::string dfn = GetDexFileName(partial_filename);
-    std::string error_msg;
-    const DexFile* dexfile = DexFile::Open(dfn.c_str(), dfn.c_str(), &error_msg);
-    if (dexfile == nullptr) {
-      LG << "Failed to open '" << dfn << "': " << error_msg;
-    }
-    return dexfile;
-  }
 };
 
 TEST_F(DexMethodIteratorTest, Basic) {
   ScopedObjectAccess soa(Thread::Current());
   std::vector<const DexFile*> dex_files;
-  dex_files.push_back(OpenDexFile("core-libart"));
-  dex_files.push_back(OpenDexFile("conscrypt"));
-  dex_files.push_back(OpenDexFile("okhttp"));
-  dex_files.push_back(OpenDexFile("core-junit"));
-  dex_files.push_back(OpenDexFile("bouncycastle"));
+  const char* jars[] = { "core-libart", "conscrypt", "okhttp", "core-junit", "bouncycastle" };
+  for (size_t i = 0; i < 5; ++i) {
+    dex_files.push_back(LoadExpectSingleDexFile(GetDexFileName(jars[i]).c_str()));
+  }
   DexMethodIterator it(dex_files);
   while (it.HasNext()) {
     const DexFile& dex_file = it.GetDexFile();
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index 3301254..dde74de 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -154,10 +154,12 @@
 }
 
 // Generate the entrypoint functions.
+#if !defined(__APPLE__) || !defined(__LP64__)
 GENERATE_ENTRYPOINTS(_dlmalloc);
 GENERATE_ENTRYPOINTS(_rosalloc);
 GENERATE_ENTRYPOINTS(_bump_pointer);
 GENERATE_ENTRYPOINTS(_tlab);
+#endif
 
 static bool entry_points_instrumented = false;
 static gc::AllocatorType entry_points_allocator = gc::kAllocatorTypeDlMalloc;
@@ -172,6 +174,7 @@
 
 void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints) {
   switch (entry_points_allocator) {
+#if !defined(__APPLE__) || !defined(__LP64__)
     case gc::kAllocatorTypeDlMalloc: {
       SetQuickAllocEntryPoints_dlmalloc(qpoints, entry_points_instrumented);
       break;
@@ -190,6 +193,7 @@
       SetQuickAllocEntryPoints_tlab(qpoints, entry_points_instrumented);
       break;
     }
+#endif
     default: {
       LOG(FATAL) << "Unimplemented";
     }
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index d637a94..29d3c8a 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -115,12 +115,13 @@
   // Delete all the JNI references.
   JNIEnv* env = self->GetJniEnv();
   for (const auto& pair : object_to_entry_) {
-    const ObjectRegistryEntry& entry = *pair.second;
-    if (entry.jni_reference_type == JNIWeakGlobalRefType) {
-      env->DeleteWeakGlobalRef(entry.jni_reference);
+    const ObjectRegistryEntry* entry = pair.second;
+    if (entry->jni_reference_type == JNIWeakGlobalRefType) {
+      env->DeleteWeakGlobalRef(entry->jni_reference);
     } else {
-      env->DeleteGlobalRef(entry.jni_reference);
+      env->DeleteGlobalRef(entry->jni_reference);
     }
+    delete entry;
   }
   // Clear the maps.
   object_to_entry_.clear();
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 513b409..8842f59 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -2447,13 +2447,18 @@
   static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
     if (capacity < 0) {
       JniAbortF("NewDirectByteBuffer", "negative buffer capacity: %" PRId64, capacity);
+      return nullptr;
     }
     if (address == nullptr && capacity != 0) {
       JniAbortF("NewDirectByteBuffer", "non-zero capacity for nullptr pointer: %" PRId64, capacity);
+      return nullptr;
     }
 
-    // At the moment, the capacity is limited to 32 bits.
-    CHECK_LE(capacity, 0xffffffff);
+    // At the moment, the capacity of DirectByteBuffer is limited to a signed int.
+    if (capacity > INT_MAX) {
+      JniAbortF("NewDirectByteBuffer", "buffer capacity greater than maximum jint: %" PRId64, capacity);
+      return nullptr;
+    }
     jlong address_arg = reinterpret_cast<jlong>(address);
     jint capacity_arg = static_cast<jint>(capacity);
 
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index 5e46c57..a933f86 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -1515,6 +1515,12 @@
   ASSERT_TRUE(env_->IsInstanceOf(buffer, buffer_class));
   ASSERT_EQ(env_->GetDirectBufferAddress(buffer), bytes);
   ASSERT_EQ(env_->GetDirectBufferCapacity(buffer), static_cast<jlong>(sizeof(bytes)));
+
+  {
+    CheckJniAbortCatcher check_jni_abort_catcher;
+    env_->NewDirectByteBuffer(bytes, static_cast<jlong>(INT_MAX) + 1);
+    check_jni_abort_catcher.Check("in call to NewDirectByteBuffer");
+  }
 }
 
 TEST_F(JniInternalTest, MonitorEnterExit) {
@@ -1568,7 +1574,6 @@
     CheckJniAbortCatcher check_jni_abort_catcher;
     env_->MonitorEnter(nullptr);
     check_jni_abort_catcher.Check("in call to MonitorEnter");
-
     env_->MonitorExit(nullptr);
     check_jni_abort_catcher.Check("in call to MonitorExit");
   }
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 8d987df..1074253 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -72,7 +72,7 @@
 
 std::multimap<void*, MemMap*> MemMap::maps_;
 
-#if defined(__LP64__) && !defined(__x86_64__)
+#if USE_ART_LOW_4G_ALLOCATOR
 // Handling mem_map in 32b address range for 64b architectures that do not support MAP_32BIT.
 
 // The regular start of memory allocations. The first 64KB is protected by SELinux.
@@ -235,7 +235,7 @@
   // A page allocator would be a useful abstraction here, as
   // 1) It is doubtful that MAP_32BIT on x86_64 is doing the right job for us
   // 2) The linear scheme, even with simple saving of the last known position, is very crude
-#if defined(__LP64__) && !defined(__x86_64__)
+#if USE_ART_LOW_4G_ALLOCATOR
   // MAP_32BIT only available on x86_64.
   void* actual = MAP_FAILED;
   if (low_4gb && expected == nullptr) {
@@ -299,7 +299,7 @@
   }
 
 #else
-#ifdef __x86_64__
+#if defined(__LP64__)
   if (low_4gb && expected == nullptr) {
     flags |= MAP_32BIT;
   }
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index e42251c..defa6a5 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -30,6 +30,12 @@
 
 namespace art {
 
+#if defined(__LP64__) && (!defined(__x86_64__) || defined(__APPLE__))
+#define USE_ART_LOW_4G_ALLOCATOR 1
+#else
+#define USE_ART_LOW_4G_ALLOCATOR 0
+#endif
+
 #ifdef __linux__
 static constexpr bool kMadviseZeroes = true;
 #else
@@ -147,8 +153,8 @@
   size_t base_size_;  // Length of mapping. May be changed by RemapAtEnd (ie Zygote).
   int prot_;  // Protection of the map.
 
-#if defined(__LP64__) && !defined(__x86_64__)
-  static uintptr_t next_mem_pos_;   // next memory location to check for low_4g extent
+#if USE_ART_LOW_4G_ALLOCATOR
+  static uintptr_t next_mem_pos_;   // Next memory location to check for low_4g extent.
 #endif
 
   // All the non-empty MemMaps. Use a multimap as we do a reserve-and-divide (eg ElfMap::Load()).
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 9512a5a..440d3d0 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -26,6 +26,7 @@
 #include <unistd.h>
 
 #include "base/logging.h"
+#include "base/stl_util.h"
 #include "class_linker.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
@@ -106,34 +107,19 @@
     return 0;
   }
 
-  uint32_t dex_location_checksum;
-  uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
-  std::vector<std::string> error_msgs;
-  std::string error_msg;
-  if (!DexFile::GetChecksum(sourceName.c_str(), dex_location_checksum_pointer, &error_msg)) {
-    dex_location_checksum_pointer = NULL;
-  }
-
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  const DexFile* dex_file;
-  if (outputName.c_str() == nullptr) {
-    // FindOrCreateOatFileForDexLocation can tolerate a missing dex_location_checksum
-    dex_file = linker->FindDexFileInOatFileFromDexLocation(sourceName.c_str(),
-                                                           dex_location_checksum_pointer,
-                                                           kRuntimeISA,
-                                                           &error_msgs);
+  std::unique_ptr<std::vector<const DexFile*>> dex_files(new std::vector<const DexFile*>());
+  std::vector<std::string> error_msgs;
+
+  bool success = linker->OpenDexFilesFromOat(sourceName.c_str(), outputName.c_str(), &error_msgs,
+                                             dex_files.get());
+
+  if (success) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(dex_files.release()));
   } else {
-    // FindOrCreateOatFileForDexLocation requires the dex_location_checksum
-    if (dex_location_checksum_pointer == NULL) {
-      ScopedObjectAccess soa(env);
-      DCHECK(!error_msg.empty());
-      ThrowIOException("%s", error_msg.c_str());
-      return 0;
-    }
-    dex_file = linker->FindOrCreateOatFileForDexLocation(sourceName.c_str(), dex_location_checksum,
-                                                         outputName.c_str(), &error_msgs);
-  }
-  if (dex_file == nullptr) {
+    // The vector should be empty after a failed loading attempt.
+    DCHECK_EQ(0U, dex_files->size());
+
     ScopedObjectAccess soa(env);
     CHECK(!error_msgs.empty());
     // The most important message is at the end. So set up nesting by going forward, which will
@@ -146,35 +132,41 @@
 
     return 0;
   }
-  return static_cast<jlong>(reinterpret_cast<uintptr_t>(dex_file));
 }
 
-static const DexFile* toDexFile(jlong dex_file_address, JNIEnv* env) {
-  const DexFile* dex_file = reinterpret_cast<const DexFile*>(static_cast<uintptr_t>(dex_file_address));
-  if (UNLIKELY(dex_file == nullptr)) {
+static std::vector<const DexFile*>* toDexFiles(jlong dex_file_address, JNIEnv* env) {
+  std::vector<const DexFile*>* dex_files = reinterpret_cast<std::vector<const DexFile*>*>(
+      static_cast<uintptr_t>(dex_file_address));
+  if (UNLIKELY(dex_files == nullptr)) {
     ScopedObjectAccess soa(env);
     ThrowNullPointerException(NULL, "dex_file == null");
   }
-  return dex_file;
+  return dex_files;
 }
 
 static void DexFile_closeDexFile(JNIEnv* env, jclass, jlong cookie) {
-  const DexFile* dex_file;
-  dex_file = toDexFile(cookie, env);
-  if (dex_file == nullptr) {
+  std::unique_ptr<std::vector<const DexFile*>> dex_files(toDexFiles(cookie, env));
+  if (dex_files.get() == nullptr) {
     return;
   }
   ScopedObjectAccess soa(env);
-  if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
-    return;
+
+  size_t index = 0;
+  for (const DexFile* dex_file : *dex_files) {
+    if (Runtime::Current()->GetClassLinker()->IsDexFileRegistered(*dex_file)) {
+      (*dex_files)[index] = nullptr;
+    }
+    index++;
   }
-  delete dex_file;
+
+  STLDeleteElements(dex_files.get());
+  // Unique_ptr will delete the vector itself.
 }
 
 static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, jobject javaLoader,
                                         jlong cookie) {
-  const DexFile* dex_file = toDexFile(cookie, env);
-  if (dex_file == NULL) {
+  std::vector<const DexFile*>* dex_files = toDexFiles(cookie, env);
+  if (dex_files == NULL) {
     VLOG(class_linker) << "Failed to find dex_file";
     return NULL;
   }
@@ -184,33 +176,60 @@
     return NULL;
   }
   const std::string descriptor(DotToDescriptor(class_name.c_str()));
-  const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str());
-  if (dex_class_def == NULL) {
-    VLOG(class_linker) << "Failed to find dex_class_def";
-    return NULL;
+
+  for (const DexFile* dex_file : *dex_files) {
+    const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str());
+    if (dex_class_def != nullptr) {
+      ScopedObjectAccess soa(env);
+      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+      class_linker->RegisterDexFile(*dex_file);
+      StackHandleScope<1> hs(soa.Self());
+      Handle<mirror::ClassLoader> class_loader(
+          hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
+      mirror::Class* result = class_linker->DefineClass(descriptor.c_str(), class_loader, *dex_file,
+                                                        *dex_class_def);
+      if (result != nullptr) {
+        VLOG(class_linker) << "DexFile_defineClassNative returning " << result;
+        return soa.AddLocalReference<jclass>(result);
+      }
+    }
   }
-  ScopedObjectAccess soa(env);
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  class_linker->RegisterDexFile(*dex_file);
-  StackHandleScope<1> hs(soa.Self());
-  Handle<mirror::ClassLoader> class_loader(
-      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
-  mirror::Class* result = class_linker->DefineClass(descriptor.c_str(), class_loader, *dex_file,
-                                                    *dex_class_def);
-  VLOG(class_linker) << "DexFile_defineClassNative returning " << result;
-  return soa.AddLocalReference<jclass>(result);
+  VLOG(class_linker) << "Failed to find dex_class_def";
+  return nullptr;
 }
 
+// Needed as a compare functor for sets of const char
+struct CharPointerComparator {
+  bool operator()(const char *str1, const char *str2) const {
+    return strcmp(str1, str2) < 0;
+  }
+};
+
+// Note: this can be an expensive call, as we sort out duplicates in MultiDex files.
 static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jlong cookie) {
   jobjectArray result = nullptr;
-  const DexFile* dex_file = toDexFile(cookie, env);
-  if (dex_file != nullptr) {
-    result = env->NewObjectArray(dex_file->NumClassDefs(), WellKnownClasses::java_lang_String,
-                                 nullptr);
-    if (result != nullptr) {
+  std::vector<const DexFile*>* dex_files = toDexFiles(cookie, env);
+
+  if (dex_files != nullptr) {
+    // Push all class descriptors into a set. Use set instead of unordered_set as we want to
+    // retrieve all in the end.
+    std::set<const char*, CharPointerComparator> descriptors;
+    for (const DexFile* dex_file : *dex_files) {
       for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) {
         const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
-        std::string descriptor(DescriptorToDot(dex_file->GetClassDescriptor(class_def)));
+        const char* descriptor = dex_file->GetClassDescriptor(class_def);
+        descriptors.insert(descriptor);
+      }
+    }
+
+    // Now create output array and copy the set into it.
+    result = env->NewObjectArray(descriptors.size(), WellKnownClasses::java_lang_String, nullptr);
+    if (result != nullptr) {
+      auto it = descriptors.begin();
+      auto it_end = descriptors.end();
+      jsize i = 0;
+      for (; it != it_end; it++, ++i) {
+        std::string descriptor(DescriptorToDot(*it));
         ScopedLocalRef<jstring> jdescriptor(env, env->NewStringUTF(descriptor.c_str()));
         if (jdescriptor.get() == nullptr) {
           return nullptr;
diff --git a/runtime/utils.cc b/runtime/utils.cc
index e5b8b22..c52549e 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1232,6 +1232,7 @@
 std::string DexFilenameToOdexFilename(const std::string& location, const InstructionSet isa) {
   // location = /foo/bar/baz.jar
   // odex_location = /foo/bar/<isa>/baz.odex
+
   CHECK_GE(location.size(), 4U) << location;  // must be at least .123
   std::string odex_location(location);
   InsertIsaDirectory(isa, &odex_location);
diff --git a/runtime/utils.h b/runtime/utils.h
index a61d30f..68ea475 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -401,6 +401,7 @@
 
 // Returns an .odex file name next adjacent to the dex location.
 // For example, for "/foo/bar/baz.jar", return "/foo/bar/<isa>/baz.odex".
+// Note: does not support multidex location strings.
 std::string DexFilenameToOdexFilename(const std::string& location, InstructionSet isa);
 
 // Check whether the given magic matches a known file type.
diff --git a/test/113-multidex/build b/test/113-multidex/build
new file mode 100644
index 0000000..ec8706e
--- /dev/null
+++ b/test/113-multidex/build
@@ -0,0 +1,32 @@
+#!/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.
+
+# Stop if something fails.
+set -e
+
+mkdir classes
+
+# All except Main
+${JAVAC} -d classes `find src -name '*.java'`
+rm classes/Main.class
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+
+# Only Main
+${JAVAC} -d classes `find src -name '*.java'`
+rm classes/Second.class classes/FillerA.class classes/FillerB.class classes/Inf*.class
+${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes
+
+zip $TEST_NAME.jar classes.dex classes2.dex
diff --git a/test/113-multidex/expected.txt b/test/113-multidex/expected.txt
new file mode 100644
index 0000000..603e911
--- /dev/null
+++ b/test/113-multidex/expected.txt
@@ -0,0 +1,12 @@
+FillerA
+Second
+Second::zcall
+Second::zcall1
+Second::zcall2
+Second::zcall3
+Second::zcall4
+Second::zcall5
+Second::zcall6
+Second::zcall7
+Second::zcall8
+Second::zcall9
diff --git a/test/113-multidex/info.txt b/test/113-multidex/info.txt
new file mode 100644
index 0000000..d0a4ac1
--- /dev/null
+++ b/test/113-multidex/info.txt
@@ -0,0 +1,2 @@
+Test whether we can run code from an application split into multiple dex files (similar to
+MultiDex).
diff --git a/test/113-multidex/src/FillerA.java b/test/113-multidex/src/FillerA.java
new file mode 100644
index 0000000..d169018
--- /dev/null
+++ b/test/113-multidex/src/FillerA.java
@@ -0,0 +1,23 @@
+/*
+ * 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 FillerA {
+  public void methodA() {
+  }
+
+  public void methodB() {
+  }
+}
diff --git a/test/113-multidex/src/FillerB.java b/test/113-multidex/src/FillerB.java
new file mode 100644
index 0000000..ec3ac9d
--- /dev/null
+++ b/test/113-multidex/src/FillerB.java
@@ -0,0 +1,23 @@
+/*
+ * 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 FillerB {
+  public void methodC() {
+  }
+
+  public void methodD() {
+  }
+}
diff --git a/test/113-multidex/src/Inf1.java b/test/113-multidex/src/Inf1.java
new file mode 100644
index 0000000..3deb6b4
--- /dev/null
+++ b/test/113-multidex/src/Inf1.java
@@ -0,0 +1,28 @@
+/*
+ * 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 interface Inf1 {
+  public void zcall();
+  public void zcall1();
+  public void zcall2();
+  public void zcall3();
+  public void zcall4();
+  public void zcall5();
+  public void zcall6();
+  public void zcall7();
+  public void zcall8();
+  public void zcall9();
+}
\ No newline at end of file
diff --git a/test/113-multidex/src/Inf2.java b/test/113-multidex/src/Inf2.java
new file mode 100644
index 0000000..ac09509
--- /dev/null
+++ b/test/113-multidex/src/Inf2.java
@@ -0,0 +1,28 @@
+/*
+ * 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 interface Inf2 {
+  public void zcall();
+  public void zcall1();
+  public void zcall2();
+  public void zcall3();
+  public void zcall4();
+  public void zcall5();
+  public void zcall6();
+  public void zcall7();
+  public void zcall8();
+  public void zcall9();
+}
\ No newline at end of file
diff --git a/test/113-multidex/src/Inf3.java b/test/113-multidex/src/Inf3.java
new file mode 100644
index 0000000..d6c377b
--- /dev/null
+++ b/test/113-multidex/src/Inf3.java
@@ -0,0 +1,28 @@
+/*
+ * 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 interface Inf3 {
+  public void zcall();
+  public void zcall1();
+  public void zcall2();
+  public void zcall3();
+  public void zcall4();
+  public void zcall5();
+  public void zcall6();
+  public void zcall7();
+  public void zcall8();
+  public void zcall9();
+}
\ No newline at end of file
diff --git a/test/113-multidex/src/Inf4.java b/test/113-multidex/src/Inf4.java
new file mode 100644
index 0000000..a1801b9
--- /dev/null
+++ b/test/113-multidex/src/Inf4.java
@@ -0,0 +1,28 @@
+/*
+ * 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 interface Inf4 {
+  public void zcall();
+  public void zcall1();
+  public void zcall2();
+  public void zcall3();
+  public void zcall4();
+  public void zcall5();
+  public void zcall6();
+  public void zcall7();
+  public void zcall8();
+  public void zcall9();
+}
\ No newline at end of file
diff --git a/test/113-multidex/src/Inf5.java b/test/113-multidex/src/Inf5.java
new file mode 100644
index 0000000..e8115ce
--- /dev/null
+++ b/test/113-multidex/src/Inf5.java
@@ -0,0 +1,28 @@
+/*
+ * 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 interface Inf5 {
+  public void zcall();
+  public void zcall1();
+  public void zcall2();
+  public void zcall3();
+  public void zcall4();
+  public void zcall5();
+  public void zcall6();
+  public void zcall7();
+  public void zcall8();
+  public void zcall9();
+}
\ No newline at end of file
diff --git a/test/113-multidex/src/Inf6.java b/test/113-multidex/src/Inf6.java
new file mode 100644
index 0000000..554bdb8
--- /dev/null
+++ b/test/113-multidex/src/Inf6.java
@@ -0,0 +1,28 @@
+/*
+ * 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 interface Inf6 {
+  public void zcall();
+  public void zcall1();
+  public void zcall2();
+  public void zcall3();
+  public void zcall4();
+  public void zcall5();
+  public void zcall6();
+  public void zcall7();
+  public void zcall8();
+  public void zcall9();
+}
\ No newline at end of file
diff --git a/test/113-multidex/src/Inf7.java b/test/113-multidex/src/Inf7.java
new file mode 100644
index 0000000..1982775
--- /dev/null
+++ b/test/113-multidex/src/Inf7.java
@@ -0,0 +1,28 @@
+/*
+ * 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 interface Inf7 {
+  public void zcall();
+  public void zcall1();
+  public void zcall2();
+  public void zcall3();
+  public void zcall4();
+  public void zcall5();
+  public void zcall6();
+  public void zcall7();
+  public void zcall8();
+  public void zcall9();
+}
\ No newline at end of file
diff --git a/test/113-multidex/src/Inf8.java b/test/113-multidex/src/Inf8.java
new file mode 100644
index 0000000..87296db
--- /dev/null
+++ b/test/113-multidex/src/Inf8.java
@@ -0,0 +1,28 @@
+/*
+ * 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 interface Inf8 {
+  public void zcall();
+  public void zcall1();
+  public void zcall2();
+  public void zcall3();
+  public void zcall4();
+  public void zcall5();
+  public void zcall6();
+  public void zcall7();
+  public void zcall8();
+  public void zcall9();
+}
\ No newline at end of file
diff --git a/test/113-multidex/src/Main.java b/test/113-multidex/src/Main.java
new file mode 100644
index 0000000..1c74220
--- /dev/null
+++ b/test/113-multidex/src/Main.java
@@ -0,0 +1,35 @@
+/*
+ * 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 {
+    static public void main(String[] args) throws Exception {
+      System.out.println(new FillerA().getClass().getName());
+
+      Inf1 second = new Second();
+      System.out.println(second.getClass().getName());
+      second.zcall();
+      second.zcall1();
+      second.zcall2();
+      second.zcall3();
+      second.zcall4();
+      second.zcall5();
+      second.zcall6();
+      second.zcall7();
+      second.zcall8();
+      second.zcall9();
+    }
+
+}
diff --git a/test/113-multidex/src/Second.java b/test/113-multidex/src/Second.java
new file mode 100644
index 0000000..d0c2535
--- /dev/null
+++ b/test/113-multidex/src/Second.java
@@ -0,0 +1,57 @@
+/*
+ * 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 Second implements Inf1, Inf2, Inf3, Inf4, Inf5, Inf6, Inf7, Inf8 {
+  public void zcall() {
+    System.out.println("Second::zcall");
+  }
+
+  public void zcall1() {
+    System.out.println("Second::zcall1");
+  }
+
+  public void zcall2() {
+    System.out.println("Second::zcall2");
+  }
+
+  public void zcall3() {
+    System.out.println("Second::zcall3");
+  }
+
+  public void zcall4() {
+    System.out.println("Second::zcall4");
+  }
+
+  public void zcall5() {
+    System.out.println("Second::zcall5");
+  }
+
+  public void zcall6() {
+    System.out.println("Second::zcall6");
+  }
+
+  public void zcall7() {
+    System.out.println("Second::zcall7");
+  }
+
+  public void zcall8() {
+    System.out.println("Second::zcall8");
+  }
+
+  public void zcall9() {
+    System.out.println("Second::zcall9");
+  }
+}
diff --git a/tools/generate-operator-out.py b/tools/generate-operator-out.py
index 56b8674..6baa6e3 100755
--- a/tools/generate-operator-out.py
+++ b/tools/generate-operator-out.py
@@ -23,11 +23,12 @@
 import sys
 
 
-_ENUM_START_RE = re.compile(r'\benum\b\s+(\S+)\s+:?.*\{')
+_ENUM_START_RE = re.compile(r'\benum\b\s+(class\s+)?(\S+)\s+:?.*\{(\s+// private)?')
 _ENUM_VALUE_RE = re.compile(r'([A-Za-z0-9_]+)(.*)')
 _ENUM_END_RE = re.compile(r'^\s*\};$')
 _ENUMS = {}
 _NAMESPACES = {}
+_ENUM_CLASSES = {}
 
 def Confused(filename, line_number, line):
   sys.stderr.write('%s:%d: confused by:\n%s\n' % (filename, line_number, line))
@@ -38,7 +39,9 @@
 def ProcessFile(filename):
   lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')
   in_enum = False
+  is_enum_class = False
   line_number = 0
+  
 
   namespaces = []
   enclosing_classes = []
@@ -51,11 +54,18 @@
       m = _ENUM_START_RE.search(raw_line)
       if m:
         # Yes, so add an empty entry to _ENUMS for this enum.
-        enum_name = m.group(1)
+        
+        # Except when it's private
+        if m.group(3) is not None:
+          continue
+        
+        is_enum_class = m.group(1) is not None
+        enum_name = m.group(2)
         if len(enclosing_classes) > 0:
           enum_name = '::'.join(enclosing_classes) + '::' + enum_name
         _ENUMS[enum_name] = []
         _NAMESPACES[enum_name] = '::'.join(namespaces)
+        _ENUM_CLASSES[enum_name] = is_enum_class
         in_enum = True
         continue
 
@@ -139,7 +149,10 @@
       Confused(filename, line_number, raw_line)
 
     if len(enclosing_classes) > 0:
-      enum_value = '::'.join(enclosing_classes) + '::' + enum_value
+      if is_enum_class:
+        enum_value = enum_name + '::' + enum_value
+      else:
+        enum_value = '::'.join(enclosing_classes) + '::' + enum_value
 
     _ENUMS[enum_name].append((enum_value, enum_text))
 
@@ -170,7 +183,8 @@
     print '  switch (rhs) {'
     for (enum_value, enum_text) in _ENUMS[enum_name]:
       print '    case %s: os << "%s"; break;' % (enum_value, enum_text)
-    print '    default: os << "%s[" << static_cast<int>(rhs) << "]"; break;' % enum_name
+    if not _ENUM_CLASSES[enum_name]:
+      print '    default: os << "%s[" << static_cast<int>(rhs) << "]"; break;' % enum_name
     print '  }'
     print '  return os;'
     print '}'