summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r--runtime/class_linker.cc1158
1 files changed, 831 insertions, 327 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 511d468412..d29a6b7577 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -61,6 +61,7 @@
#include "dex/dex_file-inl.h"
#include "dex/dex_file_exception_helpers.h"
#include "dex/dex_file_loader.h"
+#include "dex/signature-inl.h"
#include "dex/utf.h"
#include "entrypoints/entrypoint_utils.h"
#include "entrypoints/runtime_asm_entrypoints.h"
@@ -79,7 +80,7 @@
#include "image-inl.h"
#include "imt_conflict_table.h"
#include "imtable-inl.h"
-#include "intern_table.h"
+#include "intern_table-inl.h"
#include "interpreter/interpreter.h"
#include "jit/debugger_interface.h"
#include "jit/jit.h"
@@ -87,7 +88,10 @@
#include "jni/java_vm_ext.h"
#include "jni/jni_internal.h"
#include "linear_alloc.h"
+#include "mirror/array-alloc-inl.h"
+#include "mirror/array-inl.h"
#include "mirror/call_site.h"
+#include "mirror/class-alloc-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class.h"
#include "mirror/class_ext.h"
@@ -103,7 +107,10 @@
#include "mirror/method_type.h"
#include "mirror/object-inl.h"
#include "mirror/object-refvisitor-inl.h"
+#include "mirror/object_array-alloc-inl.h"
#include "mirror/object_array-inl.h"
+#include "mirror/object_reference.h"
+#include "mirror/object_reference-inl.h"
#include "mirror/proxy.h"
#include "mirror/reference-inl.h"
#include "mirror/stack_trace_element.h"
@@ -206,7 +213,25 @@ static void HandleEarlierVerifyError(Thread* self,
self->AssertPendingException();
}
-void ClassLinker::ThrowEarlierClassFailure(ObjPtr<mirror::Class> c, bool wrap_in_no_class_def) {
+// Ensures that methods have the kAccSkipAccessChecks bit set. We use the
+// kAccVerificationAttempted bit on the class access flags to determine whether this has been done
+// before.
+template <bool kNeedsVerified = false>
+static void EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass, PointerSize pointer_size)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (kNeedsVerified) {
+ // To not fail access-flags access checks, push a minimal state.
+ mirror::Class::SetStatus(klass, ClassStatus::kVerified, Thread::Current());
+ }
+ if (!klass->WasVerificationAttempted()) {
+ klass->SetSkipAccessChecksFlagOnAllMethods(pointer_size);
+ klass->SetVerificationAttempted();
+ }
+}
+
+void ClassLinker::ThrowEarlierClassFailure(ObjPtr<mirror::Class> c,
+ bool wrap_in_no_class_def,
+ bool log) {
// The class failed to initialize on a previous attempt, so we want to throw
// a NoClassDefFoundError (v2 2.17.5). The exception to this rule is if we
// failed in verification, in which case v2 5.4.1 says we need to re-throw
@@ -222,8 +247,10 @@ void ClassLinker::ThrowEarlierClassFailure(ObjPtr<mirror::Class> c, bool wrap_in
extra = verify_error->AsThrowable()->Dump();
}
}
- LOG(INFO) << "Rejecting re-init on previously-failed class " << c->PrettyClass()
- << ": " << extra;
+ if (log) {
+ LOG(INFO) << "Rejecting re-init on previously-failed class " << c->PrettyClass()
+ << ": " << extra;
+ }
}
CHECK(c->IsErroneous()) << c->PrettyClass() << " " << c->GetStatus();
@@ -307,7 +334,7 @@ struct FieldGapsComparator {
return lhs.size < rhs.size || (lhs.size == rhs.size && lhs.start_offset > rhs.start_offset);
}
};
-typedef std::priority_queue<FieldGap, std::vector<FieldGap>, FieldGapsComparator> FieldGaps;
+using FieldGaps = std::priority_queue<FieldGap, std::vector<FieldGap>, FieldGapsComparator>;
// Adds largest aligned gaps to queue of gaps.
static void AddFieldGap(uint32_t gap_start, uint32_t gap_end, FieldGaps* gaps) {
@@ -431,6 +458,8 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
heap->IncrementDisableMovingGC(self);
StackHandleScope<64> hs(self); // 64 is picked arbitrarily.
auto class_class_size = mirror::Class::ClassClassSize(image_pointer_size_);
+ // Allocate the object as non-movable so that there are no cases where Object::IsClass returns
+ // the incorrect result when comparing to-space vs from-space.
Handle<mirror::Class> java_lang_Class(hs.NewHandle(ObjPtr<mirror::Class>::DownCast(MakeObjPtr(
heap->AllocNonMovableObject<true>(self, nullptr, class_class_size, VoidFunctor())))));
CHECK(java_lang_Class != nullptr);
@@ -492,7 +521,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
// Space (LOS) -- see the comment about the dirty card scanning logic in
// art::gc::collector::ConcurrentCopying::MarkingPhase.
Handle<mirror::Class> java_lang_String(hs.NewHandle(
- AllocClass</* kMovable */ false>(
+ AllocClass</* kMovable= */ false>(
self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_))));
java_lang_String->SetStringClass();
mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self);
@@ -790,6 +819,8 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b
FindSystemClass(self, "Ljava/lang/StackTraceElement;"));
SetClassRoot(ClassRoot::kJavaLangStackTraceElementArrayClass,
FindSystemClass(self, "[Ljava/lang/StackTraceElement;"));
+ SetClassRoot(ClassRoot::kJavaLangClassLoaderArrayClass,
+ FindSystemClass(self, "[Ljava/lang/ClassLoader;"));
// Create conflict tables that depend on the class linker.
runtime->FixupConflictTables();
@@ -957,9 +988,6 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) {
runtime->GetOatFileManager().RegisterImageOatFiles(spaces);
DCHECK(!oat_files.empty());
const OatHeader& default_oat_header = oat_files[0]->GetOatHeader();
- const char* image_file_location = oat_files[0]->GetOatHeader().
- GetStoreValueByKey(OatHeader::kImageLocationKey);
- CHECK(image_file_location == nullptr || *image_file_location == 0);
quick_resolution_trampoline_ = default_oat_header.GetQuickResolutionTrampoline();
quick_imt_conflict_trampoline_ = default_oat_header.GetQuickImtConflictTrampoline();
quick_generic_jni_trampoline_ = default_oat_header.GetQuickGenericJniTrampoline();
@@ -1030,13 +1058,15 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) {
runtime->SetSentinel(heap->AllocNonMovableObject<true>(
self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor()));
- for (gc::space::ImageSpace* image_space : spaces) {
+ const std::vector<std::string>& boot_class_path_locations = runtime->GetBootClassPathLocations();
+ CHECK_LE(spaces.size(), boot_class_path_locations.size());
+ for (size_t i = 0u, size = spaces.size(); i != size; ++i) {
// Boot class loader, use a null handle.
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!AddImageSpace(image_space,
+ if (!AddImageSpace(spaces[i],
ScopedNullHandle<mirror::ClassLoader>(),
- /*dex_elements*/nullptr,
- /*dex_location*/nullptr,
+ /*dex_elements=*/ nullptr,
+ /*dex_location=*/ boot_class_path_locations[i].c_str(),
/*out*/&dex_files,
error_msg)) {
return false;
@@ -1055,6 +1085,15 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) {
return true;
}
+void ClassLinker::AddExtraBootDexFiles(
+ Thread* self,
+ std::vector<std::unique_ptr<const DexFile>>&& additional_dex_files) {
+ for (std::unique_ptr<const DexFile>& dex_file : additional_dex_files) {
+ AppendToBootClassPath(self, *dex_file);
+ boot_dex_files_.push_back(std::move(dex_file));
+ }
+}
+
bool ClassLinker::IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
ObjPtr<mirror::ClassLoader> class_loader) {
return class_loader == nullptr ||
@@ -1087,48 +1126,165 @@ static bool GetDexPathListElementName(ObjPtr<mirror::Object> element,
return false;
}
-static bool FlattenPathClassLoader(ObjPtr<mirror::ClassLoader> class_loader,
- std::list<ObjPtr<mirror::String>>* out_dex_file_names,
- std::string* error_msg)
+static bool GetDexFileNames(ScopedObjectAccessUnchecked& soa,
+ ObjPtr<mirror::ClassLoader> class_loader,
+ /*out*/std::list<ObjPtr<mirror::String>>* dex_files,
+ /*out*/std::string* error_msg)
REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(out_dex_file_names != nullptr);
- DCHECK(error_msg != nullptr);
- ScopedObjectAccessUnchecked soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> handle(hs.NewHandle(class_loader));
- while (!ClassLinker::IsBootClassLoader(soa, class_loader)) {
- if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
- class_loader->GetClass()) {
- *error_msg = StringPrintf("Unknown class loader type %s",
- class_loader->PrettyTypeOf().c_str());
- // Unsupported class loader.
+ // Get element names. Sets error to true on failure.
+ auto add_element_names = [&](ObjPtr<mirror::Object> element, bool* error)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (element == nullptr) {
+ *error_msg = "Null dex element";
+ *error = true; // Null element is a critical error.
+ return false; // Had an error, stop the visit.
+ }
+ ObjPtr<mirror::String> name;
+ if (!GetDexPathListElementName(element, &name)) {
+ *error_msg = "Invalid dex path list element";
+ *error = true; // Invalid element, make it a critical error.
+ return false; // Stop the visit.
+ }
+ if (name != nullptr) {
+ dex_files->push_front(name);
+ }
+ return true; // Continue with the next Element.
+ };
+ bool error = VisitClassLoaderDexElements(soa,
+ handle,
+ add_element_names,
+ /*defaultReturn=*/ false);
+ return !error;
+}
+
+static bool CompareClassLoaderTypes(ScopedObjectAccessUnchecked& soa,
+ ObjPtr<mirror::ClassLoader> image_class_loader,
+ ObjPtr<mirror::ClassLoader> class_loader,
+ std::string* error_msg)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (ClassLinker::IsBootClassLoader(soa, class_loader)) {
+ if (!ClassLinker::IsBootClassLoader(soa, image_class_loader)) {
+ *error_msg = "Hierarchies don't match";
return false;
}
- // Get element names. Sets error to true on failure.
- auto add_element_names = [&](ObjPtr<mirror::Object> element, bool* error)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (element == nullptr) {
- *error_msg = "Null dex element";
- *error = true; // Null element is a critical error.
- return false; // Had an error, stop the visit.
- }
- ObjPtr<mirror::String> name;
- if (!GetDexPathListElementName(element, &name)) {
- *error_msg = "Invalid dex path list element";
- *error = false; // Invalid element is not a critical error.
- return false; // Stop the visit.
- }
- if (name != nullptr) {
- out_dex_file_names->push_front(name);
- }
- return true; // Continue with the next Element.
- };
- bool error = VisitClassLoaderDexElements(soa, handle, add_element_names, /* error */ false);
- if (error) {
- // An error occurred during DexPathList Element visiting.
+ } else if (ClassLinker::IsBootClassLoader(soa, image_class_loader)) {
+ *error_msg = "Hierarchies don't match";
+ return false;
+ } else if (class_loader->GetClass() != image_class_loader->GetClass()) {
+ *error_msg = StringPrintf("Class loader types don't match %s and %s",
+ image_class_loader->PrettyTypeOf().c_str(),
+ class_loader->PrettyTypeOf().c_str());
+ return false;
+ } else if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+ class_loader->GetClass()) {
+ *error_msg = StringPrintf("Unknown class loader type %s",
+ class_loader->PrettyTypeOf().c_str());
+ // Unsupported class loader.
+ return false;
+ }
+ return true;
+}
+
+static bool CompareDexFiles(const std::list<ObjPtr<mirror::String>>& image_dex_files,
+ const std::list<ObjPtr<mirror::String>>& loader_dex_files,
+ std::string* error_msg)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ bool equal = (image_dex_files.size() == loader_dex_files.size()) &&
+ std::equal(image_dex_files.begin(),
+ image_dex_files.end(),
+ loader_dex_files.begin(),
+ [](ObjPtr<mirror::String> lhs, ObjPtr<mirror::String> rhs)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return lhs->Equals(rhs);
+ });
+ if (!equal) {
+ VLOG(image) << "Image dex files " << image_dex_files.size();
+ for (ObjPtr<mirror::String> name : image_dex_files) {
+ VLOG(image) << name->ToModifiedUtf8();
+ }
+ VLOG(image) << "Loader dex files " << loader_dex_files.size();
+ for (ObjPtr<mirror::String> name : loader_dex_files) {
+ VLOG(image) << name->ToModifiedUtf8();
+ }
+ *error_msg = "Mismatch in dex files";
+ }
+ return equal;
+}
+
+static bool CompareClassLoaders(ScopedObjectAccessUnchecked& soa,
+ ObjPtr<mirror::ClassLoader> image_class_loader,
+ ObjPtr<mirror::ClassLoader> class_loader,
+ bool check_dex_file_names,
+ std::string* error_msg)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!CompareClassLoaderTypes(soa, image_class_loader, class_loader, error_msg)) {
+ return false;
+ }
+
+ if (ClassLinker::IsBootClassLoader(soa, class_loader)) {
+ // No need to check further.
+ return true;
+ }
+
+ if (check_dex_file_names) {
+ std::list<ObjPtr<mirror::String>> image_dex_files;
+ if (!GetDexFileNames(soa, image_class_loader, &image_dex_files, error_msg)) {
+ return false;
+ }
+
+ std::list<ObjPtr<mirror::String>> loader_dex_files;
+ if (!GetDexFileNames(soa, class_loader, &loader_dex_files, error_msg)) {
+ return false;
+ }
+
+ if (!CompareDexFiles(image_dex_files, loader_dex_files, error_msg)) {
return false;
}
- class_loader = class_loader->GetParent();
+ }
+
+ ArtField* field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ ObjPtr<mirror::Object> shared_libraries_image_loader = field->GetObject(image_class_loader.Ptr());
+ ObjPtr<mirror::Object> shared_libraries_loader = field->GetObject(class_loader.Ptr());
+ if (shared_libraries_image_loader == nullptr) {
+ if (shared_libraries_loader != nullptr) {
+ *error_msg = "Mismatch in shared libraries";
+ return false;
+ }
+ } else if (shared_libraries_loader == nullptr) {
+ *error_msg = "Mismatch in shared libraries";
+ return false;
+ } else {
+ ObjPtr<mirror::ObjectArray<mirror::ClassLoader>> array1 =
+ shared_libraries_image_loader->AsObjectArray<mirror::ClassLoader>();
+ ObjPtr<mirror::ObjectArray<mirror::ClassLoader>> array2 =
+ shared_libraries_loader->AsObjectArray<mirror::ClassLoader>();
+ if (array1->GetLength() != array2->GetLength()) {
+ *error_msg = "Mismatch in number of shared libraries";
+ return false;
+ }
+
+ for (int32_t i = 0; i < array1->GetLength(); ++i) {
+ // Do a full comparison of the class loaders, including comparing their dex files.
+ if (!CompareClassLoaders(soa,
+ array1->Get(i),
+ array2->Get(i),
+ /*check_dex_file_names=*/ true,
+ error_msg)) {
+ return false;
+ }
+ }
+ }
+
+ // Do a full comparison of the class loaders, including comparing their dex files.
+ if (!CompareClassLoaders(soa,
+ image_class_loader->GetParent(),
+ class_loader->GetParent(),
+ /*check_dex_file_names=*/ true,
+ error_msg)) {
+ return false;
}
return true;
}
@@ -1157,7 +1313,7 @@ class VerifyDeclaringClassVisitor : public ArtMethodVisitor {
VerifyDeclaringClassVisitor() REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_)
: live_bitmap_(Runtime::Current()->GetHeap()->GetLiveBitmap()) {}
- virtual void Visit(ArtMethod* method)
+ void Visit(ArtMethod* method) override
REQUIRES_SHARED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
ObjPtr<mirror::Class> klass = method->GetDeclaringClassUnchecked();
if (klass != nullptr) {
@@ -1169,18 +1325,36 @@ class VerifyDeclaringClassVisitor : public ArtMethodVisitor {
gc::accounting::HeapBitmap* const live_bitmap_;
};
-class FixupInternVisitor {
+/*
+ * A class used to ensure that all strings in an AppImage have been properly
+ * interned, and is only ever run in debug mode.
+ */
+class VerifyStringInterningVisitor {
public:
- ALWAYS_INLINE ObjPtr<mirror::Object> TryInsertIntern(mirror::Object* obj) const
+ explicit VerifyStringInterningVisitor(const gc::space::ImageSpace& space) :
+ space_(space),
+ intern_table_(*Runtime::Current()->GetInternTable()) {}
+
+ void TestObject(ObjPtr<mirror::Object> referred_obj) const
REQUIRES_SHARED(Locks::mutator_lock_) {
- if (obj != nullptr && obj->IsString()) {
- const auto intern = Runtime::Current()->GetInternTable()->InternStrong(obj->AsString());
- return intern;
+ if (referred_obj != nullptr &&
+ space_.HasAddress(referred_obj.Ptr()) &&
+ referred_obj->IsString()) {
+ ObjPtr<mirror::String> referred_str = referred_obj->AsString();
+
+ if (kIsDebugBuild) {
+ // Saved to temporary variables to aid in debugging.
+ ObjPtr<mirror::String> strong_lookup_result =
+ intern_table_.LookupStrong(Thread::Current(), referred_str);
+ ObjPtr<mirror::String> weak_lookup_result =
+ intern_table_.LookupWeak(Thread::Current(), referred_str);
+
+ DCHECK((strong_lookup_result == referred_str) || (weak_lookup_result == referred_str));
+ }
}
- return obj;
}
- ALWAYS_INLINE void VisitRootIfNonNull(
+ void VisitRootIfNonNull(
mirror::CompressedReference<mirror::Object>* root) const
REQUIRES_SHARED(Locks::mutator_lock_) {
if (!root->IsNull()) {
@@ -1188,48 +1362,77 @@ class FixupInternVisitor {
}
}
- ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
+ void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
REQUIRES_SHARED(Locks::mutator_lock_) {
- root->Assign(TryInsertIntern(root->AsMirrorPtr()));
+ TestObject(root->AsMirrorPtr());
}
// Visit Class Fields
- ALWAYS_INLINE void operator()(ObjPtr<mirror::Object> obj,
- MemberOffset offset,
- bool is_static ATTRIBUTE_UNUSED) const
+ void operator()(ObjPtr<mirror::Object> obj,
+ MemberOffset offset,
+ bool is_static ATTRIBUTE_UNUSED) const
REQUIRES_SHARED(Locks::mutator_lock_) {
// There could be overlap between ranges, we must avoid visiting the same reference twice.
// Avoid the class field since we already fixed it up in FixupClassVisitor.
if (offset.Uint32Value() != mirror::Object::ClassOffset().Uint32Value()) {
// Updating images, don't do a read barrier.
- // Only string fields are fixed, don't do a verify.
- mirror::Object* ref = obj->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(
- offset);
- obj->SetFieldObject<false, false>(offset, TryInsertIntern(ref));
+ ObjPtr<mirror::Object> referred_obj =
+ obj->GetFieldObject<mirror::Object, kVerifyNone, kWithoutReadBarrier>(offset);
+
+ TestObject(referred_obj);
}
}
void operator()(ObjPtr<mirror::Class> klass ATTRIBUTE_UNUSED,
ObjPtr<mirror::Reference> ref) const
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) {
- this->operator()(ref, mirror::Reference::ReferentOffset(), false);
+ operator()(ref, mirror::Reference::ReferentOffset(), false);
}
- void operator()(mirror::Object* obj) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (obj->IsDexCache()) {
- obj->VisitReferences<true, kVerifyNone, kWithoutReadBarrier>(*this, *this);
- } else {
- // Don't visit native roots for non-dex-cache
- obj->VisitReferences<false, kVerifyNone, kWithoutReadBarrier>(*this, *this);
- }
- }
+ const gc::space::ImageSpace& space_;
+ InternTable& intern_table_;
};
+/*
+ * This function verifies that string references in the AppImage have been
+ * properly interned. To be considered properly interned a reference must
+ * point to the same version of the string that the intern table does.
+ */
+void VerifyStringInterning(gc::space::ImageSpace& space) REQUIRES_SHARED(Locks::mutator_lock_) {
+ const gc::accounting::ContinuousSpaceBitmap* bitmap = space.GetMarkBitmap();
+ const ImageHeader& image_header = space.GetImageHeader();
+ const uint8_t* target_base = space.GetMemMap()->Begin();
+ const ImageSection& objects_section = image_header.GetObjectsSection();
+
+ auto objects_begin = reinterpret_cast<uintptr_t>(target_base + objects_section.Offset());
+ auto objects_end = reinterpret_cast<uintptr_t>(target_base + objects_section.End());
+
+ VerifyStringInterningVisitor visitor(space);
+ bitmap->VisitMarkedRange(objects_begin,
+ objects_end,
+ [&space, &visitor](mirror::Object* obj)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (space.HasAddress(obj)) {
+ if (obj->IsDexCache()) {
+ obj->VisitReferences</* kVisitNativeRoots= */ true,
+ kVerifyNone,
+ kWithoutReadBarrier>(visitor, visitor);
+ } else {
+ // Don't visit native roots for non-dex-cache as they can't contain
+ // native references to strings. This is verified during compilation
+ // by ImageWriter::VerifyNativeGCRootInvariants.
+ obj->VisitReferences</* kVisitNativeRoots= */ false,
+ kVerifyNone,
+ kWithoutReadBarrier>(visitor, visitor);
+ }
+ }
+ });
+}
+
// new_class_set is the set of classes that were read from the class table section in the image.
// If there was no class table section, it is null.
// Note: using a class here to avoid having to make ClassLinker internals public.
-class AppImageClassLoadersAndDexCachesHelper {
+class AppImageLoadingHelper {
public:
static void Update(
ClassLinker* class_linker,
@@ -1239,9 +1442,17 @@ class AppImageClassLoadersAndDexCachesHelper {
ClassTable::ClassSet* new_class_set)
REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static void HandleAppImageStrings(gc::space::ImageSpace* space)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ static void UpdateInternStrings(
+ gc::space::ImageSpace* space,
+ const SafeMap<mirror::String*, mirror::String*>& intern_remap)
+ REQUIRES_SHARED(Locks::mutator_lock_);
};
-void AppImageClassLoadersAndDexCachesHelper::Update(
+void AppImageLoadingHelper::Update(
ClassLinker* class_linker,
gc::space::ImageSpace* space,
Handle<mirror::ClassLoader> class_loader,
@@ -1249,6 +1460,8 @@ void AppImageClassLoadersAndDexCachesHelper::Update(
ClassTable::ClassSet* new_class_set)
REQUIRES(!Locks::dex_lock_)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ ScopedTrace app_image_timing("AppImage:Updating");
+
Thread* const self = Thread::Current();
gc::Heap* const heap = Runtime::Current()->GetHeap();
const ImageHeader& header = space->GetImageHeader();
@@ -1264,6 +1477,7 @@ void AppImageClassLoadersAndDexCachesHelper::Update(
CHECK(!class_linker->FindDexCacheDataLocked(*dex_file).IsValid());
class_linker->RegisterDexFileLocked(*dex_file, dex_cache, class_loader.Get());
}
+
if (kIsDebugBuild) {
CHECK(new_class_set != nullptr);
mirror::TypeDexCacheType* const types = dex_cache->GetResolvedTypes();
@@ -1271,17 +1485,20 @@ void AppImageClassLoadersAndDexCachesHelper::Update(
for (size_t j = 0; j != num_types; ++j) {
// The image space is not yet added to the heap, avoid read barriers.
ObjPtr<mirror::Class> klass = types[j].load(std::memory_order_relaxed).object.Read();
+
if (space->HasAddress(klass.Ptr())) {
DCHECK(!klass->IsErroneous()) << klass->GetStatus();
auto it = new_class_set->find(ClassTable::TableSlot(klass));
DCHECK(it != new_class_set->end());
DCHECK_EQ(it->Read(), klass);
ObjPtr<mirror::Class> super_class = klass->GetSuperClass();
+
if (super_class != nullptr && !heap->ObjectIsInBootImageSpace(super_class)) {
auto it2 = new_class_set->find(ClassTable::TableSlot(super_class));
DCHECK(it2 != new_class_set->end());
DCHECK_EQ(it2->Read(), super_class);
}
+
for (ArtMethod& m : klass->GetDirectMethods(kRuntimePointerSize)) {
const void* code = m.GetEntryPointFromQuickCompiledCode();
const void* oat_code = m.IsInvokable() ? class_linker->GetQuickOatCodeFor(&m) : code;
@@ -1292,6 +1509,7 @@ void AppImageClassLoadersAndDexCachesHelper::Update(
DCHECK_EQ(code, oat_code) << m.PrettyMethod();
}
}
+
for (ArtMethod& m : klass->GetVirtualMethods(kRuntimePointerSize)) {
const void* code = m.GetEntryPointFromQuickCompiledCode();
const void* oat_code = m.IsInvokable() ? class_linker->GetQuickOatCodeFor(&m) : code;
@@ -1307,47 +1525,171 @@ void AppImageClassLoadersAndDexCachesHelper::Update(
}
}
}
- if (ClassLinker::kAppImageMayContainStrings) {
- // Fixup all the literal strings happens at app images which are supposed to be interned.
- ScopedTrace timing("Fixup String Intern in image and dex_cache");
- const auto& image_header = space->GetImageHeader();
- const auto bitmap = space->GetMarkBitmap(); // bitmap of objects
- const uint8_t* target_base = space->GetMemMap()->Begin();
- const ImageSection& objects_section = image_header.GetObjectsSection();
- uintptr_t objects_begin = reinterpret_cast<uintptr_t>(target_base + objects_section.Offset());
- uintptr_t objects_end = reinterpret_cast<uintptr_t>(target_base + objects_section.End());
+ if (ClassLinker::kAppImageMayContainStrings) {
+ HandleAppImageStrings(space);
- FixupInternVisitor fixup_intern_visitor;
- bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_intern_visitor);
+ if (kIsDebugBuild) {
+ VerifyStringInterning(*space);
+ }
}
+
if (kVerifyArtMethodDeclaringClasses) {
- ScopedTrace timing("Verify declaring classes");
+ ScopedTrace timing("AppImage:VerifyDeclaringClasses");
ReaderMutexLock rmu(self, *Locks::heap_bitmap_lock_);
VerifyDeclaringClassVisitor visitor;
header.VisitPackedArtMethods(&visitor, space->Begin(), kRuntimePointerSize);
}
}
-// Update the class loader. Should only be used on classes in the image space.
-class UpdateClassLoaderVisitor {
- public:
- UpdateClassLoaderVisitor(gc::space::ImageSpace* space, ObjPtr<mirror::ClassLoader> class_loader)
- : space_(space),
- class_loader_(class_loader) {}
-
- bool operator()(ObjPtr<mirror::Class> klass) const REQUIRES_SHARED(Locks::mutator_lock_) {
- // Do not update class loader for boot image classes where the app image
- // class loader is only the initiating loader but not the defining loader.
- if (klass->GetClassLoader() != nullptr) {
- klass->SetClassLoader(class_loader_);
+void AppImageLoadingHelper::UpdateInternStrings(
+ gc::space::ImageSpace* space,
+ const SafeMap<mirror::String*, mirror::String*>& intern_remap) {
+ const uint8_t* target_base = space->Begin();
+ const ImageSection& sro_section =
+ space->GetImageHeader().GetImageStringReferenceOffsetsSection();
+ const size_t num_string_offsets = sro_section.Size() / sizeof(AppImageReferenceOffsetInfo);
+
+ VLOG(image)
+ << "ClassLinker:AppImage:InternStrings:imageStringReferenceOffsetCount = "
+ << num_string_offsets;
+
+ const auto* sro_base =
+ reinterpret_cast<const AppImageReferenceOffsetInfo*>(target_base + sro_section.Offset());
+
+ for (size_t offset_index = 0; offset_index < num_string_offsets; ++offset_index) {
+ uint32_t base_offset = sro_base[offset_index].first;
+
+ if (HasDexCacheStringNativeRefTag(base_offset)) {
+ base_offset = ClearDexCacheNativeRefTags(base_offset);
+ DCHECK_ALIGNED(base_offset, 2);
+
+ ObjPtr<mirror::DexCache> dex_cache =
+ reinterpret_cast<mirror::DexCache*>(space->Begin() + base_offset);
+ uint32_t string_index = sro_base[offset_index].second;
+
+ mirror::StringDexCachePair source = dex_cache->GetStrings()[string_index].load();
+ ObjPtr<mirror::String> referred_string = source.object.Read();
+ DCHECK(referred_string != nullptr);
+
+ auto it = intern_remap.find(referred_string.Ptr());
+ if (it != intern_remap.end()) {
+ // This doesn't use SetResolvedString to maintain consistency with how
+ // we load the string. The index from the source string must be
+ // re-used due to the circular nature of the cache. Because we are not
+ // using a helper function we need to mark the GC card manually.
+ WriteBarrier::ForEveryFieldWrite(dex_cache);
+ dex_cache->GetStrings()[string_index].store(
+ mirror::StringDexCachePair(it->second, source.index));
+ }
+ } else if (HasDexCachePreResolvedStringNativeRefTag(base_offset)) {
+ base_offset = ClearDexCacheNativeRefTags(base_offset);
+ DCHECK_ALIGNED(base_offset, 2);
+
+ ObjPtr<mirror::DexCache> dex_cache =
+ reinterpret_cast<mirror::DexCache*>(space->Begin() + base_offset);
+ uint32_t string_index = sro_base[offset_index].second;
+
+ ObjPtr<mirror::String> referred_string =
+ dex_cache->GetPreResolvedStrings()[string_index].Read();
+ DCHECK(referred_string != nullptr);
+
+ auto it = intern_remap.find(referred_string.Ptr());
+ if (it != intern_remap.end()) {
+ // Because we are not using a helper function we need to mark the GC card manually.
+ WriteBarrier::ForEveryFieldWrite(dex_cache);
+ dex_cache->GetPreResolvedStrings()[string_index] = GcRoot<mirror::String>(it->second);
+ }
+ } else {
+ uint32_t raw_member_offset = sro_base[offset_index].second;
+ DCHECK_ALIGNED(base_offset, 2);
+ DCHECK_ALIGNED(raw_member_offset, 2);
+
+ ObjPtr<mirror::Object> obj_ptr =
+ reinterpret_cast<mirror::Object*>(space->Begin() + base_offset);
+ MemberOffset member_offset(raw_member_offset);
+ ObjPtr<mirror::String> referred_string =
+ obj_ptr->GetFieldObject<mirror::String,
+ kVerifyNone,
+ kWithoutReadBarrier,
+ /* kIsVolatile= */ false>(member_offset);
+ DCHECK(referred_string != nullptr);
+
+ auto it = intern_remap.find(referred_string.Ptr());
+ if (it != intern_remap.end()) {
+ obj_ptr->SetFieldObject</* kTransactionActive= */ false,
+ /* kCheckTransaction= */ false,
+ kVerifyNone,
+ /* kIsVolatile= */ false>(member_offset, it->second);
+ }
+ }
+ }
+}
+
+void AppImageLoadingHelper::HandleAppImageStrings(gc::space::ImageSpace* space) {
+ // Iterate over the string reference offsets stored in the image and intern
+ // the strings they point to.
+ ScopedTrace timing("AppImage:InternString");
+
+ InternTable* const intern_table = Runtime::Current()->GetInternTable();
+
+ // Add the intern table, removing any conflicts. For conflicts, store the new address in a map
+ // for faster lookup.
+ // TODO: Optimize with a bitmap or bloom filter
+ SafeMap<mirror::String*, mirror::String*> intern_remap;
+ intern_table->AddImageStringsToTable(space, [&](InternTable::UnorderedSet& interns)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(Locks::intern_table_lock_) {
+ const size_t non_boot_image_strings = intern_table->CountInterns(
+ /*visit_boot_images=*/false,
+ /*visit_non_boot_images=*/true);
+ VLOG(image) << "AppImage:stringsInInternTableSize = " << interns.size();
+ VLOG(image) << "AppImage:nonBootImageInternStrings = " << non_boot_image_strings;
+ // Visit the smaller of the two sets to compute the intersection.
+ if (interns.size() < non_boot_image_strings) {
+ for (auto it = interns.begin(); it != interns.end(); ) {
+ ObjPtr<mirror::String> string = it->Read();
+ ObjPtr<mirror::String> existing = intern_table->LookupWeakLocked(string);
+ if (existing == nullptr) {
+ existing = intern_table->LookupStrongLocked(string);
+ }
+ if (existing != nullptr) {
+ intern_remap.Put(string.Ptr(), existing.Ptr());
+ it = interns.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ } else {
+ intern_table->VisitInterns([&](const GcRoot<mirror::String>& root)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(Locks::intern_table_lock_) {
+ auto it = interns.find(root);
+ if (it != interns.end()) {
+ ObjPtr<mirror::String> existing = root.Read();
+ intern_remap.Put(it->Read(), existing.Ptr());
+ it = interns.erase(it);
+ }
+ }, /*visit_boot_images=*/false, /*visit_non_boot_images=*/true);
}
- return true;
- }
+ // Sanity check to ensure correctness.
+ if (kIsDebugBuild) {
+ for (GcRoot<mirror::String>& root : interns) {
+ ObjPtr<mirror::String> string = root.Read();
+ CHECK(intern_table->LookupWeakLocked(string) == nullptr) << string->ToModifiedUtf8();
+ CHECK(intern_table->LookupStrongLocked(string) == nullptr) << string->ToModifiedUtf8();
+ }
+ }
+ });
- gc::space::ImageSpace* const space_;
- ObjPtr<mirror::ClassLoader> const class_loader_;
-};
+ VLOG(image) << "AppImage:conflictingInternStrings = " << intern_remap.size();
+
+ // For debug builds, always run the code below to get coverage.
+ if (kIsDebugBuild || !intern_remap.empty()) {
+ // Slow path case is when there are conflicting intern strings to fix up.
+ UpdateInternStrings(space, intern_remap);
+ }
+}
static std::unique_ptr<const DexFile> OpenOatDexFile(const OatFile* oat_file,
const char* location,
@@ -1557,7 +1899,7 @@ static void VerifyAppImage(const ImageHeader& header,
public:
explicit VerifyClassInTableArtMethodVisitor(ClassTable* table) : table_(table) {}
- virtual void Visit(ArtMethod* method)
+ void Visit(ArtMethod* method) override
REQUIRES_SHARED(Locks::mutator_lock_, Locks::classlinker_classes_lock_) {
ObjPtr<mirror::Class> klass = method->GetDeclaringClass();
if (klass != nullptr && !Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(klass)) {
@@ -1671,13 +2013,7 @@ bool ClassLinker::AddImageSpace(
std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
// TODO: Only store qualified paths.
// If non qualified, qualify it.
- if (dex_file_location.find('/') == std::string::npos) {
- std::string dex_location_path = dex_location;
- const size_t pos = dex_location_path.find_last_of('/');
- CHECK_NE(pos, std::string::npos);
- dex_location_path = dex_location_path.substr(0, pos + 1); // Keep trailing '/'
- dex_file_location = dex_location_path + dex_file_location;
- }
+ dex_file_location = OatFile::ResolveRelativeEncodedDexLocation(dex_location, dex_file_location);
std::unique_ptr<const DexFile> dex_file = OpenOatDexFile(oat_file,
dex_file_location.c_str(),
error_msg);
@@ -1711,11 +2047,12 @@ bool ClassLinker::AddImageSpace(
if (app_image) {
ScopedObjectAccessUnchecked soa(Thread::Current());
+ ScopedAssertNoThreadSuspension sants("Checking app image", soa.Self());
// Check that the class loader resolves the same way as the ones in the image.
// Image class loader [A][B][C][image dex files]
// Class loader = [???][dex_elements][image dex files]
// Need to ensure that [???][dex_elements] == [A][B][C].
- // For each class loader, PathClassLoader, the laoder checks the parent first. Also the logic
+ // For each class loader, PathClassLoader, the loader checks the parent first. Also the logic
// for PathClassLoader does this by looping through the array of dex files. To ensure they
// resolve the same way, simply flatten the hierarchy in the way the resolution order would be,
// and check that the dex file names are the same.
@@ -1723,21 +2060,12 @@ bool ClassLinker::AddImageSpace(
*error_msg = "Unexpected BootClassLoader in app image";
return false;
}
- std::list<ObjPtr<mirror::String>> image_dex_file_names;
- std::string temp_error_msg;
- if (!FlattenPathClassLoader(image_class_loader.Get(), &image_dex_file_names, &temp_error_msg)) {
- *error_msg = StringPrintf("Failed to flatten image class loader hierarchy '%s'",
- temp_error_msg.c_str());
- return false;
- }
- std::list<ObjPtr<mirror::String>> loader_dex_file_names;
- if (!FlattenPathClassLoader(class_loader.Get(), &loader_dex_file_names, &temp_error_msg)) {
- *error_msg = StringPrintf("Failed to flatten class loader hierarchy '%s'",
- temp_error_msg.c_str());
- return false;
- }
- // Add the temporary dex path list elements at the end.
+ // The dex files of `class_loader` are not setup yet, so we cannot do a full comparison
+ // of `class_loader` and `image_class_loader` in `CompareClassLoaders`. Therefore, we
+ // special case the comparison of dex files of the two class loaders, but then do full
+ // comparisons for their shared libraries and parent.
auto elements = soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements);
+ std::list<ObjPtr<mirror::String>> loader_dex_file_names;
for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
ObjPtr<mirror::Object> element = elements->GetWithoutChecks(i);
if (element != nullptr) {
@@ -1748,31 +2076,29 @@ bool ClassLinker::AddImageSpace(
}
}
}
- // Ignore the number of image dex files since we are adding those to the class loader anyways.
- CHECK_GE(static_cast<size_t>(image_dex_file_names.size()),
- static_cast<size_t>(dex_caches->GetLength()));
- size_t image_count = image_dex_file_names.size() - dex_caches->GetLength();
- // Check that the dex file names match.
- bool equal = image_count == loader_dex_file_names.size();
- if (equal) {
- auto it1 = image_dex_file_names.begin();
- auto it2 = loader_dex_file_names.begin();
- for (size_t i = 0; equal && i < image_count; ++i, ++it1, ++it2) {
- equal = equal && (*it1)->Equals(*it2);
- }
- }
- if (!equal) {
- VLOG(image) << "Image dex files " << image_dex_file_names.size();
- for (ObjPtr<mirror::String> name : image_dex_file_names) {
- VLOG(image) << name->ToModifiedUtf8();
- }
- VLOG(image) << "Loader dex files " << loader_dex_file_names.size();
- for (ObjPtr<mirror::String> name : loader_dex_file_names) {
- VLOG(image) << name->ToModifiedUtf8();
- }
- *error_msg = "Rejecting application image due to class loader mismatch";
- // Ignore class loader mismatch for now since these would just use possibly incorrect
- // oat code anyways. The structural class check should be done in the parent.
+ std::string temp_error_msg;
+ std::list<ObjPtr<mirror::String>> image_dex_file_names;
+ bool success = GetDexFileNames(
+ soa, image_class_loader.Get(), &image_dex_file_names, &temp_error_msg);
+ if (success) {
+ // Ignore the number of image dex files since we are adding those to the class loader anyways.
+ CHECK_GE(static_cast<size_t>(image_dex_file_names.size()),
+ static_cast<size_t>(dex_caches->GetLength()));
+ size_t image_count = image_dex_file_names.size() - dex_caches->GetLength();
+ image_dex_file_names.resize(image_count);
+ success = success && CompareDexFiles(image_dex_file_names,
+ loader_dex_file_names,
+ &temp_error_msg);
+ success = success && CompareClassLoaders(soa,
+ image_class_loader.Get(),
+ class_loader.Get(),
+ /*check_dex_file_names=*/ false,
+ &temp_error_msg);
+ }
+ if (!success) {
+ *error_msg = StringPrintf("Rejecting application image due to class loader mismatch: '%s'",
+ temp_error_msg.c_str());
+ return false;
}
}
@@ -1816,16 +2142,24 @@ bool ClassLinker::AddImageSpace(
VLOG(image) << "Adding class table classes took " << PrettyDuration(NanoTime() - start_time2);
}
if (app_image) {
- AppImageClassLoadersAndDexCachesHelper::Update(this,
- space,
- class_loader,
- dex_caches,
- &temp_set);
- // Update class loader and resolved strings. If added_class_table is false, the resolved
- // strings were forwarded UpdateAppImageClassLoadersAndDexCaches.
- UpdateClassLoaderVisitor visitor(space, class_loader.Get());
- for (const ClassTable::TableSlot& root : temp_set) {
- visitor(root.Read());
+ AppImageLoadingHelper::Update(this, space, class_loader, dex_caches, &temp_set);
+
+ {
+ ScopedTrace trace("AppImage:UpdateClassLoaders");
+ // Update class loader and resolved strings. If added_class_table is false, the resolved
+ // strings were forwarded UpdateAppImageClassLoadersAndDexCaches.
+ ObjPtr<mirror::ClassLoader> loader(class_loader.Get());
+ for (const ClassTable::TableSlot& root : temp_set) {
+ // Note: We probably don't need the read barrier unless we copy the app image objects into
+ // the region space.
+ ObjPtr<mirror::Class> klass(root.Read());
+ // Do not update class loader for boot image classes where the app image
+ // class loader is only the initiating loader but not the defining loader.
+ // Avoid read barrier since we are comparing against null.
+ if (klass->GetClassLoader<kDefaultVerifyFlags, kWithoutReadBarrier>() != nullptr) {
+ klass->SetClassLoader</*kCheckTransaction=*/ false>(loader);
+ }
+ }
}
if (kBitstringSubtypeCheckEnabled) {
@@ -1840,7 +2174,7 @@ bool ClassLinker::AddImageSpace(
// Force every app image class's SubtypeCheck to be at least kIninitialized.
//
// See also ImageWriter::FixupClass.
- ScopedTrace trace("Recalculate app image SubtypeCheck bitstrings");
+ ScopedTrace trace("AppImage:RecacluateSubtypeCheckBitstrings");
MutexLock subtype_check_lock(Thread::Current(), *Locks::subtype_check_lock_);
for (const ClassTable::TableSlot& root : temp_set) {
SubtypeCheck<ObjPtr<mirror::Class>>::EnsureInitialized(root.Read());
@@ -1860,7 +2194,7 @@ bool ClassLinker::AddImageSpace(
if (kIsDebugBuild && app_image) {
// This verification needs to happen after the classes have been added to the class loader.
// Since it ensures classes are in the class table.
- ScopedTrace trace("VerifyAppImage");
+ ScopedTrace trace("AppImage:Verify");
VerifyAppImage(header, class_loader, dex_caches, class_table, space);
}
@@ -2107,7 +2441,7 @@ ClassLinker::~ClassLinker() {
for (const ClassLoaderData& data : class_loaders_) {
// CHA unloading analysis is not needed. No negative consequences are expected because
// all the classloaders are deleted at the same time.
- DeleteClassLoader(self, data, false /*cleanup_cha*/);
+ DeleteClassLoader(self, data, /*cleanup_cha=*/ false);
}
class_loaders_.clear();
}
@@ -2211,7 +2545,7 @@ ObjPtr<mirror::Class> ClassLinker::AllocPrimitiveArrayClass(Thread* self,
// in the `klass_` field of one of its instances allocated in the Large-Object
// Space (LOS) -- see the comment about the dirty card scanning logic in
// art::gc::collector::ConcurrentCopying::MarkingPhase.
- return AllocClass</* kMovable */ false>(
+ return AllocClass</* kMovable= */ false>(
self, java_lang_Class, mirror::Array::ClassSize(image_pointer_size_));
}
@@ -2299,13 +2633,13 @@ ObjPtr<mirror::Class> ClassLinker::EnsureResolved(Thread* self,
return klass;
}
-typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry;
+using ClassPathEntry = std::pair<const DexFile*, const dex::ClassDef*>;
// Search a collection of DexFiles for a descriptor
ClassPathEntry FindInClassPath(const char* descriptor,
size_t hash, const std::vector<const DexFile*>& class_path) {
for (const DexFile* dex_file : class_path) {
- const DexFile::ClassDef* dex_class_def = OatDexFile::FindClassDef(*dex_file, descriptor, hash);
+ const dex::ClassDef* dex_class_def = OatDexFile::FindClassDef(*dex_file, descriptor, hash);
if (dex_class_def != nullptr) {
return ClassPathEntry(dex_file, dex_class_def);
}
@@ -2313,6 +2647,35 @@ ClassPathEntry FindInClassPath(const char* descriptor,
return ClassPathEntry(nullptr, nullptr);
}
+bool ClassLinker::FindClassInSharedLibraries(ScopedObjectAccessAlreadyRunnable& soa,
+ Thread* self,
+ const char* descriptor,
+ size_t hash,
+ Handle<mirror::ClassLoader> class_loader,
+ /*out*/ ObjPtr<mirror::Class>* result) {
+ ArtField* field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader.Get());
+ if (raw_shared_libraries == nullptr) {
+ return true;
+ }
+
+ StackHandleScope<2> hs(self);
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries(
+ hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>()));
+ MutableHandle<mirror::ClassLoader> temp_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
+ for (int32_t i = 0; i < shared_libraries->GetLength(); ++i) {
+ temp_loader.Assign(shared_libraries->Get(i));
+ if (!FindClassInBaseDexClassLoader(soa, self, descriptor, hash, temp_loader, result)) {
+ return false; // One of the shared libraries is not supported.
+ }
+ if (*result != nullptr) {
+ return true; // Found the class up the chain.
+ }
+ }
+ return true;
+}
+
bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
Thread* self,
const char* descriptor,
@@ -2325,9 +2688,10 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl
return true;
}
- if (IsPathOrDexClassLoader(soa, class_loader)) {
+ if (IsPathOrDexClassLoader(soa, class_loader) || IsInMemoryDexClassLoader(soa, class_loader)) {
// For regular path or dex class loader the search order is:
// - parent
+ // - shared libraries
// - class loader dex files
// Handles as RegisterDexFile may allocate dex caches (and cause thread suspension).
@@ -2340,6 +2704,13 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl
return true; // Found the class up the chain.
}
+ if (!FindClassInSharedLibraries(soa, self, descriptor, hash, class_loader, result)) {
+ return false; // One of the shared library loader is not supported.
+ }
+ if (*result != nullptr) {
+ return true; // Found the class in a shared library.
+ }
+
// Search the current class loader classpath.
*result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader);
return true;
@@ -2348,6 +2719,7 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl
if (IsDelegateLastClassLoader(soa, class_loader)) {
// For delegate last, the search order is:
// - boot class path
+ // - shared libraries
// - class loader dex files
// - parent
*result = FindClassInBootClassLoaderClassPath(self, descriptor, hash);
@@ -2355,6 +2727,13 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl
return true; // The class is part of the boot class path.
}
+ if (!FindClassInSharedLibraries(soa, self, descriptor, hash, class_loader, result)) {
+ return false; // One of the shared library loader is not supported.
+ }
+ if (*result != nullptr) {
+ return true; // Found the class in a shared library.
+ }
+
*result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader);
if (*result != nullptr) {
return true; // Found the class in the current class loader
@@ -2403,13 +2782,14 @@ ObjPtr<mirror::Class> ClassLinker::FindClassInBaseDexClassLoaderClassPath(
const char* descriptor,
size_t hash,
Handle<mirror::ClassLoader> class_loader) {
- DCHECK(IsPathOrDexClassLoader(soa, class_loader) || IsDelegateLastClassLoader(soa, class_loader))
+ DCHECK(IsPathOrDexClassLoader(soa, class_loader) ||
+ IsInMemoryDexClassLoader(soa, class_loader) ||
+ IsDelegateLastClassLoader(soa, class_loader))
<< "Unexpected class loader for descriptor " << descriptor;
ObjPtr<mirror::Class> ret;
auto define_class = [&](const DexFile* cp_dex_file) REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile::ClassDef* dex_class_def =
- OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash);
+ const dex::ClassDef* dex_class_def = OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash);
if (dex_class_def != nullptr) {
ObjPtr<mirror::Class> klass = DefineClass(soa.Self(),
descriptor,
@@ -2497,7 +2877,8 @@ ObjPtr<mirror::Class> ClassLinker::FindClass(Thread* self,
// the Java-side could still succeed for racy programs if another thread is actively
// modifying the class loader's path list.
- if (!self->CanCallIntoJava()) {
+ // The runtime is not allowed to call into java from a runtime-thread so just abort.
+ if (self->IsRuntimeThread()) {
// Oops, we can't call into java so we can't run actual class-loader code.
// This is true for e.g. for the compiler (jit or aot).
ObjPtr<mirror::Throwable> pre_allocated =
@@ -2608,7 +2989,7 @@ ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,
size_t hash,
Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
- const DexFile::ClassDef& dex_class_def) {
+ const dex::ClassDef& dex_class_def) {
StackHandleScope<3> hs(self);
auto klass = hs.NewHandle<mirror::Class>(nullptr);
@@ -2630,6 +3011,17 @@ ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,
}
}
+ // This is to prevent the calls to ClassLoad and ClassPrepare which can cause java/user-supplied
+ // code to be executed. We put it up here so we can avoid all the allocations associated with
+ // creating the class. This can happen with (eg) jit threads.
+ if (!self->CanLoadClasses()) {
+ // Make sure we don't try to load anything, potentially causing an infinite loop.
+ ObjPtr<mirror::Throwable> pre_allocated =
+ Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(pre_allocated);
+ return nullptr;
+ }
+
if (klass == nullptr) {
// Allocate a class with the status of not ready.
// Interface object should get the right size here. Regular class will
@@ -2644,7 +3036,7 @@ ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,
// Get the real dex file. This will return the input if there aren't any callbacks or they do
// nothing.
DexFile const* new_dex_file = nullptr;
- DexFile::ClassDef const* new_class_def = nullptr;
+ dex::ClassDef const* new_class_def = nullptr;
// TODO We should ideally figure out some way to move this after we get a lock on the klass so it
// will only be called once.
Runtime::Current()->GetRuntimeCallbacks()->ClassPreDefine(descriptor,
@@ -2765,7 +3157,7 @@ ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self,
}
uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
- const DexFile::ClassDef& dex_class_def) {
+ const dex::ClassDef& dex_class_def) {
size_t num_ref = 0;
size_t num_8 = 0;
size_t num_16 = 0;
@@ -2783,7 +3175,7 @@ uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
continue;
}
last_field_idx = field_idx;
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+ const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id);
char c = descriptor[0];
switch (c) {
@@ -3012,7 +3404,7 @@ static void LinkCode(ClassLinker* class_linker,
}
void ClassLinker::SetupClass(const DexFile& dex_file,
- const DexFile::ClassDef& dex_class_def,
+ const dex::ClassDef& dex_class_def,
Handle<mirror::Class> klass,
ObjPtr<mirror::ClassLoader> class_loader) {
CHECK(klass != nullptr);
@@ -3093,9 +3485,11 @@ LinearAlloc* ClassLinker::GetOrCreateAllocatorForClassLoader(ObjPtr<mirror::Clas
void ClassLinker::LoadClass(Thread* self,
const DexFile& dex_file,
- const DexFile::ClassDef& dex_class_def,
+ const dex::ClassDef& dex_class_def,
Handle<mirror::Class> klass) {
- ClassAccessor accessor(dex_file, dex_class_def);
+ ClassAccessor accessor(dex_file,
+ dex_class_def,
+ /* parse_hiddenapi_class_data= */ klass->IsBootStrapClassLoaded());
if (!accessor.HasClassData()) {
return;
}
@@ -3207,14 +3601,8 @@ void ClassLinker::LoadField(const ClassAccessor::Field& field,
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
- // Get access flags from the DexFile. If this is a boot class path class,
- // also set its runtime hidden API access flags.
- uint32_t access_flags = field.GetAccessFlags();
- if (klass->IsBootStrapClassLoaded()) {
- access_flags =
- HiddenApiAccessFlags::EncodeForRuntime(access_flags, field.DecodeHiddenAccessFlags());
- }
- dst->SetAccessFlags(access_flags);
+ // Get access flags from the DexFile and set hiddenapi runtime access flags.
+ dst->SetAccessFlags(field.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(field));
}
void ClassLinker::LoadMethod(const DexFile& dex_file,
@@ -3222,7 +3610,7 @@ void ClassLinker::LoadMethod(const DexFile& dex_file,
Handle<mirror::Class> klass,
ArtMethod* dst) {
const uint32_t dex_method_idx = method.GetIndex();
- const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
+ const dex::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
ScopedAssertNoThreadSuspension ants("LoadMethod");
@@ -3230,14 +3618,8 @@ void ClassLinker::LoadMethod(const DexFile& dex_file,
dst->SetDeclaringClass(klass.Get());
dst->SetCodeItemOffset(method.GetCodeItemOffset());
- // Get access flags from the DexFile. If this is a boot class path class,
- // also set its runtime hidden API access flags.
- uint32_t access_flags = method.GetAccessFlags();
-
- if (klass->IsBootStrapClassLoaded()) {
- access_flags =
- HiddenApiAccessFlags::EncodeForRuntime(access_flags, method.DecodeHiddenAccessFlags());
- }
+ // Get access flags from the DexFile and set hiddenapi runtime access flags.
+ uint32_t access_flags = method.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(method);
if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
// Set finalizable flag on declaring class.
@@ -3279,6 +3661,10 @@ void ClassLinker::LoadMethod(const DexFile& dex_file,
dex_file, dst->GetClassDef(), dex_method_idx);
}
dst->SetAccessFlags(access_flags);
+ // Must be done after SetAccessFlags since IsAbstract depends on it.
+ if (klass->IsInterface() && dst->IsAbstract()) {
+ dst->CalculateAndSetImtIndex();
+ }
}
void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) {
@@ -3295,7 +3681,7 @@ void ClassLinker::AppendToBootClassPath(const DexFile& dex_file,
CHECK(dex_cache != nullptr) << dex_file.GetLocation();
boot_class_path_.push_back(&dex_file);
WriterMutexLock mu(Thread::Current(), *Locks::dex_lock_);
- RegisterDexFileLocked(dex_file, dex_cache, /* class_loader */ nullptr);
+ RegisterDexFileLocked(dex_file, dex_cache, /* class_loader= */ nullptr);
}
void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
@@ -3374,8 +3760,7 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
data.weak_root = dex_cache_jweak;
data.dex_file = dex_cache->GetDexFile();
data.class_table = ClassTableForClassLoader(class_loader);
- AddNativeDebugInfoForDex(self, ArrayRef<const uint8_t>(data.dex_file->Begin(),
- data.dex_file->Size()));
+ AddNativeDebugInfoForDex(self, data.dex_file);
DCHECK(data.class_table != nullptr);
// Make sure to hold the dex cache live in the class table. This case happens for the boot class
// path dex caches without an image.
@@ -3585,6 +3970,7 @@ ObjPtr<mirror::Class> ClassLinker::CreatePrimitiveClass(Thread* self, Primitive:
h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
h_class->SetPrimitiveType(type);
h_class->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable());
+ EnsureSkipAccessChecksMethods</* kNeedsVerified= */ true>(h_class, image_pointer_size_);
mirror::Class::SetStatus(h_class, ClassStatus::kInitialized, self);
const char* descriptor = Primitive::Descriptor(type);
ObjPtr<mirror::Class> existing = InsertClass(descriptor,
@@ -3618,6 +4004,18 @@ ObjPtr<mirror::Class> ClassLinker::CreateArrayClass(Thread* self,
// Identify the underlying component type
CHECK_EQ('[', descriptor[0]);
StackHandleScope<2> hs(self);
+
+ // This is to prevent the calls to ClassLoad and ClassPrepare which can cause java/user-supplied
+ // code to be executed. We put it up here so we can avoid all the allocations associated with
+ // creating the class. This can happen with (eg) jit threads.
+ if (!self->CanLoadClasses()) {
+ // Make sure we don't try to load anything, potentially causing an infinite loop.
+ ObjPtr<mirror::Throwable> pre_allocated =
+ Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(pre_allocated);
+ return nullptr;
+ }
+
MutableHandle<mirror::Class> component_type(hs.NewHandle(FindClass(self, descriptor + 1,
class_loader)));
if (component_type == nullptr) {
@@ -3720,6 +4118,7 @@ ObjPtr<mirror::Class> ClassLinker::CreateArrayClass(Thread* self,
new_class->PopulateEmbeddedVTable(image_pointer_size_);
ImTable* object_imt = java_lang_Object->GetImt(image_pointer_size_);
new_class->SetImt(object_imt, image_pointer_size_);
+ EnsureSkipAccessChecksMethods</* kNeedsVerified= */ true>(new_class, image_pointer_size_);
mirror::Class::SetStatus(new_class, ClassStatus::kInitialized, self);
// don't need to set new_class->SetObjectSize(..)
// because Object::SizeOf delegates to Array::SizeOf
@@ -3750,6 +4149,8 @@ ObjPtr<mirror::Class> ClassLinker::CreateArrayClass(Thread* self,
// and remove "interface".
access_flags |= kAccAbstract | kAccFinal;
access_flags &= ~kAccInterface;
+ // Arrays are access-checks-clean and preverified.
+ access_flags |= kAccVerificationAttempted;
new_class->SetAccessFlags(access_flags);
@@ -3773,38 +4174,37 @@ ObjPtr<mirror::Class> ClassLinker::CreateArrayClass(Thread* self,
return existing;
}
-ObjPtr<mirror::Class> ClassLinker::FindPrimitiveClass(char type) {
- ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = GetClassRoots();
+ObjPtr<mirror::Class> ClassLinker::LookupPrimitiveClass(char type) {
+ ClassRoot class_root;
switch (type) {
- case 'B':
- return GetClassRoot(ClassRoot::kPrimitiveByte, class_roots);
- case 'C':
- return GetClassRoot(ClassRoot::kPrimitiveChar, class_roots);
- case 'D':
- return GetClassRoot(ClassRoot::kPrimitiveDouble, class_roots);
- case 'F':
- return GetClassRoot(ClassRoot::kPrimitiveFloat, class_roots);
- case 'I':
- return GetClassRoot(ClassRoot::kPrimitiveInt, class_roots);
- case 'J':
- return GetClassRoot(ClassRoot::kPrimitiveLong, class_roots);
- case 'S':
- return GetClassRoot(ClassRoot::kPrimitiveShort, class_roots);
- case 'Z':
- return GetClassRoot(ClassRoot::kPrimitiveBoolean, class_roots);
- case 'V':
- return GetClassRoot(ClassRoot::kPrimitiveVoid, class_roots);
+ case 'B': class_root = ClassRoot::kPrimitiveByte; break;
+ case 'C': class_root = ClassRoot::kPrimitiveChar; break;
+ case 'D': class_root = ClassRoot::kPrimitiveDouble; break;
+ case 'F': class_root = ClassRoot::kPrimitiveFloat; break;
+ case 'I': class_root = ClassRoot::kPrimitiveInt; break;
+ case 'J': class_root = ClassRoot::kPrimitiveLong; break;
+ case 'S': class_root = ClassRoot::kPrimitiveShort; break;
+ case 'Z': class_root = ClassRoot::kPrimitiveBoolean; break;
+ case 'V': class_root = ClassRoot::kPrimitiveVoid; break;
default:
- break;
+ return nullptr;
}
- std::string printable_type(PrintableChar(type));
- ThrowNoClassDefFoundError("Not a primitive type: %s", printable_type.c_str());
- return nullptr;
+ return GetClassRoot(class_root, this);
+}
+
+ObjPtr<mirror::Class> ClassLinker::FindPrimitiveClass(char type) {
+ ObjPtr<mirror::Class> result = LookupPrimitiveClass(type);
+ if (UNLIKELY(result == nullptr)) {
+ std::string printable_type(PrintableChar(type));
+ ThrowNoClassDefFoundError("Not a primitive type: %s", printable_type.c_str());
+ }
+ return result;
}
ObjPtr<mirror::Class> ClassLinker::InsertClass(const char* descriptor,
ObjPtr<mirror::Class> klass,
size_t hash) {
+ DCHECK(Thread::Current()->CanLoadClasses());
if (VLOG_IS_ON(class_linker)) {
ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
std::string source;
@@ -3985,17 +4385,6 @@ bool ClassLinker::AttemptSupertypeVerification(Thread* self,
return false;
}
-// Ensures that methods have the kAccSkipAccessChecks bit set. We use the
-// kAccVerificationAttempted bit on the class access flags to determine whether this has been done
-// before.
-static void EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass, PointerSize pointer_size)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (!klass->WasVerificationAttempted()) {
- klass->SetSkipAccessChecksFlagOnAllMethods(pointer_size);
- klass->SetVerificationAttempted();
- }
-}
-
verifier::FailureKind ClassLinker::VerifyClass(
Thread* self, Handle<mirror::Class> klass, verifier::HardFailLogMode log_level) {
{
@@ -4329,6 +4718,18 @@ ObjPtr<mirror::Class> ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRun
jobjectArray methods,
jobjectArray throws) {
Thread* self = soa.Self();
+
+ // This is to prevent the calls to ClassLoad and ClassPrepare which can cause java/user-supplied
+ // code to be executed. We put it up here so we can avoid all the allocations associated with
+ // creating the class. This can happen with (eg) jit-threads.
+ if (!self->CanLoadClasses()) {
+ // Make sure we don't try to load anything, potentially causing an infinite loop.
+ ObjPtr<mirror::Throwable> pre_allocated =
+ Runtime::Current()->GetPreAllocatedNoClassDefFoundError();
+ self->SetException(pre_allocated);
+ return nullptr;
+ }
+
StackHandleScope<10> hs(self);
MutableHandle<mirror::Class> temp_klass(hs.NewHandle(
AllocClass(self, GetClassRoot<mirror::Class>(this), sizeof(mirror::Class))));
@@ -4460,6 +4861,7 @@ ObjPtr<mirror::Class> ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRun
{
// Lock on klass is released. Lock new class object.
ObjectLock<mirror::Class> initialization_lock(self, klass);
+ EnsureSkipAccessChecksMethods(klass, image_pointer_size_);
mirror::Class::SetStatus(klass, ClassStatus::kInitialized, self);
}
@@ -4589,7 +4991,7 @@ bool ClassLinker::CanWeInitializeClass(ObjPtr<mirror::Class> klass, bool can_ini
}
// Check if there are encoded static values needing initialization.
if (klass->NumStaticFields() != 0) {
- const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
+ const dex::ClassDef* dex_class_def = klass->GetClassDef();
DCHECK(dex_class_def != nullptr);
if (dex_class_def->static_values_off_ != 0) {
return false;
@@ -4646,7 +5048,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
// Was the class already found to be erroneous? Done under the lock to match the JLS.
if (klass->IsErroneous()) {
- ThrowEarlierClassFailure(klass.Get(), true);
+ ThrowEarlierClassFailure(klass.Get(), true, /* log= */ true);
VlogClassInitializationFailure(klass);
return false;
}
@@ -4678,7 +5080,10 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
} else {
CHECK(Runtime::Current()->IsAotCompiler());
CHECK_EQ(klass->GetStatus(), ClassStatus::kRetryVerificationAtRuntime);
+ self->AssertNoPendingException();
+ self->SetException(Runtime::Current()->GetPreAllocatedNoClassDefFoundError());
}
+ self->AssertPendingException();
return false;
} else {
self->AssertNoPendingException();
@@ -4803,7 +5208,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
const size_t num_static_fields = klass->NumStaticFields();
if (num_static_fields > 0) {
- const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
+ const dex::ClassDef* dex_class_def = klass->GetClassDef();
CHECK(dex_class_def != nullptr);
StackHandleScope<3> hs(self);
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
@@ -4817,8 +5222,10 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
ArtField* resolved_field = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
if (resolved_field == nullptr) {
// Populating cache of a dex file which defines `klass` should always be allowed.
- DCHECK_EQ(hiddenapi::GetMemberAction(
- field, class_loader.Get(), dex_cache.Get(), hiddenapi::kNone), hiddenapi::kAllow);
+ DCHECK(!hiddenapi::ShouldDenyAccessToMember(
+ field,
+ hiddenapi::AccessContext(class_loader.Get(), dex_cache.Get()),
+ hiddenapi::AccessMethod::kNone));
dex_cache->SetResolvedField(field_idx, field, image_pointer_size_);
} else {
DCHECK_EQ(field, resolved_field);
@@ -4841,7 +5248,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
ArtField* art_field = ResolveField(field.GetIndex(),
dex_cache,
class_loader,
- /* is_static */ true);
+ /* is_static= */ true);
if (Runtime::Current()->IsActiveTransaction()) {
value_it.ReadValueToField<true>(art_field);
} else {
@@ -5010,8 +5417,8 @@ static void ThrowSignatureCheckResolveReturnTypeException(Handle<mirror::Class>
DCHECK(Thread::Current()->IsExceptionPending());
DCHECK(!m->IsProxyMethod());
const DexFile* dex_file = m->GetDexFile();
- const DexFile::MethodId& method_id = dex_file->GetMethodId(m->GetDexMethodIndex());
- const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
+ const dex::MethodId& method_id = dex_file->GetMethodId(m->GetDexMethodIndex());
+ const dex::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
std::string return_type = dex_file->PrettyType(return_type_idx);
std::string class_loader = mirror::Object::PrettyTypeOf(m->GetDeclaringClass()->GetClassLoader());
@@ -5089,8 +5496,8 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self,
return false;
}
}
- const DexFile::TypeList* types1 = method1->GetParameterTypeList();
- const DexFile::TypeList* types2 = method2->GetParameterTypeList();
+ const dex::TypeList* types1 = method1->GetParameterTypeList();
+ const dex::TypeList* types2 = method2->GetParameterTypeList();
if (types1 == nullptr) {
if (types2 != nullptr && types2->Size() != 0) {
ThrowSignatureMismatch(klass, super_klass, method1,
@@ -5205,8 +5612,7 @@ bool ClassLinker::EnsureInitialized(Thread* self,
DCHECK(c != nullptr);
if (c->IsInitialized()) {
- EnsureSkipAccessChecksMethods(c, image_pointer_size_);
- self->AssertNoPendingException();
+ DCHECK(c->WasVerificationAttempted()) << c->PrettyClassAndClassLoader();
return true;
}
// SubtypeCheckInfo::Initialized must happen-before any new-instance for that type.
@@ -5450,7 +5856,7 @@ bool ClassLinker::LinkClass(Thread* self,
bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) {
CHECK_EQ(ClassStatus::kIdx, klass->GetStatus());
- const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
+ const dex::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
dex::TypeIndex super_class_idx = class_def.superclass_idx_;
if (super_class_idx.IsValid()) {
// Check that a class does not inherit from itself directly.
@@ -5481,7 +5887,7 @@ bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexF
CHECK(super_class->IsResolved());
klass->SetSuperClass(super_class);
}
- const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def);
+ const dex::TypeList* interfaces = dex_file.GetInterfacesList(class_def);
if (interfaces != nullptr) {
for (size_t i = 0; i < interfaces->Size(); i++) {
dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
@@ -5625,7 +6031,7 @@ class MethodNameAndSignatureComparator final : public ValueObject {
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(!other->IsProxyMethod()) << other->PrettyMethod();
const DexFile* other_dex_file = other->GetDexFile();
- const DexFile::MethodId& other_mid = other_dex_file->GetMethodId(other->GetDexMethodIndex());
+ const dex::MethodId& other_mid = other_dex_file->GetMethodId(other->GetDexMethodIndex());
if (dex_file_ == other_dex_file) {
return mid_->name_idx_ == other_mid.name_idx_ && mid_->proto_idx_ == other_mid.proto_idx_;
}
@@ -5643,7 +6049,7 @@ class MethodNameAndSignatureComparator final : public ValueObject {
// Dex file for the method to compare against.
const DexFile* const dex_file_;
// MethodId for the method to compare against.
- const DexFile::MethodId* const mid_;
+ const dex::MethodId* const mid_;
// Lazily computed name from the dex file's strings.
const char* name_;
// Lazily computed name length.
@@ -6241,8 +6647,8 @@ void ClassLinker::FillIMTAndConflictTables(ObjPtr<mirror::Class> klass) {
unimplemented_method,
conflict_method,
klass,
- /*create_conflict_tables*/true,
- /*ignore_copied_methods*/false,
+ /*create_conflict_tables=*/true,
+ /*ignore_copied_methods=*/false,
&new_conflict,
&imt_data[0]);
}
@@ -6340,7 +6746,7 @@ void ClassLinker::FillIMTFromIfTable(ObjPtr<mirror::IfTable> if_table,
// or interface methods in the IMT here they will not create extra conflicts since we compare
// names and signatures in SetIMTRef.
ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_);
- const uint32_t imt_index = ImTable::GetImtIndex(interface_method);
+ const uint32_t imt_index = interface_method->GetImtIndex();
// There is only any conflicts if all of the interface methods for an IMT slot don't have
// the same implementation method, keep track of this to avoid creating a conflict table in
@@ -6394,7 +6800,7 @@ void ClassLinker::FillIMTFromIfTable(ObjPtr<mirror::IfTable> if_table,
}
DCHECK(implementation_method != nullptr);
ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_);
- const uint32_t imt_index = ImTable::GetImtIndex(interface_method);
+ const uint32_t imt_index = interface_method->GetImtIndex();
if (!imt[imt_index]->IsRuntimeMethod() ||
imt[imt_index] == unimplemented_method ||
imt[imt_index] == imt_conflict_method) {
@@ -6446,7 +6852,7 @@ static bool NotSubinterfaceOfAny(
// iftable must be large enough to hold all interfaces without changing its size.
static size_t FillIfTable(ObjPtr<mirror::IfTable> iftable,
size_t super_ifcount,
- std::vector<ObjPtr<mirror::Class>> to_process)
+ const std::vector<ObjPtr<mirror::Class>>& to_process)
REQUIRES(Roles::uninterruptible_)
REQUIRES_SHARED(Locks::mutator_lock_) {
// This is the set of all class's already in the iftable. Used to make checking if a class has
@@ -6730,8 +7136,8 @@ void ClassLinker::FillImtFromSuperClass(Handle<mirror::Class> klass,
unimplemented_method,
imt_conflict_method,
klass.Get(),
- /*create_conflict_table*/false,
- /*ignore_copied_methods*/true,
+ /*create_conflict_tables=*/false,
+ /*ignore_copied_methods=*/true,
/*out*/new_conflict,
/*out*/imt);
}
@@ -7081,9 +7487,12 @@ void ClassLinker::LinkInterfaceMethodsHelper::ReallocMethods() {
// mark this as a default, non-abstract method, since thats what it is. Also clear the
// kAccSkipAccessChecks bit since this class hasn't been verified yet it shouldn't have
// methods that are skipping access checks.
+ // Also clear potential kAccSingleImplementation to avoid CHA trying to inline
+ // the default method.
DCHECK_EQ(new_method.GetAccessFlags() & kAccNative, 0u);
constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict | kAccCopied;
- constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccSkipAccessChecks);
+ constexpr uint32_t kMaskFlags =
+ ~(kAccAbstract | kAccSkipAccessChecks | kAccSingleImplementation);
new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags);
DCHECK(new_method.IsDefaultConflicting());
// The actual method might or might not be marked abstract since we just copied it from a
@@ -7317,7 +7726,7 @@ bool ClassLinker::LinkInterfaceMethods(
auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j, image_pointer_size_);
MethodNameAndSignatureComparator interface_name_comparator(
interface_method->GetInterfaceMethodIfProxy(image_pointer_size_));
- uint32_t imt_index = ImTable::GetImtIndex(interface_method);
+ uint32_t imt_index = interface_method->GetImtIndex();
ArtMethod** imt_ptr = &out_imt[imt_index];
// For each method listed in the interface's method list, find the
// matching method in our class's method list. We want to favor the
@@ -7776,7 +8185,7 @@ ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx,
if (descriptor[1] == '\0') {
// only the descriptors of primitive types should be 1 character long, also avoid class lookup
// for primitive classes that aren't backed by dex files.
- type = FindPrimitiveClass(descriptor[0]);
+ type = LookupPrimitiveClass(descriptor[0]);
} else {
Thread* const self = Thread::Current();
DCHECK(self != nullptr);
@@ -7794,14 +8203,22 @@ ObjPtr<mirror::Class> ClassLinker::DoLookupResolvedType(dex::TypeIndex type_idx,
return type;
}
-ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
- ObjPtr<mirror::Class> referrer) {
+template <typename T>
+ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx, T referrer) {
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
return DoResolveType(type_idx, dex_cache, class_loader);
}
+// Instantiate the above.
+template ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
+ ArtField* referrer);
+template ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
+ ArtMethod* referrer);
+template ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> referrer);
+
ObjPtr<mirror::Class> ClassLinker::DoResolveType(dex::TypeIndex type_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader) {
@@ -7846,8 +8263,9 @@ ArtMethod* ClassLinker::FindResolvedMethod(ObjPtr<mirror::Class> klass,
}
DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr);
if (resolved != nullptr &&
- hiddenapi::GetMemberAction(
- resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) {
+ hiddenapi::ShouldDenyAccessToMember(resolved,
+ hiddenapi::AccessContext(class_loader, dex_cache),
+ hiddenapi::AccessMethod::kLinking)) {
resolved = nullptr;
}
if (resolved != nullptr) {
@@ -7877,11 +8295,9 @@ static bool CheckNoSuchMethod(ArtMethod* method,
ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_) {
return method == nullptr ||
- hiddenapi::GetMemberAction(method,
- class_loader,
- dex_cache,
- hiddenapi::kNone) // do not print warnings
- == hiddenapi::kDeny;
+ hiddenapi::ShouldDenyAccessToMember(method,
+ hiddenapi::AccessContext(class_loader, dex_cache),
+ hiddenapi::AccessMethod::kNone); // no warnings
}
ArtMethod* ClassLinker::FindIncompatibleMethod(ObjPtr<mirror::Class> klass,
@@ -7924,7 +8340,7 @@ ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
return resolved;
}
const DexFile& dex_file = *dex_cache->GetDexFile();
- const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
+ const dex::MethodId& method_id = dex_file.GetMethodId(method_idx);
ObjPtr<mirror::Class> klass = nullptr;
if (valid_dex_cache_method) {
// We have a valid method from the DexCache but we need to perform ICCE and IAE checks.
@@ -7946,7 +8362,7 @@ ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
// Check if the invoke type matches the class type.
if (kResolveMode == ResolveMode::kCheckICCEAndIAE &&
- CheckInvokeClassMismatch</* kThrow */ true>(
+ CheckInvokeClassMismatch</* kThrow= */ true>(
dex_cache.Get(), type, [klass]() { return klass; })) {
DCHECK(Thread::Current()->IsExceptionPending());
return nullptr;
@@ -8005,7 +8421,7 @@ ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(uint32_t method_idx,
return resolved;
}
// Fail, get the declaring class.
- const DexFile::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
+ const dex::MethodId& method_id = dex_cache->GetDexFile()->GetMethodId(method_idx);
ObjPtr<mirror::Class> klass = ResolveType(method_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
Thread::Current()->AssertPendingException();
@@ -8017,8 +8433,10 @@ ArtMethod* ClassLinker::ResolveMethodWithoutInvokeType(uint32_t method_idx,
resolved = klass->FindClassMethod(dex_cache.Get(), method_idx, image_pointer_size_);
}
if (resolved != nullptr &&
- hiddenapi::GetMemberAction(
- resolved, class_loader.Get(), dex_cache.Get(), hiddenapi::kLinking) == hiddenapi::kDeny) {
+ hiddenapi::ShouldDenyAccessToMember(
+ resolved,
+ hiddenapi::AccessContext(class_loader.Get(), dex_cache.Get()),
+ hiddenapi::AccessMethod::kLinking)) {
resolved = nullptr;
}
return resolved;
@@ -8029,7 +8447,7 @@ ArtField* ClassLinker::LookupResolvedField(uint32_t field_idx,
ObjPtr<mirror::ClassLoader> class_loader,
bool is_static) {
const DexFile& dex_file = *dex_cache->GetDexFile();
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+ const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(field_id.class_idx_);
if (klass == nullptr) {
klass = LookupResolvedType(field_id.class_idx_, dex_cache, class_loader);
@@ -8054,7 +8472,7 @@ ArtField* ClassLinker::ResolveField(uint32_t field_idx,
return resolved;
}
const DexFile& dex_file = *dex_cache->GetDexFile();
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+ const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
@@ -8080,7 +8498,7 @@ ArtField* ClassLinker::ResolveFieldJLS(uint32_t field_idx,
return resolved;
}
const DexFile& dex_file = *dex_cache->GetDexFile();
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+ const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
ObjPtr<mirror::Class> klass = ResolveType(field_id.class_idx_, dex_cache, class_loader);
if (klass == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
@@ -8109,7 +8527,7 @@ ArtField* ClassLinker::FindResolvedField(ObjPtr<mirror::Class> klass,
: klass->FindInstanceField(dex_cache, field_idx);
if (resolved == nullptr) {
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+ const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
const char* name = dex_file.GetFieldName(field_id);
const char* type = dex_file.GetFieldTypeDescriptor(field_id);
resolved = is_static ? mirror::Class::FindStaticField(self, klass, name, type)
@@ -8117,8 +8535,9 @@ ArtField* ClassLinker::FindResolvedField(ObjPtr<mirror::Class> klass,
}
if (resolved != nullptr &&
- hiddenapi::GetMemberAction(
- resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) {
+ hiddenapi::ShouldDenyAccessToMember(resolved,
+ hiddenapi::AccessContext(class_loader, dex_cache),
+ hiddenapi::AccessMethod::kLinking)) {
resolved = nullptr;
}
@@ -8136,15 +8555,16 @@ ArtField* ClassLinker::FindResolvedFieldJLS(ObjPtr<mirror::Class> klass,
ArtField* resolved = nullptr;
Thread* self = Thread::Current();
const DexFile& dex_file = *dex_cache->GetDexFile();
- const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx);
+ const dex::FieldId& field_id = dex_file.GetFieldId(field_idx);
const char* name = dex_file.GetFieldName(field_id);
const char* type = dex_file.GetFieldTypeDescriptor(field_id);
resolved = mirror::Class::FindField(self, klass, name, type);
if (resolved != nullptr &&
- hiddenapi::GetMemberAction(
- resolved, class_loader, dex_cache, hiddenapi::kLinking) == hiddenapi::kDeny) {
+ hiddenapi::ShouldDenyAccessToMember(resolved,
+ hiddenapi::AccessContext(class_loader, dex_cache),
+ hiddenapi::AccessMethod::kLinking)) {
resolved = nullptr;
}
@@ -8172,7 +8592,7 @@ ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(
// First resolve the return type.
const DexFile& dex_file = *dex_cache->GetDexFile();
- const DexFile::ProtoId& proto_id = dex_file.GetProtoId(proto_idx);
+ const dex::ProtoId& proto_id = dex_file.GetProtoId(proto_idx);
Handle<mirror::Class> return_type(hs.NewHandle(
ResolveType(proto_id.return_type_idx_, dex_cache, class_loader)));
if (return_type == nullptr) {
@@ -8228,7 +8648,7 @@ ObjPtr<mirror::MethodType> ClassLinker::ResolveMethodType(Thread* self,
mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
Thread* self,
- const DexFile::MethodHandleItem& method_handle,
+ const dex::MethodHandleItem& method_handle,
ArtMethod* referrer) {
DexFile::MethodHandleType handle_type =
static_cast<DexFile::MethodHandleType>(method_handle.method_handle_type_);
@@ -8305,7 +8725,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
switch (handle_type) {
case DexFile::MethodHandleType::kStaticPut: {
method_params->Set(0, target_field->ResolveType());
- return_type = hs.NewHandle(FindPrimitiveClass('V'));
+ return_type = hs.NewHandle(GetClassRoot(ClassRoot::kPrimitiveVoid, this));
break;
}
case DexFile::MethodHandleType::kStaticGet: {
@@ -8315,7 +8735,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
case DexFile::MethodHandleType::kInstancePut: {
method_params->Set(0, target_field->GetDeclaringClass());
method_params->Set(1, target_field->ResolveType());
- return_type = hs.NewHandle(FindPrimitiveClass('V'));
+ return_type = hs.NewHandle(GetClassRoot(ClassRoot::kPrimitiveVoid, this));
break;
}
case DexFile::MethodHandleType::kInstanceGet: {
@@ -8356,7 +8776,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
Thread* self,
- const DexFile::MethodHandleItem& method_handle,
+ const dex::MethodHandleItem& method_handle,
ArtMethod* referrer) {
DexFile::MethodHandleType handle_type =
static_cast<DexFile::MethodHandleType>(method_handle.method_handle_type_);
@@ -8469,7 +8889,7 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
target_method->GetShorty(&shorty_length);
int32_t num_params = static_cast<int32_t>(shorty_length + receiver_count - 1);
- StackHandleScope<7> hs(self);
+ StackHandleScope<5> hs(self);
ObjPtr<mirror::Class> array_of_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(this);
Handle<mirror::ObjectArray<mirror::Class>> method_params(hs.NewHandle(
mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, num_params)));
@@ -8478,20 +8898,25 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
return nullptr;
}
+ const DexFile* dex_file = referrer->GetDexFile();
+ const dex::MethodId& method_id = dex_file->GetMethodId(method_handle.field_or_method_idx_);
int32_t index = 0;
if (receiver_count != 0) {
- // Insert receiver
- method_params->Set(index++, target_method->GetDeclaringClass());
+ // Insert receiver. Use the class identified in the method handle rather than the declaring
+ // class of the resolved method which may be super class or default interface method
+ // (b/115964401).
+ ObjPtr<mirror::Class> receiver_class = LookupResolvedType(method_id.class_idx_, referrer);
+ // receiver_class should have been resolved when resolving the target method.
+ DCHECK(receiver_class != nullptr);
+ method_params->Set(index++, receiver_class);
}
- DexFileParameterIterator it(*target_method->GetDexFile(), target_method->GetPrototype());
- Handle<mirror::DexCache> target_method_dex_cache(hs.NewHandle(target_method->GetDexCache()));
- Handle<mirror::ClassLoader> target_method_class_loader(hs.NewHandle(target_method->GetClassLoader()));
+
+ const dex::ProtoId& proto_id = dex_file->GetProtoId(method_id.proto_idx_);
+ DexFileParameterIterator it(*dex_file, proto_id);
while (it.HasNext()) {
DCHECK_LT(index, num_params);
const dex::TypeIndex type_idx = it.GetTypeIdx();
- ObjPtr<mirror::Class> klass = ResolveType(type_idx,
- target_method_dex_cache,
- target_method_class_loader);
+ ObjPtr<mirror::Class> klass = ResolveType(type_idx, referrer);
if (nullptr == klass) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -8500,7 +8925,8 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
it.Next();
}
- Handle<mirror::Class> return_type = hs.NewHandle(target_method->ResolveReturnType());
+ Handle<mirror::Class> return_type =
+ hs.NewHandle(ResolveType(proto_id.return_type_idx_, referrer));
if (UNLIKELY(return_type.IsNull())) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -8529,7 +8955,7 @@ ObjPtr<mirror::MethodHandle> ClassLinker::ResolveMethodHandle(Thread* self,
ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_) {
const DexFile* const dex_file = referrer->GetDexFile();
- const DexFile::MethodHandleItem& method_handle = dex_file->GetMethodHandle(method_handle_idx);
+ const dex::MethodHandleItem& method_handle = dex_file->GetMethodHandle(method_handle_idx);
switch (static_cast<DexFile::MethodHandleType>(method_handle.method_handle_type_)) {
case DexFile::MethodHandleType::kStaticPut:
case DexFile::MethodHandleType::kStaticGet:
@@ -8590,6 +9016,49 @@ void ClassLinker::DumpForSigQuit(std::ostream& os) {
ReaderMutexLock mu(soa.Self(), *Locks::classlinker_classes_lock_);
os << "Zygote loaded classes=" << NumZygoteClasses() << " post zygote classes="
<< NumNonZygoteClasses() << "\n";
+ ReaderMutexLock mu2(soa.Self(), *Locks::dex_lock_);
+ os << "Dumping registered class loaders\n";
+ size_t class_loader_index = 0;
+ for (const ClassLoaderData& class_loader : class_loaders_) {
+ ObjPtr<mirror::ClassLoader> loader =
+ ObjPtr<mirror::ClassLoader>::DownCast(soa.Self()->DecodeJObject(class_loader.weak_root));
+ if (loader != nullptr) {
+ os << "#" << class_loader_index++ << " " << loader->GetClass()->PrettyDescriptor() << ": [";
+ bool saw_one_dex_file = false;
+ for (const DexCacheData& dex_cache : dex_caches_) {
+ if (dex_cache.IsValid() && dex_cache.class_table == class_loader.class_table) {
+ if (saw_one_dex_file) {
+ os << ":";
+ }
+ saw_one_dex_file = true;
+ os << dex_cache.dex_file->GetLocation();
+ }
+ }
+ os << "]";
+ bool found_parent = false;
+ if (loader->GetParent() != nullptr) {
+ size_t parent_index = 0;
+ for (const ClassLoaderData& class_loader2 : class_loaders_) {
+ ObjPtr<mirror::ClassLoader> loader2 = ObjPtr<mirror::ClassLoader>::DownCast(
+ soa.Self()->DecodeJObject(class_loader2.weak_root));
+ if (loader2 == loader->GetParent()) {
+ os << ", parent #" << parent_index;
+ found_parent = true;
+ break;
+ }
+ parent_index++;
+ }
+ if (!found_parent) {
+ os << ", unregistered parent of type "
+ << loader->GetParent()->GetClass()->PrettyDescriptor();
+ }
+ } else {
+ os << ", no parent";
+ }
+ os << "\n";
+ }
+ }
+ os << "Done dumping class loaders\n";
}
class CountClassesVisitor : public ClassLoaderVisitor {
@@ -8662,21 +9131,14 @@ void ClassLinker::AllocAndSetPrimitiveArrayClassRoot(Thread* self,
CheckSystemClass(self, primitive_array_class, descriptor);
}
-jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
- const std::vector<const DexFile*>& dex_files,
- jclass loader_class,
- jobject parent_loader) {
- CHECK(self->GetJniEnv()->IsSameObject(loader_class,
- WellKnownClasses::dalvik_system_PathClassLoader) ||
- self->GetJniEnv()->IsSameObject(loader_class,
- WellKnownClasses::dalvik_system_DelegateLastClassLoader));
-
- // SOAAlreadyRunnable is protected, and we need something to add a global reference.
- // We could move the jobject to the callers, but all call-sites do this...
- ScopedObjectAccessUnchecked soa(self);
+ObjPtr<mirror::ClassLoader> ClassLinker::CreateWellKnownClassLoader(
+ Thread* self,
+ const std::vector<const DexFile*>& dex_files,
+ Handle<mirror::Class> loader_class,
+ Handle<mirror::ClassLoader> parent_loader,
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries) {
- // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
- StackHandleScope<6> hs(self);
+ StackHandleScope<5> hs(self);
ArtField* dex_elements_field =
jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements);
@@ -8712,7 +9174,7 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
self,
kDexFileIndexStart + 1));
DCHECK(h_long_array != nullptr);
- h_long_array->Set(kDexFileIndexStart, reinterpret_cast<intptr_t>(dex_file));
+ h_long_array->Set(kDexFileIndexStart, reinterpret_cast64<int64_t>(dex_file));
// Note that this creates a finalizable dalvik.system.DexFile object and a corresponding
// FinalizerReference which will never get cleaned up without a started runtime.
@@ -8766,8 +9228,8 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
}
// Create the class loader..
- Handle<mirror::Class> h_loader_class = hs.NewHandle(soa.Decode<mirror::Class>(loader_class));
- Handle<mirror::Object> h_class_loader = hs.NewHandle(h_loader_class->AllocObject(self));
+ Handle<mirror::ClassLoader> h_class_loader = hs.NewHandle<mirror::ClassLoader>(
+ ObjPtr<mirror::ClassLoader>::DownCast(loader_class->AllocObject(self)));
DCHECK(h_class_loader != nullptr);
// Set DexPathList.
ArtField* path_list_field =
@@ -8783,15 +9245,57 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
"parent",
"Ljava/lang/ClassLoader;");
DCHECK(parent_field != nullptr);
+ if (parent_loader.Get() == nullptr) {
+ ScopedObjectAccessUnchecked soa(self);
+ ObjPtr<mirror::Object> boot_loader(soa.Decode<mirror::Class>(
+ WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self));
+ parent_field->SetObject<false>(h_class_loader.Get(), boot_loader);
+ } else {
+ parent_field->SetObject<false>(h_class_loader.Get(), parent_loader.Get());
+ }
+
+ ArtField* shared_libraries_field =
+ jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+ DCHECK(shared_libraries_field != nullptr);
+ shared_libraries_field->SetObject<false>(h_class_loader.Get(), shared_libraries.Get());
+
+ return h_class_loader.Get();
+}
+
+jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
+ const std::vector<const DexFile*>& dex_files,
+ jclass loader_class,
+ jobject parent_loader,
+ jobject shared_libraries) {
+ CHECK(self->GetJniEnv()->IsSameObject(loader_class,
+ WellKnownClasses::dalvik_system_PathClassLoader) ||
+ self->GetJniEnv()->IsSameObject(loader_class,
+ WellKnownClasses::dalvik_system_DelegateLastClassLoader));
+
+ // SOAAlreadyRunnable is protected, and we need something to add a global reference.
+ // We could move the jobject to the callers, but all call-sites do this...
+ ScopedObjectAccessUnchecked soa(self);
+
+ // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
+ StackHandleScope<4> hs(self);
- ObjPtr<mirror::Object> parent = (parent_loader != nullptr)
- ? soa.Decode<mirror::ClassLoader>(parent_loader)
- : soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
- parent_field->SetObject<false>(h_class_loader.Get(), parent);
+ Handle<mirror::Class> h_loader_class =
+ hs.NewHandle<mirror::Class>(soa.Decode<mirror::Class>(loader_class));
+ Handle<mirror::ClassLoader> h_parent =
+ hs.NewHandle<mirror::ClassLoader>(soa.Decode<mirror::ClassLoader>(parent_loader));
+ Handle<mirror::ObjectArray<mirror::ClassLoader>> h_shared_libraries =
+ hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::ClassLoader>>(shared_libraries));
+
+ ObjPtr<mirror::ClassLoader> loader = CreateWellKnownClassLoader(
+ self,
+ dex_files,
+ h_loader_class,
+ h_parent,
+ h_shared_libraries);
// Make it a global ref and return.
ScopedLocalRef<jobject> local_ref(
- soa.Env(), soa.Env()->AddLocalReference<jobject>(h_class_loader.Get()));
+ soa.Env(), soa.Env()->AddLocalReference<jobject>(loader));
return soa.Env()->NewGlobalRef(local_ref.get());
}
@@ -8865,7 +9369,7 @@ void ClassLinker::CleanupClassLoaders() {
}
for (ClassLoaderData& data : to_delete) {
// CHA unloading analysis and SingleImplementaion cleanups are required.
- DeleteClassLoader(self, data, true /*cleanup_cha*/);
+ DeleteClassLoader(self, data, /*cleanup_cha=*/ true);
}
}
@@ -9011,11 +9515,11 @@ template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kNoChec
InvokeType type);
// Instantiate ClassLinker::AllocClass.
-template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable */ true>(
+template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable= */ true>(
Thread* self,
ObjPtr<mirror::Class> java_lang_Class,
uint32_t class_size);
-template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable */ false>(
+template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable= */ false>(
Thread* self,
ObjPtr<mirror::Class> java_lang_Class,
uint32_t class_size);