Support directly invoking interface default methods
With the Java 8 Language one is allowed to directly call default
interface methods of interfaces one (directly) implements through the
use of the super keyword. We support this behavior through the
invoke-super opcode with the target being an interface.
We add 3 tests for this behavior.
Currently only supports slow-path interpreter.
Invoke-super is currently extremely slow.
Bug: 24618811
Change-Id: I7e06e17326f7dbae0116bd7dfefca151f0092bd2
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index d75587b..1c95648 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3639,8 +3639,9 @@
return *common_super;
}
+// TODO Maybe I should just add a METHOD_SUPER to MethodType?
ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(
- uint32_t dex_method_idx, MethodType method_type) {
+ uint32_t dex_method_idx, MethodType method_type, bool is_super) {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx);
const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_);
if (klass_type.IsConflict()) {
@@ -3667,6 +3668,8 @@
res_method = klass->FindDirectMethod(name, signature, pointer_size);
} else if (method_type == METHOD_INTERFACE) {
res_method = klass->FindInterfaceMethod(name, signature, pointer_size);
+ } else if (is_super && klass->IsInterface()) {
+ res_method = klass->FindInterfaceMethod(name, signature, pointer_size);
} else {
res_method = klass->FindVirtualMethod(name, signature, pointer_size);
}
@@ -3939,7 +3942,7 @@
// we're making.
const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
- ArtMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type);
+ ArtMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type, is_super);
if (res_method == nullptr) { // error or class is unresolved
// Check what we can statically.
if (!have_pending_hard_failure_) {
@@ -3949,24 +3952,32 @@
}
// If we're using invoke-super(method), make sure that the executing method's class' superclass
- // has a vtable entry for the target method.
+ // has a vtable entry for the target method. Or the target is on a interface.
if (is_super) {
DCHECK(method_type == METHOD_VIRTUAL);
- const RegType& super = GetDeclaringClass().GetSuperClass(®_types_);
- if (super.IsUnresolvedTypes()) {
- Fail(VERIFY_ERROR_NO_METHOD) << "unknown super class in invoke-super from "
- << PrettyMethod(dex_method_idx_, *dex_file_)
- << " to super " << PrettyMethod(res_method);
- return nullptr;
- }
- mirror::Class* super_klass = super.GetClass();
- if (res_method->GetMethodIndex() >= super_klass->GetVTableLength()) {
- Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from "
- << PrettyMethod(dex_method_idx_, *dex_file_)
- << " to super " << super
- << "." << res_method->GetName()
- << res_method->GetSignature();
- return nullptr;
+ if (res_method->GetDeclaringClass()->IsInterface()) {
+ // TODO Fill in this part. Verify what we can...
+ if (Runtime::Current()->IsAotCompiler()) {
+ Fail(VERIFY_ERROR_FORCE_INTERPRETER) << "Currently we only allow invoke-super in "
+ << "interpreter when using interface methods";
+ }
+ } else {
+ const RegType& super = GetDeclaringClass().GetSuperClass(®_types_);
+ if (super.IsUnresolvedTypes()) {
+ Fail(VERIFY_ERROR_NO_METHOD) << "unknown super class in invoke-super from "
+ << PrettyMethod(dex_method_idx_, *dex_file_)
+ << " to super " << PrettyMethod(res_method);
+ return nullptr;
+ }
+ mirror::Class* super_klass = super.GetClass();
+ if (res_method->GetMethodIndex() >= super_klass->GetVTableLength()) {
+ Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from "
+ << PrettyMethod(dex_method_idx_, *dex_file_)
+ << " to super " << super
+ << "." << res_method->GetName()
+ << res_method->GetSignature();
+ return nullptr;
+ }
}
}
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 79db576..ec0a8f9 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -654,7 +654,7 @@
* the referrer can access the resolved method.
* Does not throw exceptions.
*/
- ArtMethod* ResolveMethodAndCheckAccess(uint32_t method_idx, MethodType method_type)
+ ArtMethod* ResolveMethodAndCheckAccess(uint32_t method_idx, MethodType method_type, bool is_super)
SHARED_REQUIRES(Locks::mutator_lock_);
/*
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index 80b751c..7c7981e 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -246,28 +246,18 @@
}
/*
- * A basic Join operation on classes. For a pair of types S and T the Join,
- *written S v T = J, is
- * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is
- *J is the parent of
- * S and T such that there isn't a parent of both S and T that isn't also the
- *parent of J (ie J
+ * A basic Join operation on classes. For a pair of types S and T the Join, written S v T = J, is
+ * S <: J, T <: J and for-all U such that S <: U, T <: U then J <: U. That is J is the parent of
+ * S and T such that there isn't a parent of both S and T that isn't also the parent of J (ie J
* is the deepest (lowest upper bound) parent of S and T).
*
- * This operation applies for regular classes and arrays, however, for
- *interface types there
- * needn't be a partial ordering on the types. We could solve the problem of a
- *lack of a partial
- * order by introducing sets of types, however, the only operation permissible
- *on an interface is
- * invoke-interface. In the tradition of Java verifiers [1] we defer the
- *verification of interface
- * types until an invoke-interface call on the interface typed reference at
- *runtime and allow
- * the perversion of Object being assignable to an interface type (note,
- *however, that we don't
- * allow assignment of Object or Interface to any concrete class and are
- *therefore type safe).
+ * This operation applies for regular classes and arrays, however, for interface types there
+ * needn't be a partial ordering on the types. We could solve the problem of a lack of a partial
+ * order by introducing sets of types, however, the only operation permissible on an interface is
+ * invoke-interface. In the tradition of Java verifiers [1] we defer the verification of interface
+ * types until an invoke-interface call on the interface typed reference at runtime and allow
+ * the perversion of Object being assignable to an interface type (note, however, that we don't
+ * allow assignment of Object or Interface to any concrete class and are therefore type safe).
*
* [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy
*/