Merge "Fix bug in CardTable::ModifyCardsAtomic."
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index f5bb85a..364a8bc 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -141,24 +141,25 @@
 CompilationUnit::~CompilationUnit() {
 }
 
-// TODO: Add a cumulative version of logging, and combine with dex2oat --dump-timing
 void CompilationUnit::StartTimingSplit(const char* label) {
-  if (enable_debug & (1 << kDebugTimings)) {
+  if (compiler_driver->GetDumpPasses()) {
     timings.StartSplit(label);
   }
 }
 
 void CompilationUnit::NewTimingSplit(const char* label) {
-  if (enable_debug & (1 << kDebugTimings)) {
+  if (compiler_driver->GetDumpPasses()) {
     timings.NewSplit(label);
   }
 }
 
 void CompilationUnit::EndTiming() {
-  if (enable_debug & (1 << kDebugTimings)) {
+  if (compiler_driver->GetDumpPasses()) {
     timings.EndSplit();
-    LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
-    LOG(INFO) << Dumpable<TimingLogger>(timings);
+    if (enable_debug & (1 << kDebugTimings)) {
+      LOG(INFO) << "TIMINGS " << PrettyMethod(method_idx, *dex_file);
+      LOG(INFO) << Dumpable<TimingLogger>(timings);
+    }
   }
 }
 
@@ -316,6 +317,9 @@
   }
 
   cu.EndTiming();
+  compiler.GetTimingsLogger().Start();
+  compiler.GetTimingsLogger().AddLogger(cu.timings);
+  compiler.GetTimingsLogger().End();
   return result;
 }
 
diff --git a/compiler/dex/pass_driver.cc b/compiler/dex/pass_driver.cc
index 99541ac..820dc5a 100644
--- a/compiler/dex/pass_driver.cc
+++ b/compiler/dex/pass_driver.cc
@@ -25,7 +25,20 @@
 
 namespace art {
 
-PassDriver::PassDriver(CompilationUnit* const cu, bool create_default_passes) : cu_(cu) {
+namespace {  // anonymous namespace
+
+/**
+ * @brief Helper function to create a single instance of a given Pass and can be shared across the threads
+ */
+template <typename PassType>
+const Pass* GetPassInstance() {
+  static const PassType pass;
+  return &pass;
+}
+
+}  // anonymous namespace
+
+PassDriver::PassDriver(CompilationUnit* cu, bool create_default_passes) : cu_(cu) {
   dump_cfg_folder_ = "/sdcard/";
 
   // If need be, create the default passes.
@@ -39,7 +52,7 @@
   pass_map_.clear();
 }
 
-void PassDriver::InsertPass(Pass* new_pass, bool warn_override) {
+void PassDriver::InsertPass(const Pass* new_pass, bool warn_override) {
   assert(new_pass != 0);
 
   // Get name here to not do it all over the method.
@@ -47,7 +60,7 @@
 
   // Do we want to warn the user about squashing a pass?
   if (warn_override == false) {
-    SafeMap<std::string, Pass* >::iterator it = pass_map_.find(name);
+    auto it = pass_map_.find(name);
 
     if (it != pass_map_.end()) {
       LOG(INFO) << "Pass name " << name << " already used, overwriting pass";
@@ -71,16 +84,16 @@
    * Disadvantage is the passes can't change their internal states depending on CompilationUnit:
    *   - This is not yet an issue: no current pass would require it.
    */
-  static UniquePtr<Pass> *passes[] = {
-      new UniquePtr<Pass>(new CodeLayout()),
-      new UniquePtr<Pass>(new SSATransformation()),
-      new UniquePtr<Pass>(new ConstantPropagation()),
-      new UniquePtr<Pass>(new InitRegLocations()),
-      new UniquePtr<Pass>(new MethodUseCount()),
-      new UniquePtr<Pass>(new NullCheckEliminationAndTypeInferenceInit()),
-      new UniquePtr<Pass>(new NullCheckEliminationAndTypeInference()),
-      new UniquePtr<Pass>(new BBCombine()),
-      new UniquePtr<Pass>(new BBOptimizations()),
+  static const Pass* passes[] = {
+      GetPassInstance<CodeLayout>(),
+      GetPassInstance<SSATransformation>(),
+      GetPassInstance<ConstantPropagation>(),
+      GetPassInstance<InitRegLocations>(),
+      GetPassInstance<MethodUseCount>(),
+      GetPassInstance<NullCheckEliminationAndTypeInferenceInit>(),
+      GetPassInstance<NullCheckEliminationAndTypeInference>(),
+      GetPassInstance<BBCombine>(),
+      GetPassInstance<BBOptimizations>(),
   };
 
   // Get number of elements in the array.
@@ -90,17 +103,17 @@
   //   - Map is used for the lookup
   //   - List is used for the pass walk
   for (unsigned int i = 0; i < nbr; i++) {
-    InsertPass(passes[i]->get());
+    InsertPass(passes[i]);
   }
 }
 
-void PassDriver::HandlePassFlag(CompilationUnit* c_unit, Pass* pass) {
+void PassDriver::HandlePassFlag(CompilationUnit* c_unit, const Pass* pass) {
   // Unused parameters for the moment.
   UNUSED(c_unit);
   UNUSED(pass);
 }
 
-void PassDriver::DispatchPass(CompilationUnit* c_unit, Pass* curPass) {
+void PassDriver::DispatchPass(CompilationUnit* c_unit, const Pass* curPass) {
   DataflowIterator* iterator = 0;
 
   LOG(DEBUG) << "Dispatching " << curPass->GetName();
@@ -147,13 +160,13 @@
   }
 }
 
-void PassDriver::ApplyPass(CompilationUnit* c_unit, Pass* curPass) {
+void PassDriver::ApplyPass(CompilationUnit* c_unit, const Pass* curPass) {
   curPass->Start(c_unit);
   DispatchPass(c_unit, curPass);
   curPass->End(c_unit);
 }
 
-bool PassDriver::RunPass(CompilationUnit* c_unit, Pass* curPass, bool time_split) {
+bool PassDriver::RunPass(CompilationUnit* c_unit, const Pass* curPass, bool time_split) {
   // Paranoid: c_unit or curPass cannot be 0, and the pass should have a name.
   if (c_unit == 0 || curPass == 0 || (strcmp(curPass->GetName(), "") == 0)) {
     return false;
@@ -200,7 +213,7 @@
     return false;
   }
 
-  Pass* curPass = GetPass(pass_name);
+  const Pass* curPass = GetPass(pass_name);
 
   if (curPass != 0) {
     return RunPass(c_unit, curPass);
@@ -211,8 +224,7 @@
 }
 
 void PassDriver::Launch() {
-  for (std::list<Pass* >::iterator it = pass_list_.begin(); it != pass_list_.end(); it++) {
-    Pass* curPass = *it;
+  for (const Pass *curPass : pass_list_) {
     RunPass(cu_, curPass, true);
   }
 }
@@ -220,14 +232,13 @@
 void PassDriver::PrintPassNames() const {
   LOG(INFO) << "Loop Passes are:";
 
-  for (std::list<Pass* >::const_iterator it = pass_list_.begin(); it != pass_list_.end(); it++) {
-    const Pass* curPass = *it;
+  for (const Pass *curPass : pass_list_) {
     LOG(INFO) << "\t-" << curPass->GetName();
   }
 }
 
-Pass* PassDriver::GetPass(const std::string& name) const {
-  SafeMap<std::string, Pass*>::const_iterator it = pass_map_.find(name);
+const Pass* PassDriver::GetPass(const std::string& name) const {
+  auto it = pass_map_.find(name);
 
   if (it != pass_map_.end()) {
     return it->second;
diff --git a/compiler/dex/pass_driver.h b/compiler/dex/pass_driver.h
index 29da351..d580460 100644
--- a/compiler/dex/pass_driver.h
+++ b/compiler/dex/pass_driver.h
@@ -33,7 +33,7 @@
  */
 class PassDriver {
  public:
-  explicit PassDriver(CompilationUnit* const cu, bool create_default_passes = true);
+  explicit PassDriver(CompilationUnit* cu, bool create_default_passes = true);
 
   ~PassDriver();
 
@@ -42,7 +42,7 @@
    * @param new_pass the new Pass to insert in the map and list.
    * @param warn_override warn if the name of the Pass is already used.
    */
-  void InsertPass(Pass *new_pass, bool warn_override = true);
+  void InsertPass(const Pass* new_pass, bool warn_override = true);
 
   /**
    * @brief Run a pass using the name as key.
@@ -57,25 +57,25 @@
    * @param time_split do we want a time split request(default: false)?
    * @return whether the pass was applied.
    */
-  bool RunPass(CompilationUnit* c_unit, Pass* pass, bool time_split = false);
+  bool RunPass(CompilationUnit* c_unit, const Pass* pass, bool time_split = false);
 
   void Launch();
 
-  void HandlePassFlag(CompilationUnit* c_unit, Pass* pass);
+  void HandlePassFlag(CompilationUnit* c_unit, const Pass* pass);
 
   /**
    * @brief Apply a patch: perform start/work/end functions.
    */
-  void ApplyPass(CompilationUnit* c_unit, Pass* pass);
+  void ApplyPass(CompilationUnit* c_unit, const Pass* pass);
 
   /**
    * @brief Dispatch a patch: walk the BasicBlocks depending on the traversal mode
    */
-  void DispatchPass(CompilationUnit* c_unit, Pass* pass);
+  void DispatchPass(CompilationUnit* c_unit, const Pass* pass);
 
   void PrintPassNames() const;
 
-  Pass* GetPass(const std::string& name) const;
+  const Pass* GetPass(const std::string& name) const;
 
   const char *GetDumpCFGFolder() const {
     return dump_cfg_folder_;
@@ -85,10 +85,10 @@
   void CreatePasses();
 
   /** @brief The Pass Map: contains name -> pass for quick lookup. */
-  SafeMap<std::string, Pass*> pass_map_;
+  SafeMap<std::string, const Pass*> pass_map_;
 
   /** @brief List of passes: provides the order to execute the passes. */
-  std::list<Pass*> pass_list_;
+  std::list<const Pass*> pass_list_;
 
   /** @brief The CompilationUnit on which to execute the passes on. */
   CompilationUnit* const cu_;
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5edc8b6..714dc4c 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -341,7 +341,7 @@
                                CompilerBackend compiler_backend, InstructionSet instruction_set,
                                InstructionSetFeatures instruction_set_features,
                                bool image, DescriptorSet* image_classes, size_t thread_count,
-                               bool dump_stats)
+                               bool dump_stats, bool dump_passes, CumulativeLogger* timer)
     : verified_methods_data_(verified_methods_data),
       method_inliner_map_(method_inliner_map),
       compiler_backend_(compiler_backend),
@@ -356,6 +356,8 @@
       start_ns_(0),
       stats_(new AOTCompilationStats),
       dump_stats_(dump_stats),
+      dump_passes_(dump_passes),
+      timings_logger_(timer),
       compiler_library_(NULL),
       compiler_(NULL),
       compiler_context_(NULL),
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 9e31624..aabdf2f 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "base/mutex.h"
+#include "base/timing_logger.h"
 #include "class_reference.h"
 #include "compiled_class.h"
 #include "compiled_method.h"
@@ -97,7 +98,8 @@
                           CompilerBackend compiler_backend, InstructionSet instruction_set,
                           InstructionSetFeatures instruction_set_features,
                           bool image, DescriptorSet* image_classes,
-                          size_t thread_count, bool dump_stats);
+                          size_t thread_count, bool dump_stats, bool dump_passes,
+                          CumulativeLogger* timer);
 
   ~CompilerDriver();
 
@@ -267,6 +269,14 @@
     return thread_count_;
   }
 
+  bool GetDumpPasses() const {
+    return dump_passes_;
+  }
+
+  CumulativeLogger& GetTimingsLogger() const {
+    return *timings_logger_;
+  }
+
   class PatchInformation {
    public:
     const DexFile& GetDexFile() const {
@@ -436,6 +446,9 @@
   UniquePtr<AOTCompilationStats> stats_;
 
   bool dump_stats_;
+  const bool dump_passes_;
+
+  CumulativeLogger* const timings_logger_;
 
   typedef void (*CompilerCallbackFn)(CompilerDriver& driver);
   typedef MutexLock* (*CompilerMutexLockFn)(CompilerDriver& driver);
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 2434262..12d8212 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -82,10 +82,11 @@
   verified_methods_data_.reset(new VerifiedMethodsData);
   method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
   callbacks_.Reset(verified_methods_data_.get(), method_inliner_map_.get());
+  CumulativeLogger timer("Compilation times");
   compiler_driver_.reset(new CompilerDriver(verified_methods_data_.get(),
                                             method_inliner_map_.get(),
                                             compiler_backend, insn_set,
-                                            insn_features, false, NULL, 2, true));
+                                            insn_features, false, NULL, 2, true, true, &timer));
   jobject class_loader = NULL;
   if (kCompile) {
     TimingLogger timings("OatTest::WriteRead", false, false);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 26fac23..20fafe2 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -249,7 +249,9 @@
                                       bool image,
                                       UniquePtr<CompilerDriver::DescriptorSet>& image_classes,
                                       bool dump_stats,
-                                      TimingLogger& timings) {
+                                      bool dump_passes,
+                                      TimingLogger& timings,
+                                      CumulativeLogger& compiler_phases_timings) {
     // SirtRef and ClassLoader creation needs to come after Runtime::Create
     jobject class_loader = NULL;
     Thread* self = Thread::Current();
@@ -276,7 +278,9 @@
                                                         image,
                                                         image_classes.release(),
                                                         thread_count_,
-                                                        dump_stats));
+                                                        dump_stats,
+                                                        dump_passes,
+                                                        &compiler_phases_timings));
 
     if (compiler_backend_ == kPortable) {
       driver->SetBitcodeFileName(bitcode_filename);
@@ -650,6 +654,7 @@
 
 static int dex2oat(int argc, char** argv) {
   TimingLogger timings("compiler", false, false);
+  CumulativeLogger compiler_phases_timings("compilation times");
 
   InitLogging(argv);
 
@@ -703,6 +708,7 @@
   bool is_host = false;
   bool dump_stats = false;
   bool dump_timing = false;
+  bool dump_passes = false;
   bool dump_slow_timing = kIsDebugBuild;
   bool watch_dog_enabled = !kIsTargetBuild;
 
@@ -796,6 +802,8 @@
       runtime_args.push_back(argv[i]);
     } else if (option == "--dump-timing") {
       dump_timing = true;
+    } else if (option == "--dump-passes") {
+      dump_passes = true;
     } else if (option == "--dump-stats") {
       dump_stats = true;
     } else {
@@ -1067,7 +1075,9 @@
                                                                   image,
                                                                   image_classes,
                                                                   dump_stats,
-                                                                  timings));
+                                                                  dump_passes,
+                                                                  timings,
+                                                                  compiler_phases_timings));
 
   if (compiler.get() == NULL) {
     LOG(ERROR) << "Failed to create oat file: " << oat_location;
@@ -1143,6 +1153,9 @@
     if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
       LOG(INFO) << Dumpable<TimingLogger>(timings);
     }
+    if (dump_passes) {
+      LOG(INFO) << Dumpable<CumulativeLogger>(compiler.get()->GetTimingsLogger());
+    }
     return EXIT_SUCCESS;
   }
 
@@ -1185,6 +1198,9 @@
   if (dump_timing || (dump_slow_timing && timings.GetTotalNs() > MsToNs(1000))) {
     LOG(INFO) << Dumpable<TimingLogger>(timings);
   }
+  if (dump_passes) {
+    LOG(INFO) << Dumpable<CumulativeLogger>(compiler_phases_timings);
+  }
 
   // Everything was successfully written, do an explicit exit here to avoid running Runtime
   // destructors that take time (bug 10645725) unless we're a debug build or running on valgrind.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 131ebf8..b1117a2 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -540,7 +540,8 @@
 
 bool ClassLinker::GenerateOatFile(const char* dex_filename,
                                   int oat_fd,
-                                  const char* oat_cache_filename) {
+                                  const char* oat_cache_filename,
+                                  std::string* error_msg) {
   Locks::mutator_lock_->AssertNotHeld(Thread::Current());  // Avoid starving GC.
   std::string dex2oat_string(GetAndroidRoot());
   dex2oat_string += (kIsDebugBuild ? "/bin/dex2oatd" : "/bin/dex2oat");
@@ -633,15 +634,13 @@
     int status;
     pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
     if (got_pid != pid) {
-      ScopedObjectAccess soa(Thread::Current());
-      ThrowIOException("Failed to create oat file. Waitpid failed: wanted %d, got %d", pid,
-                       got_pid);
+      *error_msg = StringPrintf("Failed to create oat file. Waitpid failed: wanted %d, got %d",
+                                pid, got_pid);
       return false;
     }
     if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-      ScopedObjectAccess soa(Thread::Current());
-      ThrowIOException("Failed to create oat file. %s failed with dex-file '%s'", dex2oat,
-                       dex_filename);
+      *error_msg = StringPrintf("Failed to create oat file. %s failed with dex-file '%s'",
+                                dex2oat, dex_filename);
       return false;
     }
   }
@@ -827,10 +826,24 @@
       << oat_location << "': " << *error_msg;
   error_msg->clear();
 
+  {
+    // We might have registered an outdated OatFile in FindDexFileInOatLocation().
+    // Get rid of it as its MAP_PRIVATE mapping may not reflect changes we're about to do.
+    WriterMutexLock mu(Thread::Current(), dex_lock_);
+    for (size_t i = 0; i < oat_files_.size(); ++i) {
+      if (oat_location == oat_files_[i]->GetLocation()) {
+        VLOG(class_linker) << "De-registering old OatFile: " << oat_location;
+        delete oat_files_[i];
+        oat_files_.erase(oat_files_.begin() + i);
+        break;
+      }
+    }
+  }
+
   // 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)) {
-    CHECK(Thread::Current()->IsExceptionPending());
+  if (!GenerateOatFile(dex_location, scoped_flock.GetFile().Fd(), oat_location, error_msg)) {
+    CHECK(!error_msg->empty());
     return nullptr;
   }
   const OatFile* oat_file = OatFile::Open(oat_location, oat_location, NULL,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index d468e1e..8722de3 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -251,7 +251,8 @@
   // Generate an oat file from a dex file
   bool GenerateOatFile(const char* dex_filename,
                        int oat_fd,
-                       const char* oat_cache_filename);
+                       const char* oat_cache_filename,
+                       std::string* error_msg);
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   const OatFile* FindOatFileFromOatLocation(const std::string& location,
diff --git a/runtime/common_test.h b/runtime/common_test.h
index ee95d5b..a75a513 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -474,12 +474,13 @@
         }
       }
       class_linker_->FixupDexCaches(runtime_->GetResolutionMethod());
+      CumulativeLogger timer("Compilation times");
       compiler_driver_.reset(new CompilerDriver(verified_methods_data_.get(),
                                                 method_inliner_map_.get(),
                                                 compiler_backend, instruction_set,
                                                 instruction_set_features,
                                                 true, new CompilerDriver::DescriptorSet,
-                                                2, true));
+                                                2, true, true, &timer));
     }
     // We typically don't generate an image in unit tests, disable this optimization by default.
     compiler_driver_->SetSupportBootImageFixup(false);
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 39e838f..97b34ef 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -16,7 +16,7 @@
 
 #include "mem_map.h"
 
-#include <backtrace/backtrace.h>
+#include <backtrace/BacktraceMap.h>
 
 #include "base/stringprintf.h"
 #include "ScopedFd.h"
@@ -32,12 +32,16 @@
 
 #if !defined(NDEBUG)
 
-static std::ostream& operator<<(std::ostream& os, backtrace_map_info_t* rhs) {
-  for (backtrace_map_info_t* m = rhs; m != NULL; m = m->next) {
-    os << StringPrintf("0x%08x-0x%08x %c%c %s\n",
-                       static_cast<uint32_t>(m->start),
-                       static_cast<uint32_t>(m->end),
-                       m->is_readable ? 'r' : '-', m->is_executable ? 'x' : '-', m->name);
+static std::ostream& operator<<(
+    std::ostream& os,
+    std::pair<BacktraceMap::const_iterator, BacktraceMap::const_iterator> iters) {
+  for (BacktraceMap::const_iterator it = iters.first; it != iters.second; ++it) {
+    os << StringPrintf("0x%08x-0x%08x %c%c%c %s\n",
+                       static_cast<uint32_t>(it->start),
+                       static_cast<uint32_t>(it->end),
+                       (it->flags & PROT_READ) ? 'r' : '-',
+                       (it->flags & PROT_WRITE) ? 'w' : '-',
+                       (it->flags & PROT_EXEC) ? 'x' : '-', it->name.c_str());
   }
   return os;
 }
@@ -47,20 +51,24 @@
     return;
   }
 
-  uint32_t base = reinterpret_cast<size_t>(addr);
-  uint32_t limit = base + byte_count;
+  uintptr_t base = reinterpret_cast<uintptr_t>(addr);
+  uintptr_t limit = base + byte_count;
 
-  backtrace_map_info_t* map_info_list = backtrace_create_map_info_list(getpid());
-  for (backtrace_map_info_t* m = map_info_list; m != NULL; m = m->next) {
-    CHECK(!(base >= m->start && base < m->end)     // start of new within old
-        && !(limit > m->start && limit < m->end)   // end of new within old
-        && !(base <= m->start && limit > m->end))  // start/end of new includes all of old
+  BacktraceMap map(getpid());
+  if (!map.Build()) {
+    PLOG(WARNING) << "Failed to build process map";
+    return;
+  }
+  for (BacktraceMap::const_iterator it = map.begin(); it != map.end(); ++it) {
+    CHECK(!(base >= it->start && base < it->end)     // start of new within old
+        && !(limit > it->start && limit < it->end)   // end of new within old
+        && !(base <= it->start && limit > it->end))  // start/end of new includes all of old
         << StringPrintf("Requested region 0x%08x-0x%08x overlaps with existing map 0x%08x-0x%08x (%s)\n",
                         base, limit,
-                        static_cast<uint32_t>(m->start), static_cast<uint32_t>(m->end), m->name)
-        << map_info_list;
+                        static_cast<uint32_t>(it->start), static_cast<uint32_t>(it->end),
+                        it->name.c_str())
+        << std::make_pair(it, map.end());
   }
-  backtrace_destroy_map_info_list(map_info_list);
 }
 
 #else
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 600045f..45a2eed 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -120,7 +120,9 @@
                                                          outputName.c_str(), &error_msg);
   }
   if (dex_file == nullptr) {
-    CHECK_EQ(env->ExceptionCheck(), JNI_TRUE);
+    ScopedObjectAccess soa(env);
+    CHECK(!error_msg.empty());
+    ThrowIOException("%s", error_msg.c_str());
     return 0;
   }
   return static_cast<jint>(reinterpret_cast<uintptr_t>(dex_file));
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 2ad4c4a..a293043 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -16,6 +16,7 @@
 
 #include "utils.h"
 
