< prev index next >
src/hotspot/share/interpreter/linkResolver.cpp
Print this page
*** 385,400 ****
// returns first instance method
// Looks up method in classes, then looks up local default methods
methodHandle LinkResolver::lookup_instance_method_in_klasses(Klass* klass,
Symbol* name,
! Symbol* signature, TRAPS) {
! Method* result = klass->uncached_lookup_method(name, signature, Klass::find_overpass);
while (result != NULL && result->is_static() && result->method_holder()->super() != NULL) {
Klass* super_klass = result->method_holder()->super();
! result = super_klass->uncached_lookup_method(name, signature, Klass::find_overpass);
}
if (klass->is_array_klass()) {
// Only consider klass and super klass for arrays
return methodHandle(THREAD, result);
--- 385,401 ----
// returns first instance method
// Looks up method in classes, then looks up local default methods
methodHandle LinkResolver::lookup_instance_method_in_klasses(Klass* klass,
Symbol* name,
! Symbol* signature,
! Klass::PrivateLookupMode private_mode, TRAPS) {
! Method* result = klass->uncached_lookup_method(name, signature, Klass::find_overpass, private_mode);
while (result != NULL && result->is_static() && result->method_holder()->super() != NULL) {
Klass* super_klass = result->method_holder()->super();
! result = super_klass->uncached_lookup_method(name, signature, Klass::find_overpass, private_mode);
}
if (klass->is_array_klass()) {
// Only consider klass and super klass for arrays
return methodHandle(THREAD, result);
*** 585,594 ****
--- 586,599 ----
if (!Reflection::verify_field_access(ref_klass,
resolved_klass,
sel_klass,
flags,
true)) {
+ // Propagate any existing exceptions that may have been thrown
+ if (HAS_PENDING_EXCEPTION) {
+ return;
+ }
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"tried to access method %s.%s%s from class %s",
*** 753,763 ****
link_info.name(),
link_info.signature()),
nested_exception, NULL);
}
! // 5. access checks, access checking may be turned off when calling from within the VM.
Klass* current_klass = link_info.current_klass();
if (link_info.check_access()) {
assert(current_klass != NULL , "current_klass should not be null");
// check if method can be accessed by the referring class
--- 758,768 ----
link_info.name(),
link_info.signature()),
nested_exception, NULL);
}
! // 6. access checks, access checking may be turned off when calling from within the VM.
Klass* current_klass = link_info.current_klass();
if (link_info.check_access()) {
assert(current_klass != NULL , "current_klass should not be null");
// check if method can be accessed by the referring class
*** 769,778 ****
--- 774,803 ----
// check loader constraints
check_method_loader_constraints(link_info, resolved_method, "method", CHECK_NULL);
}
+ // For private method invocation we should only find the method in the resolved class.
+ // If that is not the case then we have a found a supertype method that we have nestmate
+ // access to.
+ // FIXME: the "ignoring xxx" part is for debugging only
+ if (resolved_method->is_private() && resolved_method->method_holder() != resolved_klass) {
+ ResourceMark rm(THREAD);
+ DEBUG_ONLY(bool is_nestmate = InstanceKlass::cast(link_info.current_klass())->has_nestmate_access_to(InstanceKlass::cast(resolved_klass), THREAD);)
+ assert(is_nestmate, "was only expecting nestmates to get here!");
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_NoSuchMethodError(),
+ "%s: method %s%s not found (ignoring %s)",
+ resolved_klass->external_name(),
+ resolved_method->name()->as_C_string(),
+ resolved_method->signature()->as_C_string(),
+ resolved_method->method_holder()->external_name()
+ );
+ return NULL;
+ }
+
return resolved_method;
}
static void trace_method_resolution(const char* prefix,
Klass* klass,
*** 870,892 ****
Method::name_and_sig_as_C_string(resolved_klass,
resolved_method->name(), resolved_method->signature()));
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
- if (code == Bytecodes::_invokeinterface && resolved_method->is_private()) {
- ResourceMark rm(THREAD);
- char buf[200];
-
- Klass* current_klass = link_info.current_klass();
- jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokeinterface: method %s, caller-class:%s",
- Method::name_and_sig_as_C_string(resolved_klass,
- resolved_method->name(),
- resolved_method->signature()),
- (current_klass == NULL ? "<NULL>" : current_klass->internal_name()));
- THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
- }
-
if (log_develop_is_enabled(Trace, itables)) {
char buf[200];
jio_snprintf(buf, sizeof(buf), "%s resolved interface method: caller-class:",
Bytecodes::name(code));
trace_method_resolution(buf, link_info.current_klass(), resolved_klass,
--- 895,904 ----
*** 907,916 ****
--- 919,933 ----
if (!Reflection::verify_field_access(ref_klass,
resolved_klass,
sel_klass,
fd.access_flags(),
true)) {
+ // Propagate any existing exceptions that may have been thrown
+ if (HAS_PENDING_EXCEPTION) {
+ return;
+ }
+
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IllegalAccessError(),
"tried to access field %s.%s from class %s",
*** 1124,1134 ****
resolved_method->signature()->as_C_string()
);
return NULL;
}
! // check if invokespecial's interface method reference is in an indirect superinterface
Klass* current_klass = link_info.current_klass();
if (current_klass != NULL && resolved_klass->is_interface()) {
InstanceKlass* ck = InstanceKlass::cast(current_klass);
InstanceKlass *klass_to_check = !ck->is_anonymous() ?
ck :
--- 1141,1152 ----
resolved_method->signature()->as_C_string()
);
return NULL;
}
! // ensure that invokespecial's interface method reference is in
! // a direct superinterface, not an indirect superinterface
Klass* current_klass = link_info.current_klass();
if (current_klass != NULL && resolved_klass->is_interface()) {
InstanceKlass* ck = InstanceKlass::cast(current_klass);
InstanceKlass *klass_to_check = !ck->is_anonymous() ?
ck :
*** 1196,1211 ****
// b) check if the class of the resolved_klass is a superclass
// (not supertype in order to exclude interface classes) of the current class.
// This check is not performed for super.invoke for interface methods
// in super interfaces.
current_klass->is_subclass_of(resolved_klass) &&
! current_klass != resolved_klass) {
// Lookup super method
Klass* super_klass = current_klass->super();
sel_method = lookup_instance_method_in_klasses(super_klass,
resolved_method->name(),
! resolved_method->signature(), CHECK);
// check if found
if (sel_method.is_null()) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
Method::name_and_sig_as_C_string(resolved_klass,
--- 1214,1231 ----
// b) check if the class of the resolved_klass is a superclass
// (not supertype in order to exclude interface classes) of the current class.
// This check is not performed for super.invoke for interface methods
// in super interfaces.
current_klass->is_subclass_of(resolved_klass) &&
! current_klass != resolved_klass
! ) {
// Lookup super method
Klass* super_klass = current_klass->super();
sel_method = lookup_instance_method_in_klasses(super_klass,
resolved_method->name(),
! resolved_method->signature(),
! Klass::find_private, CHECK);
// check if found
if (sel_method.is_null()) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_AbstractMethodError(),
Method::name_and_sig_as_C_string(resolved_klass,
*** 1352,1366 ****
} else {
// at this point we are sure that resolved_method is virtual and not
// a default or miranda method; therefore, it must have a valid vtable index.
assert(!resolved_method->has_itable_index(), "");
vtable_index = resolved_method->vtable_index();
! // We could get a negative vtable_index for final methods,
! // because as an optimization they are never put in the vtable,
! // unless they override an existing method.
! // If we do get a negative, it means the resolved method is the the selected
! // method, and it can never be changed by an override.
if (vtable_index == Method::nonvirtual_vtable_index) {
assert(resolved_method->can_be_statically_bound(), "cannot override this method");
selected_method = resolved_method;
} else {
selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
--- 1372,1387 ----
} else {
// at this point we are sure that resolved_method is virtual and not
// a default or miranda method; therefore, it must have a valid vtable index.
assert(!resolved_method->has_itable_index(), "");
vtable_index = resolved_method->vtable_index();
! // We could get a negative vtable_index of nonvirtual_vtable_index for private
! // methods, or for final methods. Private methods never appear in the vtable
! // and never override other methods. As an optimization, final methods are
! // never put in the vtable, unless they override an existing method.
! // So if we do get nonvirtual_vtable_index, it means the selected method is the
! // resolved method, and it can never be changed by an override.
if (vtable_index == Method::nonvirtual_vtable_index) {
assert(resolved_method->can_be_statically_bound(), "cannot override this method");
selected_method = resolved_method;
} else {
selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
*** 1411,1420 ****
--- 1432,1442 ----
const methodHandle& resolved_method,
Klass* resolved_klass,
Handle recv,
Klass* recv_klass,
bool check_null_and_abstract, TRAPS) {
+
// check if receiver exists
if (check_null_and_abstract && recv.is_null()) {
THROW(vmSymbols::java_lang_NullPointerException());
}
*** 1426,1441 ****
recv_klass->external_name(),
resolved_klass->external_name());
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
// do lookup based on receiver klass
// This search must match the linktime preparation search for itable initialization
! // to correctly enforce loader constraints for interface method inheritance
! methodHandle selected_method = lookup_instance_method_in_klasses(recv_klass,
resolved_method->name(),
! resolved_method->signature(), CHECK);
if (selected_method.is_null() && !check_null_and_abstract) {
// In theory this is a harmless placeholder value, but
// in practice leaving in null affects the nsk default method tests.
// This needs further study.
selected_method = resolved_method;
--- 1448,1470 ----
recv_klass->external_name(),
resolved_klass->external_name());
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
+ methodHandle selected_method = resolved_method;
+
+ // resolve the method in the receiver class, unless it is private
+ if (!resolved_method()->is_private()) {
// do lookup based on receiver klass
// This search must match the linktime preparation search for itable initialization
! // to correctly enforce loader constraints for interface method inheritance.
! // Private methods are skipped as the resolved method was not private.
! selected_method = lookup_instance_method_in_klasses(recv_klass,
resolved_method->name(),
! resolved_method->signature(),
! Klass::skip_private, CHECK);
!
if (selected_method.is_null() && !check_null_and_abstract) {
// In theory this is a harmless placeholder value, but
// in practice leaving in null affects the nsk default method tests.
// This needs further study.
selected_method = resolved_method;
*** 1456,1478 ****
}
// check if abstract
if (check_null_and_abstract && selected_method->is_abstract()) {
throw_abstract_method_error(resolved_method, selected_method, recv_klass, CHECK);
}
if (log_develop_is_enabled(Trace, itables)) {
trace_method_resolution("invokeinterface selected method: receiver-class:",
recv_klass, resolved_klass, selected_method, true);
}
// setup result
! if (!resolved_method->has_itable_index()) {
int vtable_index = resolved_method->vtable_index();
assert(vtable_index == selected_method->vtable_index(), "sanity check");
result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK);
! } else {
int itable_index = resolved_method()->itable_index();
result.set_interface(resolved_klass, recv_klass, resolved_method, selected_method, itable_index, CHECK);
}
}
methodHandle LinkResolver::linktime_resolve_interface_method_or_null(
--- 1485,1520 ----
}
// check if abstract
if (check_null_and_abstract && selected_method->is_abstract()) {
throw_abstract_method_error(resolved_method, selected_method, recv_klass, CHECK);
}
+ }
if (log_develop_is_enabled(Trace, itables)) {
trace_method_resolution("invokeinterface selected method: receiver-class:",
recv_klass, resolved_klass, selected_method, true);
}
// setup result
! if (resolved_method->has_vtable_index()) {
int vtable_index = resolved_method->vtable_index();
+ log_develop_trace(itables)(" -- vtable index: %d", vtable_index);
assert(vtable_index == selected_method->vtable_index(), "sanity check");
result.set_virtual(resolved_klass, recv_klass, resolved_method, selected_method, vtable_index, CHECK);
! } else if (resolved_method->has_itable_index()) {
int itable_index = resolved_method()->itable_index();
+ log_develop_trace(itables)(" -- itable index: %d", itable_index);
result.set_interface(resolved_klass, recv_klass, resolved_method, selected_method, itable_index, CHECK);
+ } else {
+ int index = resolved_method->vtable_index();
+ log_develop_trace(itables)(" -- non itable/vtable index: %d", index);
+ assert(index == Method::nonvirtual_vtable_index, "Oops hit another case!");
+ assert(resolved_method()->is_private() ||
+ (resolved_method()->is_final() && resolved_method->method_holder() == SystemDictionary::Object_klass()),
+ "Should only have non-virtual invokeinterface for private or final-Object methods!");
+ assert(resolved_method()->can_be_statically_bound(), "Should only have non-virtual invokeinterface for statically bound methods!");
+ // This sets up the nonvirtual form of "virtual" call (as needed for final and private methods)
+ result.set_virtual(resolved_klass, resolved_klass, resolved_method, resolved_method, index, CHECK);
}
}
methodHandle LinkResolver::linktime_resolve_interface_method_or_null(
< prev index next >