Merge "Fix HandleScope with wrong thread error"
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 63f5f94..d0a72bb 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2596,7 +2596,8 @@
                                                          Register out_hi) {
   if (offset != 0) {
     __ LoadImmediate(out_lo, offset);
-    __ add(addr, addr, ShifterOperand(out_lo));
+    __ add(IP, addr, ShifterOperand(out_lo));
+    addr = IP;
   }
   __ ldrexd(out_lo, out_hi, addr);
 }
@@ -2610,7 +2611,8 @@
   Label fail;
   if (offset != 0) {
     __ LoadImmediate(temp1, offset);
-    __ add(addr, addr, ShifterOperand(temp1));
+    __ add(IP, addr, ShifterOperand(temp1));
+    addr = IP;
   }
   __ Bind(&fail);
   // We need a load followed by store. (The address used in a STREX instruction must
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 63009bf..4f279f2 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1014,17 +1014,16 @@
   bool Setup() {
     TimingLogger::ScopedTiming t("dex2oat Setup", timings_);
     RuntimeOptions runtime_options;
-    std::vector<const DexFile*> boot_class_path;
     art::MemMap::Init();  // For ZipEntry::ExtractToMemMap.
     if (boot_image_option_.empty()) {
-      size_t failure_count = OpenDexFiles(dex_filenames_, dex_locations_, boot_class_path);
-      if (failure_count > 0) {
-        LOG(ERROR) << "Failed to open some dex files: " << failure_count;
-        return false;
-      }
-      runtime_options.push_back(std::make_pair("bootclasspath", &boot_class_path));
+      std::string boot_class_path = "-Xbootclasspath:";
+      boot_class_path += Join(dex_filenames_, ':');
+      runtime_options.push_back(std::make_pair(boot_class_path, nullptr));
+      std::string boot_class_path_locations = "-Xbootclasspath-locations:";
+      boot_class_path_locations += Join(dex_locations_, ':');
+      runtime_options.push_back(std::make_pair(boot_class_path_locations, nullptr));
     } else {
-      runtime_options.push_back(std::make_pair(boot_image_option_.c_str(), nullptr));
+      runtime_options.push_back(std::make_pair(boot_image_option_, nullptr));
     }
     for (size_t i = 0; i < runtime_args_.size(); i++) {
       runtime_options.push_back(std::make_pair(runtime_args_[i], nullptr));
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 98fe079..75ba9dd 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -201,22 +201,17 @@
   int mkdir_result = mkdir(dalvik_cache_.c_str(), 0700);
   ASSERT_EQ(mkdir_result, 0);
 
-  MemMap::Init();  // For LoadExpectSingleDexFile
-
-  std::string error_msg;
-  java_lang_dex_file_ = LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str());
-  boot_class_path_.push_back(java_lang_dex_file_);
-
   std::string min_heap_string(StringPrintf("-Xms%zdm", gc::Heap::kDefaultInitialSize / MB));
   std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB));
 
   callbacks_.reset(new NoopCompilerCallbacks());
 
   RuntimeOptions options;
-  options.push_back(std::make_pair("bootclasspath", &boot_class_path_));
+  std::string boot_class_path_string = "-Xbootclasspath:" + GetLibCoreDexFileName();
+  options.push_back(std::make_pair(boot_class_path_string, nullptr));
   options.push_back(std::make_pair("-Xcheck:jni", nullptr));
