Merge "Go to suspended before waiting for GC to complete."
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
index 558c7d5..de32351 100644
--- a/compiler/debug/elf_debug_info_writer.h
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -411,7 +411,7 @@
for (const auto& base_class_reference : base_class_references) {
size_t reference_offset = base_class_reference.first;
mirror::Class* base_class = base_class_reference.second;
- const auto& it = class_declarations.find(base_class);
+ const auto it = class_declarations.find(base_class);
if (it != class_declarations.end()) {
info_.UpdateUint32(reference_offset, it->second);
} else {
@@ -512,7 +512,7 @@
using namespace dwarf; // NOLINT. For easy access to DWARF constants.
DCHECK(!desc.empty());
- const auto& it = type_cache_.find(desc);
+ const auto it = type_cache_.find(desc);
if (it != type_cache_.end()) {
return it->second;
}
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 5a6a20d..a0533f2 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -350,6 +350,55 @@
return true;
}
+ // Runs DexFileLayout test twice (second time is run on output of first time)
+ // for behavior consistency.
+ bool DexFileLayoutFixedPointExec(std::string* error_msg) {
+ ScratchFile tmp_file;
+ std::string tmp_name = tmp_file.GetFilename();
+ size_t tmp_last_slash = tmp_name.rfind("/");
+ std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
+
+ // Write inputs and expected outputs.
+ std::string dex_file = tmp_dir + "classes.dex";
+ WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str());
+ std::string profile_file = tmp_dir + "primary.prof";
+ WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
+ std::string output_dex = tmp_dir + "classes.dex.new";
+ std::string second_output_dex = tmp_dir + "classes.dex.new.new";
+
+ std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
+ EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
+
+ // -v makes sure that the layout did not corrupt the dex file.
+ std::vector<std::string> dexlayout_exec_argv =
+ { dexlayout, "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
+ if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ return false;
+ }
+
+ // -v makes sure that the layout did not corrupt the dex file.
+ std::vector<std::string> second_dexlayout_exec_argv =
+ { dexlayout, "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
+ if (!::art::Exec(second_dexlayout_exec_argv, error_msg)) {
+ return false;
+ }
+
+ bool diff_result = true;
+ std::vector<std::string> diff_exec_argv =
+ { "/usr/bin/diff", output_dex, second_output_dex };
+ if (!::art::Exec(diff_exec_argv, error_msg)) {
+ diff_result = false;
+ }
+
+ std::vector<std::string> rm_exec_argv =
+ { "/bin/rm", dex_file, profile_file, output_dex, second_output_dex };
+ if (!::art::Exec(rm_exec_argv, error_msg)) {
+ return false;
+ }
+
+ return diff_result;
+ }
+
// Runs UnreferencedCatchHandlerTest & Unreferenced0SizeCatchHandlerTest.
bool UnreferencedCatchHandlerExec(std::string* error_msg, const char* filename) {
ScratchFile tmp_file;
@@ -427,6 +476,13 @@
ASSERT_TRUE(DexFileLayoutExec(&error_msg)) << error_msg;
}
+TEST_F(DexLayoutTest, DexFileLayoutFixedPoint) {
+ // Disable test on target.
+ TEST_DISABLED_FOR_TARGET();
+ std::string error_msg;
+ ASSERT_TRUE(DexFileLayoutFixedPointExec(&error_msg)) << error_msg;
+}
+
TEST_F(DexLayoutTest, UnreferencedCatchHandler) {
// Disable test on target.
TEST_DISABLED_FOR_TARGET();
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 3f60968..ef4fa28 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -981,7 +981,46 @@
// TODO: Switch to standard begin and end to use ranged a based loop.
for (auto* it = allocation_stack_->Begin(), *end = allocation_stack_->End(); it < end; ++it) {
mirror::Object* const obj = it->AsMirrorPtr();
- if (obj != nullptr && obj->GetClass() != nullptr) {
+
+ mirror::Class* kls = nullptr;
+ if (obj != nullptr && (kls = obj->GetClass()) != nullptr) {
+ // Below invariant is safe regardless of what space the Object is in.
+ // For speed reasons, only perform it when Rosalloc could possibly be used.
+ // (Disabled for read barriers because it never uses Rosalloc).
+ // (See the DCHECK in RosAllocSpace constructor).
+ if (!kUseReadBarrier) {
+ // Rosalloc has a race in allocation. Objects can be written into the allocation
+ // stack before their header writes are visible to this thread.
+ // See b/28790624 for more details.
+ //
+ // obj.class will either be pointing to a valid Class*, or it will point
+ // to a rosalloc free buffer.
+ //
+ // If it's pointing to a valid Class* then that Class's Class will be the
+ // ClassClass (whose Class is itself).
+ //
+ // A rosalloc free buffer will point to another rosalloc free buffer
+ // (or to null), and never to itself.
+ //
+ // Either way dereferencing while its not-null is safe because it will
+ // always point to another valid pointer or to null.
+ mirror::Class* klsClass = kls->GetClass();
+
+ if (klsClass == nullptr) {
+ continue;
+ } else if (klsClass->GetClass() != klsClass) {
+ continue;
+ }
+ } else {
+ // Ensure the invariant is not broken for non-rosalloc cases.
+ DCHECK(Heap::rosalloc_space_ == nullptr)
+ << "unexpected rosalloc with read barriers";
+ DCHECK(kls->GetClass() != nullptr)
+ << "invalid object: class does not have a class";
+ DCHECK_EQ(kls->GetClass()->GetClass(), kls->GetClass())
+ << "invalid object: class's class is not ClassClass";
+ }
+
// Avoid the race condition caused by the object not yet being written into the allocation
// stack or the class not yet being written in the object. Or, if
// kUseThreadLocalAllocationStack, there can be nulls on the allocation stack.
@@ -4011,7 +4050,7 @@
<< " IsVariableSize=" << c->IsVariableSize()
<< " ObjectSize=" << c->GetObjectSize()
<< " sizeof(Class)=" << sizeof(mirror::Class)
- << " klass=" << c.Ptr();
+ << verification_->DumpObjectInfo(c.Ptr(), /*tag*/ "klass");
CHECK_GE(byte_count, sizeof(mirror::Object));
}
diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc
index 7cdd7c5..ae00044 100644
--- a/runtime/jit/debugger_interface.cc
+++ b/runtime/jit/debugger_interface.cc
@@ -143,7 +143,7 @@
bool DeleteJITCodeEntryForAddress(uintptr_t address) {
Thread* self = Thread::Current();
MutexLock mu(self, g_jit_debug_mutex);
- const auto& it = g_jit_code_entries.find(address);
+ const auto it = g_jit_code_entries.find(address);
if (it == g_jit_code_entries.end()) {
return false;
}
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index 4d5c9d6..220f298 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -446,7 +446,7 @@
ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
const std::string& profile_key,
uint32_t checksum) {
- const auto& profile_index_it = profile_key_map_.FindOrAdd(profile_key, profile_key_map_.size());
+ const auto profile_index_it = profile_key_map_.FindOrAdd(profile_key, profile_key_map_.size());
if (profile_key_map_.size() > std::numeric_limits<uint8_t>::max()) {
// Allow only 255 dex files to be profiled. This allows us to save bytes
// when encoding. The number is well above what we expect for normal applications.
@@ -480,7 +480,7 @@
const ProfileCompilationInfo::DexFileData* ProfileCompilationInfo::FindDexData(
const std::string& profile_key) const {
- const auto& profile_index_it = profile_key_map_.find(profile_key);
+ const auto profile_index_it = profile_key_map_.find(profile_key);
if (profile_index_it == profile_key_map_.end()) {
return nullptr;
}
@@ -1314,7 +1314,7 @@
}
std::set<DexCacheResolvedClasses> ret;
for (const DexFileData* dex_data : info_) {
- const auto& it = key_to_location_map.find(dex_data->profile_key);
+ const auto it = key_to_location_map.find(dex_data->profile_key);
if (it != key_to_location_map.end()) {
DexCacheResolvedClasses classes(it->second, it->second, dex_data->checksum);
classes.AddClasses(dex_data->class_set.begin(), dex_data->class_set.end());
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 77554e8..e618323 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -657,7 +657,7 @@
return oat_file != nullptr;
}
-static jstring DexFile_getDexFileOutputPath(JNIEnv* env,
+static jobjectArray DexFile_getDexFileOutputPaths(JNIEnv* env,
jclass,
jstring javaFilename,
jstring javaInstructionSet) {
@@ -689,7 +689,26 @@
return nullptr;
}
- return env->NewStringUTF(best_oat_file->GetLocation().c_str());
+ std::string oat_filename = best_oat_file->GetLocation();
+ std::string vdex_filename = GetVdexFilename(best_oat_file->GetLocation());
+
+ ScopedLocalRef<jstring> jvdexFilename(env, env->NewStringUTF(vdex_filename.c_str()));
+ if (jvdexFilename.get() == nullptr) {
+ return nullptr;
+ }
+ ScopedLocalRef<jstring> joatFilename(env, env->NewStringUTF(oat_filename.c_str()));
+ if (joatFilename.get() == nullptr) {
+ return nullptr;
+ }
+
+ // Now create output array and copy the set into it.
+ jobjectArray result = env->NewObjectArray(2,
+ WellKnownClasses::java_lang_String,
+ nullptr);
+ env->SetObjectArrayElement(result, 0, jvdexFilename.get());
+ env->SetObjectArrayElement(result, 1, joatFilename.get());
+
+ return result;
}
static JNINativeMethod gMethods[] = {
@@ -726,8 +745,8 @@
NATIVE_METHOD(DexFile, isBackedByOatFile, "(Ljava/lang/Object;)Z"),
NATIVE_METHOD(DexFile, getDexFileStatus,
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
- NATIVE_METHOD(DexFile, getDexFileOutputPath,
- "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;")
+ NATIVE_METHOD(DexFile, getDexFileOutputPaths,
+ "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;")
};
void register_dalvik_system_DexFile(JNIEnv* env) {
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 9affeb0..a816522 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1064,7 +1064,7 @@
CHECK(!oat_filename.empty()) << oat_location;
CheckLocation(oat_location);
- std::string vdex_filename = ReplaceFileExtension(oat_filename, "vdex");
+ std::string vdex_filename = GetVdexFilename(oat_filename);
// Check that the files even exist, fast-fail.
if (kIsVdexEnabled && !OS::FileExists(vdex_filename.c_str())) {
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 603bbbf..9e08b34 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -630,7 +630,7 @@
return kUpdateNotAttempted;
}
const std::string& oat_file_name = *info.Filename();
- const std::string& vdex_file_name = ReplaceFileExtension(oat_file_name, "vdex");
+ const std::string& vdex_file_name = GetVdexFilename(oat_file_name);
// dex2oat ignores missing dex files and doesn't report an error.
// Check explicitly here so we can detect the error properly.
@@ -962,7 +962,7 @@
if (file == nullptr) {
// Check to see if there is a vdex file we can make use of.
std::string error_msg;
- std::string vdex_filename = ReplaceFileExtension(filename_, "vdex");
+ std::string vdex_filename = GetVdexFilename(filename_);
std::unique_ptr<VdexFile> vdex = VdexFile::Open(vdex_filename,
/*writeable*/false,
/*low_4gb*/false,
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 8d216ce..20a53b7 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -841,6 +841,10 @@
return true;
}
+std::string GetVdexFilename(const std::string& oat_location) {
+ return ReplaceFileExtension(oat_location, "vdex");
+}
+
static void InsertIsaDirectory(const InstructionSet isa, std::string* filename) {
// in = /foo/bar/baz
// out = /foo/bar/<isa>/baz
diff --git a/runtime/utils.h b/runtime/utils.h
index 2011d9e..f1f5576 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -173,6 +173,9 @@
// Returns the system location for an image
std::string GetSystemImageFilename(const char* location, InstructionSet isa);
+// Returns the vdex filename for the given oat filename.
+std::string GetVdexFilename(const std::string& oat_filename);
+
// Returns true if the file exists.
bool FileExists(const std::string& filename);
bool FileExistsAndNotEmpty(const std::string& filename);
diff --git a/sigchainlib/Android.bp b/sigchainlib/Android.bp
index 08af254..0c64b7d 100644
--- a/sigchainlib/Android.bp
+++ b/sigchainlib/Android.bp
@@ -32,6 +32,12 @@
shared_libs: ["liblog"],
},
},
+ // Sigchainlib is whole-statically linked into binaries. For Android.mk-based binaries,
+ // this will drag ASAN symbols into the binary, even for modules using LOCAL_SANITIZE := never.
+ // So disable sanitization for now. b/38456126
+ sanitize: {
+ never: true,
+ },
}
// Create a dummy version of libsigchain which expose the necessary symbols