Merge "Add native memory accounting through custom allocator." into lmp-dev
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 4021c95..bed86d8 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -947,9 +947,9 @@
 bool Mir2Lir::CheckCorePoolSanity() {
   GrowableArray<RegisterInfo*>::Iterator it(&tempreg_info_);
   for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
-    if (info->IsTemp() && info->IsLive() && info->IsWide()) {
+    int my_sreg = info->SReg();
+    if (info->IsTemp() && info->IsLive() && info->IsWide() && my_sreg != INVALID_SREG) {
       RegStorage my_reg = info->GetReg();
-      int my_sreg = info->SReg();
       RegStorage partner_reg = info->Partner();
       RegisterInfo* partner = GetRegInfo(partner_reg);
       DCHECK(partner != NULL);
@@ -957,12 +957,8 @@
       DCHECK_EQ(my_reg.GetReg(), partner->Partner().GetReg());
       DCHECK(partner->IsLive());
       int partner_sreg = partner->SReg();
-      if (my_sreg == INVALID_SREG) {
-        DCHECK_EQ(partner_sreg, INVALID_SREG);
-      } else {
-        int diff = my_sreg - partner_sreg;
-        DCHECK((diff == 0) || (diff == -1) || (diff == 1));
-      }
+      int diff = my_sreg - partner_sreg;
+      DCHECK((diff == 0) || (diff == -1) || (diff == 1));
     }
     if (info->Master() != info) {
       // Aliased.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index efcc07d..c1610c2 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -61,6 +61,8 @@
 
 namespace art {
 
+static constexpr bool kTimeCompileMethod = !kIsDebugBuild;
+
 static double Percentage(size_t x, size_t y) {
   return 100.0 * (static_cast<double>(x)) / (static_cast<double>(x + y));
 }
@@ -1986,7 +1988,7 @@
                                    const DexFile& dex_file,
                                    DexToDexCompilationLevel dex_to_dex_compilation_level) {
   CompiledMethod* compiled_method = NULL;
-  uint64_t start_ns = NanoTime();
+  uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
 
   if ((access_flags & kAccNative) != 0) {
     // Are we interpreting only and have support for generic JNI down calls?
@@ -2014,10 +2016,12 @@
                               dex_to_dex_compilation_level);
     }
   }
-  uint64_t duration_ns = NanoTime() - start_ns;
-  if (duration_ns > MsToNs(compiler_->GetMaximumCompilationTimeBeforeWarning()) && !kIsDebugBuild) {
-    LOG(WARNING) << "Compilation of " << PrettyMethod(method_idx, dex_file)
-                 << " took " << PrettyDuration(duration_ns);
+  if (kTimeCompileMethod) {
+    uint64_t duration_ns = NanoTime() - start_ns;
+    if (duration_ns > MsToNs(compiler_->GetMaximumCompilationTimeBeforeWarning())) {
+      LOG(WARNING) << "Compilation of " << PrettyMethod(method_idx, dex_file)
+                   << " took " << PrettyDuration(duration_ns);
+    }
   }
 
   Thread* self = Thread::Current();
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index 28b69ec..564fcba 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -16,6 +16,7 @@
 
 
 #include "fault_handler.h"
+
 #include <sys/ucontext.h>
 #include "base/macros.h"
 #include "base/hex_dump.h"
@@ -46,6 +47,23 @@
   return instr_size;
 }
 
+void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+  // Note that in this handler we set up the registers and return to
+  // longjmp directly rather than going through an assembly language stub.  The
+  // reason for this is that longjmp is (currently) in ARM mode and that would
+  // require switching modes in the stub - incurring an unwanted relocation.
+
+  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+  Thread* self = Thread::Current();
+  CHECK(self != nullptr);       // This will cause a SIGABRT if self is nullptr.
+
+  sc->arm_r0 = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
+  sc->arm_r1 = 1;
+  sc->arm_pc = reinterpret_cast<uintptr_t>(longjmp);
+  VLOG(signals) << "longjmp address: " << reinterpret_cast<void*>(sc->arm_pc);
+}
+
 void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index b5948cb..687d232 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -37,6 +37,20 @@
 
 namespace art {
 
+void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+  // To match the case used in ARM we return directly to the longjmp function
+  // rather than through a trivial assembly language stub.
+
+  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+  Thread* self = Thread::Current();
+  CHECK(self != nullptr);       // This will cause a SIGABRT if self is nullptr.
+
+  sc->regs[0] = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
+  sc->regs[1] = 1;
+  sc->pc = reinterpret_cast<uintptr_t>(longjmp);
+}
+
 void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index 0e76aab..aa6d68a 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -29,6 +29,9 @@
 
 namespace art {
 
+void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+}
+
 void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index 65a48f6..fb26f5f 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -35,12 +35,14 @@
 #define CTX_EIP uc_mcontext->__ss.__rip
 #define CTX_EAX uc_mcontext->__ss.__rax
 #define CTX_METHOD uc_mcontext->__ss.__rdi
+#define CTX_JMP_BUF uc_mcontext->__ss.__rdi
 #else
 // 32 bit mac build.
 #define CTX_ESP uc_mcontext->__ss.__esp
 #define CTX_EIP uc_mcontext->__ss.__eip
 #define CTX_EAX uc_mcontext->__ss.__eax
 #define CTX_METHOD uc_mcontext->__ss.__eax
+#define CTX_JMP_BUF uc_mcontext->__ss.__eax
 #endif
 
 #elif defined(__x86_64__)
@@ -49,12 +51,15 @@
 #define CTX_EIP uc_mcontext.gregs[REG_RIP]
 #define CTX_EAX uc_mcontext.gregs[REG_RAX]
 #define CTX_METHOD uc_mcontext.gregs[REG_RDI]
+#define CTX_RDI uc_mcontext.gregs[REG_RDI]
+#define CTX_JMP_BUF uc_mcontext.gregs[REG_RDI]
 #else
 // 32 bit linux build.
 #define CTX_ESP uc_mcontext.gregs[REG_ESP]
 #define CTX_EIP uc_mcontext.gregs[REG_EIP]
 #define CTX_EAX uc_mcontext.gregs[REG_EAX]
 #define CTX_METHOD uc_mcontext.gregs[REG_EAX]
+#define CTX_JMP_BUF uc_mcontext.gregs[REG_EAX]
 #endif
 
 //
@@ -76,6 +81,12 @@
 #define EXT_SYM(sym) sym
 #endif
 
+// Note this is different from the others (no underscore on 64 bit mac) due to
+// the way the symbol is defined in the .S file.
+// TODO: fix the symbols for 64 bit mac - there is a double underscore prefix for some
+// of them.
+extern "C" void art_nested_signal_return();
+
 // Get the size of an instruction in bytes.
 // Return 0 if the instruction is not handled.
 static uint32_t GetInstructionSize(const uint8_t* pc) {
@@ -215,6 +226,21 @@
   return pc - startpc;
 }
 
+void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+  // For the Intel architectures we need to go to an assembly language
+  // stub.  This is because the 32 bit call to longjmp is much different
+  // from the 64 bit ABI call and pushing things onto the stack inside this
+  // handler was unwieldy and ugly.  The use of the stub means we can keep
+  // this code the same for both 32 and 64 bit.
+
+  Thread* self = Thread::Current();
+  CHECK(self != nullptr);       // This will cause a SIGABRT if self is nullptr.
+
+  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+  uc->CTX_JMP_BUF = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
+  uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_nested_signal_return);
+}
+
 void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
                                              mirror::ArtMethod** out_method,
                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 2f3e317..75c8646 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1357,5 +1357,18 @@
     ret
 END_FUNCTION art_quick_string_compareto
 
