Fixes for constant method handles
Add support for constant direct and interface method handles in the
DEX file.
Add error handling for field and method resolution failures in
ClassLinker::ResolveMethodHandle().
Bug: 36957105
Test: art/test/run-test --host 952-invoke-custom-kinds
Change-Id: I91a2a23ba3365310eccb8cadd193b62f57e5811c
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 10e0bd2..7aab9de 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -8256,65 +8256,139 @@
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;
}
}
@@ -8331,44 +8405,51 @@
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: {
@@ -8388,7 +8469,14 @@
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 {