-  options.push_back(std::make_pair(min_heap_string.c_str(), nullptr));
-  options.push_back(std::make_pair(max_heap_string.c_str(), nullptr));
+  options.push_back(std::make_pair(min_heap_string, nullptr));
+  options.push_back(std::make_pair(max_heap_string, nullptr));
   options.push_back(std::make_pair("compilercallbacks", callbacks_.get()));
   SetUpRuntimeOptions(&options);
   if (!Runtime::Create(options, false)) {
@@ -239,6 +234,11 @@
   // pool is created by the runtime.
   runtime_->GetHeap()->CreateThreadPool();
   runtime_->GetHeap()->VerifyHeap();  // Check for heap corruption before the test
+
+  // Get the boot class path from the runtime so it can be used in tests.
+  boot_class_path_ = class_linker_->GetBootClassPath();
+  ASSERT_FALSE(boot_class_path_.empty());
+  java_lang_dex_file_ = boot_class_path_[0];
 }
 
 void CommonRuntimeTest::ClearDirectory(const char* dirpath) {
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 8851185..35dc30f 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -116,7 +116,7 @@
   std::string android_data_;
   std::string dalvik_cache_;
   const DexFile* java_lang_dex_file_;  // owned by runtime_
-  std::vector<const DexFile*> boot_class_path_;
+  std::vector<const DexFile*> boot_class_path_;  // owned by runtime_
   std::unique_ptr<Runtime> runtime_;
   // Owned by the runtime
   ClassLinker* class_linker_;
diff --git a/runtime/java_vm_ext_test.cc b/runtime/java_vm_ext_test.cc
index 60c6a5c..2cbfa81 100644
--- a/runtime/java_vm_ext_test.cc
+++ b/runtime/java_vm_ext_test.cc
@@ -69,7 +69,12 @@
     } else {
       ok = vms_buf[0]->AttachCurrentThreadAsDaemon(&env, nullptr);
     }
-    EXPECT_EQ(gSmallStack ? JNI_ERR : JNI_OK, ok);
+    // TODO: Find a way to test with exact SMALL_STACK value, for which we would bail. The pthreads
+    //       spec says that the stack size argument is a lower bound, and bionic currently gives us
+    //       a chunk more on arm64.
+    if (!gSmallStack) {
+      EXPECT_EQ(JNI_OK, ok);
+    }
     if (ok == JNI_OK) {
       ok = vms_buf[0]->DetachCurrentThread();
       EXPECT_EQ(JNI_OK, ok);
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 1b992d5..4ba3cb9 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -34,7 +34,6 @@
 
 ParsedOptions::ParsedOptions()
     :
-    boot_class_path_(nullptr),
     check_jni_(kIsDebugBuild),                      // -Xcheck:jni is off by default for regular
                                                     // builds but on by default in debug builds.
     force_copy_(false),
@@ -288,6 +287,9 @@
     } else if (StartsWith(option, "-Xbootclasspath:")) {
       boot_class_path_string_ = option.substr(strlen("-Xbootclasspath:")).data();
       LOG(INFO) << "setting boot class path to " << boot_class_path_string_;
+    } else if (StartsWith(option, "-Xbootclasspath-locations:")) {
+      boot_class_path_locations_string_ = option.substr(
+          strlen("-Xbootclasspath-locations:")).data();
     } else if (option == "-classpath" || option == "-cp") {
       // TODO: support -Djava.class.path
       i++;
@@ -297,9 +299,6 @@
       }
       const StringPiece& value = options[i].first;
       class_path_string_ = value.data();
