< prev index next >

src/hotspot/share/interpreter/linkResolver.cpp

Print this page
rev 50604 : imported patch jep181-rev1
rev 50605 : imported patch jep181-rev2
rev 50606 : imported patch jep181-rev3

*** 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);
*** 580,594 **** new_flags = new_flags | JVM_ACC_PUBLIC; flags.set_flags(new_flags); } // assert(extra_arg_result_or_null != NULL, "must be able to return extra argument"); ! if (!Reflection::verify_field_access(ref_klass, resolved_klass, sel_klass, flags, ! true)) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalAccessError(), "tried to access method %s.%s%s from class %s", --- 581,598 ---- new_flags = new_flags | JVM_ACC_PUBLIC; flags.set_flags(new_flags); } // assert(extra_arg_result_or_null != NULL, "must be able to return extra argument"); ! bool can_access = Reflection::verify_member_access(ref_klass, resolved_klass, sel_klass, flags, ! true, false, CHECK); ! // Any existing exceptions that may have been thrown, for example LinkageErrors ! // from nest-host resolution, have been allowed to propagate. ! if (!can_access) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalAccessError(), "tried to access method %s.%s%s from class %s",
*** 755,765 **** 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 --- 759,769 ---- 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
*** 771,780 **** --- 775,802 ---- // 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. + 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", + resolved_klass->external_name(), + resolved_method->name()->as_C_string(), + resolved_method->signature()->as_C_string() + ); + return NULL; + } + return resolved_method; } static void trace_method_resolution(const char* prefix, Klass* klass,
*** 872,894 **** 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, --- 894,903 ----
*** 904,918 **** void LinkResolver::check_field_accessability(Klass* ref_klass, Klass* resolved_klass, Klass* sel_klass, const fieldDescriptor& fd, TRAPS) { ! if (!Reflection::verify_field_access(ref_klass, resolved_klass, sel_klass, fd.access_flags(), ! true)) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalAccessError(), "tried to access field %s.%s from class %s", --- 913,930 ---- void LinkResolver::check_field_accessability(Klass* ref_klass, Klass* resolved_klass, Klass* sel_klass, const fieldDescriptor& fd, TRAPS) { ! bool can_access = Reflection::verify_member_access(ref_klass, resolved_klass, sel_klass, fd.access_flags(), ! true, false, CHECK); ! // Any existing exceptions that may have been thrown, for example LinkageErrors ! // from nest-host resolution, have been allowed to propagate. ! if (!can_access) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalAccessError(), "tried to access field %s.%s from class %s",
*** 1126,1136 **** 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 : --- 1138,1149 ---- 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 :
*** 1198,1213 **** // 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, --- 1211,1228 ---- // 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,
*** 1354,1368 **** } 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)); --- 1369,1384 ---- } 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));
*** 1413,1422 **** --- 1429,1439 ---- 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()); }
*** 1428,1443 **** 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; --- 1445,1467 ---- 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;
*** 1458,1480 **** } // 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( --- 1482,1517 ---- } // 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 >