+// Return from a nested signal:
+// Entry:
+//  eax: address of jmp_buf in TLS
+
+DEFINE_FUNCTION art_nested_signal_return
+    SETUP_GOT_NOSAVE                // sets %ebx for call into PLT
+    movl LITERAL(1), %ecx
+    pushl %ecx                      // second arg to longjmp (1)
+    pushl %eax                      // first arg to longjmp (jmp_buf)
+    call PLT_SYMBOL(longjmp)
+    int3                            // won't get here.
+END_FUNCTION art_nested_signal_return
+
     // TODO: implement these!
 UNIMPLEMENTED art_quick_memcmp16
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index f95bd22..5798092 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1581,3 +1581,17 @@
     RESTORE_FP_CALLEE_SAVE_FRAME
     ret
 END_FUNCTION art_quick_assignable_from_code
+
+
+// Return from a nested signal:
+// Entry:
+//  rdi: address of jmp_buf in TLS
+
+DEFINE_FUNCTION art_nested_signal_return
+                                    // first arg to longjmp is already in correct register
+    movq LITERAL(1), %rsi           // second arg to longjmp (1)
+    call PLT_SYMBOL(longjmp)
+    int3                            // won't get here
+END_FUNCTION art_nested_signal_return
+
+
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 97f20d3..51ee448 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -947,31 +947,35 @@
     return nullptr;
   }
   Runtime* runtime = Runtime::Current();
-  const ImageHeader& image_header = runtime->GetHeap()->GetImageSpace()->GetImageHeader();
-  uint32_t expected_image_oat_checksum = image_header.GetOatChecksum();
-  uint32_t actual_image_oat_checksum = oat_file->GetOatHeader().GetImageFileLocationOatChecksum();
-  if (expected_image_oat_checksum != actual_image_oat_checksum) {
-    *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat checksum of "
-                              "0x%x, found 0x%x", oat_location, expected_image_oat_checksum,
-                              actual_image_oat_checksum);
-    return nullptr;
+  const gc::space::ImageSpace* image_space = runtime->GetHeap()->GetImageSpace();
+  if (image_space != nullptr) {
+    const ImageHeader& image_header = image_space->GetImageHeader();
+    uint32_t expected_image_oat_checksum = image_header.GetOatChecksum();
+    uint32_t actual_image_oat_checksum = oat_file->GetOatHeader().GetImageFileLocationOatChecksum();
+    if (expected_image_oat_checksum != actual_image_oat_checksum) {
+      *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat checksum of "
+                                "0x%x, found 0x%x", oat_location, expected_image_oat_checksum,
+                                actual_image_oat_checksum);
+      return nullptr;
+    }
+
+    uintptr_t expected_image_oat_offset = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
+    uint32_t actual_image_oat_offset = oat_file->GetOatHeader().GetImageFileLocationOatDataBegin();
+    if (expected_image_oat_offset != actual_image_oat_offset) {
+      *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat offset %"
+                                PRIuPTR ", found %ud", oat_location, expected_image_oat_offset,
+                                actual_image_oat_offset);
+      return nullptr;
+    }
+    int32_t expected_patch_delta = image_header.GetPatchDelta();
+    int32_t actual_patch_delta = oat_file->GetOatHeader().GetImagePatchDelta();
+    if (expected_patch_delta != actual_patch_delta) {
+      *error_msg = StringPrintf("Failed to find oat file at '%s' with expected patch delta %d, "
+                                " found %d", oat_location, expected_patch_delta, actual_patch_delta);
+      return nullptr;
+    }
   }
 
-  uintptr_t expected_image_oat_offset = reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin());
-  uint32_t actual_image_oat_offset = oat_file->GetOatHeader().GetImageFileLocationOatDataBegin();
-  if (expected_image_oat_offset != actual_image_oat_offset) {
-    *error_msg = StringPrintf("Failed to find oat file at '%s' with expected image oat offset %"
-                              PRIuPTR ", found %ud", oat_location, expected_image_oat_offset,
-                              actual_image_oat_offset);
-    return nullptr;
-  }
-  int32_t expected_patch_delta = image_header.GetPatchDelta();
-  int32_t actual_patch_delta = oat_file->GetOatHeader().GetImagePatchDelta();
-  if (expected_patch_delta != actual_patch_delta) {
-    *error_msg = StringPrintf("Failed to find oat file at '%s' with expected patch delta %d, "
-                              " found %d", oat_location, expected_patch_delta, actual_patch_delta);
-    return nullptr;
-  }
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
                                                                     &dex_location_checksum);
   if (oat_dex_file == nullptr) {
@@ -1171,6 +1175,7 @@
                                        error_msg.c_str()));
     return nullptr;
   } else if (!oat_file->IsExecutable() &&
+             Runtime::Current()->GetHeap()->HasImageSpace() &&
              !VerifyOatImageChecksum(oat_file.get(), isa)) {
     error_msgs->push_back(StringPrintf("Failed to verify non-executable oat file '%s' found for "
                                        "dex location '%s'. Image checksum incorrect.",
@@ -1253,6 +1258,7 @@
   std::string odex_error_msg;
   bool should_patch_system = false;
   bool odex_checksum_verified = false;
+  bool have_system_odex = false;
   {
     // There is a high probability that these both these oat files map similar/the same address
     // spaces so we must scope them like this so they each gets its turn.
@@ -1263,14 +1269,18 @@
                                                        &odex_error_msg)) {
       error_msgs->push_back(odex_error_msg);
       return odex_oat_file.release();
-    } else if (odex_checksum_verified) {
-      // We can just relocate
-      should_patch_system = true;
-      odex_error_msg = "Image Patches are incorrect";
+    } else {
+      if (odex_checksum_verified) {
+        // We can just relocate
+        should_patch_system = true;
+        odex_error_msg = "Image Patches are incorrect";
+      }
+      if (odex_oat_file.get() != nullptr) {
+        have_system_odex = true;
+      }
     }
   }
 
-
   std::string cache_error_msg;
   bool should_patch_cache = false;
   bool cache_checksum_verified = false;
@@ -1306,6 +1316,8 @@
         CHECK(have_dalvik_cache);
         ret = PatchAndRetrieveOat(cache_filename, cache_filename, image_location, isa, &error_msg);
       }
+    } else if (have_system_odex) {
+      ret = GetInterpretedOnlyOat(odex_filename, isa, &error_msg);
     }
   }
   if (ret == nullptr && have_dalvik_cache && OS::FileExists(cache_filename.c_str())) {
@@ -1355,7 +1367,8 @@
   if (output.get() == nullptr) {
     return nullptr;
   }
-  if (VerifyOatImageChecksum(output.get(), isa)) {
+  if (!Runtime::Current()->GetHeap()->HasImageSpace() ||
+      VerifyOatImageChecksum(output.get(), isa)) {
     return output.release();
   } else {
     *error_msg = StringPrintf("Could not use oat file '%s', image checksum failed to verify.",
@@ -2056,6 +2069,7 @@
     }
     return nullptr;
   }
+  self->AssertNoPendingException();
   CHECK(new_class != nullptr) << descriptor;
   CHECK(new_class->IsResolved()) << descriptor;
 
@@ -3642,6 +3656,10 @@
       proxy_class->GetDirectMethods();
   CHECK_EQ(proxy_direct_methods->GetLength(), 16);
   mirror::ArtMethod* proxy_constructor = proxy_direct_methods->Get(2);
+  // Ensure constructor is in dex cache so that we can use the dex cache to look up the overridden
+  // constructor method.
+  proxy_class->GetDexCache()->SetResolvedMethod(proxy_constructor->GetDexMethodIndex(),
+                                                proxy_constructor);
   // Clone the existing constructor of Proxy (our constructor would just invoke it so steal its
   // code_ too)
   mirror::ArtMethod* constructor = down_cast<mirror::ArtMethod*>(proxy_constructor->Clone(self));
@@ -3799,6 +3817,8 @@
           CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
         }
         return false;
+      } else {
+        self->AssertNoPendingException();
       }
     }
 
