Merge changes Ica4f766c,Iaa97520d
* changes:
ART: Blacklist test 913 for target
ART: Add forced garbage collection
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 4f273e5..c785bef 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -105,7 +105,7 @@
ART_GTEST_stub_test_DEX_DEPS := AllFields
ART_GTEST_transaction_test_DEX_DEPS := Transaction
ART_GTEST_type_lookup_table_test_DEX_DEPS := Lookup
-ART_GTEST_verifier_deps_test_DEX_DEPS := VerifierDeps
+ART_GTEST_verifier_deps_test_DEX_DEPS := VerifierDeps MultiDex
# The elf writer test has dependencies on core.oat.
ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_optimizing_no-pic_64) $(HOST_CORE_IMAGE_optimizing_no-pic_32)
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index d1ac139..59f339a 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -963,21 +963,21 @@
mirror::String* ImageWriter::FindInternedString(mirror::String* string) {
Thread* const self = Thread::Current();
for (const ImageInfo& image_info : image_infos_) {
- mirror::String* const found = image_info.intern_table_->LookupStrong(self, string);
+ ObjPtr<mirror::String> const found = image_info.intern_table_->LookupStrong(self, string);
DCHECK(image_info.intern_table_->LookupWeak(self, string) == nullptr)
<< string->ToModifiedUtf8();
if (found != nullptr) {
- return found;
+ return found.Ptr();
}
}
if (compile_app_image_) {
Runtime* const runtime = Runtime::Current();
- mirror::String* found = runtime->GetInternTable()->LookupStrong(self, string);
+ ObjPtr<mirror::String> found = runtime->GetInternTable()->LookupStrong(self, string);
// If we found it in the runtime intern table it could either be in the boot image or interned
// during app image compilation. If it was in the boot image return that, otherwise return null
// since it belongs to another image space.
- if (found != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(found)) {
- return found;
+ if (found != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(found.Ptr())) {
+ return found.Ptr();
}
DCHECK(runtime->GetInternTable()->LookupWeak(self, string) == nullptr)
<< string->ToModifiedUtf8();
@@ -1088,7 +1088,8 @@
mirror::String* interned = FindInternedString(obj->AsString());
if (interned == nullptr) {
// Not in another image space, insert to our table.
- interned = GetImageInfo(oat_index).intern_table_->InternStrongImageString(obj->AsString());
+ interned =
+ GetImageInfo(oat_index).intern_table_->InternStrongImageString(obj->AsString()).Ptr();
DCHECK_EQ(interned, obj);
}
} else if (obj->IsDexCache()) {
@@ -1448,7 +1449,7 @@
for (size_t i = 0, count = dex_file->NumStringIds(); i < count; ++i) {
uint32_t utf16_length;
const char* utf8_data = dex_file->StringDataAndUtf16LengthByIdx(i, &utf16_length);
- mirror::String* string = intern_table->LookupStrong(self, utf16_length, utf8_data);
+ mirror::String* string = intern_table->LookupStrong(self, utf16_length, utf8_data).Ptr();
TryAssignBinSlot(work_stack, string, oat_index);
}
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 6cbca7a..f9173f5 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -1759,7 +1759,7 @@
}
std::vector<uint8_t> buffer;
- verifier_deps->Encode(&buffer);
+ verifier_deps->Encode(*dex_files_, &buffer);
if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
PLOG(ERROR) << "Failed to write verifier deps."
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 8c76927..19fd6f9 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -170,6 +170,15 @@
if (visualizer_enabled_) {
MutexLock mu(Thread::Current(), visualizer_dump_mutex_);
*visualizer_output_ << visualizer_oss_.str();
+ // The destructor of `visualizer_output_` is normally
+ // responsible for flushing (and closing) the stream, but it
+ // won't be invoked during fast exits in non-debug mode -- see
+ // art::Dex2Oat::~Dex2Oat, which explicitly abandons some
+ // objects (such as the compiler driver) in non-debug mode, to
+ // avoid the cost of destructing them. Therefore we explicitly
+ // flush the stream here to prevent truncated CFG visualizer
+ // files.
+ visualizer_output_->flush();
}
}
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 9664e43..3a53998 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -79,17 +79,24 @@
callbacks->SetVerifierDeps(verifier_deps_.get());
}
+ void LoadDexFile(ScopedObjectAccess* soa, const char* name1, const char* name2 = nullptr)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ class_loader_ = (name2 == nullptr) ? LoadDex(name1) : LoadMultiDex(name1, name2);
+ dex_files_ = GetDexFiles(class_loader_);
+ primary_dex_file_ = dex_files_.front();
+
+ SetVerifierDeps(dex_files_);
+ StackHandleScope<1> hs(soa->Self());
+ Handle<mirror::ClassLoader> loader =
+ hs.NewHandle(soa->Decode<mirror::ClassLoader>(class_loader_));
+ for (const DexFile* dex_file : dex_files_) {
+ class_linker_->RegisterDexFile(*dex_file, loader.Get());
+ }
+ }
+
void LoadDexFile(ScopedObjectAccess* soa) REQUIRES_SHARED(Locks::mutator_lock_) {
- class_loader_ = LoadDex("VerifierDeps");
- std::vector<const DexFile*> dex_files = GetDexFiles(class_loader_);
- CHECK_EQ(dex_files.size(), 1u);
- dex_file_ = dex_files.front();
-
- SetVerifierDeps(dex_files);
-
- ObjPtr<mirror::ClassLoader> loader = soa->Decode<mirror::ClassLoader>(class_loader_);
- class_linker_->RegisterDexFile(*dex_file_, loader.Ptr());
-
+ LoadDexFile(soa, "VerifierDeps");
+ CHECK_EQ(dex_files_.size(), 1u);
klass_Main_ = FindClassByName("LMain;", soa);
CHECK(klass_Main_ != nullptr);
}
@@ -98,16 +105,16 @@
ScopedObjectAccess soa(Thread::Current());
LoadDexFile(&soa);
- StackHandleScope<2> hs(Thread::Current());
+ StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader_handle(
hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
Handle<mirror::DexCache> dex_cache_handle(hs.NewHandle(klass_Main_->GetDexCache()));
const DexFile::ClassDef* class_def = klass_Main_->GetClassDef();
- const uint8_t* class_data = dex_file_->GetClassData(*class_def);
+ const uint8_t* class_data = primary_dex_file_->GetClassData(*class_def);
CHECK(class_data != nullptr);
- ClassDataItemIterator it(*dex_file_, class_data);
+ ClassDataItemIterator it(*primary_dex_file_, class_data);
while (it.HasNextStaticField() || it.HasNextInstanceField()) {
it.Next();
}
@@ -115,7 +122,7 @@
ArtMethod* method = nullptr;
while (it.HasNextDirectMethod()) {
ArtMethod* resolved_method = class_linker_->ResolveMethod<ClassLinker::kNoICCECheckForCache>(
- *dex_file_,
+ *primary_dex_file_,
it.GetMemberIndex(),
dex_cache_handle,
class_loader_handle,
@@ -131,7 +138,7 @@
CHECK(method != nullptr);
MethodVerifier verifier(Thread::Current(),
- dex_file_,
+ primary_dex_file_,
dex_cache_handle,
class_loader_handle,
*class_def,
@@ -148,19 +155,16 @@
return !verifier.HasFailures();
}
- void VerifyDexFile() {
+ void VerifyDexFile(const char* multidex = nullptr) {
std::string error_msg;
{
ScopedObjectAccess soa(Thread::Current());
- LoadDexFile(&soa);
+ LoadDexFile(&soa, "VerifierDeps", multidex);
}
- SetVerifierDeps({ dex_file_ });
TimingLogger timings("Verify", false, false);
- std::vector<const DexFile*> dex_files;
- dex_files.push_back(dex_file_);
compiler_options_->boot_image_ = false;
compiler_driver_->InitializeThreadPools();
- compiler_driver_->Verify(class_loader_, dex_files, &timings);
+ compiler_driver_->Verify(class_loader_, dex_files_, &timings);
}
bool TestAssignabilityRecording(const std::string& dst,
@@ -173,7 +177,7 @@
DCHECK(klass_dst != nullptr);
mirror::Class* klass_src = FindClassByName(src, &soa);
DCHECK(klass_src != nullptr);
- verifier_deps_->AddAssignability(*dex_file_,
+ verifier_deps_->AddAssignability(*primary_dex_file_,
klass_dst,
klass_src,
is_strict,
@@ -182,9 +186,9 @@
}
bool HasUnverifiedClass(const std::string& cls) {
- const DexFile::TypeId* type_id = dex_file_->FindTypeId(cls.c_str());
+ const DexFile::TypeId* type_id = primary_dex_file_->FindTypeId(cls.c_str());
DCHECK(type_id != nullptr);
- uint16_t index = dex_file_->GetIndexForTypeId(*type_id);
+ uint16_t index = primary_dex_file_->GetIndexForTypeId(*type_id);
MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const auto& dex_dep : verifier_deps_->dex_deps_) {
for (uint16_t entry : dex_dep.second->unverified_classes_) {
@@ -396,7 +400,8 @@
}
std::unique_ptr<verifier::VerifierDeps> verifier_deps_;
- const DexFile* dex_file_;
+ std::vector<const DexFile*> dex_files_;
+ const DexFile* primary_dex_file_;
jobject class_loader_;
mirror::Class* klass_Main_;
};
@@ -407,21 +412,21 @@
MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
- uint32_t id_Main1 = verifier_deps_->GetIdFromString(*dex_file_, "LMain;");
- ASSERT_LT(id_Main1, dex_file_->NumStringIds());
- ASSERT_EQ("LMain;", verifier_deps_->GetStringFromId(*dex_file_, id_Main1));
+ uint32_t id_Main1 = verifier_deps_->GetIdFromString(*primary_dex_file_, "LMain;");
+ ASSERT_LT(id_Main1, primary_dex_file_->NumStringIds());
+ ASSERT_EQ("LMain;", verifier_deps_->GetStringFromId(*primary_dex_file_, id_Main1));
- uint32_t id_Main2 = verifier_deps_->GetIdFromString(*dex_file_, "LMain;");
- ASSERT_LT(id_Main2, dex_file_->NumStringIds());
- ASSERT_EQ("LMain;", verifier_deps_->GetStringFromId(*dex_file_, id_Main2));
+ uint32_t id_Main2 = verifier_deps_->GetIdFromString(*primary_dex_file_, "LMain;");
+ ASSERT_LT(id_Main2, primary_dex_file_->NumStringIds());
+ ASSERT_EQ("LMain;", verifier_deps_->GetStringFromId(*primary_dex_file_, id_Main2));
- uint32_t id_Lorem1 = verifier_deps_->GetIdFromString(*dex_file_, "Lorem ipsum");
- ASSERT_GE(id_Lorem1, dex_file_->NumStringIds());
- ASSERT_EQ("Lorem ipsum", verifier_deps_->GetStringFromId(*dex_file_, id_Lorem1));
+ uint32_t id_Lorem1 = verifier_deps_->GetIdFromString(*primary_dex_file_, "Lorem ipsum");
+ ASSERT_GE(id_Lorem1, primary_dex_file_->NumStringIds());
+ ASSERT_EQ("Lorem ipsum", verifier_deps_->GetStringFromId(*primary_dex_file_, id_Lorem1));
- uint32_t id_Lorem2 = verifier_deps_->GetIdFromString(*dex_file_, "Lorem ipsum");
- ASSERT_GE(id_Lorem2, dex_file_->NumStringIds());
- ASSERT_EQ("Lorem ipsum", verifier_deps_->GetStringFromId(*dex_file_, id_Lorem2));
+ uint32_t id_Lorem2 = verifier_deps_->GetIdFromString(*primary_dex_file_, "Lorem ipsum");
+ ASSERT_GE(id_Lorem2, primary_dex_file_->NumStringIds());
+ ASSERT_EQ("Lorem ipsum", verifier_deps_->GetStringFromId(*primary_dex_file_, id_Lorem2));
ASSERT_EQ(id_Main1, id_Main2);
ASSERT_EQ(id_Lorem1, id_Lorem2);
@@ -1068,13 +1073,41 @@
ASSERT_TRUE(HasEachKindOfRecord());
std::vector<uint8_t> buffer;
- verifier_deps_->Encode(&buffer);
+ verifier_deps_->Encode(dex_files_, &buffer);
ASSERT_FALSE(buffer.empty());
- VerifierDeps decoded_deps({ dex_file_ }, ArrayRef<uint8_t>(buffer));
+ VerifierDeps decoded_deps(dex_files_, ArrayRef<const uint8_t>(buffer));
ASSERT_TRUE(verifier_deps_->Equals(decoded_deps));
}
+TEST_F(VerifierDepsTest, EncodeDecodeMulti) {
+ VerifyDexFile("MultiDex");
+
+ ASSERT_GT(NumberOfCompiledDexFiles(), 1u);
+ std::vector<uint8_t> buffer;
+ verifier_deps_->Encode(dex_files_, &buffer);
+ ASSERT_FALSE(buffer.empty());
+
+ // Create new DexFile, to mess with std::map order: the verifier deps used
+ // to iterate over the map, which doesn't guarantee insertion order. We fixed
+ // this by passing the expected order when encoding/decoding.
+ std::vector<std::unique_ptr<const DexFile>> first_dex_files = OpenTestDexFiles("VerifierDeps");
+ std::vector<std::unique_ptr<const DexFile>> second_dex_files = OpenTestDexFiles("MultiDex");
+ std::vector<const DexFile*> dex_files;
+ for (auto& dex_file : first_dex_files) {
+ dex_files.push_back(dex_file.get());
+ }
+ for (auto& dex_file : second_dex_files) {
+ dex_files.push_back(dex_file.get());
+ }
+
+ // Dump the new verifier deps to ensure it can properly read the data.
+ VerifierDeps decoded_deps(dex_files, ArrayRef<const uint8_t>(buffer));
+ std::ostringstream stream;
+ VariableIndentationOutputStream os(&stream);
+ decoded_deps.Dump(&os);
+}
+
TEST_F(VerifierDepsTest, UnverifiedClasses) {
VerifyDexFile();
ASSERT_FALSE(HasUnverifiedClass("LMyThread;"));
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index da0db01..3d208b5 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -66,6 +66,7 @@
#include "type_lookup_table.h"
#include "vdex_file.h"
#include "verifier/method_verifier.h"
+#include "verifier/verifier_deps.h"
#include "well_known_classes.h"
#include <sys/stat.h>
@@ -483,6 +484,28 @@
os << "\n";
if (!options_.dump_header_only_) {
+ VariableIndentationOutputStream vios(&os);
+ VdexFile::Header vdex_header = oat_file_.GetVdexFile()->GetHeader();
+ if (vdex_header.IsValid()) {
+ std::string error_msg;
+ std::vector<const DexFile*> dex_files;
+ for (size_t i = 0; i < oat_dex_files_.size(); i++) {
+ const DexFile* dex_file = OpenDexFile(oat_dex_files_[i], &error_msg);
+ if (dex_file == nullptr) {
+ os << "Error opening dex file: " << error_msg << std::endl;
+ return false;
+ }
+ dex_files.push_back(dex_file);
+ }
+ verifier::VerifierDeps deps(dex_files, oat_file_.GetVdexFile()->GetVerifierDepsData());
+ deps.Dump(&vios);
+ } else {
+ os << "UNRECOGNIZED vdex file, magic "
+ << vdex_header.GetMagic()
+ << ", version "
+ << vdex_header.GetVersion()
+ << "\n";
+ }
for (size_t i = 0; i < oat_dex_files_.size(); i++) {
const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
CHECK(oat_dex_file != nullptr);
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 5409fcb..d929812 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -572,6 +572,29 @@
return ret;
}
+jobject CommonRuntimeTestImpl::LoadMultiDex(const char* first_dex_name,
+ const char* second_dex_name) {
+ std::vector<std::unique_ptr<const DexFile>> first_dex_files = OpenTestDexFiles(first_dex_name);
+ std::vector<std::unique_ptr<const DexFile>> second_dex_files = OpenTestDexFiles(second_dex_name);
+ std::vector<const DexFile*> class_path;
+ CHECK_NE(0U, first_dex_files.size());
+ CHECK_NE(0U, second_dex_files.size());
+ for (auto& dex_file : first_dex_files) {
+ class_path.push_back(dex_file.get());
+ loaded_dex_files_.push_back(std::move(dex_file));
+ }
+ for (auto& dex_file : second_dex_files) {
+ class_path.push_back(dex_file.get());
+ loaded_dex_files_.push_back(std::move(dex_file));
+ }
+
+ Thread* self = Thread::Current();
+ jobject class_loader = Runtime::Current()->GetClassLinker()->CreatePathClassLoader(self,
+ class_path);
+ self->SetClassLoaderOverride(class_loader);
+ return class_loader;
+}
+
jobject CommonRuntimeTestImpl::LoadDex(const char* dex_name) {
std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles(dex_name);
std::vector<const DexFile*> class_path;
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 92934c6..827e85e 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -133,6 +133,8 @@
REQUIRES_SHARED(Locks::mutator_lock_);
jobject LoadDex(const char* dex_name) REQUIRES_SHARED(Locks::mutator_lock_);
+ jobject LoadMultiDex(const char* first_dex_name, const char* second_dex_name)
+ REQUIRES_SHARED(Locks::mutator_lock_);
std::string android_data_;
std::string dalvik_cache_;
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 0251776..9f0dbbb 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -813,13 +813,11 @@
void ThrowWrongMethodTypeException(mirror::MethodType* callee_type,
mirror::MethodType* callsite_type) {
- // TODO(narayan): Should we provide more detail here ? The RI doesn't bother.
- UNUSED(callee_type);
- UNUSED(callsite_type);
-
ThrowException("Ljava/lang/invoke/WrongMethodTypeException;",
nullptr,
- "Invalid method type for signature polymorphic call");
+ StringPrintf("Expected %s but was %s",
+ callee_type->PrettyDescriptor().c_str(),
+ callsite_type->PrettyDescriptor().c_str()).c_str());
}
} // namespace art
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index a61a187..7b75109 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -63,9 +63,9 @@
strong_interns_.VisitRoots(visitor);
} else if ((flags & kVisitRootFlagNewRoots) != 0) {
for (auto& root : new_strong_intern_roots_) {
- mirror::String* old_ref = root.Read<kWithoutReadBarrier>();
+ ObjPtr<mirror::String> old_ref = root.Read<kWithoutReadBarrier>();
root.VisitRoot(visitor, RootInfo(kRootInternedString));
- mirror::String* new_ref = root.Read<kWithoutReadBarrier>();
+ ObjPtr<mirror::String> new_ref = root.Read<kWithoutReadBarrier>();
if (new_ref != old_ref) {
// The GC moved a root in the log. Need to search the strong interns and update the
// corresponding object. This is slow, but luckily for us, this may only happen with a
@@ -86,17 +86,17 @@
// Note: we deliberately don't visit the weak_interns_ table and the immutable image roots.
}
-mirror::String* InternTable::LookupWeak(Thread* self, mirror::String* s) {
+ObjPtr<mirror::String> InternTable::LookupWeak(Thread* self, ObjPtr<mirror::String> s) {
MutexLock mu(self, *Locks::intern_table_lock_);
return LookupWeakLocked(s);
}
-mirror::String* InternTable::LookupStrong(Thread* self, mirror::String* s) {
+ObjPtr<mirror::String> InternTable::LookupStrong(Thread* self, ObjPtr<mirror::String> s) {
MutexLock mu(self, *Locks::intern_table_lock_);
return LookupStrongLocked(s);
}
-mirror::String* InternTable::LookupStrong(Thread* self,
+ObjPtr<mirror::String> InternTable::LookupStrong(Thread* self,
uint32_t utf16_length,
const char* utf8_data) {
DCHECK_EQ(utf16_length, CountModifiedUtf8Chars(utf8_data));
@@ -107,11 +107,11 @@
return strong_interns_.Find(string);
}
-mirror::String* InternTable::LookupWeakLocked(mirror::String* s) {
+ObjPtr<mirror::String> InternTable::LookupWeakLocked(ObjPtr<mirror::String> s) {
return weak_interns_.Find(s);
}
-mirror::String* InternTable::LookupStrongLocked(mirror::String* s) {
+ObjPtr<mirror::String> InternTable::LookupStrongLocked(ObjPtr<mirror::String> s) {
return strong_interns_.Find(s);
}
@@ -121,7 +121,7 @@
strong_interns_.AddNewTable();
}
-mirror::String* InternTable::InsertStrong(mirror::String* s) {
+ObjPtr<mirror::String> InternTable::InsertStrong(ObjPtr<mirror::String> s) {
Runtime* runtime = Runtime::Current();
if (runtime->IsActiveTransaction()) {
runtime->RecordStrongStringInsertion(s);
@@ -133,7 +133,7 @@
return s;
}
-mirror::String* InternTable::InsertWeak(mirror::String* s) {
+ObjPtr<mirror::String> InternTable::InsertWeak(ObjPtr<mirror::String> s) {
Runtime* runtime = Runtime::Current();
if (runtime->IsActiveTransaction()) {
runtime->RecordWeakStringInsertion(s);
@@ -142,11 +142,11 @@
return s;
}
-void InternTable::RemoveStrong(mirror::String* s) {
+void InternTable::RemoveStrong(ObjPtr<mirror::String> s) {
strong_interns_.Remove(s);
}
-void InternTable::RemoveWeak(mirror::String* s) {
+void InternTable::RemoveWeak(ObjPtr<mirror::String> s) {
Runtime* runtime = Runtime::Current();
if (runtime->IsActiveTransaction()) {
runtime->RecordWeakStringRemoval(s);
@@ -155,19 +155,22 @@
}
// Insert/remove methods used to undo changes made during an aborted transaction.
-mirror::String* InternTable::InsertStrongFromTransaction(mirror::String* s) {
+ObjPtr<mirror::String> InternTable::InsertStrongFromTransaction(ObjPtr<mirror::String> s) {
DCHECK(!Runtime::Current()->IsActiveTransaction());
return InsertStrong(s);
}
-mirror::String* InternTable::InsertWeakFromTransaction(mirror::String* s) {
+
+ObjPtr<mirror::String> InternTable::InsertWeakFromTransaction(ObjPtr<mirror::String> s) {
DCHECK(!Runtime::Current()->IsActiveTransaction());
return InsertWeak(s);
}
-void InternTable::RemoveStrongFromTransaction(mirror::String* s) {
+
+void InternTable::RemoveStrongFromTransaction(ObjPtr<mirror::String> s) {
DCHECK(!Runtime::Current()->IsActiveTransaction());
RemoveStrong(s);
}
-void InternTable::RemoveWeakFromTransaction(mirror::String* s) {
+
+void InternTable::RemoveWeakFromTransaction(ObjPtr<mirror::String> s) {
DCHECK(!Runtime::Current()->IsActiveTransaction());
RemoveWeak(s);
}
@@ -203,7 +206,9 @@
Locks::intern_table_lock_->ExclusiveLock(self);
}
-mirror::String* InternTable::Insert(mirror::String* s, bool is_strong, bool holding_locks) {
+ObjPtr<mirror::String> InternTable::Insert(ObjPtr<mirror::String> s,
+ bool is_strong,
+ bool holding_locks) {
if (s == nullptr) {
return nullptr;
}
@@ -222,7 +227,7 @@
}
}
// Check the strong table for a match.
- mirror::String* strong = LookupStrongLocked(s);
+ ObjPtr<mirror::String> strong = LookupStrongLocked(s);
if (strong != nullptr) {
return strong;
}
@@ -244,7 +249,7 @@
CHECK(self->GetWeakRefAccessEnabled());
}
// There is no match in the strong table, check the weak table.
- mirror::String* weak = LookupWeakLocked(s);
+ ObjPtr<mirror::String> weak = LookupWeakLocked(s);
if (weak != nullptr) {
if (is_strong) {
// A match was found in the weak table. Promote to the strong table.
@@ -257,11 +262,11 @@
return is_strong ? InsertStrong(s) : InsertWeak(s);
}
-mirror::String* InternTable::InternStrong(int32_t utf16_length, const char* utf8_data) {
+ObjPtr<mirror::String> InternTable::InternStrong(int32_t utf16_length, const char* utf8_data) {
DCHECK(utf8_data != nullptr);
Thread* self = Thread::Current();
// Try to avoid allocation.
- mirror::String* s = LookupStrong(self, utf16_length, utf8_data);
+ ObjPtr<mirror::String> s = LookupStrong(self, utf16_length, utf8_data);
if (s != nullptr) {
return s;
}
@@ -269,25 +274,25 @@
self, utf16_length, utf8_data));
}
-mirror::String* InternTable::InternStrong(const char* utf8_data) {
+ObjPtr<mirror::String> InternTable::InternStrong(const char* utf8_data) {
DCHECK(utf8_data != nullptr);
return InternStrong(mirror::String::AllocFromModifiedUtf8(Thread::Current(), utf8_data));
}
-mirror::String* InternTable::InternStrongImageString(mirror::String* s) {
+ObjPtr<mirror::String> InternTable::InternStrongImageString(ObjPtr<mirror::String> s) {
// May be holding the heap bitmap lock.
return Insert(s, true, true);
}
-mirror::String* InternTable::InternStrong(mirror::String* s) {
+ObjPtr<mirror::String> InternTable::InternStrong(ObjPtr<mirror::String> s) {
return Insert(s, true, false);
}
-mirror::String* InternTable::InternWeak(mirror::String* s) {
+ObjPtr<mirror::String> InternTable::InternWeak(ObjPtr<mirror::String> s) {
return Insert(s, false, false);
}
-bool InternTable::ContainsWeak(mirror::String* s) {
+bool InternTable::ContainsWeak(ObjPtr<mirror::String> s) {
return LookupWeak(Thread::Current(), s) == s;
}
@@ -314,7 +319,7 @@
if (kIsDebugBuild) {
Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
}
- return static_cast<size_t>(root.Read()->GetHashCode());
+ return static_cast<size_t>(root.Read<kWithoutReadBarrier>()->GetHashCode());
}
bool InternTable::StringHashEquals::operator()(const GcRoot<mirror::String>& a,
@@ -322,7 +327,7 @@
if (kIsDebugBuild) {
Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
}
- return a.Read()->Equals(b.Read());
+ return a.Read<kWithoutReadBarrier>()->Equals(b.Read<kWithoutReadBarrier>());
}
bool InternTable::StringHashEquals::operator()(const GcRoot<mirror::String>& a,
@@ -330,7 +335,7 @@
if (kIsDebugBuild) {
Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
}
- mirror::String* a_string = a.Read();
+ ObjPtr<mirror::String> a_string = a.Read<kWithoutReadBarrier>();
uint32_t a_length = static_cast<uint32_t>(a_string->GetLength());
if (a_length != b.GetUtf16Length()) {
return false;
@@ -392,7 +397,7 @@
return table_to_write->WriteToMemory(ptr);
}
-void InternTable::Table::Remove(mirror::String* s) {
+void InternTable::Table::Remove(ObjPtr<mirror::String> s) {
for (UnorderedSet& table : tables_) {
auto it = table.Find(GcRoot<mirror::String>(s));
if (it != table.end()) {
@@ -403,7 +408,7 @@
LOG(FATAL) << "Attempting to remove non-interned string " << s->ToModifiedUtf8();
}
-mirror::String* InternTable::Table::Find(mirror::String* s) {
+ObjPtr<mirror::String> InternTable::Table::Find(ObjPtr<mirror::String> s) {
Locks::intern_table_lock_->AssertHeld(Thread::Current());
for (UnorderedSet& table : tables_) {
auto it = table.Find(GcRoot<mirror::String>(s));
@@ -414,7 +419,7 @@
return nullptr;
}
-mirror::String* InternTable::Table::Find(const Utf8String& string) {
+ObjPtr<mirror::String> InternTable::Table::Find(const Utf8String& string) {
Locks::intern_table_lock_->AssertHeld(Thread::Current());
for (UnorderedSet& table : tables_) {
auto it = table.Find(string);
@@ -429,7 +434,7 @@
tables_.push_back(UnorderedSet());
}
-void InternTable::Table::Insert(mirror::String* s) {
+void InternTable::Table::Insert(ObjPtr<mirror::String> s) {
// Always insert the last table, the image tables are before and we avoid inserting into these
// to prevent dirty pages.
DCHECK(!tables_.empty());
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 30ff55d..acb2067 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -57,43 +57,44 @@
InternTable();
// Interns a potentially new string in the 'strong' table. May cause thread suspension.
- mirror::String* InternStrong(int32_t utf16_length, const char* utf8_data)
+ ObjPtr<mirror::String> InternStrong(int32_t utf16_length, const char* utf8_data)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
// Only used by image writer. Special version that may not cause thread suspension since the GC
// cannot be running while we are doing image writing. Maybe be called while while holding a
// lock since there will not be thread suspension.
- mirror::String* InternStrongImageString(mirror::String* s)
+ ObjPtr<mirror::String> InternStrongImageString(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_);
// Interns a potentially new string in the 'strong' table. May cause thread suspension.
- mirror::String* InternStrong(const char* utf8_data) REQUIRES_SHARED(Locks::mutator_lock_)
+ ObjPtr<mirror::String> InternStrong(const char* utf8_data) REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
// Interns a potentially new string in the 'strong' table. May cause thread suspension.
- mirror::String* InternStrong(mirror::String* s) REQUIRES_SHARED(Locks::mutator_lock_)
+ ObjPtr<mirror::String> InternStrong(ObjPtr<mirror::String> s)
+ REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
// Interns a potentially new string in the 'weak' table. May cause thread suspension.
- mirror::String* InternWeak(mirror::String* s) REQUIRES_SHARED(Locks::mutator_lock_)
+ ObjPtr<mirror::String> InternWeak(ObjPtr<mirror::String> s) REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
void SweepInternTableWeaks(IsMarkedVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::intern_table_lock_);
- bool ContainsWeak(mirror::String* s) REQUIRES_SHARED(Locks::mutator_lock_)
+ bool ContainsWeak(ObjPtr<mirror::String> s) REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::intern_table_lock_);
// Lookup a strong intern, returns null if not found.
- mirror::String* LookupStrong(Thread* self, mirror::String* s)
+ ObjPtr<mirror::String> LookupStrong(Thread* self, ObjPtr<mirror::String> s)
REQUIRES(!Locks::intern_table_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- mirror::String* LookupStrong(Thread* self, uint32_t utf16_length, const char* utf8_data)
+ ObjPtr<mirror::String> LookupStrong(Thread* self, uint32_t utf16_length, const char* utf8_data)
REQUIRES(!Locks::intern_table_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
// Lookup a weak intern, returns null if not found.
- mirror::String* LookupWeak(Thread* self, mirror::String* s)
+ ObjPtr<mirror::String> LookupWeak(Thread* self, ObjPtr<mirror::String> s)
REQUIRES(!Locks::intern_table_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -181,13 +182,13 @@
class Table {
public:
Table();
- mirror::String* Find(mirror::String* s) REQUIRES_SHARED(Locks::mutator_lock_)
+ ObjPtr<mirror::String> Find(ObjPtr<mirror::String> s) REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(Locks::intern_table_lock_);
- mirror::String* Find(const Utf8String& string) REQUIRES_SHARED(Locks::mutator_lock_)
+ ObjPtr<mirror::String> Find(const Utf8String& string) REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(Locks::intern_table_lock_);
- void Insert(mirror::String* s) REQUIRES_SHARED(Locks::mutator_lock_)
+ void Insert(ObjPtr<mirror::String> s) REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(Locks::intern_table_lock_);
- void Remove(mirror::String* s)
+ void Remove(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
void VisitRoots(RootVisitor* visitor)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
@@ -221,30 +222,30 @@
// Insert if non null, otherwise return null. Must be called holding the mutator lock.
// If holding_locks is true, then we may also hold other locks. If holding_locks is true, then we
// require GC is not running since it is not safe to wait while holding locks.
- mirror::String* Insert(mirror::String* s, bool is_strong, bool holding_locks)
+ ObjPtr<mirror::String> Insert(ObjPtr<mirror::String> s, bool is_strong, bool holding_locks)
REQUIRES(!Locks::intern_table_lock_) REQUIRES_SHARED(Locks::mutator_lock_);
- mirror::String* LookupStrongLocked(mirror::String* s)
+ ObjPtr<mirror::String> LookupStrongLocked(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
- mirror::String* LookupWeakLocked(mirror::String* s)
+ ObjPtr<mirror::String> LookupWeakLocked(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
- mirror::String* InsertStrong(mirror::String* s)
+ ObjPtr<mirror::String> InsertStrong(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
- mirror::String* InsertWeak(mirror::String* s)
+ ObjPtr<mirror::String> InsertWeak(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
- void RemoveStrong(mirror::String* s)
+ void RemoveStrong(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
- void RemoveWeak(mirror::String* s)
+ void RemoveWeak(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
// Transaction rollback access.
- mirror::String* InsertStrongFromTransaction(mirror::String* s)
+ ObjPtr<mirror::String> InsertStrongFromTransaction(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
- mirror::String* InsertWeakFromTransaction(mirror::String* s)
+ ObjPtr<mirror::String> InsertWeakFromTransaction(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
- void RemoveStrongFromTransaction(mirror::String* s)
+ void RemoveStrongFromTransaction(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
- void RemoveWeakFromTransaction(mirror::String* s)
+ void RemoveWeakFromTransaction(ObjPtr<mirror::String> s)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::intern_table_lock_);
size_t AddTableFromMemoryLocked(const uint8_t* ptr)
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index 74cec57..b91d946 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -193,22 +193,22 @@
ASSERT_NE(foo.Get(), bar.Get());
ASSERT_NE(foo.Get(), foobar.Get());
ASSERT_NE(bar.Get(), foobar.Get());
- mirror::String* lookup_foo = intern_table.LookupStrong(soa.Self(), 3, "foo");
- EXPECT_EQ(lookup_foo, foo.Get());
- mirror::String* lookup_bar = intern_table.LookupStrong(soa.Self(), 3, "bar");
- EXPECT_EQ(lookup_bar, bar.Get());
- mirror::String* lookup_foobar = intern_table.LookupStrong(soa.Self(), 6, "foobar");
- EXPECT_EQ(lookup_foobar, foobar.Get());
- mirror::String* lookup_foox = intern_table.LookupStrong(soa.Self(), 4, "foox");
+ ObjPtr<mirror::String> lookup_foo = intern_table.LookupStrong(soa.Self(), 3, "foo");
+ EXPECT_OBJ_PTR_EQ(lookup_foo, foo.Get());
+ ObjPtr<mirror::String> lookup_bar = intern_table.LookupStrong(soa.Self(), 3, "bar");
+ EXPECT_OBJ_PTR_EQ(lookup_bar, bar.Get());
+ ObjPtr<mirror::String> lookup_foobar = intern_table.LookupStrong(soa.Self(), 6, "foobar");
+ EXPECT_OBJ_PTR_EQ(lookup_foobar, foobar.Get());
+ ObjPtr<mirror::String> lookup_foox = intern_table.LookupStrong(soa.Self(), 4, "foox");
EXPECT_TRUE(lookup_foox == nullptr);
- mirror::String* lookup_fooba = intern_table.LookupStrong(soa.Self(), 5, "fooba");
+ ObjPtr<mirror::String> lookup_fooba = intern_table.LookupStrong(soa.Self(), 5, "fooba");
EXPECT_TRUE(lookup_fooba == nullptr);
- mirror::String* lookup_foobaR = intern_table.LookupStrong(soa.Self(), 6, "foobaR");
+ ObjPtr<mirror::String> lookup_foobaR = intern_table.LookupStrong(soa.Self(), 6, "foobaR");
EXPECT_TRUE(lookup_foobaR == nullptr);
// Try a hash conflict.
ASSERT_EQ(ComputeUtf16HashFromModifiedUtf8("foobar", 6),
ComputeUtf16HashFromModifiedUtf8("foobbS", 6));
- mirror::String* lookup_foobbS = intern_table.LookupStrong(soa.Self(), 6, "foobbS");
+ ObjPtr<mirror::String> lookup_foobbS = intern_table.LookupStrong(soa.Self(), 6, "foobbS");
EXPECT_TRUE(lookup_foobbS == nullptr);
}
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 179e48b..4fc92a3 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -836,7 +836,7 @@
Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
CHECK(handle_type.Get() != nullptr);
if (UNLIKELY(is_invoke_exact && !callsite_type->IsExactMatch(handle_type.Get()))) {
- ThrowWrongMethodTypeException(callsite_type.Get(), handle_type.Get());
+ ThrowWrongMethodTypeException(handle_type.Get(), callsite_type.Get());
return false;
}
diff --git a/runtime/mirror/method_type.cc b/runtime/mirror/method_type.cc
index 0b52931..9b0f872 100644
--- a/runtime/mirror/method_type.cc
+++ b/runtime/mirror/method_type.cc
@@ -65,6 +65,25 @@
return true;
}
+std::string MethodType::PrettyDescriptor() REQUIRES_SHARED(Locks::mutator_lock_) {
+ std::ostringstream ss;
+ ss << "(";
+
+ mirror::ObjectArray<Class>* const p_types = GetPTypes();
+ const int32_t params_length = p_types->GetLength();
+ for (int32_t i = 0; i < params_length; ++i) {
+ ss << p_types->GetWithoutChecks(i)->PrettyDescriptor();
+ if (i != (params_length - 1)) {
+ ss << ", ";
+ }
+ }
+
+ ss << ")";
+ ss << GetRType()->PrettyDescriptor();
+
+ return ss.str();
+}
+
void MethodType::SetClass(Class* klass) {
CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
CHECK(klass != nullptr);
diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h
index 5b50409..fa700b6 100644
--- a/runtime/mirror/method_type.h
+++ b/runtime/mirror/method_type.h
@@ -56,6 +56,10 @@
// iff. they have the same return types and parameter types.
bool IsExactMatch(mirror::MethodType* other) REQUIRES_SHARED(Locks::mutator_lock_);
+ // Returns the pretty descriptor for this method type, suitable for display in
+ // exception messages and the like.
+ std::string PrettyDescriptor() REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
static MemberOffset FormOffset() {
return MemberOffset(OFFSETOF_MEMBER(MethodType, form_));
diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h
index d42bb92..d94b39f 100644
--- a/runtime/mirror/string-inl.h
+++ b/runtime/mirror/string-inl.h
@@ -160,7 +160,7 @@
const int32_t offset_;
};
-inline String* String::Intern() {
+inline ObjPtr<String> String::Intern() {
return Runtime::Current()->GetInternTable()->InternWeak(this);
}
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index a1b674a..6ce75bc 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -93,7 +93,7 @@
void SetCharAt(int32_t index, uint16_t c) REQUIRES_SHARED(Locks::mutator_lock_);
- String* Intern() REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<String> Intern() REQUIRES_SHARED(Locks::mutator_lock_);
template <bool kIsInstrumented>
ALWAYS_INLINE static String* AllocFromByteArray(Thread* self, int32_t byte_length,
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d645c5a..262608d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1953,31 +1953,31 @@
preinitialization_transaction_->RecordWriteArray(array, index, value);
}
-void Runtime::RecordStrongStringInsertion(mirror::String* s) const {
+void Runtime::RecordStrongStringInsertion(ObjPtr<mirror::String> s) const {
DCHECK(IsAotCompiler());
DCHECK(IsActiveTransaction());
preinitialization_transaction_->RecordStrongStringInsertion(s);
}
-void Runtime::RecordWeakStringInsertion(mirror::String* s) const {
+void Runtime::RecordWeakStringInsertion(ObjPtr<mirror::String> s) const {
DCHECK(IsAotCompiler());
DCHECK(IsActiveTransaction());
preinitialization_transaction_->RecordWeakStringInsertion(s);
}
-void Runtime::RecordStrongStringRemoval(mirror::String* s) const {
+void Runtime::RecordStrongStringRemoval(ObjPtr<mirror::String> s) const {
DCHECK(IsAotCompiler());
DCHECK(IsActiveTransaction());
preinitialization_transaction_->RecordStrongStringRemoval(s);
}
-void Runtime::RecordWeakStringRemoval(mirror::String* s) const {
+void Runtime::RecordWeakStringRemoval(ObjPtr<mirror::String> s) const {
DCHECK(IsAotCompiler());
DCHECK(IsActiveTransaction());
preinitialization_transaction_->RecordWeakStringRemoval(s);
}
-void Runtime::RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx) const {
+void Runtime::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache, uint32_t string_idx) const {
DCHECK(IsAotCompiler());
DCHECK(IsActiveTransaction());
preinitialization_transaction_->RecordResolveString(dex_cache, string_idx);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 043ff5d..86464ab 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -510,15 +510,15 @@
REQUIRES_SHARED(Locks::mutator_lock_);
void RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) const
REQUIRES_SHARED(Locks::mutator_lock_);
- void RecordStrongStringInsertion(mirror::String* s) const
+ void RecordStrongStringInsertion(ObjPtr<mirror::String> s) const
REQUIRES(Locks::intern_table_lock_);
- void RecordWeakStringInsertion(mirror::String* s) const
+ void RecordWeakStringInsertion(ObjPtr<mirror::String> s) const
REQUIRES(Locks::intern_table_lock_);
- void RecordStrongStringRemoval(mirror::String* s) const
+ void RecordStrongStringRemoval(ObjPtr<mirror::String> s) const
REQUIRES(Locks::intern_table_lock_);
- void RecordWeakStringRemoval(mirror::String* s) const
+ void RecordWeakStringRemoval(ObjPtr<mirror::String> s) const
REQUIRES(Locks::intern_table_lock_);
- void RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx) const
+ void RecordResolveString(ObjPtr<mirror::DexCache> dex_cache, uint32_t string_idx) const
REQUIRES_SHARED(Locks::mutator_lock_);
void SetFaultMessage(const std::string& message) REQUIRES(!fault_message_lock_);
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index 9f8d981..c5da5d2 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -167,29 +167,29 @@
array_log.LogValue(index, value);
}
-void Transaction::RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx) {
+void Transaction::RecordResolveString(ObjPtr<mirror::DexCache> dex_cache, uint32_t string_idx) {
DCHECK(dex_cache != nullptr);
DCHECK_LT(string_idx, dex_cache->GetDexFile()->NumStringIds());
MutexLock mu(Thread::Current(), log_lock_);
resolve_string_logs_.push_back(ResolveStringLog(dex_cache, string_idx));
}
-void Transaction::RecordStrongStringInsertion(mirror::String* s) {
+void Transaction::RecordStrongStringInsertion(ObjPtr<mirror::String> s) {
InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
LogInternedString(log);
}
-void Transaction::RecordWeakStringInsertion(mirror::String* s) {
+void Transaction::RecordWeakStringInsertion(ObjPtr<mirror::String> s) {
InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kInsert);
LogInternedString(log);
}
-void Transaction::RecordStrongStringRemoval(mirror::String* s) {
+void Transaction::RecordStrongStringRemoval(ObjPtr<mirror::String> s) {
InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kRemove);
LogInternedString(log);
}
-void Transaction::RecordWeakStringRemoval(mirror::String* s) {
+void Transaction::RecordWeakStringRemoval(ObjPtr<mirror::String> s) {
InternStringLog log(s, InternStringLog::kWeakString, InternStringLog::kRemove);
LogInternedString(log);
}
@@ -470,10 +470,10 @@
case InternStringLog::kInsert: {
switch (string_kind_) {
case InternStringLog::kStrongString:
- intern_table->RemoveStrongFromTransaction(str_);
+ intern_table->RemoveStrongFromTransaction(str_.Read());
break;
case InternStringLog::kWeakString:
- intern_table->RemoveWeakFromTransaction(str_);
+ intern_table->RemoveWeakFromTransaction(str_.Read());
break;
default:
LOG(FATAL) << "Unknown interned string kind";
@@ -484,10 +484,10 @@
case InternStringLog::kRemove: {
switch (string_kind_) {
case InternStringLog::kStrongString:
- intern_table->InsertStrongFromTransaction(str_);
+ intern_table->InsertStrongFromTransaction(str_.Read());
break;
case InternStringLog::kWeakString:
- intern_table->InsertWeakFromTransaction(str_);
+ intern_table->InsertWeakFromTransaction(str_.Read());
break;
default:
LOG(FATAL) << "Unknown interned string kind";
@@ -502,14 +502,15 @@
}
void Transaction::InternStringLog::VisitRoots(RootVisitor* visitor) {
- visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&str_), RootInfo(kRootInternedString));
+ str_.VisitRoot(visitor, RootInfo(kRootInternedString));
}
void Transaction::ResolveStringLog::Undo() {
dex_cache_.Read()->ClearString(string_idx_);
}
-Transaction::ResolveStringLog::ResolveStringLog(mirror::DexCache* dex_cache, uint32_t string_idx)
+Transaction::ResolveStringLog::ResolveStringLog(ObjPtr<mirror::DexCache> dex_cache,
+ uint32_t string_idx)
: dex_cache_(dex_cache),
string_idx_(string_idx) {
DCHECK(dex_cache != nullptr);
@@ -520,6 +521,15 @@
dex_cache_.VisitRoot(visitor, RootInfo(kRootVMInternal));
}
+Transaction::InternStringLog::InternStringLog(ObjPtr<mirror::String> s,
+ StringKind kind,
+ StringOp op)
+ : str_(s),
+ string_kind_(kind),
+ string_op_(op) {
+ DCHECK(s != nullptr);
+}
+
void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
auto it = array_values_.find(index);
if (it == array_values_.end()) {
diff --git a/runtime/transaction.h b/runtime/transaction.h
index 584dfb8..2ec2f50 100644
--- a/runtime/transaction.h
+++ b/runtime/transaction.h
@@ -83,21 +83,21 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Record intern string table changes.
- void RecordStrongStringInsertion(mirror::String* s)
+ void RecordStrongStringInsertion(ObjPtr<mirror::String> s)
REQUIRES(Locks::intern_table_lock_)
REQUIRES(!log_lock_);
- void RecordWeakStringInsertion(mirror::String* s)
+ void RecordWeakStringInsertion(ObjPtr<mirror::String> s)
REQUIRES(Locks::intern_table_lock_)
REQUIRES(!log_lock_);
- void RecordStrongStringRemoval(mirror::String* s)
+ void RecordStrongStringRemoval(ObjPtr<mirror::String> s)
REQUIRES(Locks::intern_table_lock_)
REQUIRES(!log_lock_);
- void RecordWeakStringRemoval(mirror::String* s)
+ void RecordWeakStringRemoval(ObjPtr<mirror::String> s)
REQUIRES(Locks::intern_table_lock_)
REQUIRES(!log_lock_);
// Record resolve string.
- void RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx)
+ void RecordResolveString(ObjPtr<mirror::DexCache> dex_cache, uint32_t string_idx)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!log_lock_);
@@ -182,10 +182,7 @@
kInsert,
kRemove
};
- InternStringLog(mirror::String* s, StringKind kind, StringOp op)
- : str_(s), string_kind_(kind), string_op_(op) {
- DCHECK(s != nullptr);
- }
+ InternStringLog(ObjPtr<mirror::String> s, StringKind kind, StringOp op);
void Undo(InternTable* intern_table)
REQUIRES_SHARED(Locks::mutator_lock_)
@@ -193,14 +190,14 @@
void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
private:
- mirror::String* str_;
+ GcRoot<mirror::String> str_;
const StringKind string_kind_;
const StringOp string_op_;
};
class ResolveStringLog : public ValueObject {
public:
- ResolveStringLog(mirror::DexCache* dex_cache, uint32_t string_idx);
+ ResolveStringLog(ObjPtr<mirror::DexCache> dex_cache, uint32_t string_idx);
void Undo() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 28f9bb3..edd6ffe 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <string>
+#include "base/array_ref.h"
#include "base/macros.h"
#include "mem_map.h"
#include "os.h"
@@ -44,8 +45,11 @@
public:
Header(uint32_t dex_size, uint32_t verifier_deps_size, uint32_t quickening_info_size);
+ const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
+ const char* GetVersion() const { return reinterpret_cast<const char*>(version_); }
bool IsMagicValid() const;
bool IsVersionValid() const;
+ bool IsValid() const { return IsMagicValid() && IsVersionValid(); }
uint32_t GetDexSize() const { return dex_size_; }
uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
@@ -71,6 +75,15 @@
const uint8_t* End() const { return mmap_->End(); }
size_t Size() const { return mmap_->Size(); }
+ const Header& GetHeader() const {
+ return *reinterpret_cast<const Header*>(Begin());
+ }
+
+ ArrayRef<const uint8_t> GetVerifierDepsData() const {
+ return ArrayRef<const uint8_t>(
+ Begin() + sizeof(Header) + GetHeader().GetDexSize(), GetHeader().GetVerifierDepsSize());
+ }
+
private:
explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index 4d1e337..149861c 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -39,6 +39,11 @@
return (it == dex_deps_.end()) ? nullptr : it->second.get();
}
+const VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) const {
+ auto it = dex_deps_.find(&dex_file);
+ return (it == dex_deps_.end()) ? nullptr : it->second.get();
+}
+
template <typename T>
uint16_t VerifierDeps::GetAccessFlags(T* element) {
static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
@@ -95,12 +100,12 @@
return new_id;
}
-std::string VerifierDeps::GetStringFromId(const DexFile& dex_file, uint32_t string_id) {
+std::string VerifierDeps::GetStringFromId(const DexFile& dex_file, uint32_t string_id) const {
uint32_t num_ids_in_dex = dex_file.NumStringIds();
if (string_id < num_ids_in_dex) {
return std::string(dex_file.StringDataByIdx(string_id));
} else {
- DexFileDeps* deps = GetDexFileDeps(dex_file);
+ const DexFileDeps* deps = GetDexFileDeps(dex_file);
DCHECK(deps != nullptr);
string_id -= num_ids_in_dex;
CHECK_LT(string_id, deps->strings_.size());
@@ -108,7 +113,7 @@
}
}
-bool VerifierDeps::IsInClassPath(ObjPtr<mirror::Class> klass) {
+bool VerifierDeps::IsInClassPath(ObjPtr<mirror::Class> klass) const {
DCHECK(klass != nullptr);
ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
@@ -431,35 +436,45 @@
}
}
-void VerifierDeps::Encode(std::vector<uint8_t>* buffer) const {
+void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files,
+ std::vector<uint8_t>* buffer) const {
MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
- for (auto& entry : dex_deps_) {
- EncodeStringVector(buffer, entry.second->strings_);
- EncodeSet(buffer, entry.second->assignable_types_);
- EncodeSet(buffer, entry.second->unassignable_types_);
- EncodeSet(buffer, entry.second->classes_);
- EncodeSet(buffer, entry.second->fields_);
- EncodeSet(buffer, entry.second->direct_methods_);
- EncodeSet(buffer, entry.second->virtual_methods_);
- EncodeSet(buffer, entry.second->interface_methods_);
- EncodeUint16Vector(buffer, entry.second->unverified_classes_);
+ for (const DexFile* dex_file : dex_files) {
+ const DexFileDeps& deps = *GetDexFileDeps(*dex_file);
+ EncodeStringVector(buffer, deps.strings_);
+ EncodeSet(buffer, deps.assignable_types_);
+ EncodeSet(buffer, deps.unassignable_types_);
+ EncodeSet(buffer, deps.classes_);
+ EncodeSet(buffer, deps.fields_);
+ EncodeSet(buffer, deps.direct_methods_);
+ EncodeSet(buffer, deps.virtual_methods_);
+ EncodeSet(buffer, deps.interface_methods_);
+ EncodeUint16Vector(buffer, deps.unverified_classes_);
}
}
-VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files, ArrayRef<uint8_t> data)
+VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files,
+ ArrayRef<const uint8_t> data)
: VerifierDeps(dex_files) {
+ if (data.empty()) {
+ // Return eagerly, as the first thing we expect from VerifierDeps data is
+ // the number of created strings, even if there is no dependency.
+ // Currently, only the boot image does not have any VerifierDeps data.
+ return;
+ }
const uint8_t* data_start = data.data();
const uint8_t* data_end = data_start + data.size();
- for (auto& entry : dex_deps_) {
- DecodeStringVector(&data_start, data_end, &entry.second->strings_);
- DecodeSet(&data_start, data_end, &entry.second->assignable_types_);
- DecodeSet(&data_start, data_end, &entry.second->unassignable_types_);
- DecodeSet(&data_start, data_end, &entry.second->classes_);
- DecodeSet(&data_start, data_end, &entry.second->fields_);
- DecodeSet(&data_start, data_end, &entry.second->direct_methods_);
- DecodeSet(&data_start, data_end, &entry.second->virtual_methods_);
- DecodeSet(&data_start, data_end, &entry.second->interface_methods_);
- DecodeUint16Vector(&data_start, data_end, &entry.second->unverified_classes_);
+ for (const DexFile* dex_file : dex_files) {
+ DexFileDeps* deps = GetDexFileDeps(*dex_file);
+ DecodeStringVector(&data_start, data_end, &deps->strings_);
+ DecodeSet(&data_start, data_end, &deps->assignable_types_);
+ DecodeSet(&data_start, data_end, &deps->unassignable_types_);
+ DecodeSet(&data_start, data_end, &deps->classes_);
+ DecodeSet(&data_start, data_end, &deps->fields_);
+ DecodeSet(&data_start, data_end, &deps->direct_methods_);
+ DecodeSet(&data_start, data_end, &deps->virtual_methods_);
+ DecodeSet(&data_start, data_end, &deps->interface_methods_);
+ DecodeUint16Vector(&data_start, data_end, &deps->unverified_classes_);
}
CHECK_LE(data_start, data_end);
}
@@ -504,5 +519,93 @@
(unverified_classes_ == rhs.unverified_classes_);
}
+void VerifierDeps::Dump(VariableIndentationOutputStream* vios) const {
+ for (const auto& dep : dex_deps_) {
+ const DexFile& dex_file = *dep.first;
+ vios->Stream()
+ << "Dependencies of "
+ << dex_file.GetLocation()
+ << ":\n";
+
+ ScopedIndentation indent(vios);
+
+ for (const std::string& str : dep.second->strings_) {
+ vios->Stream() << "Extra string: " << str << "\n";
+ }
+
+ for (const TypeAssignability& entry : dep.second->assignable_types_) {
+ vios->Stream()
+ << GetStringFromId(dex_file, entry.GetSource())
+ << " must be assignable to "
+ << GetStringFromId(dex_file, entry.GetDestination())
+ << "\n";
+ }
+
+ for (const TypeAssignability& entry : dep.second->unassignable_types_) {
+ vios->Stream()
+ << GetStringFromId(dex_file, entry.GetSource())
+ << " must not be assignable to "
+ << GetStringFromId(dex_file, entry.GetDestination())
+ << "\n";
+ }
+
+ for (const ClassResolution& entry : dep.second->classes_) {
+ vios->Stream()
+ << dex_file.StringByTypeIdx(entry.GetDexTypeIndex())
+ << (entry.IsResolved() ? " must be resolved " : "must not be resolved ")
+ << " with access flags " << std::hex << entry.GetAccessFlags() << std::dec
+ << "\n";
+ }
+
+ for (const FieldResolution& entry : dep.second->fields_) {
+ const DexFile::FieldId& field_id = dex_file.GetFieldId(entry.GetDexFieldIndex());
+ vios->Stream()
+ << dex_file.GetFieldDeclaringClassDescriptor(field_id) << "->"
+ << dex_file.GetFieldName(field_id) << ":"
+ << dex_file.GetFieldTypeDescriptor(field_id)
+ << " is expected to be ";
+ if (!entry.IsResolved()) {
+ vios->Stream() << "unresolved\n";
+ } else {
+ vios->Stream()
+ << "in class "
+ << GetStringFromId(dex_file, entry.GetDeclaringClassIndex())
+ << ", and have the access flags " << std::hex << entry.GetAccessFlags() << std::dec
+ << "\n";
+ }
+ }
+
+ for (const auto& entry :
+ { std::make_pair(kDirectMethodResolution, dep.second->direct_methods_),
+ std::make_pair(kVirtualMethodResolution, dep.second->virtual_methods_),
+ std::make_pair(kInterfaceMethodResolution, dep.second->interface_methods_) }) {
+ for (const MethodResolution& method : entry.second) {
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(method.GetDexMethodIndex());
+ vios->Stream()
+ << dex_file.GetMethodDeclaringClassDescriptor(method_id) << "->"
+ << dex_file.GetMethodName(method_id)
+ << dex_file.GetMethodSignature(method_id).ToString()
+ << " is expected to be ";
+ if (!method.IsResolved()) {
+ vios->Stream() << "unresolved\n";
+ } else {
+ vios->Stream()
+ << "in class "
+ << GetStringFromId(dex_file, method.GetDeclaringClassIndex())
+ << ", have the access flags " << std::hex << method.GetAccessFlags() << std::dec
+ << ", and be of kind " << entry.first
+ << "\n";
+ }
+ }
+ }
+
+ for (uint16_t type_index : dep.second->unverified_classes_) {
+ vios->Stream()
+ << dex_file.StringByTypeIdx(type_index)
+ << " is expected to be verified at runtime\n";
+ }
+ }
+}
+
} // namespace verifier
} // namespace art
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 9d2622d..fab4323 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -25,6 +25,7 @@
#include "art_method.h"
#include "base/array_ref.h"
#include "base/mutex.h"
+#include "indenter.h"
#include "method_resolution_kind.h"
#include "method_verifier.h" // For MethodVerifier::FailureKind.
#include "obj_ptr.h"
@@ -50,6 +51,10 @@
explicit VerifierDeps(const std::vector<const DexFile*>& dex_files)
REQUIRES(!Locks::verifier_deps_lock_);
+ VerifierDeps(const std::vector<const DexFile*>& dex_files,
+ ArrayRef<const uint8_t> data)
+ REQUIRES(!Locks::verifier_deps_lock_);
+
// Record the verification status of the class at `type_idx`.
static void MaybeRecordVerificationStatus(const DexFile& dex_file,
uint16_t type_idx,
@@ -94,16 +99,19 @@
REQUIRES(!Locks::verifier_deps_lock_);
// Serialize the recorded dependencies and store the data into `buffer`.
- void Encode(std::vector<uint8_t>* buffer) const
+ // `dex_files` provides the order of the dex files in which the dependencies
+ // should be emitted.
+ void Encode(const std::vector<const DexFile*>& dex_files, std::vector<uint8_t>* buffer) const
REQUIRES(!Locks::verifier_deps_lock_);
+ // NO_THREAD_SAFETY_ANALYSIS as Dump iterates over dex_deps_, which is guarded by
+ // verifier_deps_lock_, but we expect Dump to be called once the deps collection is done.
+ void Dump(VariableIndentationOutputStream* vios) const
+ NO_THREAD_SAFETY_ANALYSIS;
+
private:
static constexpr uint16_t kUnresolvedMarker = static_cast<uint16_t>(-1);
- // Only used in tests to reconstruct the data structure from serialized data.
- VerifierDeps(const std::vector<const DexFile*>& dex_files, ArrayRef<uint8_t> data)
- REQUIRES(!Locks::verifier_deps_lock_);
-
using ClassResolutionBase = std::tuple<uint32_t, uint16_t>;
struct ClassResolution : public ClassResolutionBase {
ClassResolution() = default;
@@ -185,9 +193,12 @@
DexFileDeps* GetDexFileDeps(const DexFile& dex_file)
NO_THREAD_SAFETY_ANALYSIS;
+ const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const
+ NO_THREAD_SAFETY_ANALYSIS;
+
// Returns true if `klass` is null or not defined in any of dex files which
// were reported as being compiled.
- bool IsInClassPath(ObjPtr<mirror::Class> klass)
+ bool IsInClassPath(ObjPtr<mirror::Class> klass) const
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the index of `str`. If it is defined in `dex_file_`, this is the dex
@@ -198,13 +209,13 @@
REQUIRES(Locks::verifier_deps_lock_);
// Returns the string represented by `id`.
- std::string GetStringFromId(const DexFile& dex_file, uint32_t string_id)
+ std::string GetStringFromId(const DexFile& dex_file, uint32_t string_id) const
REQUIRES(Locks::verifier_deps_lock_);
// Returns the bytecode access flags of `element` (bottom 16 bits), or
// `kUnresolvedMarker` if `element` is null.
template <typename T>
- uint16_t GetAccessFlags(T* element)
+ static uint16_t GetAccessFlags(T* element)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a string ID of the descriptor of the declaring class of `element`,
@@ -251,6 +262,7 @@
friend class VerifierDepsTest;
ART_FRIEND_TEST(VerifierDepsTest, StringToId);
ART_FRIEND_TEST(VerifierDepsTest, EncodeDecode);
+ ART_FRIEND_TEST(VerifierDepsTest, EncodeDecodeMulti);
};
} // namespace verifier
diff --git a/test/956-methodhandles/expected.txt b/test/956-methodhandles/expected.txt
index ddc1cb0..ad1c43c 100644
--- a/test/956-methodhandles/expected.txt
+++ b/test/956-methodhandles/expected.txt
@@ -3,3 +3,4 @@
foo_A
foo_B
privateRyan_D
+Received exception: Expected (java.lang.String, java.lang.String)java.lang.String but was (java.lang.String, java.lang.Object)void
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index 42265a9..58ba55d 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -57,6 +57,7 @@
public static void main(String[] args) throws Throwable {
testfindSpecial_invokeSuperBehaviour();
testfindSpecial_invokeDirectBehaviour();
+ testExceptionDetailMessages();
}
public static void testfindSpecial_invokeSuperBehaviour() throws Throwable {
@@ -127,6 +128,18 @@
} catch (IllegalAccessException expected) {
}
}
+
+ public static void testExceptionDetailMessages() throws Throwable {
+ MethodHandle handle = MethodHandles.lookup().findVirtual(String.class, "concat",
+ MethodType.methodType(String.class, String.class));
+
+ try {
+ handle.invokeExact("a", new Object());
+ System.out.println("invokeExact(\"a\", new Object()) unexpectedly succeeded.");
+ } catch (WrongMethodTypeException ex) {
+ System.out.println("Received exception: " + ex.getMessage());
+ }
+ }
}
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 4248148..a2eb370 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -128,9 +128,10 @@
return;
}
+ Thread* self = Thread::Current();
ArtMethod* method = nullptr;
{
- ScopedObjectAccess soa(Thread::Current());
+ ScopedObjectAccess soa(self);
ScopedUtfChars chars(env, method_name);
CHECK(chars.c_str() != nullptr);
@@ -147,11 +148,11 @@
} else {
// Sleep to yield to the compiler thread.
usleep(1000);
- ScopedObjectAccess soa(Thread::Current());
+ ScopedObjectAccess soa(self);
// Make sure there is a profiling info, required by the compiler.
- ProfilingInfo::Create(soa.Self(), method, /* retry_allocation */ true);
+ ProfilingInfo::Create(self, method, /* retry_allocation */ true);
// Will either ensure it's compiled or do the compilation itself.
- jit->CompileMethod(method, soa.Self(), /* osr */ false);
+ jit->CompileMethod(method, self, /* osr */ false);
}
}
}
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 3535f32..cc0d008 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -148,7 +148,7 @@
SECONDARY_DEX=":$DEX_LOCATION/$TEST_NAME-ex.jar"
# Enable cfg-append to make sure we get the dump for both dex files.
# (otherwise the runtime compilation of the secondary dex will overwrite
- # the dump of the first one)
+ # the dump of the first one).
FLAGS="${FLAGS} -Xcompiler-option --dump-cfg-append"
COMPILE_FLAGS="${COMPILE_FLAGS} --dump-cfg-append"
shift