diff options
Diffstat (limited to 'runtime/class_linker.cc')
| -rw-r--r-- | runtime/class_linker.cc | 456 |
1 files changed, 341 insertions, 115 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 928645ac0f..a19085f5b5 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -55,6 +55,7 @@ #include "gc_root-inl.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap-inl.h" +#include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" #include "gc/scoped_gc_critical_section.h" #include "gc/space/image_space.h" @@ -88,6 +89,7 @@ #include "mirror/method_handles_lookup.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "mirror/object-refvisitor-inl.h" #include "mirror/proxy.h" #include "mirror/reference-inl.h" #include "mirror/stack_trace_element.h" @@ -1193,6 +1195,63 @@ class VerifyDeclaringClassVisitor : public ArtMethodVisitor { gc::accounting::HeapBitmap* const live_bitmap_; }; +class FixupInternVisitor { + public: + ALWAYS_INLINE ObjPtr<mirror::Object> TryInsertIntern(mirror::Object* obj) const + REQUIRES_SHARED(Locks::mutator_lock_) { + if (obj != nullptr && obj->IsString()) { + const auto intern = Runtime::Current()->GetInternTable()->InternStrong(obj->AsString()); + return intern; + } + return obj; + } + + ALWAYS_INLINE void VisitRootIfNonNull( + mirror::CompressedReference<mirror::Object>* root) const + REQUIRES_SHARED(Locks::mutator_lock_) { + if (!root->IsNull()) { + VisitRoot(root); + } + } + + ALWAYS_INLINE void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const + REQUIRES_SHARED(Locks::mutator_lock_) { + root->Assign(TryInsertIntern(root->AsMirrorPtr())); + } + + // Visit Class Fields + ALWAYS_INLINE 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)); + } + } + + 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); + } + + 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); + } + } +}; + // Copies data from one array to another array at the same position // if pred returns false. If there is a page of continuous data in // the src array for which pred consistently returns true then @@ -1285,6 +1344,7 @@ bool AppImageClassLoadersAndDexCachesHelper::Update( return false; } } + // Only add the classes to the class loader after the points where we can return false. for (size_t i = 0; i < num_dex_caches; i++) { ObjPtr<mirror::DexCache> dex_cache = dex_caches->Get(i); @@ -1448,6 +1508,21 @@ bool AppImageClassLoadersAndDexCachesHelper::Update( } } } + { + // 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.GetImageSection(ImageHeader::kSectionObjects); + + 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()); + + FixupInternVisitor fixup_intern_visitor; + bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_intern_visitor); + } if (*out_forward_dex_cache_array) { ScopedTrace timing("Fixup ArtMethod dex cache arrays"); FixupArtMethodArrayVisitor visitor(header); @@ -2410,74 +2485,121 @@ ClassPathEntry FindInClassPath(const char* descriptor, return ClassPathEntry(nullptr, nullptr); } +// Returns true if the given class loader is either a PathClassLoader or a DexClassLoader. +// (they both have the same behaviour with respect to class lockup order) +static bool IsPathOrDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa, + Handle<mirror::ClassLoader> class_loader) + REQUIRES_SHARED(Locks::mutator_lock_) { + mirror::Class* class_loader_class = class_loader->GetClass(); + return + (class_loader_class == + soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader)) || + (class_loader_class == + soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_DexClassLoader)); +} + +static bool IsDelegateLastClassLoader(ScopedObjectAccessAlreadyRunnable& soa, + Handle<mirror::ClassLoader> class_loader) + REQUIRES_SHARED(Locks::mutator_lock_) { + mirror::Class* class_loader_class = class_loader->GetClass(); + return class_loader_class == + soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_DelegateLastClassLoader); +} + bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa, Thread* self, const char* descriptor, size_t hash, Handle<mirror::ClassLoader> class_loader, ObjPtr<mirror::Class>* result) { - // Termination case: boot class-loader. + // Termination case: boot class loader. if (IsBootClassLoader(soa, class_loader.Get())) { - // The boot class loader, search the boot class path. - ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_); - if (pair.second != nullptr) { - ObjPtr<mirror::Class> klass = LookupClass(self, descriptor, hash, nullptr); - if (klass != nullptr) { - *result = EnsureResolved(self, descriptor, klass); - } else { - *result = DefineClass(self, - descriptor, - hash, - ScopedNullHandle<mirror::ClassLoader>(), - *pair.first, - *pair.second); - } - if (*result == nullptr) { - CHECK(self->IsExceptionPending()) << descriptor; - self->ClearException(); - } - } else { - *result = nullptr; - } + *result = FindClassInBootClassLoaderClassPath(self, descriptor, hash); return true; } - // Unsupported class-loader? - if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) != - class_loader->GetClass()) { - // PathClassLoader is the most common case, so it's the one we check first. For secondary dex - // files, we also check DexClassLoader here. - if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_DexClassLoader) != - class_loader->GetClass()) { - *result = nullptr; - return false; + if (IsPathOrDexClassLoader(soa, class_loader)) { + // For regular path or dex class loader the search order is: + // - parent + // - class loader dex files + + // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension). + StackHandleScope<1> hs(self); + Handle<mirror::ClassLoader> h_parent(hs.NewHandle(class_loader->GetParent())); + if (!FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result)) { + return false; // One of the parents is not supported. + } + if (*result != nullptr) { + return true; // Found the class up the chain. } + + // Search the current class loader classpath. + *result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader); + return true; } - // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension). - StackHandleScope<4> hs(self); - Handle<mirror::ClassLoader> h_parent(hs.NewHandle(class_loader->GetParent())); - bool recursive_result = FindClassInBaseDexClassLoader(soa, - self, - descriptor, - hash, - h_parent, - result); + if (IsDelegateLastClassLoader(soa, class_loader)) { + // For delegate last, the search order is: + // - boot class path + // - class loader dex files + // - parent + *result = FindClassInBootClassLoaderClassPath(self, descriptor, hash); + if (*result != nullptr) { + return true; // The class is part of the boot class path. + } - if (!recursive_result) { - // Something wrong up the chain. - return false; + *result = FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader); + if (*result != nullptr) { + return true; // Found the class in the current class loader + } + + // Handles as RegisterDexFile may allocate dex caches (and cause thread suspension). + StackHandleScope<1> hs(self); + Handle<mirror::ClassLoader> h_parent(hs.NewHandle(class_loader->GetParent())); + return FindClassInBaseDexClassLoader(soa, self, descriptor, hash, h_parent, result); } - if (*result != nullptr) { - // Found the class up the chain. - return true; + // Unsupported class loader. + *result = nullptr; + return false; +} + +// Finds the class in the boot class loader. +// If the class is found the method returns the resolved class. Otherwise it returns null. +ObjPtr<mirror::Class> ClassLinker::FindClassInBootClassLoaderClassPath(Thread* self, + const char* descriptor, + size_t hash) { + ObjPtr<mirror::Class> result = nullptr; + ClassPathEntry pair = FindInClassPath(descriptor, hash, boot_class_path_); + if (pair.second != nullptr) { + ObjPtr<mirror::Class> klass = LookupClass(self, descriptor, hash, nullptr); + if (klass != nullptr) { + result = EnsureResolved(self, descriptor, klass); + } else { + result = DefineClass(self, + descriptor, + hash, + ScopedNullHandle<mirror::ClassLoader>(), + *pair.first, + *pair.second); + } + if (result == nullptr) { + CHECK(self->IsExceptionPending()) << descriptor; + self->ClearException(); + } } + return result; +} - // Handle this step. - // Handle as if this is the child PathClassLoader. - // The class loader is a PathClassLoader which inherits from BaseDexClassLoader. - // We need to get the DexPathList and loop through it. +ObjPtr<mirror::Class> ClassLinker::FindClassInBaseDexClassLoaderClassPath( + ScopedObjectAccessAlreadyRunnable& soa, + const char* descriptor, + size_t hash, + Handle<mirror::ClassLoader> class_loader) { + CHECK(IsPathOrDexClassLoader(soa, class_loader) || IsDelegateLastClassLoader(soa, class_loader)) + << "Unexpected class loader for descriptor " << descriptor; + + Thread* self = soa.Self(); ArtField* const cookie_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie); ArtField* const dex_file_field = @@ -2489,10 +2611,11 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl // DexPathList has an array dexElements of Elements[] which each contain a dex file. ObjPtr<mirror::Object> dex_elements_obj = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements)-> - GetObject(dex_path_list); + GetObject(dex_path_list); // Loop through each dalvik.system.DexPathList$Element's dalvik.system.DexFile and look // at the mCookie which is a DexFile vector. if (dex_elements_obj != nullptr) { + StackHandleScope<1> hs(self); Handle<mirror::ObjectArray<mirror::Object>> dex_elements = hs.NewHandle(dex_elements_obj->AsObjectArray<mirror::Object>()); for (int32_t i = 0; i < dex_elements->GetLength(); ++i) { @@ -2518,19 +2641,18 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl OatDexFile::FindClassDef(*cp_dex_file, descriptor, hash); if (dex_class_def != nullptr) { ObjPtr<mirror::Class> klass = DefineClass(self, - descriptor, - hash, - class_loader, - *cp_dex_file, - *dex_class_def); + descriptor, + hash, + class_loader, + *cp_dex_file, + *dex_class_def); if (klass == nullptr) { CHECK(self->IsExceptionPending()) << descriptor; self->ClearException(); // TODO: Is it really right to break here, and not check the other dex files? - return true; + return nullptr; } - *result = klass; - return true; + return klass; } } } @@ -2538,9 +2660,7 @@ bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnabl } self->AssertNoPendingException(); } - - // Result is still null from the parent call, no need to set it again... - return true; + return nullptr; } mirror::Class* ClassLinker::FindClass(Thread* self, @@ -4064,7 +4184,10 @@ verifier::FailureKind ClassLinker::VerifyClass( while (old_status == mirror::Class::kStatusVerifying || old_status == mirror::Class::kStatusVerifyingAtRuntime) { lock.WaitIgnoringInterrupts(); - CHECK(klass->IsErroneous() || (klass->GetStatus() > old_status)) + // WaitIgnoringInterrupts can still receive an interrupt and return early, in this + // case we may see the same status again. b/62912904. This is why the check is + // greater or equal. + CHECK(klass->IsErroneous() || (klass->GetStatus() >= old_status)) << "Class '" << klass->PrettyClass() << "' performed an illegal verification state transition from " << old_status << " to " << klass->GetStatus(); @@ -8253,65 +8376,139 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_id const DexFile* const dex_file = referrer->GetDexFile(); const DexFile::MethodHandleItem& mh = dex_file->GetMethodHandle(method_handle_idx); - union { - ArtField* field; - ArtMethod* method; - uintptr_t field_or_method; - } target; - uint32_t num_params; - mirror::MethodHandle::Kind kind; + ArtField* target_field = nullptr; + ArtMethod* target_method = nullptr; + DexFile::MethodHandleType handle_type = static_cast<DexFile::MethodHandleType>(mh.method_handle_type_); switch (handle_type) { case DexFile::MethodHandleType::kStaticPut: { + target_field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */); + break; + } + case DexFile::MethodHandleType::kStaticGet: { + target_field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */); + break; + } + case DexFile::MethodHandleType::kInstancePut: { + target_field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */); + break; + } + case DexFile::MethodHandleType::kInstanceGet: { + target_field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */); + break; + } + case DexFile::MethodHandleType::kInvokeStatic: { + target_method = ResolveMethod<kNoICCECheckForCache>(self, + mh.field_or_method_idx_, + referrer, + InvokeType::kStatic); + break; + } + case DexFile::MethodHandleType::kInvokeInstance: { + target_method = ResolveMethod<kNoICCECheckForCache>(self, + mh.field_or_method_idx_, + referrer, + InvokeType::kVirtual); + break; + } + case DexFile::MethodHandleType::kInvokeConstructor: { + UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform."; + break; + } + case DexFile::MethodHandleType::kInvokeDirect: { + target_method = ResolveMethod<kNoICCECheckForCache>(self, + mh.field_or_method_idx_, + referrer, + InvokeType::kDirect); + break; + } + case DexFile::MethodHandleType::kInvokeInterface: { + target_method = ResolveMethod<kNoICCECheckForCache>(self, + mh.field_or_method_idx_, + referrer, + InvokeType::kInterface); + break; + } + } + + if (target_field != nullptr) { + ObjPtr<mirror::Class> target_class = target_field->GetDeclaringClass(); + ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); + if (!referring_class->CanAccessMember(target_class, target_field->GetAccessFlags())) { + ThrowIllegalAccessErrorField(referring_class, target_field); + return nullptr; + } + } else if (target_method != nullptr) { + ObjPtr<mirror::Class> target_class = target_method->GetDeclaringClass(); + ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass(); + if (!referring_class->CanAccessMember(target_class, target_method->GetAccessFlags())) { + ThrowIllegalAccessErrorMethod(referring_class, target_method); + return nullptr; + } + } else { + // Common check for resolution failure. + DCHECK(Thread::Current()->IsExceptionPending()); + return nullptr; + } + + // Determine the kind and number of parameters after it's safe to + // follow the field or method pointer. + mirror::MethodHandle::Kind kind; + uint32_t num_params; + switch (handle_type) { + case DexFile::MethodHandleType::kStaticPut: { kind = mirror::MethodHandle::Kind::kStaticPut; - target.field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */); num_params = 1; break; } case DexFile::MethodHandleType::kStaticGet: { kind = mirror::MethodHandle::Kind::kStaticGet; - target.field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */); num_params = 0; break; } case DexFile::MethodHandleType::kInstancePut: { kind = mirror::MethodHandle::Kind::kInstancePut; - target.field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */); num_params = 2; break; } case DexFile::MethodHandleType::kInstanceGet: { kind = mirror::MethodHandle::Kind::kInstanceGet; - target.field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */); num_params = 1; break; } case DexFile::MethodHandleType::kInvokeStatic: { kind = mirror::MethodHandle::Kind::kInvokeStatic; - target.method = ResolveMethod<kNoICCECheckForCache>(self, - mh.field_or_method_idx_, - referrer, - InvokeType::kStatic); uint32_t shorty_length; - target.method->GetShorty(&shorty_length); - num_params = shorty_length - 1; // Remove 1 for return value. + target_method->GetShorty(&shorty_length); + num_params = shorty_length - 1; // Remove 1 for the return value. break; } case DexFile::MethodHandleType::kInvokeInstance: { kind = mirror::MethodHandle::Kind::kInvokeVirtual; - target.method = ResolveMethod<kNoICCECheckForCache>(self, - mh.field_or_method_idx_, - referrer, - InvokeType::kVirtual); uint32_t shorty_length; - target.method->GetShorty(&shorty_length); - num_params = shorty_length - 1; // Remove 1 for return value. + target_method->GetShorty(&shorty_length); + num_params = shorty_length; // Add 1 for the receiver, remove 1 for the return value. break; } case DexFile::MethodHandleType::kInvokeConstructor: { UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform."; num_params = 0; + break; + } + case DexFile::MethodHandleType::kInvokeDirect: { + kind = mirror::MethodHandle::Kind::kInvokeDirect; + uint32_t shorty_length; + target_method->GetShorty(&shorty_length); + num_params = shorty_length; // Add 1 for the receiver, remove 1 for the return value. + break; + } + case DexFile::MethodHandleType::kInvokeInterface: { + kind = mirror::MethodHandle::Kind::kInvokeInterface; + uint32_t shorty_length; + target_method->GetShorty(&shorty_length); + num_params = shorty_length; // Add 1 for the receiver, remove 1 for the return value. + break; } } @@ -8328,44 +8525,51 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_id Handle<mirror::Class> return_type; switch (handle_type) { case DexFile::MethodHandleType::kStaticPut: { - method_params->Set(0, target.field->GetType<true>()); + method_params->Set(0, target_field->GetType<true>()); return_type = hs.NewHandle(FindPrimitiveClass('V')); break; } case DexFile::MethodHandleType::kStaticGet: { - return_type = hs.NewHandle(target.field->GetType<true>()); + return_type = hs.NewHandle(target_field->GetType<true>()); break; } case DexFile::MethodHandleType::kInstancePut: { - method_params->Set(0, target.field->GetDeclaringClass()); - method_params->Set(1, target.field->GetType<true>()); + method_params->Set(0, target_field->GetDeclaringClass()); + method_params->Set(1, target_field->GetType<true>()); return_type = hs.NewHandle(FindPrimitiveClass('V')); break; } case DexFile::MethodHandleType::kInstanceGet: { - method_params->Set(0, target.field->GetDeclaringClass()); - return_type = hs.NewHandle(target.field->GetType<true>()); + method_params->Set(0, target_field->GetDeclaringClass()); + return_type = hs.NewHandle(target_field->GetType<true>()); break; } - case DexFile::MethodHandleType::kInvokeStatic: - case DexFile::MethodHandleType::kInvokeInstance: { + case DexFile::MethodHandleType::kInvokeDirect: + case DexFile::MethodHandleType::kInvokeInstance: + case DexFile::MethodHandleType::kInvokeInterface: + case DexFile::MethodHandleType::kInvokeStatic: { // TODO(oth): This will not work for varargs methods as this // requires instantiating a Transformer. This resolution step // would be best done in managed code rather than in the run // time (b/35235705) Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader())); - DexFileParameterIterator it(*dex_file, target.method->GetPrototype()); - for (int32_t i = 0; it.HasNext(); i++, it.Next()) { + DexFileParameterIterator it(*dex_file, target_method->GetPrototype()); + int32_t index = 0; + if (handle_type != DexFile::MethodHandleType::kInvokeStatic) { + method_params->Set(index++, target_method->GetDeclaringClass()); + } + while (it.HasNext()) { const dex::TypeIndex type_idx = it.GetTypeIdx(); mirror::Class* klass = ResolveType(*dex_file, type_idx, dex_cache, class_loader); if (nullptr == klass) { DCHECK(self->IsExceptionPending()); return nullptr; } - method_params->Set(i, klass); + method_params->Set(index++, klass); + it.Next(); } - return_type = hs.NewHandle(target.method->GetReturnType(true)); + return_type = hs.NewHandle(target_method->GetReturnType(true)); break; } case DexFile::MethodHandleType::kInvokeConstructor: { @@ -8385,7 +8589,14 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_id DCHECK(self->IsExceptionPending()); return nullptr; } - return mirror::MethodHandleImpl::Create(self, target.field_or_method, kind, mt); + + uintptr_t target; + if (target_field != nullptr) { + target = reinterpret_cast<uintptr_t>(target_field); + } else { + target = reinterpret_cast<uintptr_t>(target_method); + } + return mirror::MethodHandleImpl::Create(self, target, kind, mt); } bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const { @@ -8549,8 +8760,15 @@ const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) { return descriptor; } -jobject ClassLinker::CreatePathClassLoader(Thread* self, - const std::vector<const DexFile*>& dex_files) { +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); @@ -8586,8 +8804,8 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, for (const DexFile* dex_file : dex_files) { StackHandleScope<4> hs2(self); - // CreatePathClassLoader is only used by gtests. Index 0 of h_long_array is supposed to be the - // oat file but we can leave it null. + // CreateWellKnownClassLoader is only used by gtests and compiler. + // Index 0 of h_long_array is supposed to be the oat file but we can leave it null. Handle<mirror::LongArray> h_long_array = hs2.NewHandle(mirror::LongArray::Alloc( self, kDexFileIndexStart + 1)); @@ -8622,36 +8840,44 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, // Set elements. dex_elements_field->SetObject<false>(h_dex_path_list.Get(), h_dex_elements.Get()); - // Create PathClassLoader. - Handle<mirror::Class> h_path_class_class = hs.NewHandle( - soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader)); - Handle<mirror::Object> h_path_class_loader = hs.NewHandle( - h_path_class_class->AllocObject(self)); - DCHECK(h_path_class_loader != nullptr); + // 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)); + DCHECK(h_class_loader != nullptr); // Set DexPathList. ArtField* path_list_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList); DCHECK(path_list_field != nullptr); - path_list_field->SetObject<false>(h_path_class_loader.Get(), h_dex_path_list.Get()); + path_list_field->SetObject<false>(h_class_loader.Get(), h_dex_path_list.Get()); // Make a pretend boot-classpath. // TODO: Should we scan the image? ArtField* const parent_field = mirror::Class::FindField(self, - h_path_class_loader->GetClass(), + h_class_loader->GetClass(), "parent", "Ljava/lang/ClassLoader;"); DCHECK(parent_field != nullptr); - ObjPtr<mirror::Object> boot_cl = - soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self); - parent_field->SetObject<false>(h_path_class_loader.Get(), boot_cl); + + 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); // Make it a global ref and return. ScopedLocalRef<jobject> local_ref( - soa.Env(), soa.Env()->AddLocalReference<jobject>(h_path_class_loader.Get())); + soa.Env(), soa.Env()->AddLocalReference<jobject>(h_class_loader.Get())); return soa.Env()->NewGlobalRef(local_ref.get()); } +jobject ClassLinker::CreatePathClassLoader(Thread* self, + const std::vector<const DexFile*>& dex_files) { + return CreateWellKnownClassLoader(self, + dex_files, + WellKnownClasses::dalvik_system_PathClassLoader, + nullptr); +} + void ClassLinker::DropFindArrayClassCache() { std::fill_n(find_array_class_cache_, kFindArrayCacheSize, GcRoot<mirror::Class>(nullptr)); find_array_class_cache_next_victim_ = 0; |