@@ -3808,6 +3828,10 @@
     // invocation of InitializeClass will not be responsible for
     // running <clinit> and will return.
     if (klass->GetStatus() == mirror::Class::kStatusInitializing) {
+      // Could have got an exception during verification.
+      if (self->IsExceptionPending()) {
+        return false;
+      }
       // We caught somebody else in the act; was it us?
       if (klass->GetClinitThreadId() == self->GetTid()) {
         // Yes. That's fine. Return so we can continue initializing.
@@ -4009,9 +4033,17 @@
 bool ClassLinker::EnsureInitialized(Handle<mirror::Class> c, bool can_init_fields,
                                     bool can_init_parents) {
   DCHECK(c.Get() != nullptr);
-  const bool success = c->IsInitialized() || InitializeClass(c, can_init_fields, can_init_parents);
-  if (!success && can_init_fields && can_init_parents) {
-    CHECK(Thread::Current()->IsExceptionPending()) << PrettyClass(c.Get());
+  if (c->IsInitialized()) {
+    return true;
+  }
+  const bool success = InitializeClass(c, can_init_fields, can_init_parents);
+  Thread* self = Thread::Current();
+  if (!success) {
+    if (can_init_fields && can_init_parents) {
+      CHECK(self->IsExceptionPending()) << PrettyClass(c.Get());
+    }
+  } else {
+    self->AssertNoPendingException();
   }
   return success;
 }
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 6f431c3..0092160 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2281,8 +2281,9 @@
   // trying to suspend this one.
   MutexLock mu(self, *Locks::thread_list_suspend_thread_lock_);
   bool timed_out;
-  Thread* thread = ThreadList::SuspendThreadByPeer(peer.get(), request_suspension, true,
-                                                   &timed_out);
+  ThreadList* thread_list = Runtime::Current()->GetThreadList();
+  Thread* thread = thread_list->SuspendThreadByPeer(peer.get(), request_suspension, true,
+                                                    &timed_out);
   if (thread != NULL) {
     return JDWP::ERR_NONE;
   } else if (timed_out) {
@@ -3170,8 +3171,8 @@
         {
           // Take suspend thread lock to avoid races with threads trying to suspend this one.
           MutexLock mu(soa.Self(), *Locks::thread_list_suspend_thread_lock_);
-          suspended_thread = ThreadList::SuspendThreadByPeer(thread_peer, true, true,
-                                                             &timed_out);
+          ThreadList* thread_list = Runtime::Current()->GetThreadList();
+          suspended_thread = thread_list->SuspendThreadByPeer(thread_peer, true, true, &timed_out);
         }
         CHECK_EQ(soa.Self()->TransitionFromSuspendedToRunnable(), kWaitingForDebuggerSuspension);
         if (suspended_thread == nullptr) {
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index af71c19..ccbedc0 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -47,6 +47,8 @@
     if (klass == NULL) {
       DCHECK(self->IsExceptionPending());
       return nullptr;  // Failure
+    } else {
+      DCHECK(!self->IsExceptionPending());
     }
   }
   if (kAccessCheck) {
@@ -79,6 +81,8 @@
     if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) {
       DCHECK(self->IsExceptionPending());
       return nullptr;  // Failure
+    } else {
+      DCHECK(!self->IsExceptionPending());
     }
     return h_klass.Get();
   }
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index f572d27..d205e2a 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -15,6 +15,7 @@
  */
 
 #include <memory>
+#include <setjmp.h>
 
 #include "base/macros.h"
 #include "common_runtime_test.h"
@@ -130,7 +131,7 @@
                         kPointerSize);
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_end, held_mutexes, kPointerSize);
     EXPECT_OFFSET_DIFF(Thread, tlsPtr_.held_mutexes, Thread, wait_mutex_,
-                       kPointerSize * kLockLevelCount, thread_tlsptr_end);
+                       kPointerSize * kLockLevelCount + kPointerSize, thread_tlsptr_end);
   }
 
   void CheckInterpreterEntryPoints() {
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 68fad7b..25f87c5 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -16,6 +16,7 @@
 
 #include "fault_handler.h"
 
+#include <setjmp.h>
 #include <sys/mman.h>
 #include <sys/ucontext.h>
 #include "mirror/art_method.h"
@@ -24,6 +25,47 @@
 #include "thread-inl.h"
 #include "verify_object-inl.h"
 
+// Note on nested signal support
+// -----------------------------
+//
+// Typically a signal handler should not need to deal with signals that occur within it.
+// However, when a SIGSEGV occurs that is in generated code and is not one of the
+// handled signals (implicit checks), we call a function to try to dump the stack
+// to the log.  This enhances the debugging experience but may have the side effect
+// that it may not work.  If the cause of the original SIGSEGV is a corrupted stack or other
+// memory region, the stack backtrace code may run into trouble and may either crash
+// or fail with an abort (SIGABRT).  In either case we don't want that (new) signal to
+// mask the original signal and thus prevent useful debug output from being presented.
+//
+// In order to handle this situation, before we call the stack tracer we do the following:
+//
+// 1. shutdown the fault manager so that we are talking to the real signal management
+//    functions rather than those in sigchain.
+// 2. use pthread_sigmask to allow SIGSEGV and SIGABRT signals to be delivered to the
+//    thread running the signal handler.
+// 3. set the handler for SIGSEGV and SIGABRT to a secondary signal handler.
+// 4. save the thread's state to the TLS of the current thread using 'setjmp'
+//
+// We then call the stack tracer and one of two things may happen:
+// a. it completes successfully
+// b. it crashes and a signal is raised.
+//
+// In the former case, we fall through and everything is fine.  In the latter case
+// our secondary signal handler gets called in a signal context.  This results in
+// a call to FaultManager::HandledNestedSignal(), an archirecture specific function
+// whose purpose is to call 'longjmp' on the jmp_buf saved in the TLS of the current
+// thread.  This results in a return with a non-zero value from 'setjmp'.  We detect this
+// and write something to the log to tell the user that it happened.
+//
+// Regardless of how we got there, we reach the code after the stack tracer and we
+// restore the signal states to their original values, reinstate the fault manager (thus
+// reestablishing the signal chain) and continue.
+
+// This is difficult to test with a runtime test.  To invoke the nested signal code
+// on any signal, uncomment the following line and run something that throws a
+// NullPointerException.
+// #define TEST_NESTED_SIGNAL
+
 namespace art {
 // Static fault manger object accessed by signal handler.
 FaultManager fault_manager;
@@ -37,10 +79,14 @@
 
 // Signal handler called on SIGSEGV.
 static void art_fault_handler(int sig, siginfo_t* info, void* context) {
-  // std::cout << "handling fault in ART handler\n";
   fault_manager.HandleFault(sig, info, context);
 }
 
+// Signal handler for dealing with a nested signal.
+static void art_nested_signal_handler(int sig, siginfo_t* info, void* context) {
+  fault_manager.HandleNestedSignal(sig, info, context);
+}
+
 FaultManager::FaultManager() : initialized_(false) {
   sigaction(SIGSEGV, nullptr, &oldaction_);
 }
@@ -82,26 +128,36 @@
   // If malloc calls abort, it will be holding its lock.
   // If the handler tries to call malloc, it will deadlock.
 
-  // Also, there is only an 8K stack available here to logging can cause memory
-  // overwrite issues if you are unlucky.  If you want to enable logging and
-  // are getting crashes, allocate more space for the alternate signal stack.
-
   VLOG(signals) << "Handling fault";
   if (IsInGeneratedCode(info, context, true)) {
     VLOG(signals) << "in generated code, looking for handler";
     for (const auto& handler : generated_code_handlers_) {
       VLOG(signals) << "invoking Action on handler " << handler;
       if (handler->Action(sig, info, context)) {
+#ifdef TEST_NESTED_SIGNAL
+        // In test mode we want to fall through to stack trace handler
+        // on every signal (in reality this will cause a crash on the first
+        // signal).
+        break;
+#else
+        // We have handled a signal so it's time to return from the
+        // signal handler to the appropriate place.
         return;
+#endif
       }
     }
   }
+
+  // We hit a signal we didn't handle.  This might be something for which
+  // we can give more information about so call all registered handlers to see
+  // if it is.
   for (const auto& handler : other_handlers_) {
     if (handler->Action(sig, info, context)) {
       return;
     }
   }
 
+  // Set a breakpoint in this function to catch unhandled signals.
   art_sigsegv_fault();
 
   // Pass this on to the next handler in the chain, or the default if none.
@@ -242,19 +298,90 @@
 
 bool JavaStackTraceHandler::Action(int sig, siginfo_t* siginfo, void* context) {
   // Make sure that we are in the generated code, but we may not have a dex pc.
-  if (manager_->IsInGeneratedCode(siginfo, context, false)) {
+
+#ifdef TEST_NESTED_SIGNAL
+  bool in_generated_code = true;
+#else
+  bool in_generated_code = manager_->IsInGeneratedCode(siginfo, context, false);
+#endif
+  if (in_generated_code) {
     LOG(ERROR) << "Dumping java stack trace for crash in generated code";
     mirror::ArtMethod* method = nullptr;
     uintptr_t return_pc = 0;
     uintptr_t sp = 0;
-    manager_->GetMethodAndReturnPcAndSp(siginfo, context, &method, &return_pc, &sp);
     Thread* self = Thread::Current();
-    // Inside of generated code, sp[0] is the method, so sp is the frame.
-    StackReference<mirror::ArtMethod>* frame =
-        reinterpret_cast<StackReference<mirror::ArtMethod>*>(sp);
-    self->SetTopOfStack(frame, 0);  // Since we don't necessarily have a dex pc, pass in 0.
-    self->DumpJavaStack(LOG(ERROR));
+
+    // Shutdown the fault manager so that it will remove the signal chain for
+    // SIGSEGV and we call the real sigaction.
+    fault_manager.Shutdown();
+
+    // The action for SIGSEGV should be the default handler now.
+
+    // Unblock the signals we allow so that they can be delivered in the signal handler.
+    sigset_t sigset;
+    sigemptyset(&sigset);
+    sigaddset(&sigset, SIGSEGV);
+    sigaddset(&sigset, SIGABRT);
+    pthread_sigmask(SIG_UNBLOCK, &sigset, nullptr);
+
+    // If we get a signal in this code we want to invoke our nested signal
+    // handler.
+    struct sigaction action, oldsegvaction, oldabortaction;
+    action.sa_sigaction = art_nested_signal_handler;
+
+    // Explictly mask out SIGSEGV and SIGABRT from the nested signal handler.  This
+    // should be the default but we definitely don't want these happening in our
+    // nested signal handler.
+    sigemptyset(&action.sa_mask);
+    sigaddset(&action.sa_mask, SIGSEGV);
+    sigaddset(&action.sa_mask, SIGABRT);
+
+    action.sa_flags = SA_SIGINFO | SA_ONSTACK;
+#if !defined(__APPLE__) && !defined(__mips__)
+    action.sa_restorer = nullptr;
+#endif
+
+    // Catch SIGSEGV and SIGABRT to invoke our nested handler
+    int e1 = sigaction(SIGSEGV, &action, &oldsegvaction);
+    int e2 = sigaction(SIGABRT, &action, &oldabortaction);
+    if (e1 != 0 || e2 != 0) {
+      LOG(ERROR) << "Unable to register nested signal handler - no stack trace possible";
+      // If sigaction failed we have a serious problem.  We cannot catch
+      // any failures in the stack tracer and it's likely to occur since
+      // the program state is bad.  Therefore we don't even try to give
+      // a stack trace.
+    } else {
+      // Save the current state and try to dump the stack.  If this causes a signal
+      // our nested signal handler will be invoked and this will longjmp to the saved
+      // state.
+      if (setjmp(*self->GetNestedSignalState()) == 0) {
+        manager_->GetMethodAndReturnPcAndSp(siginfo, context, &method, &return_pc, &sp);
+        // Inside of generated code, sp[0] is the method, so sp is the frame.
+        StackReference<mirror::ArtMethod>* frame =
+            reinterpret_cast<StackReference<mirror::ArtMethod>*>(sp);
+        self->SetTopOfStack(frame, 0);  // Since we don't necessarily have a dex pc, pass in 0.
+#ifdef TEST_NESTED_SIGNAL
+        // To test the nested signal handler we raise a signal here.  This will cause the
+        // nested signal handler to be called and perform a longjmp back to the setjmp
+        // above.
+        abort();
+#endif
+        self->DumpJavaStack(LOG(ERROR));
+      } else {
+        LOG(ERROR) << "Stack trace aborted due to nested signal - original signal being reported";
+      }
+
+      // Restore the signal handlers.
+      sigaction(SIGSEGV, &oldsegvaction, nullptr);
+      sigaction(SIGABRT, &oldabortaction, nullptr);
+    }
+
+    // Now put the fault manager back in place.
+    fault_manager.Init();
+
+    // And we're done.
   }
+
   return false;  // Return false since we want to propagate the fault to the main signal handler.
 }
 
diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h
index 0e9b908..bb26780 100644
--- a/runtime/fault_handler.h
+++ b/runtime/fault_handler.h
@@ -42,6 +42,7 @@
   void Shutdown();
 
   void HandleFault(int sig, siginfo_t* info, void* context);
+  void HandleNestedSignal(int sig, siginfo_t* info, void* context);
   void AddHandler(FaultHandler* handler, bool generated_code);
   void RemoveHandler(FaultHandler* handler);
 
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index aafe233..90ab323 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -189,7 +189,8 @@
   }
   // If we aren't the zygote, switch to the default non zygote allocator. This may update the
   // entrypoints.
-  if (!Runtime::Current()->IsZygote()) {
+  const bool is_zygote = Runtime::Current()->IsZygote();
+  if (!is_zygote) {
     large_object_threshold_ = kDefaultLargeObjectThreshold;
     // Background compaction is currently not supported for command line runs.
     if (background_collector_type_ != foreground_collector_type_) {
@@ -223,6 +224,8 @@
   requested_alloc_space_begin ->     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
                                      +-  nonmoving space (non_moving_space_capacity)+-
                                      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
+                                     +-????????????????????????????????????????????+-
+                                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
                                      +-main alloc space / bump space 1 (capacity_) +-
                                      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
                                      +-????????????????????????????????????????????+-
@@ -237,7 +240,6 @@
   // from the main space.
   // This is not the case if we support homogeneous compaction or have a moving background
   // collector type.
-  const bool is_zygote = Runtime::Current()->IsZygote();
   bool separate_non_moving_space = is_zygote ||
       support_homogeneous_space_compaction || IsMovingGc(foreground_collector_type_) ||
       IsMovingGc(background_collector_type_);
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 416c267..41c34c9 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -16,6 +16,9 @@
 
 #include "image_space.h"
 
+#include <dirent.h>
+#include <sys/types.h>
+
 #include <random>
 
 #include "base/stl_util.h"
@@ -65,7 +68,54 @@
   return r;
 }
 
-static bool GenerateImage(const std::string& image_filename, std::string* error_msg) {
+// We are relocating or generating the core image. We should get rid of everything. It is all
+// out-of-date. We also don't really care if this fails since it is just a convienence.
+// Adapted from prune_dex_cache(const char* subdir) in frameworks/native/cmds/installd/commands.c
+// Note this should only be used during first boot.
+static void RealPruneDexCache(const std::string& cache_dir_path);
+static void PruneDexCache(InstructionSet isa) {
+  CHECK_NE(isa, kNone);
+  // Prune the base /data/dalvik-cache
+  RealPruneDexCache(GetDalvikCacheOrDie(".", false));
+  // prune /data/dalvik-cache/<isa>
+  RealPruneDexCache(GetDalvikCacheOrDie(GetInstructionSetString(isa), false));
+}
+static void RealPruneDexCache(const std::string& cache_dir_path) {
+  if (!OS::DirectoryExists(cache_dir_path.c_str())) {
+    return;
+  }
+  DIR* cache_dir = opendir(cache_dir_path.c_str());
+  if (cache_dir == nullptr) {
+    PLOG(WARNING) << "Unable to open " << cache_dir_path << " to delete it's contents";
+    return;
+  }
+
+  for (struct dirent* de = readdir(cache_dir); de != nullptr; de = readdir(cache_dir)) {
+    const char* name = de->d_name;
+    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+      continue;
+    }
+    // We only want to delete regular files.
+    if (de->d_type != DT_REG) {
+      if (de->d_type != DT_DIR) {
+        // We do expect some directories (namely the <isa> for pruning the base dalvik-cache).
+        LOG(WARNING) << "Unexpected file type of " << std::hex << de->d_type << " encountered.";
+      }
+      continue;
+    }
+    std::string cache_file(cache_dir_path);
+    cache_file += '/';
+    cache_file += name;
+    if (TEMP_FAILURE_RETRY(unlink(cache_file.c_str())) != 0) {
+      PLOG(ERROR) << "Unable to unlink " << cache_file;
+      continue;
+    }
+  }
+  CHECK_EQ(0, TEMP_FAILURE_RETRY(closedir(cache_dir))) << "Unable to close directory.";
+}
+
+static bool GenerateImage(const std::string& image_filename, InstructionSet image_isa,
+                          std::string* error_msg) {
   const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
   std::vector<std::string> boot_class_path;
   Split(boot_class_path_string, ':', boot_class_path);
@@ -73,6 +123,11 @@
     *error_msg = "Failed to generate image because no boot class path specified";
     return false;
   }
+  // We should clean up so we are more likely to have room for the image.
+  if (Runtime::Current()->IsZygote()) {
+    LOG(INFO) << "Pruning dalvik-cache since we are relocating an image and will need to recompile";
+    PruneDexCache(image_isa);
+  }
 
   std::vector<std::string> arg_vector;
 
@@ -94,6 +149,7 @@
   arg_vector.push_back(oat_file_option_string);
 
   Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
+  CHECK_EQ(image_isa, kRuntimeISA) << "We should always be generating an image for the current isa.";
 
   int32_t base_offset = ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA,
                                                     ART_BASE_ADDRESS_MAX_DELTA);
@@ -169,6 +225,12 @@
 // Relocate the image at image_location to dest_filename and relocate it by a random amount.
 static bool RelocateImage(const char* image_location, const char* dest_filename,
                                InstructionSet isa, std::string* error_msg) {
+  // We should clean up so we are more likely to have room for the image.
+  if (Runtime::Current()->IsZygote()) {
+    LOG(INFO) << "Pruning dalvik-cache since we are relocating an image and will need to recompile";
+    PruneDexCache(isa);
+  }
+
   std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
 
   std::string input_image_location_arg("--input-image-location=");
@@ -398,7 +460,7 @@
   } else if (!dalvik_cache_exists) {
     *error_msg = StringPrintf("No place to put generated image.");
     return nullptr;
-  } else if (!GenerateImage(cache_filename, error_msg)) {
+  } else if (!GenerateImage(cache_filename, image_isa, error_msg)) {
     *error_msg = StringPrintf("Failed to generate image '%s': %s",
                               cache_filename.c_str(), error_msg->c_str());
     return nullptr;
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index 4155c82..a4f427c 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -143,7 +143,7 @@
 }
 
 void JdwpState::SendBufferedRequest(uint32_t type, const std::vector<iovec>& iov) {
-  if (netState->clientSock < 0) {
+  if (!IsConnected()) {
     // Can happen with some DDMS events.
     VLOG(jdwp) << "Not sending JDWP packet: no debugger attached!";
     return;
@@ -167,7 +167,7 @@
 }
 
 void JdwpState::SendRequest(ExpandBuf* pReq) {
-  if (netState->clientSock < 0) {
+  if (!IsConnected()) {
     // Can happen with some DDMS events.
     VLOG(jdwp) << "Not sending JDWP packet: no debugger attached!";
     return;
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index b079229..eef1c46 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -34,12 +34,13 @@
   } else {
     // Suspend thread to build stack trace.
     soa.Self()->TransitionFromRunnableToSuspended(kNative);
+    ThreadList* thread_list = Runtime::Current()->GetThreadList();
     bool timed_out;
     Thread* thread;
     {
       // Take suspend thread lock to avoid races with threads trying to suspend this one.
       MutexLock mu(soa.Self(), *Locks::thread_list_suspend_thread_lock_);
-      thread = ThreadList::SuspendThreadByPeer(peer, true, false, &timed_out);
+      thread = thread_list->SuspendThreadByPeer(peer, true, false, &timed_out);
     }
     if (thread != nullptr) {
       // Must be runnable to create returned array.
@@ -47,7 +48,7 @@
       trace = thread->CreateInternalStackTrace<false>(soa);
       soa.Self()->TransitionFromRunnableToSuspended(kNative);
       // Restart suspended thread.
-      Runtime::Current()->GetThreadList()->Resume(thread, false);
+      thread_list->Resume(thread, false);
     } else {
       if (timed_out) {
         LOG(ERROR) << "Trying to get thread's stack failed as the thread failed to suspend within a "
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index 8f83f96..c0c7265 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -128,19 +128,20 @@
   // Suspend thread to avoid it from killing itself while we set its name. We don't just hold the
   // thread list lock to avoid this, as setting the thread name causes mutator to lock/unlock
   // in the DDMS send code.
+  ThreadList* thread_list = Runtime::Current()->GetThreadList();
   bool timed_out;
   // Take suspend thread lock to avoid races with threads trying to suspend this one.
   Thread* thread;
   {
     MutexLock mu(self, *Locks::thread_list_suspend_thread_lock_);
-    thread = ThreadList::SuspendThreadByPeer(peer, true, false, &timed_out);
+    thread = thread_list->SuspendThreadByPeer(peer, true, false, &timed_out);
   }
   if (thread != NULL) {
     {
       ScopedObjectAccess soa(env);
       thread->SetThreadName(name.c_str());
     }
-    Runtime::Current()->GetThreadList()->Resume(thread, false);
+    thread_list->Resume(thread, false);
   } else if (timed_out) {
     LOG(ERROR) << "Trying to set thread name to '" << name.c_str() << "' failed as the thread "
         "failed to suspend within a generous timeout.";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 6305994..2ebdebd 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -24,6 +24,7 @@
 #include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "elf_file.h"
+#include "elf_utils.h"
 #include "oat.h"
 #include "mirror/art_method.h"
 #include "mirror/art_method-inl.h"
@@ -40,6 +41,17 @@
   CHECK(!location.empty());
 }
 
+OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file,
+                                  const std::string& location,
+                                  std::string* error_msg) {
+  std::unique_ptr<OatFile> oat_file(new OatFile(location, false));
+  oat_file->elf_file_.reset(elf_file);
+  Elf32_Shdr* hdr = elf_file->FindSectionByName(".rodata");
+  oat_file->begin_ = elf_file->Begin() + hdr->sh_offset;
+  oat_file->end_ = elf_file->Begin() + hdr->sh_size + hdr->sh_offset;
+  return oat_file->Setup(error_msg) ? oat_file.release() : nullptr;
+}
+
 OatFile* OatFile::OpenMemory(std::vector<uint8_t>& oat_contents,
                              const std::string& location,
                              std::string* error_msg) {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index e2a417f..0bf2b7b 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -40,6 +40,10 @@
 
 class OatFile {
  public:
+  // Opens an oat file contained within the given elf file. This is always opened as
+  // non-executable at the moment.
+  static OatFile* OpenWithElfFile(ElfFile* elf_file, const std::string& location,
+                                  std::string* error_msg);
   // Open an oat file. Returns NULL on failure.  Requested base can
   // optionally be used to request where the file should be loaded.
   static OatFile* Open(const std::string& filename,
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 9049020..c438ef7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -46,6 +46,7 @@
 #include "atomic.h"
 #include "class_linker.h"
 #include "debugger.h"
+#include "elf_file.h"
 #include "fault_handler.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
@@ -66,6 +67,7 @@
 #include "native_bridge_art_interface.h"
 #include "parsed_options.h"
 #include "oat_file.h"
+#include "os.h"
 #include "quick/quick_method_frame_info.h"
 #include "reflection.h"
 #include "ScopedLocalRef.h"
@@ -549,9 +551,74 @@
   VLOG(startup) << "Runtime::StartDaemonThreads exiting";
 }
 
+static bool OpenDexFilesFromImage(const std::vector<std::string>& dex_filenames,
+                                  const std::string& image_location,
+                                  std::vector<const DexFile*>& dex_files,
+                                  size_t* failures) {
+  std::string system_filename;
+  bool has_system = false;
+  std::string cache_filename_unused;
+  bool dalvik_cache_exists_unused;
+  bool has_cache_unused;
+  bool found_image = gc::space::ImageSpace::FindImageFilename(image_location.c_str(),
+                                                              kRuntimeISA,
+                                                              &system_filename,
+                                                              &has_system,
+                                                              &cache_filename_unused,
+                                                              &dalvik_cache_exists_unused,
+                                                              &has_cache_unused);
+  *failures = 0;
+  if (!found_image || !has_system) {
+    return false;
+  }
+  std::string error_msg;
+  // We are falling back to non-executable use of the oat file because patching failed, presumably
+  // due to lack of space.
+  std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(system_filename.c_str());
+  std::string oat_location = ImageHeader::GetOatLocationFromImageLocation(image_location.c_str());
+  std::unique_ptr<File> file(OS::OpenFileForReading(oat_filename.c_str()));
+  if (file.get() == nullptr) {
+    return false;
+  }
+  std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.release(), false, false, &error_msg));
+  if (elf_file.get() == nullptr) {
+    return false;
+  }
+  std::unique_ptr<OatFile> oat_file(OatFile::OpenWithElfFile(elf_file.release(), oat_location,
+                                                             &error_msg));
+  if (oat_file.get() == nullptr) {
+    LOG(INFO) << "Unable to use '" << oat_filename << "' because " << error_msg;
+    return false;
+  }
+
+  std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file->GetOatDexFiles();
+  for (size_t i = 0; i < oat_dex_files.size(); i++) {
+    const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
+    if (oat_dex_file == nullptr) {
+      *failures += 1;
+      continue;
+    }
+    const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
+    if (dex_file == nullptr) {
+      *failures += 1;
+    } else {
+      dex_files.push_back(dex_file);
+    }
+  }
+  Runtime::Current()->GetClassLinker()->RegisterOatFile(oat_file.release());
+  return true;
+}
+
+
 static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames,
+                           const std::string& image_location,
                            std::vector<const DexFile*>& dex_files) {
   size_t failure_count = 0;
+  if (!image_location.empty() && OpenDexFilesFromImage(dex_filenames, image_location, dex_files,
+                                                       &failure_count)) {
+    return failure_count;
+  }
+  failure_count = 0;
   for (size_t i = 0; i < dex_filenames.size(); i++) {
     const char* dex_filename = dex_filenames[i].c_str();
     std::string error_msg;
@@ -715,7 +782,7 @@
     std::vector<std::string> dex_filenames;
     Split(boot_class_path_string_, ':', dex_filenames);
     std::vector<const DexFile*> boot_class_path;
-    OpenDexFiles(dex_filenames, boot_class_path);
+    OpenDexFiles(dex_filenames, options->image_, boot_class_path);
     class_linker_->InitWithoutImage(boot_class_path);
     // TODO: Should we move the following to InitWithoutImage?
     SetInstructionSet(kRuntimeISA);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index e652100..10688ff 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -487,11 +487,14 @@
 void Thread::InitStackHwm() {
   void* read_stack_base;
   size_t read_stack_size;
-  GetThreadStack(tlsPtr_.pthread_self, &read_stack_base, &read_stack_size);
+  size_t read_guard_size;
+  GetThreadStack(tlsPtr_.pthread_self, &read_stack_base, &read_stack_size, &read_guard_size);
 
-  // TODO: include this in the thread dumps; potentially useful in SIGQUIT output?
-  VLOG(threads) << StringPrintf("Native stack is at %p (%s)", read_stack_base,
-                                PrettySize(read_stack_size).c_str());
+  // This is included in the SIGQUIT output, but it's useful here for thread debugging.
+  VLOG(threads) << StringPrintf("Native stack is at %p (%s with %s guard)",
+                                read_stack_base,
+                                PrettySize(read_stack_size).c_str(),
+                                PrettySize(read_guard_size).c_str());
 
   tlsPtr_.stack_begin = reinterpret_cast<byte*>(read_stack_base);
   tlsPtr_.stack_size = read_stack_size;
@@ -539,33 +542,20 @@
 #endif
 
   // Set stack_end_ to the bottom of the stack saving space of stack overflows
-  bool implicit_stack_check = !Runtime::Current()->ExplicitStackOverflowChecks();
+
+  Runtime* runtime = Runtime::Current();
+  bool implicit_stack_check = !runtime->ExplicitStackOverflowChecks() && !runtime->IsCompiler();
   ResetDefaultStackEnd();
 
   // Install the protected region if we are doing implicit overflow checks.
   if (implicit_stack_check) {
-    size_t guardsize;
-    pthread_attr_t attributes;
-    CHECK_PTHREAD_CALL(pthread_attr_init, (&attributes), "guard size query");
-    CHECK_PTHREAD_CALL(pthread_attr_getguardsize, (&attributes, &guardsize), "guard size query");
-    CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), "guard size query");
     // The thread might have protected region at the bottom.  We need
     // to install our own region so we need to move the limits
     // of the stack to make room for it.
 
-#if defined(__i386__) || defined(__x86_64__)
-    // Work around issue trying to read last page of stack on Intel.
-    // The bug for this is b/17111575.  The problem is that we are
-    // unable to read the page just above the guard page on the
-    // main stack on an intel target.  When the bug is fixed
-    // this can be removed.
-    if (::art::GetTid() == getpid()) {
-      guardsize += 4 * KB;
-    }
-#endif
-    tlsPtr_.stack_begin += guardsize + kStackOverflowProtectedSize;
-    tlsPtr_.stack_end += guardsize + kStackOverflowProtectedSize;
-    tlsPtr_.stack_size -= guardsize;
+    tlsPtr_.stack_begin += read_guard_size + kStackOverflowProtectedSize;
+    tlsPtr_.stack_end += read_guard_size + kStackOverflowProtectedSize;
+    tlsPtr_.stack_size -= read_guard_size;
 
     InstallImplicitProtection();
   }
@@ -1077,6 +1067,7 @@
   tlsPtr_.single_step_control = new SingleStepControl;
   tlsPtr_.instrumentation_stack = new std::deque<instrumentation::InstrumentationStackFrame>;
   tlsPtr_.name = new std::string(kThreadNameDuringStartup);
+  tlsPtr_.nested_signal_state = static_cast<jmp_buf*>(malloc(sizeof(jmp_buf)));
 
   CHECK_EQ((sizeof(Thread) % 4), 0U) << sizeof(Thread);
   tls32_.state_and_flags.as_struct.flags = 0;
@@ -1209,6 +1200,7 @@
   delete tlsPtr_.instrumentation_stack;
   delete tlsPtr_.name;
   delete tlsPtr_.stack_trace_sample;
+  free(tlsPtr_.nested_signal_state);
 
   Runtime::Current()->GetHeap()->RevokeThreadLocalBuffers(this);
 
diff --git a/runtime/thread.h b/runtime/thread.h
index ea86378..0c64f1f 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -22,6 +22,7 @@
 #include <iosfwd>
 #include <list>
 #include <memory>
+#include <setjmp.h>
 #include <string>
 
 #include "atomic.h"
@@ -848,6 +849,10 @@
     tls32_.handling_signal_ = false;
   }
 
+  jmp_buf* GetNestedSignalState() {
+    return tlsPtr_.nested_signal_state;
+  }
+
  private:
   explicit Thread(bool daemon);
   ~Thread() LOCKS_EXCLUDED(Locks::mutator_lock_,
@@ -1136,6 +1141,9 @@
 
     // Support for Mutex lock hierarchy bug detection.
     BaseMutex* held_mutexes[kLockLevelCount];
+
+    // Recorded thread state for nested signals.
+    jmp_buf* nested_signal_state;
   } tlsPtr_;
 
   // Guards the 'interrupted_' and 'wait_monitor_' members.
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 9d85ec3..fc687dc 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -406,7 +406,8 @@
 void ThreadList::Resume(Thread* thread, bool for_debugger) {
   Thread* self = Thread::Current();
   DCHECK_NE(thread, self);
-  VLOG(threads) << "Resume(" << *thread << ") starting..." << (for_debugger ? " (debugger)" : "");
+  VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") starting..."
+      << (for_debugger ? " (debugger)" : "");
 
   {
     // To check Contains.
@@ -415,18 +416,22 @@
     MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
     DCHECK(thread->IsSuspended());
     if (!Contains(thread)) {
+      // We only expect threads within the thread-list to have been suspended otherwise we can't
+      // stop such threads from delete-ing themselves.
+      LOG(ERROR) << "Resume(" << reinterpret_cast<void*>(thread)
+          << ") thread not within thread list";
       return;
     }
     thread->ModifySuspendCount(self, -1, for_debugger);
   }
 
   {
-    VLOG(threads) << "Resume(" << *thread << ") waking others";
+    VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") waking others";
     MutexLock mu(self, *Locks::thread_suspend_count_lock_);
     Thread::resume_cond_->Broadcast(self);
   }
 
-  VLOG(threads) << "Resume(" << *thread << ") complete";
+  VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") complete";
 }
 
 static void ThreadSuspendByPeerWarning(Thread* self, int level, const char* message, jobject peer) {
@@ -451,6 +456,7 @@
   bool did_suspend_request = false;
   *timed_out = false;
   Thread* self = Thread::Current();
+  VLOG(threads) << "SuspendThreadByPeer starting";
   while (true) {
     Thread* thread;
     {
@@ -462,10 +468,16 @@
       ScopedObjectAccess soa(self);
       MutexLock mu(self, *Locks::thread_list_lock_);
       thread = Thread::FromManagedThread(soa, peer);
-      if (thread == NULL) {
+      if (thread == nullptr) {
         ThreadSuspendByPeerWarning(self, WARNING, "No such thread for suspend", peer);
-        return NULL;
+        return nullptr;
       }
+      if (!Contains(thread)) {
+        VLOG(threads) << "SuspendThreadByPeer failed for unattached thread: "
+            << reinterpret_cast<void*>(thread);
+        return nullptr;
+      }
+      VLOG(threads) << "SuspendThreadByPeer found thread: " << *thread;
       {
         MutexLock mu(self, *Locks::thread_suspend_count_lock_);
         if (request_suspension) {
@@ -485,6 +497,7 @@
         // count, or else we've waited and it has self suspended) or is the current thread, we're
         // done.
         if (thread->IsSuspended()) {
+          VLOG(threads) << "SuspendThreadByPeer thread suspended: " << *thread;
           return thread;
         }
         if (total_delay_us >= kTimeoutUs) {
@@ -493,11 +506,12 @@
             thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
           }
           *timed_out = true;
-          return NULL;
+          return nullptr;
         }
       }
       // Release locks and come out of runnable state.
     }
+    VLOG(threads) << "SuspendThreadByPeer sleeping to allow thread chance to suspend";
     ThreadSuspendSleep(self, &delay_us, &total_delay_us);
   }
 }
@@ -515,6 +529,7 @@
   Thread* suspended_thread = nullptr;
   Thread* self = Thread::Current();
   CHECK_NE(thread_id, kInvalidThreadId);
+  VLOG(threads) << "SuspendThreadByThreadId starting";
   while (true) {
     {
       // Note: this will transition to runnable and potentially suspend. We ensure only one thread
@@ -536,8 +551,10 @@
             << " no longer in thread list";
         // There's a race in inflating a lock and the owner giving up ownership and then dying.
         ThreadSuspendByThreadIdWarning(WARNING, "No such thread id for suspend", thread_id);
-        return NULL;
+        return nullptr;
       }
+      VLOG(threads) << "SuspendThreadByThreadId found thread: " << *thread;
+      DCHECK(Contains(thread));
       {
         MutexLock mu(self, *Locks::thread_suspend_count_lock_);
         if (suspended_thread == nullptr) {
@@ -557,6 +574,7 @@
         // count, or else we've waited and it has self suspended) or is the current thread, we're
         // done.
         if (thread->IsSuspended()) {
+          VLOG(threads) << "SuspendThreadByThreadId thread suspended: " << *thread;
           return thread;
         }
         if (total_delay_us >= kTimeoutUs) {
@@ -565,11 +583,12 @@
             thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
           }
           *timed_out = true;
-          return NULL;
+          return nullptr;
         }
       }
       // Release locks and come out of runnable state.
     }
+    VLOG(threads) << "SuspendThreadByThreadId sleeping to allow thread chance to suspend";
     ThreadSuspendSleep(self, &delay_us, &total_delay_us);
   }
 }
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 1b67ac0..bb4f775 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -66,8 +66,8 @@
   // If the thread should be suspended then value of request_suspension should be true otherwise
   // the routine will wait for a previous suspend request. If the suspension times out then *timeout
   // is set to true.
-  static Thread* SuspendThreadByPeer(jobject peer, bool request_suspension, bool debug_suspension,
-                                     bool* timed_out)
+  Thread* SuspendThreadByPeer(jobject peer, bool request_suspension, bool debug_suspension,
+                              bool* timed_out)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_suspend_thread_lock_)
       LOCKS_EXCLUDED(Locks::mutator_lock_,
                      Locks::thread_list_lock_,
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 4f73e69..d704eec 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -82,7 +82,7 @@
   return result;
 }
 
-void GetThreadStack(pthread_t thread, void** stack_base, size_t* stack_size) {
+void GetThreadStack(pthread_t thread, void** stack_base, size_t* stack_size, size_t* guard_size) {
 #if defined(__APPLE__)
   *stack_size = pthread_get_stacksize_np(thread);
   void* stack_addr = pthread_get_stackaddr_np(thread);
@@ -95,10 +95,17 @@
   } else {
     *stack_base = stack_addr;
   }
+
+  // This is wrong, but there doesn't seem to be a way to get the actual value on the Mac.
+  pthread_attr_t attributes;
+  CHECK_PTHREAD_CALL(pthread_attr_init, (&attributes), __FUNCTION__);
+  CHECK_PTHREAD_CALL(pthread_attr_getguardsize, (&attributes, guard_size), __FUNCTION__);
+  CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), __FUNCTION__);
 #else
   pthread_attr_t attributes;
   CHECK_PTHREAD_CALL(pthread_getattr_np, (thread, &attributes), __FUNCTION__);
   CHECK_PTHREAD_CALL(pthread_attr_getstack, (&attributes, stack_base, stack_size), __FUNCTION__);
+  CHECK_PTHREAD_CALL(pthread_attr_getguardsize, (&attributes, guard_size), __FUNCTION__);
   CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), __FUNCTION__);
 #endif
 }
diff --git a/runtime/utils.h b/runtime/utils.h
index d821ae1..c4a5895 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -416,7 +416,7 @@
 std::string GetThreadName(pid_t tid);
 
 // Returns details of the given thread's stack.
-void GetThreadStack(pthread_t thread, void** stack_base, size_t* stack_size);
+void GetThreadStack(pthread_t thread, void** stack_base, size_t* stack_size, size_t* guard_size);
 
 // Reads data from "/proc/self/task/${tid}/stat".
 void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index c375c77..0ee4414 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -47,6 +47,7 @@
 namespace art {
 namespace verifier {
 
+static constexpr bool kTimeVerifyMethod = !kIsDebugBuild;
 static constexpr bool gDebugVerify = false;
 // TODO: Add a constant to method_verifier to turn on verbose logging?
 
@@ -247,7 +248,7 @@
                                                          bool allow_soft_failures,
                                                          bool need_precise_constants) {
   MethodVerifier::FailureKind result = kNoFailure;
-  uint64_t start_ns = NanoTime();
+  uint64_t start_ns = kTimeVerifyMethod ? NanoTime() : 0;
 
   MethodVerifier verifier(dex_file, &dex_cache, &class_loader, class_def, code_item,
                            method_idx, method, method_access_flags, true, allow_soft_failures,
@@ -275,10 +276,12 @@
     }
     result = kHardFailure;
   }
-  uint64_t duration_ns = NanoTime() - start_ns;
-  if (duration_ns > MsToNs(100) && !kIsDebugBuild) {
-    LOG(WARNING) << "Verification of " << PrettyMethod(method_idx, *dex_file)
-                 << " took " << PrettyDuration(duration_ns);
+  if (kTimeVerifyMethod) {
+    uint64_t duration_ns = NanoTime() - start_ns;
+    if (duration_ns > MsToNs(100)) {
+      LOG(WARNING) << "Verification of " << PrettyMethod(method_idx, *dex_file)
+                   << " took " << PrettyDuration(duration_ns);
+    }
   }
   return result;
 }
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
index 2ba7405..c655226 100644
--- a/sigchainlib/sigchain.cc
+++ b/sigchainlib/sigchain.cc
@@ -45,8 +45,8 @@
 
   // Unclaim the signal and restore the old action.
   void Unclaim(int signal) {
-    sigaction(signal, &action_, NULL);        // Restore old action.
     claimed_ = false;
+    sigaction(signal, &action_, NULL);        // Restore old action.
   }
 
   // Get the action associated with this signal.
@@ -155,8 +155,12 @@
 
   void* linked_sigaction_sym = dlsym(RTLD_NEXT, "sigaction");
   if (linked_sigaction_sym == nullptr) {
-    log("Unable to find next sigaction in signal chain");
-    abort();
+    linked_sigaction_sym = dlsym(RTLD_DEFAULT, "sigaction");
+    if (linked_sigaction_sym == nullptr ||
+        linked_sigaction_sym == reinterpret_cast<void*>(sigaction)) {
+      log("Unable to find next sigaction in signal chain");
+      abort();
+    }
   }
 
   typedef int (*SigAction)(int, const struct sigaction*, struct sigaction*);
@@ -184,8 +188,12 @@
 
   void* linked_sigprocmask_sym = dlsym(RTLD_NEXT, "sigprocmask");
   if (linked_sigprocmask_sym == nullptr) {
-    log("Unable to find next sigprocmask in signal chain");
-    abort();
+    linked_sigprocmask_sym = dlsym(RTLD_DEFAULT, "sigprocmask");
+    if (linked_sigprocmask_sym == nullptr ||
+        linked_sigprocmask_sym == reinterpret_cast<void*>(sigprocmask)) {
+      log("Unable to find next sigprocmask in signal chain");
+      abort();
+    }
   }
 
   typedef int (*SigProcMask)(int how, const sigset_t*, sigset_t*);
diff --git a/test/051-thread/expected.txt b/test/051-thread/expected.txt
index 7139b7f..943d1df 100644
--- a/test/051-thread/expected.txt
+++ b/test/051-thread/expected.txt
@@ -6,4 +6,7 @@
 testThreadDaemons @ Thread bailing
 testThreadDaemons finished
 testSleepZero finished
+testSetName starting
+testSetName running
+testSetName finished
 thread test done
diff --git a/test/051-thread/src/Main.java b/test/051-thread/src/Main.java
index 608b7e0..390685d 100644
--- a/test/051-thread/src/Main.java
+++ b/test/051-thread/src/Main.java
@@ -25,6 +25,7 @@
         testThreadCapacity();
         testThreadDaemons();
         testSleepZero();
+        testSetName();
         System.out.println("thread test done");
     }
 
@@ -112,4 +113,24 @@
         }
         System.out.print("testSleepZero finished\n");
     }
