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.cc456
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;