< prev index next >

src/hotspot/share/interpreter/linkResolver.cpp

Print this page
@@ -22,10 +22,11 @@
   *
   */
  
  #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"

@@ -52,11 +53,12 @@
  #include "oops/symbolHandle.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"

@@ -116,20 +118,24 @@
                            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();

@@ -948,18 +954,24 @@
                         );
      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");

@@ -1088,10 +1100,14 @@
    // 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;

@@ -1121,10 +1137,14 @@
                                          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>

@@ -1302,11 +1322,21 @@
                                          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) {

@@ -1354,10 +1384,11 @@
                                                    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;

@@ -1375,11 +1406,13 @@
    // 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();

@@ -1389,45 +1422,62 @@
      // 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

@@ -1442,31 +1492,36 @@
  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,

@@ -1508,11 +1563,11 @@
    }
    // 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);

@@ -1525,11 +1580,13 @@
             "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) {

@@ -1704,20 +1761,24 @@
      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,

@@ -1755,10 +1816,14 @@
    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 index = pool->decode_invokedynamic_index(indy_index);
    int pool_index = pool->resolved_indy_entry_at(index)->constant_pool_index();
  
    // Resolve the bootstrap specifier (BSM + optional arguments).
    BootstrapInfo bootstrap_specifier(pool, pool_index, index);
< prev index next >