+
+    private static void testSetName() throws Exception {
+        System.out.print("testSetName starting\n");
+        Thread thread = new Thread() {
+            @Override
+            public void run() {
+                System.out.print("testSetName running\n");
+            }
+        };
+        thread.start();
+        thread.setName("HelloWorld");  // b/17302037 hang if setName called after start
+        if (!thread.getName().equals("HelloWorld")) {
+            throw new AssertionError("Unexpected thread name: " + thread.getName());
+        }
+        thread.join();
+        if (!thread.getName().equals("HelloWorld")) {
+            throw new AssertionError("Unexpected thread name after join: " + thread.getName());
+        }
+        System.out.print("testSetName finished\n");
+    }
 }
diff --git a/test/119-noimage-patchoat/expected.txt b/test/119-noimage-patchoat/expected.txt
new file mode 100644
index 0000000..e864268
--- /dev/null
+++ b/test/119-noimage-patchoat/expected.txt
@@ -0,0 +1,6 @@
+Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false
+Has image is false, is image dex2oat enabled is false.
+Run -Ximage-dex2oat
+Has image is true, is image dex2oat enabled is true.
+Run default
+Has image is true, is image dex2oat enabled is true.
diff --git a/test/119-noimage-patchoat/info.txt b/test/119-noimage-patchoat/info.txt
new file mode 100644
index 0000000..6b85368
--- /dev/null
+++ b/test/119-noimage-patchoat/info.txt
@@ -0,0 +1 @@
+Test that disables patchoat'ing the image.
diff --git a/test/119-noimage-patchoat/run b/test/119-noimage-patchoat/run
new file mode 100644
index 0000000..745b0c9
--- /dev/null
+++ b/test/119-noimage-patchoat/run
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Force relocation otherwise we will just use the already created core.oat/art pair.
+flags="${@/--no-relocate/--relocate}"
+
+if [ $(basename $RUN) == 'host-run-test-jar' ]; then
+  false_bin="/bin/false"
+else
+  false_bin="/system/bin/false"
+fi
+
+# Make sure we can run without an image file,
+echo "Run -Xnoimage-dex2oat -Xpatchoat:/system/bin/false"
+${RUN} ${flags} ${BPATH} --runtime-option -Xnoimage-dex2oat --runtime-option -Xpatchoat:${false_bin}
+
+# Make sure we can run with the image file.
+echo "Run -Ximage-dex2oat"
+${RUN} ${flags} ${BPATH} --runtime-option -Ximage-dex2oat
+
+# Make sure we can run with the default settings.
+echo "Run default"
+${RUN} ${flags} ${BPATH}
diff --git a/test/119-noimage-patchoat/src/Main.java b/test/119-noimage-patchoat/src/Main.java
new file mode 100644
index 0000000..11c736a
--- /dev/null
+++ b/test/119-noimage-patchoat/src/Main.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static void main(String[] args) {
+    boolean hasImage = hasImage();
+    System.out.println(
+        "Has image is " + hasImage + ", is image dex2oat enabled is "
+        + isImageDex2OatEnabled() + ".");
+
+    if (hasImage && !isImageDex2OatEnabled()) {
+      throw new Error("Image with dex2oat disabled runs with an oat file");
+    } else if (!hasImage && isImageDex2OatEnabled()) {
+      throw new Error("Image with dex2oat enabled runs without an oat file");
+    }
+  }
+
+  static {
+    System.loadLibrary("arttest");
+  }
+
+  private native static boolean hasImage();
+
+  private native static boolean isImageDex2OatEnabled();
+}