< prev index next > src/hotspot/share/interpreter/linkResolver.cpp
Print this page
*
*/
#include "precompiled.hpp"
#include "cds/archiveUtils.hpp"
+ #include "classfile/classLoader.hpp"
#include "classfile/defaultMethods.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
- #include "runtime/javaThread.hpp"
+ #include "runtime/javaThread.inline.hpp"
+ #include "runtime/perfData.hpp"
#include "runtime/reflection.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "runtime/vmThread.hpp"
const methodHandle& resolved_method,
const methodHandle& selected_method,
CallKind kind,
int index,
TRAPS) {
- assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond");
+ if (selected_method.not_null()) {
+ assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond");
+ }
_resolved_klass = resolved_klass;
_resolved_method = resolved_method;
_selected_method = selected_method;
_call_kind = kind;
_call_index = index;
_resolved_appendix = Handle();
DEBUG_ONLY(verify()); // verify before making side effects
- CompilationPolicy::compile_if_required(selected_method, THREAD);
+ if (selected_method.not_null()) {
+ CompilationPolicy::compile_if_required(selected_method, THREAD);
+ }
}
// utility query for unreflecting a method
CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass, TRAPS) {
Klass* resolved_method_holder = resolved_method->method_holder();
);
return;
}
}
- void LinkResolver::resolve_field_access(fieldDescriptor& fd, const constantPoolHandle& pool, int index, const methodHandle& method, Bytecodes::Code byte, TRAPS) {
+ void LinkResolver::resolve_field_access(fieldDescriptor& fd,
+ const constantPoolHandle& pool,
+ int index,
+ const methodHandle& method,
+ Bytecodes::Code byte,
+ bool initialize_class, TRAPS) {
LinkInfo link_info(pool, index, method, byte, CHECK);
- resolve_field(fd, link_info, byte, true, CHECK);
+ resolve_field(fd, link_info, byte, initialize_class, CHECK);
}
void LinkResolver::resolve_field(fieldDescriptor& fd,
const LinkInfo& link_info,
- Bytecodes::Code byte, bool initialize_class,
+ Bytecodes::Code byte,
+ bool initialize_class,
TRAPS) {
assert(byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic ||
byte == Bytecodes::_getfield || byte == Bytecodes::_putfield ||
byte == Bytecodes::_nofast_getfield || byte == Bytecodes::_nofast_putfield ||
(byte == Bytecodes::_nop && !link_info.check_access()), "bad field access bytecode");
// setup result
result.set_static(resolved_klass, methodHandle(THREAD, resolved_method), CHECK);
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
}
+ void LinkResolver::cds_resolve_static_call(CallInfo& result, const LinkInfo& link_info, TRAPS) {
+ resolve_static_call(result, link_info, /*initialize_class*/false, CHECK);
+ }
+
// throws linktime exceptions
Method* LinkResolver::linktime_resolve_static_method(const LinkInfo& link_info, TRAPS) {
Klass* resolved_klass = link_info.resolved_klass();
Method* resolved_method;
TRAPS) {
Method* resolved_method = linktime_resolve_special_method(link_info, CHECK);
runtime_resolve_special_method(result, link_info, methodHandle(THREAD, resolved_method), recv, CHECK);
}
+ void LinkResolver::cds_resolve_special_call(CallInfo& result, const LinkInfo& link_info, TRAPS) {
+ resolve_special_call(result, Handle(), link_info, CHECK);
+ }
+
// throws linktime exceptions
Method* LinkResolver::linktime_resolve_special_method(const LinkInfo& link_info, TRAPS) {
// Invokespecial is called for multiple special reasons:
// <init>
bool check_null_and_abstract, TRAPS) {
Method* resolved_method = linktime_resolve_virtual_method(link_info, CHECK);
runtime_resolve_virtual_method(result, methodHandle(THREAD, resolved_method),
link_info.resolved_klass(),
recv, receiver_klass,
- check_null_and_abstract, CHECK);
+ check_null_and_abstract,
+ /*need_selected_method*/true, CHECK);
+ }
+
+ void LinkResolver::cds_resolve_virtual_call(CallInfo& result, const LinkInfo& link_info, TRAPS) {
+ Method* resolved_method = linktime_resolve_virtual_method(link_info, CHECK);
+ runtime_resolve_virtual_method(result, methodHandle(THREAD, resolved_method),
+ link_info.resolved_klass(),
+ Handle(), nullptr,
+ /*check_null_and_abstract*/false,
+ /*need_selected_method*/false, CHECK);
}
// throws linktime exceptions
Method* LinkResolver::linktime_resolve_virtual_method(const LinkInfo& link_info,
TRAPS) {
const methodHandle& resolved_method,
Klass* resolved_klass,
Handle recv,
Klass* recv_klass,
bool check_null_and_abstract,
+ bool need_selected_method,
TRAPS) {
// setup default return values
int vtable_index = Method::invalid_vtable_index;
methodHandle selected_method;
// do lookup based on receiver klass using the vtable index
if (resolved_method->method_holder()->is_interface()) { // default or miranda method
vtable_index = vtable_index_of_interface_method(resolved_klass, resolved_method);
assert(vtable_index >= 0 , "we should have valid vtable index at this point");
- selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
+ if (need_selected_method) {
+ selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
+ }
} 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();
// 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;
+ if (need_selected_method) {
+ selected_method = resolved_method;
+ }
} else {
- selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
+ if (need_selected_method) {
+ selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
+ }
}
}
- // check if method exists
- if (selected_method.is_null()) {
- throw_abstract_method_error(resolved_method, recv_klass, CHECK);
- }
+ if (need_selected_method) {
+ // check if method exists
+ if (selected_method.is_null()) {
+ throw_abstract_method_error(resolved_method, recv_klass, CHECK);
+ }
- // check if abstract
- if (check_null_and_abstract && selected_method->is_abstract()) {
- // Pass arguments for generating a verbose error message.
- throw_abstract_method_error(resolved_method, selected_method, recv_klass, CHECK);
+ // check if abstract
+ if (check_null_and_abstract && selected_method->is_abstract()) {
+ // Pass arguments for generating a verbose error message.
+ throw_abstract_method_error(resolved_method, selected_method, recv_klass, CHECK);
+ }
}
if (log_develop_is_enabled(Trace, vtables)) {
trace_method_resolution("invokevirtual selected method: receiver-class:",
recv_klass, resolved_klass, selected_method(),
false, vtable_index);
}
// setup result
result.set_virtual(resolved_klass, resolved_method, selected_method, vtable_index, CHECK);
- JFR_ONLY(Jfr::on_resolution(result, CHECK);)
+ if (selected_method.not_null()) {
+ JFR_ONLY(Jfr::on_resolution(result, CHECK);)
+ }
}
void LinkResolver::resolve_interface_call(CallInfo& result, Handle recv, Klass* recv_klass,
const LinkInfo& link_info,
bool check_null_and_abstract, TRAPS) {
// throws linktime exceptions
Method* resolved_method = linktime_resolve_interface_method(link_info, CHECK);
methodHandle mh(THREAD, resolved_method);
runtime_resolve_interface_method(result, mh, link_info.resolved_klass(),
- recv, recv_klass, check_null_and_abstract, CHECK);
+ recv, recv_klass, check_null_and_abstract,
+ /*need_selected_method*/ true, CHECK);
+ }
+
+ void LinkResolver::cds_resolve_interface_call(CallInfo& result, const LinkInfo& link_info, TRAPS) {
+ Method* resolved_method = linktime_resolve_interface_method(link_info, CHECK);
+ runtime_resolve_interface_method(result, methodHandle(THREAD, resolved_method), link_info.resolved_klass(),
+ Handle(), nullptr,
+ /*check_null_and_abstract*/ false,
+ /*need_selected_method*/ false, CHECK);
}
Method* LinkResolver::linktime_resolve_interface_method(const LinkInfo& link_info,
TRAPS) {
// normal interface method resolution
void LinkResolver::runtime_resolve_interface_method(CallInfo& result,
const methodHandle& resolved_method,
Klass* resolved_klass,
Handle recv,
Klass* recv_klass,
- bool check_null_and_abstract, TRAPS) {
+ bool check_null_and_abstract,
+ bool need_selected_method, TRAPS) {
// check if receiver exists
if (check_null_and_abstract && recv.is_null()) {
THROW(vmSymbols::java_lang_NullPointerException());
}
// check if receiver klass implements the resolved interface
- if (!recv_klass->is_subtype_of(resolved_klass)) {
+ if (need_selected_method && !recv_klass->is_subtype_of(resolved_klass)) {
ResourceMark rm(THREAD);
char buf[200];
jio_snprintf(buf, sizeof(buf), "Class %s does not implement the requested interface %s",
recv_klass->external_name(),
resolved_klass->external_name());
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
- methodHandle selected_method = resolved_method;
+ methodHandle selected_method;
+
+ if (need_selected_method) {
+ selected_method = resolved_method;
+ }
// resolve the method in the receiver class, unless it is private
- if (!resolved_method()->is_private()) {
+ if (need_selected_method && !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.
Method* method = lookup_instance_method_in_klasses(recv_klass,
}
// 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");
+ assert(!need_selected_method || vtable_index == selected_method->vtable_index(), "sanity check");
result.set_virtual(resolved_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, resolved_method, selected_method, itable_index, CHECK);
"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_method, resolved_method, index, CHECK);
}
- JFR_ONLY(Jfr::on_resolution(result, CHECK);)
+ if (need_selected_method) {
+ JFR_ONLY(Jfr::on_resolution(result, CHECK);)
+ }
}
Method* LinkResolver::linktime_resolve_interface_method_or_null(
const LinkInfo& link_info) {
return false;
}
}
void LinkResolver::resolve_invokehandle(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) {
+ PerfTraceTimedEvent timer(ClassLoader::perf_resolve_invokehandle_time(),
+ ClassLoader::perf_resolve_invokehandle_count(),
+ THREAD->class_being_initialized() == nullptr);
+
LinkInfo link_info(pool, index, Bytecodes::_invokehandle, CHECK);
+ { // Check if the call site has been bound already, and short circuit:
+ bool is_done = resolve_previously_linked_invokehandle(result, link_info, pool, index, CHECK);
+ if (is_done) return;
+ }
if (log_is_enabled(Info, methodhandles)) {
ResourceMark rm(THREAD);
log_info(methodhandles)("resolve_invokehandle %s %s", link_info.name()->as_C_string(),
link_info.signature()->as_C_string());
}
- { // Check if the call site has been bound already, and short circuit:
- bool is_done = resolve_previously_linked_invokehandle(result, link_info, pool, index, CHECK);
- if (is_done) return;
- }
resolve_handle_call(result, link_info, CHECK);
}
void LinkResolver::resolve_handle_call(CallInfo& result,
const LinkInfo& link_info,
result.set_handle(resolved_klass, resolved_method, resolved_appendix, CHECK);
JFR_ONLY(Jfr::on_resolution(result, CHECK);)
}
void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int indy_index, TRAPS) {
+ PerfTraceTimedEvent timer(ClassLoader::perf_resolve_invokedynamic_time(),
+ ClassLoader::perf_resolve_invokedynamic_count(),
+ THREAD->class_being_initialized() == nullptr);
int pool_index = pool->resolved_indy_entry_at(indy_index)->constant_pool_index();
// Resolve the bootstrap specifier (BSM + optional arguments).
BootstrapInfo bootstrap_specifier(pool, pool_index, indy_index);
< prev index next >