-    } else if (option == "bootclasspath") {
-      boot_class_path_
-          = reinterpret_cast<const std::vector<const DexFile*>*>(options[i].second);
     } else if (StartsWith(option, "-Ximage:")) {
       if (!ParseStringAfterChar(option, ':', &image_)) {
         return false;
@@ -720,6 +719,24 @@
     boot_class_path_string_.replace(core_jar_pos, core_jar.size(), core_libart_jar);
   }
 
+  if (!boot_class_path_locations_string_.empty()) {
+    std::vector<std::string> files;
+    Split(boot_class_path_string_, ':', &files);
+
+    std::vector<std::string> locations;
+    Split(boot_class_path_locations_string_, ':', &locations);
+
+    if (files.size() != locations.size()) {
+      Usage("The number of boot class path files does not match"
+          " the number of boot class path locations given\n"
+          "  boot class path files     (%zu): %s\n"
+          "  boot class path locations (%zu): %s\n",
+          files.size(), boot_class_path_string_.c_str(),
+          locations.size(), boot_class_path_locations_string_.c_str());
+      return false;
+    }
+  }
+
   if (compiler_callbacks_ == nullptr && image_.empty()) {
     image_ += GetAndroidRoot();
     image_ += "/framework/boot.art";
@@ -804,6 +821,8 @@
   UsageMessage(stream, "  -Xgc:[no]postverify_rosalloc\n");
   UsageMessage(stream, "  -Xgc:[no]presweepingverify\n");
   UsageMessage(stream, "  -Ximage:filename\n");
+  UsageMessage(stream, "  -Xbootclasspath-locations:bootclasspath\n"
+      "     (override the dex locations of the -Xbootclasspath files)\n");
   UsageMessage(stream, "  -XX:+DisableExplicitGC\n");
   UsageMessage(stream, "  -XX:ParallelGCThreads=integervalue\n");
   UsageMessage(stream, "  -XX:ConcGCThreads=integervalue\n");
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 9294868..c7162b8 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -40,8 +40,8 @@
   // returns null if problem parsing and ignore_unrecognized is false
   static ParsedOptions* Create(const RuntimeOptions& options, bool ignore_unrecognized);
 
-  const std::vector<const DexFile*>* boot_class_path_;
   std::string boot_class_path_string_;
+  std::string boot_class_path_locations_string_;
   std::string class_path_string_;
   std::string image_;
   bool check_jni_;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index a2c9f50..fb6034d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -683,6 +683,7 @@
 
 
 static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames,
+                           const std::vector<std::string>& dex_locations,
                            const std::string& image_location,
                            std::vector<const DexFile*>& dex_files) {
   size_t failure_count = 0;
@@ -692,12 +693,13 @@
   failure_count = 0;
   for (size_t i = 0; i < dex_filenames.size(); i++) {
     const char* dex_filename = dex_filenames[i].c_str();
+    const char* dex_location = dex_locations[i].c_str();
     std::string error_msg;
     if (!OS::FileExists(dex_filename)) {
       LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'";
       continue;
     }
-    if (!DexFile::Open(dex_filename, dex_filename, &error_msg, &dex_files)) {
+    if (!DexFile::Open(dex_filename, dex_location, &error_msg, &dex_files)) {
       LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg;
       ++failure_count;
     }
@@ -858,17 +860,25 @@
 
   CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);
   class_linker_ = new ClassLinker(intern_table_);
-  bool options_class_path_used = false;
   if (GetHeap()->HasImageSpace()) {
     class_linker_->InitFromImage();
     if (kIsDebugBuild) {
       GetHeap()->GetImageSpace()->VerifyImageAllocations();
     }
-  } else if (!IsCompiler() || !image_dex2oat_enabled_) {
+  } else {
     std::vector<std::string> dex_filenames;
     Split(boot_class_path_string_, ':', &dex_filenames);
+
+    std::vector<std::string> dex_locations;
+    if (options->boot_class_path_locations_string_.empty()) {
+      dex_locations = dex_filenames;
+    } else {
+      Split(options->boot_class_path_locations_string_, ':', &dex_locations);
+      CHECK_EQ(dex_filenames.size(), dex_locations.size());
+    }
+
     std::vector<const DexFile*> boot_class_path;
-    OpenDexFiles(dex_filenames, options->image_, boot_class_path);
+    OpenDexFiles(dex_filenames, dex_locations, options->image_, boot_class_path);
     class_linker_->InitWithoutImage(boot_class_path);
     // TODO: Should we move the following to InitWithoutImage?
     SetInstructionSet(kRuntimeISA);
@@ -878,18 +888,6 @@
         SetCalleeSaveMethod(CreateCalleeSaveMethod(), type);
       }
     }
-  } else {
-    CHECK(options->boot_class_path_ != nullptr);
-    CHECK_NE(options->boot_class_path_->size(), 0U);
-    class_linker_->InitWithoutImage(*options->boot_class_path_);
-    options_class_path_used = true;
-  }
-
-  if (!options_class_path_used) {
-    // If the class linker does not take ownership of the boot class path, wipe it to prevent leaks.
-    auto boot_class_path_vector_ptr =
-        const_cast<std::vector<const DexFile*>*>(options->boot_class_path_);
-    STLDeleteElements(boot_class_path_vector_ptr);
   }
 
   CHECK(class_linker_ != nullptr);
diff --git a/runtime/utils.cc b/runtime/utils.cc
index dd0bdbb..ef12d6e 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -60,6 +60,10 @@
 
 namespace art {
 
+#if defined(__linux__)
+static constexpr bool kUseAddr2line = !kIsTargetBuild;
+#endif
+
 pid_t GetTid() {
 #if defined(__APPLE__)
   uint64_t owner;
@@ -1117,6 +1121,66 @@
   return "";
 }
 
+#if defined(__linux__)
+static bool RunCommand(std::string cmd, std::ostream* os, const char* prefix) {
+  FILE* stream = popen(cmd.c_str(), "r");
+  if (stream) {
+    if (os != nullptr) {
+      bool odd_line = true;               // We indent them differently.
+      constexpr size_t kMaxBuffer = 128;  // Relatively small buffer. Should be OK as we're on an
+                                          // alt stack, but just to be sure...
+      char buffer[kMaxBuffer];
+      while (!feof(stream)) {
+        if (fgets(buffer, kMaxBuffer, stream) != nullptr) {
+          // Split on newlines.
+          char* tmp = buffer;
+          for (;;) {
+            char* new_line = strchr(tmp, '\n');
+            if (new_line == nullptr) {
+              // Print the rest.
+              if (*tmp != 0) {
+                if (prefix != nullptr) {
+                  *os << prefix;
+                }
+                if (!odd_line) {
+                  *os << " ";
+                }
+                *os << tmp;
+              }
+              break;
+            }
+            if (prefix != nullptr) {
+              *os << prefix;
+            }
+            *os << "  ";
+            if (!odd_line) {
+              *os << " ";
+            }
+            char saved = *(new_line + 1);
+            *(new_line + 1) = 0;
+            *os << tmp;
+            *(new_line + 1) = saved;
+            tmp = new_line + 1;
+            odd_line = !odd_line;
+          }
+        }
+      }
+    }
+    pclose(stream);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static void Addr2line(const std::string& map_src, uintptr_t offset, std::ostream& os,
+                      const char* prefix) {
+  std::string cmdline(StringPrintf("addr2line --functions --inlines --demangle -e %s %zx",
+                                   map_src.c_str(), offset));
+  RunCommand(cmdline.c_str(), &os, prefix);
+}
+#endif
+
 void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix,
     mirror::ArtMethod* current_method, void* ucontext_ptr) {
 #if __linux__
@@ -1142,6 +1206,16 @@
     return;
   }
 
+  // Check whether we have and should use addr2line.
+  bool use_addr2line;
+  if (kUseAddr2line) {
+    // Try to run it to see whether we have it. Push an argument so that it doesn't assume a.out
+    // and print to stderr.
+    use_addr2line = RunCommand("addr2line -h", nullptr, nullptr);
+  } else {
+    use_addr2line = false;
+  }
+
   for (Backtrace::const_iterator it = backtrace->begin();
        it != backtrace->end(); ++it) {
     // We produce output like this:
@@ -1153,6 +1227,7 @@
     // after the <RELATIVE_ADDR>. There can be any prefix data before the
     // #XX. <RELATIVE_ADDR> has to be a hex number but with no 0x prefix.
     os << prefix << StringPrintf("#%02zu pc ", it->num);
+    bool try_addr2line = false;
     if (!it->map) {
       os << StringPrintf("%08" PRIxPTR "  ???", it->pc);
     } else {
@@ -1163,6 +1238,7 @@
         if (it->func_offset != 0) {
           os << "+" << it->func_offset;
         }
+        try_addr2line = true;
       } else if (current_method != nullptr &&
                  Locks::mutator_lock_->IsSharedHeld(Thread::Current()) &&
                  current_method->PcIsWithinQuickCode(it->pc)) {
@@ -1175,6 +1251,9 @@
       os << ")";
     }
     os << "\n";
+    if (try_addr2line && use_addr2line) {
+      Addr2line(it->map->name, it->pc - it->map->start, os, prefix);
+    }
   }
 #else
   UNUSED(os, tid, prefix, current_method, ucontext_ptr);