+#include <inttypes.h>
 #include <pthread.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
@@ -1035,17 +1036,17 @@
   return "";
 }
 
-static const char* CleanMapName(const char* map_name) {
-  if (map_name == NULL) {
+static std::string CleanMapName(const backtrace_map_t* map) {
+  if (map == NULL || map->name.empty()) {
     return "???";
   }
   // Turn "/usr/local/google/home/enh/clean-dalvik-dev/out/host/linux-x86/lib/libartd.so"
   // into "libartd.so".
-  const char* last_slash = strrchr(map_name, '/');
-  if (last_slash != NULL) {
-    map_name = last_slash + 1;
+  size_t last_slash = map->name.rfind('/');
+  if (last_slash == std::string::npos) {
+    return map->name;
   }
-  return map_name;
+  return map->name.substr(last_slash);
 }
 
 void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix, bool include_count) {
@@ -1058,25 +1059,24 @@
     return;
   }
 
-  for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
+  for (Backtrace::const_iterator it = backtrace->begin();
+       it != backtrace->end(); ++it) {
     // We produce output like this:
     // ]    #00 unwind_backtrace_thread+536 [0x55d75bb8] (libbacktrace.so)
-    const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
-
     os << prefix;
     if (include_count) {
-      os << StringPrintf("#%02zu ", i);
+      os << StringPrintf("#%02zu ", it->num);
     }
-    if (frame->func_name) {
-      os << frame->func_name;
+    if (!it->func_name.empty()) {
+      os << it->func_name;
     } else {
       os << "???";
     }
-    if (frame->func_offset != 0) {
-      os << "+" << frame->func_offset;
+    if (it->func_offset != 0) {
+      os << "+" << it->func_offset;
     }
-    os << StringPrintf(" [%p]", reinterpret_cast<void*>(frame->pc));
-    os << " (" << CleanMapName(frame->map_name) << ")\n";
+    os << StringPrintf(" [%p]", reinterpret_cast<void*>(it->pc));
+    os << " (" << CleanMapName(it->map) << ")\n";
   }
 }