Merge "Delete pin table" into lmp-dev
diff --git a/compiler/elf_patcher.cc b/compiler/elf_patcher.cc
index 137110f..ea4517f 100644
--- a/compiler/elf_patcher.cc
+++ b/compiler/elf_patcher.cc
@@ -197,7 +197,8 @@
mirror::ArtMethod* target = GetTargetMethod(patch);
uintptr_t quick_code = reinterpret_cast<uintptr_t>(class_linker->GetQuickOatCodeFor(target));
DCHECK_NE(quick_code, 0U) << PrettyMethod(target);
- const OatFile* target_oat = class_linker->FindOpenedOatFileForDexFile(*patch->GetTargetDexFile());
+ const OatFile* target_oat =
+ class_linker->FindOpenedOatDexFileForDexFile(*patch->GetTargetDexFile())->GetOatFile();
// Get where the data actually starts. if target is this oat_file_ it is oat_data_start_,
// otherwise it is wherever target_oat is loaded.
uintptr_t oat_data_addr = GetBaseAddressFor(target_oat);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 26f32f9..ed5c843 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -676,18 +676,18 @@
return *oat_file;
}
-const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
+const OatFile::OatDexFile* ClassLinker::FindOpenedOatDexFileForDexFile(const DexFile& dex_file) {
const char* dex_location = dex_file.GetLocation().c_str();
uint32_t dex_location_checksum = dex_file.GetLocationChecksum();
- return FindOpenedOatFile(nullptr, dex_location, &dex_location_checksum);
+ return FindOpenedOatDexFile(nullptr, dex_location, &dex_location_checksum);
}
-const OatFile* ClassLinker::FindOpenedOatFile(const char* oat_location, const char* dex_location,
- const uint32_t* const dex_location_checksum) {
+const OatFile::OatDexFile* ClassLinker::FindOpenedOatDexFile(const char* oat_location,
+ const char* dex_location,
+ const uint32_t* dex_location_checksum) {
ReaderMutexLock mu(Thread::Current(), dex_lock_);
- for (size_t i = 0; i < oat_files_.size(); i++) {
- const OatFile* oat_file = oat_files_[i];
- DCHECK(oat_file != NULL);
+ for (const OatFile* oat_file : oat_files_) {
+ DCHECK(oat_file != nullptr);
if (oat_location != nullptr) {
if (oat_file->GetLocation() != oat_location) {
@@ -698,11 +698,11 @@
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
dex_location_checksum,
false);
- if (oat_dex_file != NULL) {
- return oat_file;
+ if (oat_dex_file != nullptr) {
+ return oat_dex_file;
}
}
- return NULL;
+ return nullptr;
}
@@ -824,8 +824,10 @@
bool needs_registering = false;
- std::unique_ptr<const OatFile> open_oat_file(FindOpenedOatFile(oat_location, dex_location,
- dex_location_checksum_pointer));
+ const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFile(oat_location, dex_location,
+ dex_location_checksum_pointer);
+ std::unique_ptr<const OatFile> open_oat_file(
+ oat_dex_file != nullptr ? oat_dex_file->GetOatFile() : nullptr);
// 2) If we do not have an open one, maybe there's one on disk already.
@@ -946,7 +948,8 @@
}
// Try to load again, but stronger checks.
- success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, dex_location_checksum_pointer,
+ success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
+ dex_location_checksum_pointer,
true, error_msgs, dex_files);
if (success) {
RegisterOatFile(open_oat_file.release());
@@ -1121,12 +1124,11 @@
if (oat_dex_file == NULL) {
*error_msg = StringPrintf("oat file '%s' does not contain contents for '%s' with checksum 0x%x",
oat_file->GetLocation().c_str(), dex_location, dex_location_checksum);
- std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file->GetOatDexFiles();
- for (size_t i = 0; i < oat_dex_files.size(); i++) {
- const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
- *error_msg += StringPrintf("\noat file '%s' contains contents for '%s'",
+ for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
+ *error_msg += StringPrintf("\noat file '%s' contains contents for '%s' with checksum 0x%x",
oat_file->GetLocation().c_str(),
- oat_dex_file->GetDexFileLocation().c_str());
+ oat_dex_file->GetDexFileLocation().c_str(),
+ oat_dex_file->GetDexFileLocationChecksum());
}
return false;
}
@@ -1174,7 +1176,7 @@
const OatFile* ClassLinker::FindOatFileContainingDexFileFromDexLocation(
const char* dex_location,
- const uint32_t* const dex_location_checksum,
+ const uint32_t* dex_location_checksum,
InstructionSet isa,
std::vector<std::string>* error_msgs,
bool* obsolete_file_cleanup_failed) {
@@ -2066,7 +2068,7 @@
if (pair.second != nullptr) {
mirror::Class* klass = LookupClass(descriptor, nullptr);
if (klass != nullptr) {
- return klass;
+ return EnsureResolved(self, descriptor, klass);
}
klass = DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first,
*pair.second);
@@ -2311,14 +2313,10 @@
OatFile::OatClass* oat_class) {
DCHECK(oat_class != nullptr);
DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16);
- const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
- if (oat_file == nullptr) {
+ const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFileForDexFile(dex_file);
+ if (oat_dex_file == nullptr) {
return false;
}
- uint dex_location_checksum = dex_file.GetLocationChecksum();
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
- &dex_location_checksum);
- CHECK(oat_dex_file != NULL) << dex_file.GetLocation();
*oat_class = oat_dex_file->GetOatClass(class_def_idx);
return true;
}
@@ -3413,8 +3411,11 @@
ObjectLock<mirror::Class> lock(self, klass);
// Don't attempt to re-verify if already sufficiently verified.
- if (klass->IsVerified() ||
- (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler())) {
+ if (klass->IsVerified()) {
+ EnsurePreverifiedMethods(klass);
+ return;
+ }
+ if (klass->IsCompileTimeVerified() && Runtime::Current()->IsCompiler()) {
return;
}
@@ -3437,6 +3438,7 @@
// Skip verification if disabled.
if (!Runtime::Current()->IsVerificationEnabled()) {
klass->SetStatus(mirror::Class::kStatusVerified, self);
+ EnsurePreverifiedMethods(klass);
return;
}
@@ -3522,6 +3524,9 @@
klass->SetStatus(mirror::Class::kStatusRetryVerificationAtRuntime, self);
} else {
klass->SetStatus(mirror::Class::kStatusVerified, self);
+ // As this is a fake verified status, make sure the methods are _not_ marked preverified
+ // later.
+ klass->SetAccessFlags(klass->GetAccessFlags() | kAccPreverified);
}
}
} else {
@@ -3539,7 +3544,14 @@
// Note: we're going here during compilation and at runtime. When we set the
// kAccPreverified flag when compiling image classes, the flag is recorded
// in the image and is set when loading the image.
+ EnsurePreverifiedMethods(klass);
+ }
+}
+
+void ClassLinker::EnsurePreverifiedMethods(Handle<mirror::Class> klass) {
+ if ((klass->GetAccessFlags() & kAccPreverified) == 0) {
klass->SetPreverifiedFlagOnAllMethods();
+ klass->SetAccessFlags(klass->GetAccessFlags() | kAccPreverified);
}
}
@@ -3562,17 +3574,13 @@
}
}
- const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
+ const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFileForDexFile(dex_file);
// Make this work with gtests, which do not set up the image properly.
// TODO: we should clean up gtests to set up the image path properly.
- if (Runtime::Current()->IsCompiler() || (oat_file == NULL)) {
+ if (Runtime::Current()->IsCompiler() || (oat_dex_file == nullptr)) {
return false;
}
- CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
- uint dex_location_checksum = dex_file.GetLocationChecksum();
- const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation().c_str(),
- &dex_location_checksum);
CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
uint16_t class_def_index = klass->GetDexClassDefIndex();
oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus();
@@ -3677,7 +3685,8 @@
}
DCHECK(klass->GetClass() != NULL);
klass->SetObjectSize(sizeof(mirror::Proxy));
- klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal);
+ // Set the class access flags incl. preverified, so we do not try to set the flag on the methods.
+ klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccPreverified);
klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader));
DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
klass->SetName(soa.Decode<mirror::String*>(name));
@@ -4238,6 +4247,7 @@
bool can_init_parents) {
DCHECK(c.Get() != nullptr);
if (c->IsInitialized()) {
+ EnsurePreverifiedMethods(c);
return true;
}
const bool success = InitializeClass(c, can_init_fields, can_init_parents);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 79cbb02..f6b08f0 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -541,14 +541,15 @@
}
mirror::DexCache* GetDexCache(size_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_);
- const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file)
+ const OatFile::OatDexFile* FindOpenedOatDexFileForDexFile(const DexFile& dex_file)
LOCKS_EXCLUDED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- // Find an opened oat file that contains dex_location. If oat_location is not nullptr, the file
- // must have that location, else any oat location is accepted.
- const OatFile* FindOpenedOatFile(const char* oat_location, const char* dex_location,
- const uint32_t* const dex_location_checksum)
+ // Find an opened oat dex file that contains dex_location. If oat_location is not nullptr,
+ // the file must have that location, else any oat location is accepted.
+ const OatFile::OatDexFile* FindOpenedOatDexFile(const char* oat_location,
+ const char* dex_location,
+ const uint32_t* dex_location_checksum)
LOCKS_EXCLUDED(dex_lock_);
// Will open the oat file directly without relocating, even if we could/should do relocation.
@@ -598,8 +599,8 @@
// Note 1: this will not check open oat files, which are assumed to be stale when this is run.
// Note 2: Does not register the oat file. It is the caller's job to register if the file is to
// be kept.
- const OatFile* FindOatFileContainingDexFileFromDexLocation(const char* location,
- const uint32_t* const location_checksum,
+ const OatFile* FindOatFileContainingDexFileFromDexLocation(const char* dex_location,
+ const uint32_t* dex_location_checksum,
InstructionSet isa,
std::vector<std::string>* error_msgs,
bool* obsolete_file_cleanup_failed)
@@ -626,6 +627,11 @@
Handle<mirror::ArtMethod> prototype)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Ensures that methods have the kAccPreverified bit set. We use the kAccPreverfied bit on the
+ // class access flags to determine whether this has been done before.
+ void EnsurePreverifiedMethods(Handle<mirror::Class> c)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
mirror::Class* LookupClassFromTableLocked(const char* descriptor,
const mirror::ClassLoader* class_loader,
size_t hash)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 69c281e..883c6e2 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -1092,4 +1092,65 @@
EXPECT_EQ(c->GetClassSize(), mirror::ArtMethod::ClassSize());
}
+static void CheckMethod(mirror::ArtMethod* method, bool verified)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (!method->IsNative() && !method->IsAbstract()) {
+ EXPECT_EQ((method->GetAccessFlags() & kAccPreverified) != 0U, verified)
+ << PrettyMethod(method, true);
+ }
+}
+
+static void CheckPreverified(mirror::Class* c, bool preverified)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ EXPECT_EQ((c->GetAccessFlags() & kAccPreverified) != 0U, preverified)
+ << "Class " << PrettyClass(c) << " not as expected";
+ for (uint32_t i = 0; i < c->NumDirectMethods(); ++i) {
+ CheckMethod(c->GetDirectMethod(i), preverified);
+ }
+ for (uint32_t i = 0; i < c->NumVirtualMethods(); ++i) {
+ CheckMethod(c->GetVirtualMethod(i), preverified);
+ }
+}
+
+TEST_F(ClassLinkerTest, Preverified_InitializedBoot) {
+ ScopedObjectAccess soa(Thread::Current());
+
+ mirror::Class* JavaLangObject = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
+ ASSERT_TRUE(JavaLangObject != NULL);
+ EXPECT_TRUE(JavaLangObject->IsInitialized()) << "Not testing already initialized class from the "
+ "core";
+ CheckPreverified(JavaLangObject, true);
+}
+
+TEST_F(ClassLinkerTest, Preverified_UninitializedBoot) {
+ ScopedObjectAccess soa(Thread::Current());
+
+ StackHandleScope<1> hs(soa.Self());
+
+ Handle<mirror::Class> security_manager(hs.NewHandle(class_linker_->FindSystemClass(
+ soa.Self(), "Ljava/lang/SecurityManager;")));
+ EXPECT_FALSE(security_manager->IsInitialized()) << "Not testing uninitialized class from the "
+ "core";
+
+ CheckPreverified(security_manager.Get(), false);
+
+ class_linker_->EnsureInitialized(security_manager, true, true);
+ CheckPreverified(security_manager.Get(), true);
+}
+
+TEST_F(ClassLinkerTest, Preverified_App) {
+ ScopedObjectAccess soa(Thread::Current());
+
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::ClassLoader> class_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+ Handle<mirror::Class> statics(
+ hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
+
+ CheckPreverified(statics.Get(), false);
+
+ class_linker_->EnsureInitialized(statics, true, true);
+ CheckPreverified(statics.Get(), true);
+}
+
} // namespace art
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 80ce081..37cabea 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1152,7 +1152,8 @@
};
ClassListCreator clc(classes);
- Runtime::Current()->GetClassLinker()->VisitClasses(ClassListCreator::Visit, &clc);
+ Runtime::Current()->GetClassLinker()->VisitClassesWithoutClassesLock(ClassListCreator::Visit,
+ &clc);
}
JDWP::JdwpError Dbg::GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* pTypeTag,
@@ -2082,66 +2083,51 @@
return JDWP::ERR_NONE;
}
+static bool IsInDesiredThreadGroup(ScopedObjectAccessUnchecked& soa,
+ mirror::Object* desired_thread_group, mirror::Object* peer)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // Do we want threads from all thread groups?
+ if (desired_thread_group == nullptr) {
+ return true;
+ }
+ mirror::ArtField* thread_group_field = soa.DecodeField(WellKnownClasses::java_lang_Thread_group);
+ DCHECK(thread_group_field != nullptr);
+ mirror::Object* group = thread_group_field->GetObject(peer);
+ return (group == desired_thread_group);
+}
+
void Dbg::GetThreads(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& thread_ids) {
- class ThreadListVisitor {
- public:
- ThreadListVisitor(const ScopedObjectAccessUnchecked& soa, mirror::Object* desired_thread_group,
- std::vector<JDWP::ObjectId>& thread_ids)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
- : soa_(soa), desired_thread_group_(desired_thread_group), thread_ids_(thread_ids) {}
-
- static void Visit(Thread* t, void* arg) {
- reinterpret_cast<ThreadListVisitor*>(arg)->Visit(t);
- }
-
- // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
- // annotalysis.
- void Visit(Thread* t) NO_THREAD_SAFETY_ANALYSIS {
- if (t == Dbg::GetDebugThread()) {
- // Skip the JDWP thread. Some debuggers get bent out of shape when they can't suspend and
- // query all threads, so it's easier if we just don't tell them about this thread.
- return;
- }
- if (t->IsStillStarting()) {
- // This thread is being started (and has been registered in the thread list). However, it is
- // not completely started yet so we must ignore it.
- return;
- }
- mirror::Object* peer = t->GetPeer();
- if (IsInDesiredThreadGroup(peer)) {
- thread_ids_.push_back(gRegistry->Add(peer));
- }
- }
-
- private:
- bool IsInDesiredThreadGroup(mirror::Object* peer)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // peer might be NULL if the thread is still starting up.
- if (peer == NULL) {
- // We can't tell the debugger about this thread yet.
- // TODO: if we identified threads to the debugger by their Thread*
- // rather than their peer's mirror::Object*, we could fix this.
- // Doing so might help us report ZOMBIE threads too.
- return false;
- }
- // Do we want threads from all thread groups?
- if (desired_thread_group_ == NULL) {
- return true;
- }
- mirror::Object* group = soa_.DecodeField(WellKnownClasses::java_lang_Thread_group)->GetObject(peer);
- return (group == desired_thread_group_);
- }
-
- const ScopedObjectAccessUnchecked& soa_;
- mirror::Object* const desired_thread_group_;
- std::vector<JDWP::ObjectId>& thread_ids_;
- };
-
ScopedObjectAccessUnchecked soa(Thread::Current());
mirror::Object* thread_group = gRegistry->Get<mirror::Object*>(thread_group_id);
- ThreadListVisitor tlv(soa, thread_group, thread_ids);
- MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
- Runtime::Current()->GetThreadList()->ForEach(ThreadListVisitor::Visit, &tlv);
+ std::list<Thread*> all_threads_list;
+ {
+ MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
+ all_threads_list = Runtime::Current()->GetThreadList()->GetList();
+ }
+ for (Thread* t : all_threads_list) {
+ if (t == Dbg::GetDebugThread()) {
+ // Skip the JDWP thread. Some debuggers get bent out of shape when they can't suspend and
+ // query all threads, so it's easier if we just don't tell them about this thread.
+ continue;
+ }
+ if (t->IsStillStarting()) {
+ // This thread is being started (and has been registered in the thread list). However, it is
+ // not completely started yet so we must ignore it.
+ continue;
+ }
+ mirror::Object* peer = t->GetPeer();
+ if (peer == nullptr) {
+ // peer might be NULL if the thread is still starting up. We can't tell the debugger about
+ // this thread yet.
+ // TODO: if we identified threads to the debugger by their Thread*
+ // rather than their peer's mirror::Object*, we could fix this.
+ // Doing so might help us report ZOMBIE threads too.
+ continue;
+ }
+ if (IsInDesiredThreadGroup(soa, thread_group, peer)) {
+ thread_ids.push_back(gRegistry->Add(peer));
+ }
+ }
}
void Dbg::GetChildThreadGroups(JDWP::ObjectId thread_group_id, std::vector<JDWP::ObjectId>& child_thread_group_ids) {
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 38ea754..c783ee4 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -77,14 +77,13 @@
// Strip ":...", which is the location
const char* zip_entry_name = kClassesDex;
const char* file_part = filename;
- std::unique_ptr<const char> file_part_ptr;
+ std::string file_part_storage;
-
- if (IsMultiDexLocation(filename)) {
- std::pair<const char*, const char*> pair = SplitMultiDexLocation(filename);
- file_part_ptr.reset(pair.first);
- file_part = pair.first;
- zip_entry_name = pair.second;
+ if (DexFile::IsMultiDexLocation(filename)) {
+ file_part_storage = GetBaseLocation(filename);
+ file_part = file_part_storage.c_str();
+ zip_entry_name = filename + file_part_storage.size() + 1;
+ DCHECK_EQ(zip_entry_name[-1], kMultiDexSeparator);
}
ScopedFd fd(OpenAndReadMagic(file_part, &magic, error_msg));
@@ -303,7 +302,7 @@
while (i < 100) {
std::string name = StringPrintf("classes%zu.dex", i);
- std::string fake_location = location + ":" + name;
+ std::string fake_location = location + kMultiDexSeparator + name;
std::unique_ptr<const DexFile> next_dex_file(Open(zip_archive, name.c_str(), fake_location,
error_msg, &error_code));
if (next_dex_file.get() == nullptr) {
@@ -951,21 +950,6 @@
return strrchr(location, kMultiDexSeparator) != nullptr;
}
-std::pair<const char*, const char*> DexFile::SplitMultiDexLocation(
- const char* location) {
- const char* colon_ptr = strrchr(location, kMultiDexSeparator);
-
- // Check it's synthetic.
- CHECK_NE(colon_ptr, static_cast<const char*>(nullptr));
-
- size_t colon_index = colon_ptr - location;
- char* tmp = new char[colon_index + 1];
- strncpy(tmp, location, colon_index);
- tmp[colon_index] = 0;
-
- return std::make_pair(tmp, colon_ptr + 1);
-}
-
std::string DexFile::GetMultiDexClassesDexName(size_t number, const char* dex_location) {
if (number == 0) {
return dex_location;
@@ -976,26 +960,17 @@
std::string DexFile::GetDexCanonicalLocation(const char* dex_location) {
CHECK_NE(dex_location, static_cast<const char*>(nullptr));
- char* path = nullptr;
- if (!IsMultiDexLocation(dex_location)) {
- path = realpath(dex_location, nullptr);
+ std::string base_location = GetBaseLocation(dex_location);
+ const char* suffix = dex_location + base_location.size();
+ DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
+ UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
+ if (path != nullptr && path.get() != base_location) {
+ return std::string(path.get()) + suffix;
+ } else if (suffix[0] == 0) {
+ return base_location;
} else {
- std::pair<const char*, const char*> pair = DexFile::SplitMultiDexLocation(dex_location);
- const char* dex_real_location(realpath(pair.first, nullptr));
- delete pair.first;
- if (dex_real_location != nullptr) {
- int length = strlen(dex_real_location) + strlen(pair.second) + strlen(kMultiDexSeparatorString) + 1;
- char* multidex_canonical_location = reinterpret_cast<char*>(malloc(sizeof(char) * length));
- snprintf(multidex_canonical_location, length, "%s" kMultiDexSeparatorString "%s", dex_real_location, pair.second);
- free(const_cast<char*>(dex_real_location));
- path = multidex_canonical_location;
- }
+ return dex_location;
}
-
- // If realpath fails then we just copy the argument.
- std::string result(path == nullptr ? dex_location : path);
- free(path);
- return result;
}
std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 1da1f81..50d7e54 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -389,14 +389,21 @@
// For normal dex files, location and base location coincide. If a dex file is part of a multidex
// archive, the base location is the name of the originating jar/apk, stripped of any internal
// classes*.dex path.
- const std::string GetBaseLocation() const {
- if (IsMultiDexLocation(location_.c_str())) {
- std::pair<const char*, const char*> pair = SplitMultiDexLocation(location_.c_str());
- std::string res(pair.first);
- delete[] pair.first;
- return res;
+ static std::string GetBaseLocation(const char* location) {
+ const char* pos = strrchr(location, kMultiDexSeparator);
+ if (pos == nullptr) {
+ return location;
} else {
+ return std::string(location, pos - location);
+ }
+ }
+
+ std::string GetBaseLocation() const {
+ size_t pos = location_.rfind(kMultiDexSeparator);
+ if (pos == std::string::npos) {
return location_;
+ } else {
+ return location_.substr(0, pos);
}
}
@@ -918,13 +925,6 @@
// whether the string contains the separator character.
static bool IsMultiDexLocation(const char* location);
- // Splits a multidex location at the last separator character. The second component is a pointer
- // to the character after the separator. The first is a copy of the substring up to the separator.
- //
- // Note: It's the caller's job to free the first component of the returned pair.
- // Bug 15313523: gcc/libc++ don't allow a unique_ptr for the first component
- static std::pair<const char*, const char*> SplitMultiDexLocation(const char* location);
-
// The base address of the memory mapping.
const byte* const begin_;
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index fa13290..d0c5603 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -355,9 +355,10 @@
TEST_F(DexFileTest, GetDexCanonicalLocation) {
ScratchFile file;
- std::string dex_location = file.GetFilename();
+ UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
+ std::string dex_location(dex_location_real.get());
- ASSERT_EQ(file.GetFilename(), DexFile::GetDexCanonicalLocation(dex_location.c_str()));
+ ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str()));
std::string multidex_location = DexFile::GetMultiDexClassesDexName(1, dex_location.c_str());
ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str()));
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 8aaa471..6ede6de 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -33,8 +33,10 @@
namespace art {
-static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx, mirror::ArtMethod* referrer,
- int32_t component_count, Thread* self,
+static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx,
+ mirror::ArtMethod* referrer,
+ int32_t component_count,
+ Thread* self,
bool access_check)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (UNLIKELY(component_count < 0)) {
@@ -56,9 +58,10 @@
} else {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
DCHECK(throw_location.GetMethod() == referrer);
- self->ThrowNewExceptionF(throw_location, "Ljava/lang/InternalError;",
- "Found type %s; filled-new-array not implemented for anything but 'int'",
- PrettyDescriptor(klass).c_str());
+ self->ThrowNewExceptionF(
+ throw_location, "Ljava/lang/InternalError;",
+ "Found type %s; filled-new-array not implemented for anything but 'int'",
+ PrettyDescriptor(klass).c_str());
}
return nullptr; // Failure
}
@@ -92,8 +95,10 @@
}
// Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx, mirror::ArtMethod* referrer,
- int32_t component_count, Thread* self,
+mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
+ mirror::ArtMethod* referrer,
+ int32_t component_count,
+ Thread* self,
bool access_check,
gc::AllocatorType /* allocator_type */) {
mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, referrer, component_count, self,
@@ -144,24 +149,19 @@
// TODO: Use String::FromModifiedUTF...?
ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg.c_str()));
if (s.get() != nullptr) {
- jfieldID detail_message_id = env->GetFieldID(WellKnownClasses::java_lang_Throwable,
- "detailMessage", "Ljava/lang/String;");
- env->SetObjectField(exc.get(), detail_message_id, s.get());
+ env->SetObjectField(exc.get(), WellKnownClasses::java_lang_Throwable_detailMessage, s.get());
// cause.
- jfieldID cause_id = env->GetFieldID(WellKnownClasses::java_lang_Throwable,
- "cause", "Ljava/lang/Throwable;");
- env->SetObjectField(exc.get(), cause_id, exc.get());
+ env->SetObjectField(exc.get(), WellKnownClasses::java_lang_Throwable_cause, exc.get());
// suppressedExceptions.
- jfieldID emptylist_id = env->GetStaticFieldID(WellKnownClasses::java_util_Collections,
- "EMPTY_LIST", "Ljava/util/List;");
ScopedLocalRef<jobject> emptylist(env, env->GetStaticObjectField(
- WellKnownClasses::java_util_Collections, emptylist_id));
+ WellKnownClasses::java_util_Collections,
+ WellKnownClasses::java_util_Collections_EMPTY_LIST));
CHECK(emptylist.get() != nullptr);
- jfieldID suppressed_id = env->GetFieldID(WellKnownClasses::java_lang_Throwable,
- "suppressedExceptions", "Ljava/util/List;");
- env->SetObjectField(exc.get(), suppressed_id, emptylist.get());
+ env->SetObjectField(exc.get(),
+ WellKnownClasses::java_lang_Throwable_suppressedExceptions,
+ emptylist.get());
// stackState is set as result of fillInStackTrace. fillInStackTrace calls
// nativeFillInStackTrace.
@@ -171,19 +171,17 @@
stack_state_val.reset(soa.Self()->CreateInternalStackTrace<false>(soa));
}
if (stack_state_val.get() != nullptr) {
- jfieldID stackstateID = env->GetFieldID(WellKnownClasses::java_lang_Throwable,
- "stackState", "Ljava/lang/Object;");
- env->SetObjectField(exc.get(), stackstateID, stack_state_val.get());
+ env->SetObjectField(exc.get(),
+ WellKnownClasses::java_lang_Throwable_stackState,
+ stack_state_val.get());
// stackTrace.
- jfieldID stack_trace_elem_id = env->GetStaticFieldID(
- WellKnownClasses::libcore_util_EmptyArray, "STACK_TRACE_ELEMENT",
- "[Ljava/lang/StackTraceElement;");
ScopedLocalRef<jobject> stack_trace_elem(env, env->GetStaticObjectField(
- WellKnownClasses::libcore_util_EmptyArray, stack_trace_elem_id));
- jfieldID stacktrace_id = env->GetFieldID(
- WellKnownClasses::java_lang_Throwable, "stackTrace", "[Ljava/lang/StackTraceElement;");
- env->SetObjectField(exc.get(), stacktrace_id, stack_trace_elem.get());
+ WellKnownClasses::libcore_util_EmptyArray,
+ WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT));
+ env->SetObjectField(exc.get(),
+ WellKnownClasses::java_lang_Throwable_stackTrace,
+ stack_trace_elem.get());
// Throw the exception.
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
@@ -327,7 +325,8 @@
}
}
CHECK_NE(throws_index, -1);
- mirror::ObjectArray<mirror::Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index);
+ mirror::ObjectArray<mirror::Class>* declared_exceptions =
+ proxy_class->GetThrows()->Get(throws_index);
mirror::Class* exception_class = exception->GetClass();
bool declares_exception = false;
for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
diff --git a/runtime/jdwp/object_registry.h b/runtime/jdwp/object_registry.h
index f0314a3..bc3530b 100644
--- a/runtime/jdwp/object_registry.h
+++ b/runtime/jdwp/object_registry.h
@@ -62,7 +62,8 @@
JDWP::ObjectId Add(mirror::Object* o)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
- JDWP::RefTypeId AddRefType(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ JDWP::RefTypeId AddRefType(mirror::Class* c)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
template<typename T> T Get(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (id == 0) {
@@ -77,10 +78,14 @@
void Clear() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void DisableCollection(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void EnableCollection(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void DisableCollection(JDWP::ObjectId id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
- bool IsCollected(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void EnableCollection(JDWP::ObjectId id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
+ bool IsCollected(JDWP::ObjectId id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
void DisposeObject(JDWP::ObjectId id, uint32_t reference_count)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -94,12 +99,24 @@
private:
JDWP::ObjectId InternalAdd(mirror::Object* o)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::thread_list_lock_);
- mirror::Object* InternalGet(JDWP::ObjectId id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void Demote(ObjectRegistryEntry& entry) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, lock_);
- void Promote(ObjectRegistryEntry& entry) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, lock_);
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ LOCKS_EXCLUDED(lock_, Locks::thread_list_lock_);
+
+ mirror::Object* InternalGet(JDWP::ObjectId id)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ LOCKS_EXCLUDED(lock_);
+
+ void Demote(ObjectRegistryEntry& entry)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
+ void Promote(ObjectRegistryEntry& entry)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ EXCLUSIVE_LOCKS_REQUIRED(lock_);
+
bool Contains(mirror::Object* o, ObjectRegistryEntry** out_entry)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
bool ContainsLocked(Thread* self, mirror::Object* o, int32_t identity_hash_code,
ObjectRegistryEntry** out_entry)
EXCLUSIVE_LOCKS_REQUIRED(lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index b0ff7ea..8e44471 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -724,6 +724,15 @@
klass->SetDexTypeIndex(DexFile::kDexNoIndex16); // Default to no valid type index.
}
+inline void Class::SetAccessFlags(uint32_t new_access_flags) {
+ // Called inside a transaction when setting pre-verified flag during boot image compilation.
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+ } else {
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 13d0c80..43ac98d 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -217,10 +217,7 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- // Not called within a transaction.
- SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags);
- }
+ void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Returns true if the class is an interface.
bool IsInterface() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index e599b03..2814ed8 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -45,7 +45,7 @@
static const uint32_t kAccConstructor = 0x00010000; // method (dex only) <init> and <clinit>
static const uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
static const uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)
-static const uint32_t kAccPreverified = 0x00080000; // method (dex only)
+static const uint32_t kAccPreverified = 0x00080000; // class (runtime), method (dex only)
static const uint32_t kAccFastNative = 0x0080000; // method (dex only)
static const uint32_t kAccPortableCompiled = 0x0100000; // method (dex only)
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 2ebdebd..d5142a7 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -140,7 +140,7 @@
}
OatFile::~OatFile() {
- STLDeleteValues(&oat_dex_files_);
+ STLDeleteElements(&oat_dex_files_storage_);
if (dlopen_handle_ != NULL) {
dlclose(dlopen_handle_);
}
@@ -238,7 +238,9 @@
return false;
}
- for (size_t i = 0; i < GetOatHeader().GetDexFileCount(); i++) {
+ uint32_t dex_file_count = GetOatHeader().GetDexFileCount();
+ oat_dex_files_storage_.reserve(dex_file_count);
+ for (size_t i = 0; i < dex_file_count; i++) {
uint32_t dex_file_location_size = *reinterpret_cast<const uint32_t*>(oat);
if (UNLIKELY(dex_file_location_size == 0U)) {
*error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd with empty location name",
@@ -315,14 +317,24 @@
return false;
}
- // Create the OatDexFile and add it to the owning map indexed by the dex file location.
+ std::string canonical_location = DexFile::GetDexCanonicalLocation(dex_file_location.c_str());
+
+ // Create the OatDexFile and add it to the owning container.
OatDexFile* oat_dex_file = new OatDexFile(this,
dex_file_location,
+ canonical_location,
dex_file_checksum,
dex_file_pointer,
methods_offsets_pointer);
+ oat_dex_files_storage_.push_back(oat_dex_file);
+
+ // Add the location and canonical location (if different) to the oat_dex_files_ table.
StringPiece key(oat_dex_file->GetDexFileLocation());
oat_dex_files_.Put(key, oat_dex_file);
+ if (canonical_location != dex_file_location) {
+ StringPiece canonical_key(oat_dex_file->GetCanonicalDexFileLocation());
+ oat_dex_files_.Put(canonical_key, oat_dex_file);
+ }
}
return true;
}
@@ -370,20 +382,13 @@
oat_dex_file = secondary_lb->second; // May be nullptr.
} else {
// We haven't seen this dex_location before, we must check the canonical location.
- if (UNLIKELY(oat_dex_files_by_canonical_location_.empty())) {
- // Lazily fill in the oat_dex_files_by_canonical_location_.
- for (const auto& entry : oat_dex_files_) {
- const std::string& dex_location = entry.second->GetDexFileLocation();
- string_cache_.emplace_back(DexFile::GetDexCanonicalLocation(dex_location.c_str()));
- StringPiece canonical_location_key(string_cache_.back());
- oat_dex_files_by_canonical_location_.Put(canonical_location_key, entry.second);
- }
- }
std::string dex_canonical_location = DexFile::GetDexCanonicalLocation(dex_location);
- StringPiece canonical_key(dex_canonical_location);
- auto canonical_it = oat_dex_files_by_canonical_location_.find(canonical_key);
- if (canonical_it != oat_dex_files_by_canonical_location_.end()) {
- oat_dex_file = canonical_it->second;
+ if (dex_canonical_location != dex_location) {
+ StringPiece canonical_key(dex_canonical_location);
+ auto canonical_it = oat_dex_files_.find(canonical_key);
+ if (canonical_it != oat_dex_files_.end()) {
+ oat_dex_file = canonical_it->second;
+ } // else keep nullptr.
} // else keep nullptr.
// Copy the key to the string_cache_ and store the result in secondary map.
@@ -408,11 +413,11 @@
<< " ( canonical path " << dex_canonical_location << ")"
<< " with checksum " << checksum << " in OatFile " << GetLocation();
if (kIsDebugBuild) {
- for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it) {
+ for (const OatDexFile* odf : oat_dex_files_storage_) {
LOG(WARNING) << "OatFile " << GetLocation()
- << " contains OatDexFile " << it->second->GetDexFileLocation()
- << " (canonical path " << it->first << ")"
- << " with checksum 0x" << std::hex << it->second->GetDexFileLocationChecksum();
+ << " contains OatDexFile " << odf->GetDexFileLocation()
+ << " (canonical path " << odf->GetCanonicalDexFileLocation() << ")"
+ << " with checksum 0x" << std::hex << odf->GetDexFileLocationChecksum();
}
}
}
@@ -420,21 +425,15 @@
return NULL;
}
-std::vector<const OatFile::OatDexFile*> OatFile::GetOatDexFiles() const {
- std::vector<const OatFile::OatDexFile*> result;
- for (Table::const_iterator it = oat_dex_files_.begin(); it != oat_dex_files_.end(); ++it) {
- result.push_back(it->second);
- }
- return result;
-}
-
OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
const std::string& dex_file_location,
+ const std::string& canonical_dex_file_location,
uint32_t dex_file_location_checksum,
const byte* dex_file_pointer,
const uint32_t* oat_class_offsets_pointer)
: oat_file_(oat_file),
dex_file_location_(dex_file_location),
+ canonical_dex_file_location_(canonical_dex_file_location),
dex_file_location_checksum_(dex_file_location_checksum),
dex_file_pointer_(dex_file_pointer),
oat_class_offsets_pointer_(oat_class_offsets_pointer) {}
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 0bf2b7b..d8b48a9 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -204,6 +204,10 @@
// Opens the DexFile referred to by this OatDexFile from within the containing OatFile.
const DexFile* OpenDexFile(std::string* error_msg) const;
+ const OatFile* GetOatFile() const {
+ return oat_file_;
+ }
+
// Returns the size of the DexFile refered to by this OatDexFile.
size_t FileSize() const;
@@ -212,6 +216,11 @@
return dex_file_location_;
}
+ // Returns the canonical location of DexFile that was the source of this OatDexFile.
+ const std::string& GetCanonicalDexFileLocation() const {
+ return canonical_dex_file_location_;
+ }
+
// Returns checksum of original DexFile that was the source of this OatDexFile;
uint32_t GetDexFileLocationChecksum() const {
return dex_file_location_checksum_;
@@ -225,12 +234,14 @@
private:
OatDexFile(const OatFile* oat_file,
const std::string& dex_file_location,
+ const std::string& canonical_dex_file_location,
uint32_t dex_file_checksum,
const byte* dex_file_pointer,
const uint32_t* oat_class_offsets_pointer);
const OatFile* const oat_file_;
const std::string dex_file_location_;
+ const std::string canonical_dex_file_location_;
const uint32_t dex_file_location_checksum_;
const byte* const dex_file_pointer_;
const uint32_t* const oat_class_offsets_pointer_;
@@ -244,7 +255,9 @@
bool exception_if_not_found = true) const
LOCKS_EXCLUDED(secondary_lookup_lock_);
- std::vector<const OatDexFile*> GetOatDexFiles() const;
+ const std::vector<const OatDexFile*>& GetOatDexFiles() const {
+ return oat_dex_files_storage_;
+ }
size_t Size() const {
return End() - Begin();
@@ -297,6 +310,9 @@
// dlopen handle during runtime.
void* dlopen_handle_;
+ // Owning storage for the OatDexFile objects.
+ std::vector<const OatDexFile*> oat_dex_files_storage_;
+
// NOTE: We use a StringPiece as the key type to avoid a memory allocation on every
// lookup with a const char* key. The StringPiece doesn't own its backing storage,
// therefore we're using the OatDexFile::dex_file_location_ as the backing storage
@@ -304,11 +320,11 @@
// of keys in secondary_oat_dex_files_ and oat_dex_files_by_canonical_location_.
typedef AllocationTrackingSafeMap<StringPiece, const OatDexFile*, kAllocatorTagOatFile> Table;
- // Map each plain dex file location retrieved from the oat file to its OatDexFile.
- // This map doesn't change after it's constructed in Setup() and therefore doesn't
- // need any locking and provides the cheapest dex file lookup for GetOatDexFile()
- // for a very frequent use case. Never contains a nullptr value.
- Table oat_dex_files_; // Owns the OatDexFile* values.
+ // Map each location and canonical location (if different) retrieved from the
+ // oat file to its OatDexFile. This map doesn't change after it's constructed in Setup()
+ // and therefore doesn't need any locking and provides the cheapest dex file lookup
+ // for GetOatDexFile() for a very frequent use case. Never contains a nullptr value.
+ Table oat_dex_files_;
// Lock guarding all members needed for secondary lookup in GetOatDexFile().
mutable Mutex secondary_lookup_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -319,10 +335,6 @@
// location and use oat_dex_files_by_canonical_location_.
mutable Table secondary_oat_dex_files_ GUARDED_BY(secondary_lookup_lock_);
- // Map the canonical location to an OatDexFile. This lazily constructed map is used
- // when we're doing the secondary lookup for a given location for the first time.
- mutable Table oat_dex_files_by_canonical_location_ GUARDED_BY(secondary_lookup_lock_);
-
// Cache of strings. Contains the backing storage for keys in the secondary_oat_dex_files_
// and the lazily initialized oat_dex_files_by_canonical_location_.
// NOTE: We're keeping references to contained strings in form of StringPiece and adding
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 4f28dda..4e2bfa0 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -601,9 +601,7 @@
return false;
}
- std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file->GetOatDexFiles();
- for (size_t i = 0; i < oat_dex_files.size(); i++) {
- const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
+ for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
if (oat_dex_file == nullptr) {
*failures += 1;
continue;
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index c13776d..11e06fe 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -28,6 +28,7 @@
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
#include "gc/heap.h"
+#include "instruction_set.h"
#include "os.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
@@ -42,20 +43,21 @@
#if defined(__linux__)
// Show the original command line, and the current command line too if it's changed.
// On Android, /proc/self/cmdline will have been rewritten to something like "system_server".
+ // Note: The string "Cmd line:" is chosen to match the format used by debuggerd.
std::string current_cmd_line;
if (ReadFileToString("/proc/self/cmdline", ¤t_cmd_line)) {
- current_cmd_line.resize(current_cmd_line.size() - 1); // Lose the trailing '\0'.
+ current_cmd_line.resize(current_cmd_line.find_last_not_of('\0') + 1); // trim trailing '\0's
std::replace(current_cmd_line.begin(), current_cmd_line.end(), '\0', ' ');
- os << "Cmdline: " << current_cmd_line;
+ os << "Cmd line: " << current_cmd_line << "\n";
const char* stashed_cmd_line = GetCmdLine();
- if (stashed_cmd_line != NULL && current_cmd_line != stashed_cmd_line) {
- os << "Original command line: " << stashed_cmd_line;
+ if (stashed_cmd_line != NULL && current_cmd_line != stashed_cmd_line
+ && strcmp(stashed_cmd_line, "<unset>") != 0) {
+ os << "Original command line: " << stashed_cmd_line << "\n";
}
}
- os << "\n";
#else
- os << "Cmdline: " << GetCmdLine() << "\n";
+ os << "Cmd line: " << GetCmdLine() << "\n";
#endif
}
@@ -133,6 +135,9 @@
DumpCmdLine(os);
+ // Note: The string "ABI:" is chosen to match the format used by debuggerd.
+ os << "ABI: " << GetInstructionSetString(runtime->GetInstructionSet()) << "\n";
+
os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n";
runtime->DumpForSigQuit(os);
diff --git a/runtime/utils.h b/runtime/utils.h
index a34a01d..942b6ad 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -20,6 +20,7 @@
#include <pthread.h>
#include <limits>
+#include <memory>
#include <string>
#include <vector>
@@ -499,6 +500,18 @@
}
};
+// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
+struct FreeDelete {
+ // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
+ void operator()(const void* ptr) const {
+ free(const_cast<void*>(ptr));
+ }
+};
+
+// Alias for std::unique_ptr<> that uses the C function free() to delete objects.
+template <typename T>
+using UniqueCPtr = std::unique_ptr<T, FreeDelete>;
+
} // namespace art
#endif // ART_RUNTIME_UTILS_H_
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 7068a4d..6b67dfa 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -97,11 +97,18 @@
jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup;
jfieldID WellKnownClasses::java_lang_ThreadGroup_name;
jfieldID WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup;
+jfieldID WellKnownClasses::java_lang_Throwable_cause;
+jfieldID WellKnownClasses::java_lang_Throwable_detailMessage;
+jfieldID WellKnownClasses::java_lang_Throwable_stackTrace;
+jfieldID WellKnownClasses::java_lang_Throwable_stackState;
+jfieldID WellKnownClasses::java_lang_Throwable_suppressedExceptions;
jfieldID WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod;
jfieldID WellKnownClasses::java_lang_reflect_Field_artField;
jfieldID WellKnownClasses::java_lang_reflect_Proxy_h;
jfieldID WellKnownClasses::java_nio_DirectByteBuffer_capacity;
jfieldID WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress;
+jfieldID WellKnownClasses::java_util_Collections_EMPTY_LIST;
+jfieldID WellKnownClasses::libcore_util_EmptyArray_STACK_TRACE_ELEMENT;
jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_data;
jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_length;
jfieldID WellKnownClasses::org_apache_harmony_dalvik_ddmc_Chunk_offset;
@@ -205,11 +212,18 @@
java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;");
java_lang_ThreadGroup_name = CacheField(env, java_lang_ThreadGroup, false, "name", "Ljava/lang/String;");
java_lang_ThreadGroup_systemThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "systemThreadGroup", "Ljava/lang/ThreadGroup;");
+ java_lang_Throwable_cause = CacheField(env, java_lang_Throwable, false, "cause", "Ljava/lang/Throwable;");
+ java_lang_Throwable_detailMessage = CacheField(env, java_lang_Throwable, false, "detailMessage", "Ljava/lang/String;");
+ java_lang_Throwable_stackTrace = CacheField(env, java_lang_Throwable, false, "stackTrace", "[Ljava/lang/StackTraceElement;");
+ java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "stackState", "Ljava/lang/Object;");
+ java_lang_Throwable_suppressedExceptions = CacheField(env, java_lang_Throwable, false, "suppressedExceptions", "Ljava/util/List;");
java_lang_reflect_AbstractMethod_artMethod = CacheField(env, java_lang_reflect_AbstractMethod, false, "artMethod", "Ljava/lang/reflect/ArtMethod;");
java_lang_reflect_Field_artField = CacheField(env, java_lang_reflect_Field, false, "artField", "Ljava/lang/reflect/ArtField;");
java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, false, "h", "Ljava/lang/reflect/InvocationHandler;");
java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I");
java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "effectiveDirectAddress", "J");
+ java_util_Collections_EMPTY_LIST = CacheField(env, java_util_Collections, true, "EMPTY_LIST", "Ljava/util/List;");
+ libcore_util_EmptyArray_STACK_TRACE_ELEMENT = CacheField(env, libcore_util_EmptyArray, true, "STACK_TRACE_ELEMENT", "[Ljava/lang/StackTraceElement;");
org_apache_harmony_dalvik_ddmc_Chunk_data = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "data", "[B");
org_apache_harmony_dalvik_ddmc_Chunk_length = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "length", "I");
org_apache_harmony_dalvik_ddmc_Chunk_offset = CacheField(env, org_apache_harmony_dalvik_ddmc_Chunk, false, "offset", "I");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index b10106c..3780733 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -114,8 +114,15 @@
static jfieldID java_lang_ThreadGroup_mainThreadGroup;
static jfieldID java_lang_ThreadGroup_name;
static jfieldID java_lang_ThreadGroup_systemThreadGroup;
+ static jfieldID java_lang_Throwable_cause;
+ static jfieldID java_lang_Throwable_detailMessage;
+ static jfieldID java_lang_Throwable_stackTrace;
+ static jfieldID java_lang_Throwable_stackState;
+ static jfieldID java_lang_Throwable_suppressedExceptions;
static jfieldID java_nio_DirectByteBuffer_capacity;
static jfieldID java_nio_DirectByteBuffer_effectiveDirectAddress;
+ static jfieldID java_util_Collections_EMPTY_LIST;
+ static jfieldID libcore_util_EmptyArray_STACK_TRACE_ELEMENT;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_data;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_length;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_offset;
diff --git a/test/116-nodex2oat/nodex2oat.cc b/test/116-nodex2oat/nodex2oat.cc
index 4326db0..04cac45 100644
--- a/test/116-nodex2oat/nodex2oat.cc
+++ b/test/116-nodex2oat/nodex2oat.cc
@@ -28,9 +28,9 @@
ScopedObjectAccess soa(Thread::Current());
mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
const DexFile& dex_file = klass->GetDexFile();
- const OatFile* oat_file =
- Runtime::Current()->GetClassLinker()->FindOpenedOatFileForDexFile(dex_file);
- return oat_file != nullptr;
+ const OatFile::OatDexFile* oat_dex_file =
+ Runtime::Current()->GetClassLinker()->FindOpenedOatDexFileForDexFile(dex_file);
+ return oat_dex_file != nullptr;
}
};
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index ced7f6e..5994653 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -28,9 +28,9 @@
ScopedObjectAccess soa(Thread::Current());
mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
const DexFile& dex_file = klass->GetDexFile();
- const OatFile* oat_file =
- Runtime::Current()->GetClassLinker()->FindOpenedOatFileForDexFile(dex_file);
- return oat_file != nullptr && oat_file->IsExecutable();
+ const OatFile::OatDexFile* oat_dex_file =
+ Runtime::Current()->GetClassLinker()->FindOpenedOatDexFileForDexFile(dex_file);
+ return oat_dex_file != nullptr && oat_dex_file->GetOatFile()->IsExecutable();
}
};
diff --git a/test/118-noimage-dex2oat/noimage-dex2oat.cc b/test/118-noimage-dex2oat/noimage-dex2oat.cc
index 4a3d33c..7340d9e 100644
--- a/test/118-noimage-dex2oat/noimage-dex2oat.cc
+++ b/test/118-noimage-dex2oat/noimage-dex2oat.cc
@@ -28,9 +28,9 @@
ScopedObjectAccess soa(Thread::Current());
mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
const DexFile& dex_file = klass->GetDexFile();
- const OatFile* oat_file =
- Runtime::Current()->GetClassLinker()->FindOpenedOatFileForDexFile(dex_file);
- return oat_file != nullptr;
+ const OatFile::OatDexFile* oat_dex_file =
+ Runtime::Current()->GetClassLinker()->FindOpenedOatDexFileForDexFile(dex_file);
+ return oat_dex_file != nullptr;
}
};