< 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"

*** 53,11 ***
  #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/reflection.hpp"
  #include "runtime/safepointVerifiers.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "runtime/signature.hpp"
  #include "runtime/vmThread.hpp"
--- 54,12 ---
  #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.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"

*** 138,20 ***
                            const methodHandle& resolved_method,
                            const methodHandle& selected_method,
                            CallKind kind,
                            int index,
                            TRAPS) {
!   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);
  }
  
  // utility query for unreflecting a method
  CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass, TRAPS) {
    Klass* resolved_method_holder = resolved_method->method_holder();
--- 140,24 ---
                            const methodHandle& resolved_method,
                            const methodHandle& selected_method,
                            CallKind kind,
                            int index,
                            TRAPS) {
!   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
  
!   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();

*** 970,18 ***
                         );
      return;
    }
  }
  
! void LinkResolver::resolve_field_access(fieldDescriptor& fd, const constantPoolHandle& pool, int index, const methodHandle& method, Bytecodes::Code byte, TRAPS) {
    LinkInfo link_info(pool, index, method, byte, CHECK);
!   resolve_field(fd, link_info, byte, true, CHECK);
  }
  
  void LinkResolver::resolve_field(fieldDescriptor& fd,
                                   const LinkInfo& link_info,
!                                  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");
--- 976,24 ---
                         );
      return;
    }
  }
  
! 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, initialize_class, CHECK);
  }
  
  void LinkResolver::resolve_field(fieldDescriptor& fd,
                                   const LinkInfo& link_info,
!                                  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");

*** 1110,10 ***
--- 1122,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;

*** 1143,10 ***
--- 1159,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>

*** 1324,11 ***
                                          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);
  }
  
  // throws linktime exceptions
  Method* LinkResolver::linktime_resolve_virtual_method(const LinkInfo& link_info,
                                                             TRAPS) {
--- 1344,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,
+                                  /*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) {

*** 1376,10 ***
--- 1406,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;

*** 1397,11 ***
    // 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));
    } 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();
--- 1428,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");
  
!     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();

*** 1411,45 ***
      // 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));
      }
    }
  
!   // 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);
    }
  
    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);)
  }
  
  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);
  }
  
  Method* LinkResolver::linktime_resolve_interface_method(const LinkInfo& link_info,
                                                               TRAPS) {
    // normal interface method resolution
--- 1444,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");
!       if (need_selected_method) {
+         selected_method = resolved_method;
+       }
      } else {
!       if (need_selected_method) {
+         selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
+       }
      }
    }
  
!   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);
+     }
    }
  
    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);
!   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,
+                                    /*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

*** 1464,31 ***
  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) {
  
    // 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)) {
      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;
  
    // 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.
      Method* method = lookup_instance_method_in_klasses(recv_klass,
--- 1514,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,
+                                                     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 (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;
+ 
+   if (need_selected_method) {
+     selected_method = resolved_method;
+   }
  
    // resolve the method in the receiver class, unless it 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,

*** 1530,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");
      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);
--- 1585,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(!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);

*** 1547,11 ***
             "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);)
  }
  
  
  Method* LinkResolver::linktime_resolve_interface_method_or_null(
                                                   const LinkInfo& link_info) {
--- 1602,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);
    }
!   if (need_selected_method) {
+     JFR_ONLY(Jfr::on_resolution(result, CHECK);)
+   }
  }
  
  
  Method* LinkResolver::linktime_resolve_interface_method_or_null(
                                                   const LinkInfo& link_info) {

*** 1726,20 ***
      return false;
    }
  }
  
  void LinkResolver::resolve_invokehandle(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) {
    LinkInfo link_info(pool, index, Bytecodes::_invokehandle, CHECK);
    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,
--- 1783,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());
    }
    resolve_handle_call(result, link_info, CHECK);
  }
  
  void LinkResolver::resolve_handle_call(CallInfo& result,
                                         const LinkInfo& link_info,

*** 1777,10 ***
--- 1838,13 ---
    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 >