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);