src/share/vm/interpreter/linkResolver.cpp
Print this page
@@ -240,20 +240,20 @@
//
// According to JVM spec. $5.4.3c & $5.4.3d
// Look up method in klasses, including static methods
// Then look up local default methods
-void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
+void LinkResolver::lookup_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, bool checkpolymorphism, TRAPS) {
Method* result_oop = klass->uncached_lookup_method(name, signature);
if (result_oop == NULL) {
Array<Method*>* default_methods = InstanceKlass::cast(klass())->default_methods();
if (default_methods != NULL) {
result_oop = InstanceKlass::find_method(default_methods, name, signature);
}
}
- if (EnableInvokeDynamic && result_oop != NULL) {
+ if (checkpolymorphism && EnableInvokeDynamic && result_oop != NULL) {
vmIntrinsics::ID iid = result_oop->intrinsic_id();
if (MethodHandles::is_signature_polymorphic(iid)) {
// Do not link directly to these. The VM must produce a synthetic one using lookup_polymorphic_method.
return;
}
@@ -265,12 +265,12 @@
// Looks up method in classes, then looks up local default methods
void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS) {
Method* result_oop = klass->uncached_lookup_method(name, signature);
result = methodHandle(THREAD, result_oop);
while (!result.is_null() && result->is_static() && result->method_holder()->super() != NULL) {
- klass = KlassHandle(THREAD, result->method_holder()->super());
- result = methodHandle(THREAD, klass->uncached_lookup_method(name, signature));
+ KlassHandle super_klass = KlassHandle(THREAD, result->method_holder()->super());
+ result = methodHandle(THREAD, super_klass->uncached_lookup_method(name, signature));
}
if (result.is_null()) {
Array<Method*>* default_methods = InstanceKlass::cast(klass())->default_methods();
if (default_methods != NULL) {
@@ -501,15 +501,18 @@
return;
}
}
if (code == Bytecodes::_invokeinterface) {
- resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK);
+ resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK);
} else if (code == Bytecodes::_invokevirtual) {
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, true, CHECK);
- } else {
+ } else if (!resolved_klass->is_interface()) {
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, false, CHECK);
+ } else {
+ bool nostatics = (code == Bytecodes::_invokestatic) ? false : true;
+ resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, nostatics, CHECK);
}
}
void LinkResolver::resolve_method(methodHandle& resolved_method, KlassHandle resolved_klass,
Symbol* method_name, Symbol* method_signature,
@@ -526,11 +529,11 @@
resolved_klass()->external_name());
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
// 2. lookup method in resolved klass and its super klasses
- lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, CHECK);
+ lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, true, CHECK);
if (resolved_method.is_null()) { // not found in the class hierarchy
// 3. lookup method in all the interfaces implemented by the resolved klass
lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK);
@@ -610,22 +613,24 @@
void LinkResolver::resolve_interface_method(methodHandle& resolved_method,
KlassHandle resolved_klass,
Symbol* method_name,
Symbol* method_signature,
KlassHandle current_klass,
- bool check_access, TRAPS) {
+ bool check_access,
+ bool nostatics, TRAPS) {
// check if klass is interface
if (!resolved_klass->is_interface()) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf), "Found class %s, but interface was expected", resolved_klass()->external_name());
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
// lookup method in this interface or its super, java.lang.Object
- lookup_instance_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, CHECK);
+ // JDK8: also look for static methods
+ lookup_method_in_klasses(resolved_method, resolved_klass, method_name, method_signature, false, CHECK);
if (resolved_method.is_null()) {
// lookup method in all the super-interfaces
lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK);
if (resolved_method.is_null()) {
@@ -636,10 +641,20 @@
method_name,
method_signature));
}
}
+ if (nostatics && resolved_method->is_static()) {
+ ResourceMark rm(THREAD);
+ char buf[200];
+ jio_snprintf(buf, sizeof(buf), "Expected instance not static method %s", Method::name_and_sig_as_C_string(resolved_klass(),
+ resolved_method->name(),
+ resolved_method->signature()));
+ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
+ }
+
+
if (check_access) {
// JDK8 adds non-public interface methods, and accessability check requirement
assert(current_klass.not_null() , "current_klass should not be null");
// check if method can be accessed by the referring class
@@ -862,11 +877,15 @@
// throws linktime exceptions
void LinkResolver::linktime_resolve_static_method(methodHandle& resolved_method, KlassHandle resolved_klass,
Symbol* method_name, Symbol* method_signature,
KlassHandle current_klass, bool check_access, TRAPS) {
+ if (!resolved_klass->is_interface()) {
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK);
+ } else {
+ resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK);
+ }
assert(resolved_method->name() != vmSymbols::class_initializer_name(), "should have been checked in verifier");
// check if static
if (!resolved_method->is_static()) {
ResourceMark rm(THREAD);
@@ -896,11 +915,15 @@
// local private method invocation, for classes and interfaces
// superclass.method, which can also resolve to a default method
// and the selected method is recalculated relative to the direct superclass
// superinterface.method, which explicitly does not check shadowing
+ if (!resolved_klass->is_interface()) {
resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, false, CHECK);
+ } else {
+ resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, true, CHECK);
+ }
// check if method name is <init>, that it is found in same klass as static type
if (resolved_method->name() == vmSymbols::object_initializer_name() &&
resolved_method->method_holder() != resolved_klass()) {
ResourceMark rm(THREAD);
@@ -1217,11 +1240,11 @@
// throws linktime exceptions
void LinkResolver::linktime_resolve_interface_method(methodHandle& resolved_method, KlassHandle resolved_klass, Symbol* method_name,
Symbol* method_signature, KlassHandle current_klass, bool check_access, TRAPS) {
// normal interface method resolution
- resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, CHECK);
+ resolve_interface_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, check_access, true, CHECK);
assert(resolved_method->name() != vmSymbols::object_initializer_name(), "should have been checked in verifier");
assert(resolved_method->name() != vmSymbols::class_initializer_name (), "should have been checked in verifier");
}