< prev index next >

src/hotspot/share/runtime/sharedRuntime.cpp

Print this page
*** 20,15 ***
--- 20,19 ---
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   *
   */
  
+ #include "cds/archiveBuilder.hpp"
+ #include "cds/archiveUtils.inline.hpp"
+ #include "cds/cdsConfig.hpp"
  #include "classfile/classLoader.hpp"
  #include "classfile/javaClasses.inline.hpp"
  #include "classfile/stringTable.hpp"
  #include "classfile/vmClasses.hpp"
  #include "classfile/vmSymbols.hpp"
+ #include "code/SCCache.hpp"
  #include "code/codeCache.hpp"
  #include "code/compiledIC.hpp"
  #include "code/nmethod.inline.hpp"
  #include "code/scopeDesc.hpp"
  #include "code/vtableStubs.hpp"

*** 62,19 ***
  #include "runtime/init.hpp"
  #include "runtime/interfaceSupport.inline.hpp"
  #include "runtime/java.hpp"
  #include "runtime/javaCalls.hpp"
  #include "runtime/jniHandles.inline.hpp"
! #include "runtime/perfData.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "runtime/stackWatermarkSet.hpp"
  #include "runtime/stubRoutines.hpp"
  #include "runtime/synchronizer.inline.hpp"
  #include "runtime/timerTrace.hpp"
  #include "runtime/vframe.inline.hpp"
  #include "runtime/vframeArray.hpp"
  #include "runtime/vm_version.hpp"
  #include "utilities/copy.hpp"
  #include "utilities/dtrace.hpp"
  #include "utilities/events.hpp"
  #include "utilities/globalDefinitions.hpp"
  #include "utilities/resourceHash.hpp"
--- 66,20 ---
  #include "runtime/init.hpp"
  #include "runtime/interfaceSupport.inline.hpp"
  #include "runtime/java.hpp"
  #include "runtime/javaCalls.hpp"
  #include "runtime/jniHandles.inline.hpp"
! #include "runtime/perfData.inline.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "runtime/stackWatermarkSet.hpp"
  #include "runtime/stubRoutines.hpp"
  #include "runtime/synchronizer.inline.hpp"
  #include "runtime/timerTrace.hpp"
  #include "runtime/vframe.inline.hpp"
  #include "runtime/vframeArray.hpp"
  #include "runtime/vm_version.hpp"
+ #include "services/management.hpp"
  #include "utilities/copy.hpp"
  #include "utilities/dtrace.hpp"
  #include "utilities/events.hpp"
  #include "utilities/globalDefinitions.hpp"
  #include "utilities/resourceHash.hpp"

*** 96,10 ***
--- 101,16 ---
    SHARED_STUBS_DO(SHARED_STUB_FIELD_DEFINE)
  #undef SHARED_STUB_FIELD_DEFINE
  
  nmethod*            SharedRuntime::_cont_doYield_stub;
  
+ PerfTickCounters* SharedRuntime::_perf_resolve_opt_virtual_total_time = nullptr;
+ PerfTickCounters* SharedRuntime::_perf_resolve_virtual_total_time     = nullptr;
+ PerfTickCounters* SharedRuntime::_perf_resolve_static_total_time      = nullptr;
+ PerfTickCounters* SharedRuntime::_perf_handle_wrong_method_total_time = nullptr;
+ PerfTickCounters* SharedRuntime::_perf_ic_miss_total_time             = nullptr;
+ 
  #define SHARED_STUB_NAME_DECLARE(name, type) "Shared Runtime " # name "_blob",
  const char *SharedRuntime::_stub_names[] = {
    SHARED_STUBS_DO(SHARED_STUB_NAME_DECLARE)
  };
  

*** 145,12 ***
  
    _throw_NullPointerException_at_call_blob =
      generate_throw_exception(SharedStubId::throw_NullPointerException_at_call_id,
                               CAST_FROM_FN_PTR(address, SharedRuntime::throw_NullPointerException_at_call));
  
-   AdapterHandlerLibrary::initialize();
- 
  #if COMPILER2_OR_JVMCI
    // Vectors are generated only by C2 and JVMCI.
    bool support_wide = is_wide_vector(MaxVectorSize);
    if (support_wide) {
      _polling_page_vectors_safepoint_handler_blob =
--- 156,10 ---

*** 164,10 ***
--- 173,65 ---
    _polling_page_return_handler_blob =
      generate_handler_blob(SharedStubId::polling_page_return_handler_id,
                            CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception));
  
    generate_deopt_blob();
+ 
+   if (UsePerfData) {
+     EXCEPTION_MARK;
+     NEWPERFTICKCOUNTERS(_perf_resolve_opt_virtual_total_time, SUN_CI, "resovle_opt_virtual_call");
+     NEWPERFTICKCOUNTERS(_perf_resolve_virtual_total_time,     SUN_CI, "resovle_virtual_call");
+     NEWPERFTICKCOUNTERS(_perf_resolve_static_total_time,      SUN_CI, "resovle_static_call");
+     NEWPERFTICKCOUNTERS(_perf_handle_wrong_method_total_time, SUN_CI, "handle_wrong_method");
+     NEWPERFTICKCOUNTERS(_perf_ic_miss_total_time ,            SUN_CI, "ic_miss");
+     if (HAS_PENDING_EXCEPTION) {
+       vm_exit_during_initialization("SharedRuntime::generate_stubs() failed unexpectedly");
+     }
+   }
+ }
+ 
+ void SharedRuntime::init_adapter_library() {
+   AdapterHandlerLibrary::initialize();
+ }
+ 
+ static void print_counter_on(outputStream* st, const char* name, PerfTickCounters* counter, uint cnt) {
+   st->print("  %-28s " JLONG_FORMAT_W(6) "us", name, counter->elapsed_counter_value_us());
+   if (TraceThreadTime) {
+     st->print(" (elapsed) " JLONG_FORMAT_W(6) "us (thread)", counter->thread_counter_value_us());
+   }
+   st->print(" / %5d events", cnt);
+   st->cr();
+ }
+ 
+ void SharedRuntime::print_counters_on(outputStream* st) {
+   st->print_cr("SharedRuntime:");
+   if (UsePerfData) {
+     print_counter_on(st, "resolve_opt_virtual_call:", _perf_resolve_opt_virtual_total_time, _resolve_opt_virtual_ctr);
+     print_counter_on(st, "resolve_virtual_call:",     _perf_resolve_virtual_total_time,     _resolve_virtual_ctr);
+     print_counter_on(st, "resolve_static_call:",      _perf_resolve_static_total_time,      _resolve_static_ctr);
+     print_counter_on(st, "handle_wrong_method:",      _perf_handle_wrong_method_total_time, _wrong_method_ctr);
+     print_counter_on(st, "ic_miss:",                  _perf_ic_miss_total_time,             _ic_miss_ctr);
+ 
+     jlong total_elapsed_time_us = Management::ticks_to_us(_perf_resolve_opt_virtual_total_time->elapsed_counter_value() +
+                                                           _perf_resolve_virtual_total_time->elapsed_counter_value() +
+                                                           _perf_resolve_static_total_time->elapsed_counter_value() +
+                                                           _perf_handle_wrong_method_total_time->elapsed_counter_value() +
+                                                           _perf_ic_miss_total_time->elapsed_counter_value());
+     st->print("Total:                      " JLONG_FORMAT_W(5) "us", total_elapsed_time_us);
+     if (TraceThreadTime) {
+       jlong total_thread_time_us = Management::ticks_to_us(_perf_resolve_opt_virtual_total_time->thread_counter_value() +
+                                                            _perf_resolve_virtual_total_time->thread_counter_value() +
+                                                            _perf_resolve_static_total_time->thread_counter_value() +
+                                                            _perf_handle_wrong_method_total_time->thread_counter_value() +
+                                                            _perf_ic_miss_total_time->thread_counter_value());
+       st->print(" (elapsed) " JLONG_FORMAT_W(5) "us (thread)", total_thread_time_us);
+ 
+     }
+     st->cr();
+   } else {
+     st->print_cr("  no data (UsePerfData is turned off)");
+   }
  }
  
  #if INCLUDE_JFR
  //------------------------------generate jfr runtime stubs ------
  void SharedRuntime::generate_jfr_stubs() {

*** 183,17 ***
  
  #include <math.h>
  
  // Implementation of SharedRuntime
  
- #ifndef PRODUCT
  // For statistics
  uint SharedRuntime::_ic_miss_ctr = 0;
  uint SharedRuntime::_wrong_method_ctr = 0;
  uint SharedRuntime::_resolve_static_ctr = 0;
  uint SharedRuntime::_resolve_virtual_ctr = 0;
  uint SharedRuntime::_resolve_opt_virtual_ctr = 0;
  uint SharedRuntime::_implicit_null_throws = 0;
  uint SharedRuntime::_implicit_div0_throws = 0;
  
  int64_t SharedRuntime::_nof_normal_calls = 0;
  int64_t SharedRuntime::_nof_inlined_calls = 0;
--- 247,18 ---
  
  #include <math.h>
  
  // Implementation of SharedRuntime
  
  // For statistics
  uint SharedRuntime::_ic_miss_ctr = 0;
  uint SharedRuntime::_wrong_method_ctr = 0;
  uint SharedRuntime::_resolve_static_ctr = 0;
  uint SharedRuntime::_resolve_virtual_ctr = 0;
  uint SharedRuntime::_resolve_opt_virtual_ctr = 0;
+ 
+ #ifndef PRODUCT
  uint SharedRuntime::_implicit_null_throws = 0;
  uint SharedRuntime::_implicit_div0_throws = 0;
  
  int64_t SharedRuntime::_nof_normal_calls = 0;
  int64_t SharedRuntime::_nof_inlined_calls = 0;

*** 243,22 ***
    if (_ICmiss_index >= maxICmiss_count) _ICmiss_index = maxICmiss_count - 1;
    _ICmiss_at[index] = at;
    _ICmiss_count[index] = 1;
  }
  
! void SharedRuntime::print_ic_miss_histogram() {
    if (ICMissHistogram) {
!     tty->print_cr("IC Miss Histogram:");
      int tot_misses = 0;
      for (int i = 0; i < _ICmiss_index; i++) {
!       tty->print_cr("  at: " INTPTR_FORMAT "  nof: %d", p2i(_ICmiss_at[i]), _ICmiss_count[i]);
        tot_misses += _ICmiss_count[i];
      }
!     tty->print_cr("Total IC misses: %7d", tot_misses);
    }
  }
! #endif // PRODUCT
  
  
  JRT_LEAF(jlong, SharedRuntime::lmul(jlong y, jlong x))
    return x * y;
  JRT_END
--- 308,22 ---
    if (_ICmiss_index >= maxICmiss_count) _ICmiss_index = maxICmiss_count - 1;
    _ICmiss_at[index] = at;
    _ICmiss_count[index] = 1;
  }
  
! void SharedRuntime::print_ic_miss_histogram_on(outputStream* st) {
    if (ICMissHistogram) {
!     st->print_cr("IC Miss Histogram:");
      int tot_misses = 0;
      for (int i = 0; i < _ICmiss_index; i++) {
!       st->print_cr("  at: " INTPTR_FORMAT "  nof: %d", p2i(_ICmiss_at[i]), _ICmiss_count[i]);
        tot_misses += _ICmiss_count[i];
      }
!     st->print_cr("Total IC misses: %7d", tot_misses);
    }
  }
! #endif // !PRODUCT
  
  
  JRT_LEAF(jlong, SharedRuntime::lmul(jlong y, jlong x))
    return x * y;
  JRT_END

*** 721,10 ***
--- 786,22 ---
      // an error. Our method could have been redefined just after we
      // fetched the Method* from the constant pool.
      ResourceMark rm;
      log_trace(redefine, class, obsolete)("calling obsolete method '%s'", method->name_and_sig_as_C_string());
    }
+ 
+   LogStreamHandle(Trace, interpreter, bytecode) log;
+   if (log.is_enabled()) {
+     ResourceMark rm;
+     log.print("method entry: " INTPTR_FORMAT " %s %s%s%s%s",
+               p2i(thread),
+               (method->is_static() ? "static" : "virtual"),
+               method->name_and_sig_as_C_string(),
+               (method->is_native() ? " native" : ""),
+               (thread->class_being_initialized() != nullptr ? " clinit" : ""),
+               (method->method_holder()->is_initialized() ? "" : " being_initialized"));
+   }
    return 0;
  JRT_END
  
  // ret_pc points into caller; we are returning caller's exception handler
  // for given exception

*** 1360,17 ***
           (!is_virtual && invoke_code == Bytecodes::_invokedynamic) ||
           ( is_virtual && invoke_code != Bytecodes::_invokestatic ), "inconsistent bytecode");
  
    assert(!caller_nm->is_unloading(), "It should not be unloading");
  
- #ifndef PRODUCT
    // tracing/debugging/statistics
    uint *addr = (is_optimized) ? (&_resolve_opt_virtual_ctr) :
                   (is_virtual) ? (&_resolve_virtual_ctr) :
                                  (&_resolve_static_ctr);
    Atomic::inc(addr);
  
    if (TraceCallFixup) {
      ResourceMark rm(current);
      tty->print("resolving %s%s (%s) call to",
                 (is_optimized) ? "optimized " : "", (is_virtual) ? "virtual" : "static",
                 Bytecodes::name(invoke_code));
--- 1437,17 ---
           (!is_virtual && invoke_code == Bytecodes::_invokedynamic) ||
           ( is_virtual && invoke_code != Bytecodes::_invokestatic ), "inconsistent bytecode");
  
    assert(!caller_nm->is_unloading(), "It should not be unloading");
  
    // tracing/debugging/statistics
    uint *addr = (is_optimized) ? (&_resolve_opt_virtual_ctr) :
                   (is_virtual) ? (&_resolve_virtual_ctr) :
                                  (&_resolve_static_ctr);
    Atomic::inc(addr);
  
+ #ifndef PRODUCT
    if (TraceCallFixup) {
      ResourceMark rm(current);
      tty->print("resolving %s%s (%s) call to",
                 (is_optimized) ? "optimized " : "", (is_virtual) ? "virtual" : "static",
                 Bytecodes::name(invoke_code));

*** 1422,10 ***
--- 1499,12 ---
    return callee_method;
  }
  
  // Inline caches exist only in compiled code
  JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method_ic_miss(JavaThread* current))
+   PerfTraceTime timer(_perf_ic_miss_total_time);
+ 
  #ifdef ASSERT
    RegisterMap reg_map(current,
                        RegisterMap::UpdateMap::skip,
                        RegisterMap::ProcessFrames::include,
                        RegisterMap::WalkContinuation::skip);

*** 1446,10 ***
--- 1525,12 ---
  JRT_END
  
  
  // Handle call site that has been made non-entrant
  JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method(JavaThread* current))
+   PerfTraceTime timer(_perf_handle_wrong_method_total_time);
+ 
    // 6243940 We might end up in here if the callee is deoptimized
    // as we race to call it.  We don't want to take a safepoint if
    // the caller was interpreted because the caller frame will look
    // interpreted to the stack walkers and arguments are now
    // "compiled" so it is much better to make this transition

*** 1498,10 ***
--- 1579,12 ---
    return get_resolved_entry(current, callee_method);
  JRT_END
  
  // Handle abstract method call
  JRT_BLOCK_ENTRY(address, SharedRuntime::handle_wrong_method_abstract(JavaThread* current))
+   PerfTraceTime timer(_perf_handle_wrong_method_total_time);
+ 
    // Verbose error message for AbstractMethodError.
    // Get the called method from the invoke bytecode.
    vframeStream vfst(current, true);
    assert(!vfst.at_end(), "Java frame must exist");
    methodHandle caller(current, vfst.method());

*** 1544,10 ***
--- 1627,12 ---
    return callee_method->verified_code_entry();
  }
  
  // resolve a static call and patch code
  JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_static_call_C(JavaThread* current ))
+   PerfTraceTime timer(_perf_resolve_static_total_time);
+ 
    methodHandle callee_method;
    bool enter_special = false;
    JRT_BLOCK
      callee_method = SharedRuntime::resolve_helper(false, false, CHECK_NULL);
      current->set_vm_result_2(callee_method());

*** 1556,10 ***
--- 1641,12 ---
    return get_resolved_entry(current, callee_method);
  JRT_END
  
  // resolve virtual call and update inline cache to monomorphic
  JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_virtual_call_C(JavaThread* current))
+   PerfTraceTime timer(_perf_resolve_virtual_total_time);
+ 
    methodHandle callee_method;
    JRT_BLOCK
      callee_method = SharedRuntime::resolve_helper(true, false, CHECK_NULL);
      current->set_vm_result_2(callee_method());
    JRT_BLOCK_END

*** 1569,10 ***
--- 1656,12 ---
  
  
  // Resolve a virtual call that can be statically bound (e.g., always
  // monomorphic, so it has no inline cache).  Patch code to resolved target.
  JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_opt_virtual_call_C(JavaThread* current))
+   PerfTraceTime timer(_perf_resolve_opt_virtual_total_time);
+ 
    methodHandle callee_method;
    JRT_BLOCK
      callee_method = SharedRuntime::resolve_helper(true, true, CHECK_NULL);
      current->set_vm_result_2(callee_method());
    JRT_BLOCK_END

*** 1590,13 ***
    // receivers for non-static calls
    Handle receiver = find_callee_info(bc, call_info, CHECK_(methodHandle()));
  
    methodHandle callee_method(current, call_info.selected_method());
  
- #ifndef PRODUCT
    Atomic::inc(&_ic_miss_ctr);
  
    // Statistics & Tracing
    if (TraceCallFixup) {
      ResourceMark rm(current);
      tty->print("IC miss (%s) call to", Bytecodes::name(bc));
      callee_method->print_short_name(tty);
--- 1679,13 ---
    // receivers for non-static calls
    Handle receiver = find_callee_info(bc, call_info, CHECK_(methodHandle()));
  
    methodHandle callee_method(current, call_info.selected_method());
  
    Atomic::inc(&_ic_miss_ctr);
  
+ #ifndef PRODUCT
    // Statistics & Tracing
    if (TraceCallFixup) {
      ResourceMark rm(current);
      tty->print("IC miss (%s) call to", Bytecodes::name(bc));
      callee_method->print_short_name(tty);

*** 1715,14 ***
      }
    }
  
    methodHandle callee_method = find_callee_method(CHECK_(methodHandle()));
  
- 
- #ifndef PRODUCT
    Atomic::inc(&_wrong_method_ctr);
  
    if (TraceCallFixup) {
      ResourceMark rm(current);
      tty->print("handle_wrong_method reresolving call to");
      callee_method->print_short_name(tty);
      tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code()));
--- 1804,13 ---
      }
    }
  
    methodHandle callee_method = find_callee_method(CHECK_(methodHandle()));
  
    Atomic::inc(&_wrong_method_ctr);
  
+ #ifndef PRODUCT
    if (TraceCallFixup) {
      ResourceMark rm(current);
      tty->print("handle_wrong_method reresolving call to");
      callee_method->print_short_name(tty);
      tty->print_cr(" code: " INTPTR_FORMAT, p2i(callee_method->code()));

*** 2016,49 ***
  
  void SharedRuntime::print_statistics() {
    ttyLocker ttyl;
    if (xtty != nullptr)  xtty->head("statistics type='SharedRuntime'");
  
!   SharedRuntime::print_ic_miss_histogram();
! 
!   // Dump the JRT_ENTRY counters
-   if (_new_instance_ctr) tty->print_cr("%5u new instance requires GC", _new_instance_ctr);
-   if (_new_array_ctr) tty->print_cr("%5u new array requires GC", _new_array_ctr);
-   if (_multi2_ctr) tty->print_cr("%5u multianewarray 2 dim", _multi2_ctr);
-   if (_multi3_ctr) tty->print_cr("%5u multianewarray 3 dim", _multi3_ctr);
-   if (_multi4_ctr) tty->print_cr("%5u multianewarray 4 dim", _multi4_ctr);
-   if (_multi5_ctr) tty->print_cr("%5u multianewarray 5 dim", _multi5_ctr);
- 
-   tty->print_cr("%5u inline cache miss in compiled", _ic_miss_ctr);
-   tty->print_cr("%5u wrong method", _wrong_method_ctr);
-   tty->print_cr("%5u unresolved static call site", _resolve_static_ctr);
-   tty->print_cr("%5u unresolved virtual call site", _resolve_virtual_ctr);
-   tty->print_cr("%5u unresolved opt virtual call site", _resolve_opt_virtual_ctr);
- 
-   if (_mon_enter_stub_ctr) tty->print_cr("%5u monitor enter stub", _mon_enter_stub_ctr);
-   if (_mon_exit_stub_ctr) tty->print_cr("%5u monitor exit stub", _mon_exit_stub_ctr);
-   if (_mon_enter_ctr) tty->print_cr("%5u monitor enter slow", _mon_enter_ctr);
-   if (_mon_exit_ctr) tty->print_cr("%5u monitor exit slow", _mon_exit_ctr);
-   if (_partial_subtype_ctr) tty->print_cr("%5u slow partial subtype", _partial_subtype_ctr);
-   if (_jbyte_array_copy_ctr) tty->print_cr("%5u byte array copies", _jbyte_array_copy_ctr);
-   if (_jshort_array_copy_ctr) tty->print_cr("%5u short array copies", _jshort_array_copy_ctr);
-   if (_jint_array_copy_ctr) tty->print_cr("%5u int array copies", _jint_array_copy_ctr);
-   if (_jlong_array_copy_ctr) tty->print_cr("%5u long array copies", _jlong_array_copy_ctr);
-   if (_oop_array_copy_ctr) tty->print_cr("%5u oop array copies", _oop_array_copy_ctr);
-   if (_checkcast_array_copy_ctr) tty->print_cr("%5u checkcast array copies", _checkcast_array_copy_ctr);
-   if (_unsafe_array_copy_ctr) tty->print_cr("%5u unsafe array copies", _unsafe_array_copy_ctr);
-   if (_generic_array_copy_ctr) tty->print_cr("%5u generic array copies", _generic_array_copy_ctr);
-   if (_slow_array_copy_ctr) tty->print_cr("%5u slow array copies", _slow_array_copy_ctr);
-   if (_find_handler_ctr) tty->print_cr("%5u find exception handler", _find_handler_ctr);
-   if (_rethrow_ctr) tty->print_cr("%5u rethrow handler", _rethrow_ctr);
-   if (_unsafe_set_memory_ctr) tty->print_cr("%5u unsafe set memorys", _unsafe_set_memory_ctr);
- 
-   AdapterHandlerLibrary::print_statistics();
  
    if (xtty != nullptr)  xtty->tail("statistics");
  }
  
  inline double percent(int64_t x, int64_t y) {
    return 100.0 * (double)x / (double)MAX2(y, (int64_t)1);
  }
  
  class MethodArityHistogram {
--- 2104,51 ---
  
  void SharedRuntime::print_statistics() {
    ttyLocker ttyl;
    if (xtty != nullptr)  xtty->head("statistics type='SharedRuntime'");
  
!   SharedRuntime::print_ic_miss_histogram_on(tty);
!   SharedRuntime::print_counters_on(tty);
!   AdapterHandlerLibrary::print_statistics_on(tty);
  
    if (xtty != nullptr)  xtty->tail("statistics");
  }
  
+ //void SharedRuntime::print_counters_on(outputStream* st) {
+ //  // Dump the JRT_ENTRY counters
+ //  if (_new_instance_ctr) st->print_cr("%5u new instance requires GC", _new_instance_ctr);
+ //  if (_new_array_ctr)    st->print_cr("%5u new array requires GC", _new_array_ctr);
+ //  if (_multi2_ctr)       st->print_cr("%5u multianewarray 2 dim", _multi2_ctr);
+ //  if (_multi3_ctr)       st->print_cr("%5u multianewarray 3 dim", _multi3_ctr);
+ //  if (_multi4_ctr)       st->print_cr("%5u multianewarray 4 dim", _multi4_ctr);
+ //  if (_multi5_ctr)       st->print_cr("%5u multianewarray 5 dim", _multi5_ctr);
+ //
+ //  st->print_cr("%5u inline cache miss in compiled", _ic_miss_ctr);
+ //  st->print_cr("%5u wrong method", _wrong_method_ctr);
+ //  st->print_cr("%5u unresolved static call site", _resolve_static_ctr);
+ //  st->print_cr("%5u unresolved virtual call site", _resolve_virtual_ctr);
+ //  st->print_cr("%5u unresolved opt virtual call site", _resolve_opt_virtual_ctr);
+ //
+ //  if (_mon_enter_stub_ctr)       st->print_cr("%5u monitor enter stub", _mon_enter_stub_ctr);
+ //  if (_mon_exit_stub_ctr)        st->print_cr("%5u monitor exit stub", _mon_exit_stub_ctr);
+ //  if (_mon_enter_ctr)            st->print_cr("%5u monitor enter slow", _mon_enter_ctr);
+ //  if (_mon_exit_ctr)             st->print_cr("%5u monitor exit slow", _mon_exit_ctr);
+ //  if (_partial_subtype_ctr)      st->print_cr("%5u slow partial subtype", _partial_subtype_ctr);
+ //  if (_jbyte_array_copy_ctr)     st->print_cr("%5u byte array copies", _jbyte_array_copy_ctr);
+ //  if (_jshort_array_copy_ctr)    st->print_cr("%5u short array copies", _jshort_array_copy_ctr);
+ //  if (_jint_array_copy_ctr)      st->print_cr("%5u int array copies", _jint_array_copy_ctr);
+ //  if (_jlong_array_copy_ctr)     st->print_cr("%5u long array copies", _jlong_array_copy_ctr);
+ //  if (_oop_array_copy_ctr)       st->print_cr("%5u oop array copies", _oop_array_copy_ctr);
+ //  if (_checkcast_array_copy_ctr) st->print_cr("%5u checkcast array copies", _checkcast_array_copy_ctr);
+ //  if (_unsafe_array_copy_ctr)    st->print_cr("%5u unsafe array copies", _unsafe_array_copy_ctr);
+ //  if (_generic_array_copy_ctr)   st->print_cr("%5u generic array copies", _generic_array_copy_ctr);
+ //  if (_slow_array_copy_ctr)      st->print_cr("%5u slow array copies", _slow_array_copy_ctr);
+ //  if (_find_handler_ctr)         st->print_cr("%5u find exception handler", _find_handler_ctr);
+ //  if (_rethrow_ctr)              st->print_cr("%5u rethrow handler", _rethrow_ctr);
+ //  if (_unsafe_set_memory_ctr) tty->print_cr("%5u unsafe set memorys", _unsafe_set_memory_ctr);
+ //}
+ 
  inline double percent(int64_t x, int64_t y) {
    return 100.0 * (double)x / (double)MAX2(y, (int64_t)1);
  }
  
  class MethodArityHistogram {

*** 2139,11 ***
  uint64_t MethodArityHistogram::_total_compiled_calls;
  uint64_t MethodArityHistogram::_max_compiled_calls_per_method;
  int MethodArityHistogram::_max_arity;
  int MethodArityHistogram::_max_size;
  
! void SharedRuntime::print_call_statistics(uint64_t comp_total) {
    tty->print_cr("Calls from compiled code:");
    int64_t total  = _nof_normal_calls + _nof_interface_calls + _nof_static_calls;
    int64_t mono_c = _nof_normal_calls - _nof_megamorphic_calls;
    int64_t mono_i = _nof_interface_calls;
    tty->print_cr("\t" INT64_FORMAT_W(12) " (100%%)  total non-inlined   ", total);
--- 2229,11 ---
  uint64_t MethodArityHistogram::_total_compiled_calls;
  uint64_t MethodArityHistogram::_max_compiled_calls_per_method;
  int MethodArityHistogram::_max_arity;
  int MethodArityHistogram::_max_size;
  
! void SharedRuntime::print_call_statistics_on(outputStream* st) {
    tty->print_cr("Calls from compiled code:");
    int64_t total  = _nof_normal_calls + _nof_interface_calls + _nof_static_calls;
    int64_t mono_c = _nof_normal_calls - _nof_megamorphic_calls;
    int64_t mono_i = _nof_interface_calls;
    tty->print_cr("\t" INT64_FORMAT_W(12) " (100%%)  total non-inlined   ", total);

*** 2168,33 ***
  #endif
  
  #ifndef PRODUCT
  static int _lookups; // number of calls to lookup
  static int _equals;  // number of buckets checked with matching hash
! static int _hits;    // number of successful lookups
  static int _compact; // number of equals calls with compact signature
  #endif
  
  // A simple wrapper class around the calling convention information
  // that allows sharing of adapters for the same calling convention.
! class AdapterFingerPrint : public CHeapObj<mtCode> {
   private:
    enum {
      _basic_type_bits = 4,
      _basic_type_mask = right_n_bits(_basic_type_bits),
      _basic_types_per_int = BitsPerInt / _basic_type_bits,
      _compact_int_count = 3
    };
    // TO DO:  Consider integrating this with a more global scheme for compressing signatures.
    // For now, 4 bits per components (plus T_VOID gaps after double/long) is not excessive.
  
!   union {
!     int  _compact[_compact_int_count];
!     int* _fingerprint;
!   } _value;
!   int _length; // A negative length indicates the fingerprint is in the compact form,
!                // Otherwise _value._fingerprint is the array.
  
    // Remap BasicTypes that are handled equivalently by the adapters.
    // These are correct for the current system but someday it might be
    // necessary to make this mapping platform dependent.
    static int adapter_encoding(BasicType in) {
--- 2258,51 ---
  #endif
  
  #ifndef PRODUCT
  static int _lookups; // number of calls to lookup
  static int _equals;  // number of buckets checked with matching hash
! static int _archived_hits;    // number of successful lookups in archived table
+ static int _runtime_hits; // number of successful lookups in runtime table
  static int _compact; // number of equals calls with compact signature
  #endif
  
  // A simple wrapper class around the calling convention information
  // that allows sharing of adapters for the same calling convention.
! class AdapterFingerPrint : public MetaspaceObj {
   private:
    enum {
      _basic_type_bits = 4,
      _basic_type_mask = right_n_bits(_basic_type_bits),
      _basic_types_per_int = BitsPerInt / _basic_type_bits,
      _compact_int_count = 3
    };
    // TO DO:  Consider integrating this with a more global scheme for compressing signatures.
    // For now, 4 bits per components (plus T_VOID gaps after double/long) is not excessive.
  
!   int _length;
!   int _value[_compact_int_count];
! 
!   // Private construtor. Use allocate() to get an instance.
!   AdapterFingerPrint(int total_args_passed, BasicType* sig_bt) {
!     // Pack the BasicTypes with 8 per int
+     _length = (total_args_passed + (_basic_types_per_int-1)) / _basic_types_per_int;
+     int sig_index = 0;
+     for (int index = 0; index < _length; index++) {
+       int value = 0;
+       for (int byte = 0; sig_index < total_args_passed && byte < _basic_types_per_int; byte++) {
+         int bt = adapter_encoding(sig_bt[sig_index++]);
+         assert((bt & _basic_type_mask) == bt, "must fit in 4 bits");
+         value = (value << _basic_type_bits) | bt;
+       }
+       _value[index] = value;
+     }
+   }
+ 
+   // Call deallocate instead
+   ~AdapterFingerPrint() {
+     FreeHeap(this);
+   }
  
    // Remap BasicTypes that are handled equivalently by the adapters.
    // These are correct for the current system but someday it might be
    // necessary to make this mapping platform dependent.
    static int adapter_encoding(BasicType in) {

*** 2227,68 ***
          ShouldNotReachHere();
          return T_CONFLICT;
      }
    }
  
!  public:
!   AdapterFingerPrint(int total_args_passed, BasicType* sig_bt) {
!     // The fingerprint is based on the BasicType signature encoded
!     // into an array of ints with eight entries per int.
!     int* ptr;
!     int len = (total_args_passed + (_basic_types_per_int-1)) / _basic_types_per_int;
-     if (len <= _compact_int_count) {
-       assert(_compact_int_count == 3, "else change next line");
-       _value._compact[0] = _value._compact[1] = _value._compact[2] = 0;
-       // Storing the signature encoded as signed chars hits about 98%
-       // of the time.
-       _length = -len;
-       ptr = _value._compact;
-     } else {
-       _length = len;
-       _value._fingerprint = NEW_C_HEAP_ARRAY(int, _length, mtCode);
-       ptr = _value._fingerprint;
-     }
  
!     // Now pack the BasicTypes with 8 per int
!     int sig_index = 0;
!     for (int index = 0; index < len; index++) {
!       int value = 0;
!       for (int byte = 0; sig_index < total_args_passed && byte < _basic_types_per_int; byte++) {
!         int bt = adapter_encoding(sig_bt[sig_index++]);
!         assert((bt & _basic_type_mask) == bt, "must fit in 4 bits");
!         value = (value << _basic_type_bits) | bt;
        }
-       ptr[index] = value;
      }
    }
  
!   ~AdapterFingerPrint() {
!     if (_length > 0) {
!       FREE_C_HEAP_ARRAY(int, _value._fingerprint);
!     }
    }
  
    int value(int index) {
!     if (_length < 0) {
-       return _value._compact[index];
-     }
-     return _value._fingerprint[index];
    }
    int length() {
      if (_length < 0) return -_length;
      return _length;
    }
  
    bool is_compact() {
!     return _length <= 0;
    }
  
    unsigned int compute_hash() {
      int hash = 0;
      for (int i = 0; i < length(); i++) {
        int v = value(i);
!       hash = (hash << 8) ^ v ^ (hash >> 5);
      }
      return (unsigned int)hash;
    }
  
    const char* as_string() {
--- 2335,67 ---
          ShouldNotReachHere();
          return T_CONFLICT;
      }
    }
  
!   void* operator new(size_t size, size_t fp_size) throw() {
!     assert(fp_size >= size, "sanity check");
!     void* p = AllocateHeap(fp_size, mtCode);
!     memset(p, 0, fp_size);
!     return p;
!   }
  
!   template<typename Function>
!   void iterate_args(Function function) {
!     for (int i = 0; i < length(); i++) {
!       unsigned val = (unsigned)value(i);
!       // args are packed so that first/lower arguments are in the highest
!       // bits of each int value, so iterate from highest to the lowest
!       for (int j = 32 - _basic_type_bits; j >= 0; j -= _basic_type_bits) {
!         unsigned v = (val >> j) & _basic_type_mask;
+         if (v == 0) {
+           continue;
+         }
+         function(v);
        }
      }
    }
  
!  public:
!   static int allocation_size(int total_args_passed, BasicType* sig_bt) {
!     int len = (total_args_passed + (_basic_types_per_int-1)) / _basic_types_per_int;
!     return sizeof(AdapterFingerPrint) + (len > _compact_int_count ? (len - _compact_int_count) * sizeof(int) : 0);
+   }
+ 
+   static AdapterFingerPrint* allocate(int total_args_passed, BasicType* sig_bt) {
+     int size_in_bytes = allocation_size(total_args_passed, sig_bt);
+     return new (size_in_bytes) AdapterFingerPrint(total_args_passed, sig_bt);
+   }
+ 
+   static void deallocate(AdapterFingerPrint* fp) {
+     fp->~AdapterFingerPrint();
    }
  
    int value(int index) {
!     return _value[index];
    }
+ 
    int length() {
      if (_length < 0) return -_length;
      return _length;
    }
  
    bool is_compact() {
!     return _length <= _compact_int_count;
    }
  
    unsigned int compute_hash() {
      int hash = 0;
      for (int i = 0; i < length(); i++) {
        int v = value(i);
!       //Add arithmetic operation to the hash, like +3 to improve hashing
+       hash = ((hash << 8) ^ v ^ (hash >> 5)) + 3;
      }
      return (unsigned int)hash;
    }
  
    const char* as_string() {

*** 2298,125 ***
        st.print("%x", value(i));
      }
      return st.as_string();
    }
  
- #ifndef PRODUCT
-   // Reconstitutes the basic type arguments from the fingerprint,
-   // producing strings like LIJDF
    const char* as_basic_args_string() {
      stringStream st;
      bool long_prev = false;
!     for (int i = 0; i < length(); i++) {
!       unsigned val = (unsigned)value(i);
!       // args are packed so that first/lower arguments are in the highest
!       // bits of each int value, so iterate from highest to the lowest
!       for (int j = 32 - _basic_type_bits; j >= 0; j -= _basic_type_bits) {
!         unsigned v = (val >> j) & _basic_type_mask;
!         if (v == 0) {
-           assert(i == length() - 1, "Only expect zeroes in the last word");
-           continue;
-         }
-         if (long_prev) {
-           long_prev = false;
-           if (v == T_VOID) {
-             st.print("J");
-           } else {
-             st.print("L");
-           }
-         }
-         switch (v) {
-           case T_INT:    st.print("I");    break;
-           case T_LONG:   long_prev = true; break;
-           case T_FLOAT:  st.print("F");    break;
-           case T_DOUBLE: st.print("D");    break;
-           case T_VOID:   break;
-           default: ShouldNotReachHere();
          }
        }
!     }
      if (long_prev) {
        st.print("L");
      }
      return st.as_string();
    }
! #endif // !product
  
    bool equals(AdapterFingerPrint* other) {
      if (other->_length != _length) {
        return false;
-     }
-     if (_length < 0) {
-       assert(_compact_int_count == 3, "else change next line");
-       return _value._compact[0] == other->_value._compact[0] &&
-              _value._compact[1] == other->_value._compact[1] &&
-              _value._compact[2] == other->_value._compact[2];
      } else {
        for (int i = 0; i < _length; i++) {
!         if (_value._fingerprint[i] != other->_value._fingerprint[i]) {
            return false;
          }
        }
      }
      return true;
    }
  
    static bool equals(AdapterFingerPrint* const& fp1, AdapterFingerPrint* const& fp2) {
      NOT_PRODUCT(_equals++);
      return fp1->equals(fp2);
    }
  
    static unsigned int compute_hash(AdapterFingerPrint* const& fp) {
      return fp->compute_hash();
    }
  };
  
  // A hashtable mapping from AdapterFingerPrints to AdapterHandlerEntries
  using AdapterHandlerTable = ResourceHashtable<AdapterFingerPrint*, AdapterHandlerEntry*, 293,
                    AnyObj::C_HEAP, mtCode,
                    AdapterFingerPrint::compute_hash,
                    AdapterFingerPrint::equals>;
  static AdapterHandlerTable* _adapter_handler_table;
  
  // Find a entry with the same fingerprint if it exists
! static AdapterHandlerEntry* lookup(int total_args_passed, BasicType* sig_bt) {
    NOT_PRODUCT(_lookups++);
    assert_lock_strong(AdapterHandlerLibrary_lock);
!   AdapterFingerPrint fp(total_args_passed, sig_bt);
!   AdapterHandlerEntry** entry = _adapter_handler_table->get(&fp);
!   if (entry != nullptr) {
  #ifndef PRODUCT
!     if (fp.is_compact()) _compact++;
!     _hits++;
  #endif
!     return *entry;
    }
    return nullptr;
  }
  
  #ifndef PRODUCT
! static void print_table_statistics() {
    auto size = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
      return sizeof(*key) + sizeof(*a);
    };
    TableStatistics ts = _adapter_handler_table->statistics_calculate(size);
!   ts.print(tty, "AdapterHandlerTable");
!   tty->print_cr("AdapterHandlerTable (table_size=%d, entries=%d)",
!                 _adapter_handler_table->table_size(), _adapter_handler_table->number_of_entries());
!   tty->print_cr("AdapterHandlerTable: lookups %d equals %d hits %d compact %d",
!                 _lookups, _equals, _hits, _compact);
  }
! #endif
  
  // ---------------------------------------------------------------------------
  // Implementation of AdapterHandlerLibrary
  AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_no_arg_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_int_arg_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_obj_arg_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_obj_int_arg_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_obj_obj_arg_handler = nullptr;
  const int AdapterHandlerLibrary_size = 16*K;
  BufferBlob* AdapterHandlerLibrary::_buffer = nullptr;
  
  BufferBlob* AdapterHandlerLibrary::buffer_blob() {
    return _buffer;
--- 2405,198 ---
        st.print("%x", value(i));
      }
      return st.as_string();
    }
  
    const char* as_basic_args_string() {
      stringStream st;
      bool long_prev = false;
!     iterate_args([&] (int arg) {
!       if (long_prev) {
!         long_prev = false;
!         if (arg == T_VOID) {
!           st.print("J");
!         } else {
!           st.print("L");
          }
        }
!       switch (arg) {
+         case T_INT:    st.print("I");    break;
+         case T_LONG:   long_prev = true; break;
+         case T_FLOAT:  st.print("F");    break;
+         case T_DOUBLE: st.print("D");    break;
+         case T_VOID:   break;
+         default: ShouldNotReachHere();
+       }
+     });
      if (long_prev) {
        st.print("L");
      }
      return st.as_string();
    }
! 
+   BasicType* as_basic_type(int& nargs) {
+     nargs = 0;
+     GrowableArray<BasicType> btarray;
+     bool long_prev = false;
+ 
+     iterate_args([&] (int arg) {
+       if (long_prev) {
+         long_prev = false;
+         if (arg == T_VOID) {
+           btarray.append(T_LONG);
+         } else {
+           btarray.append(T_OBJECT); // it could be T_ARRAY; it shouldn't matter
+         }
+       }
+       switch (arg) {
+         case T_INT: // fallthrough
+         case T_FLOAT: // fallthrough
+         case T_DOUBLE:
+         case T_VOID:
+           btarray.append((BasicType)arg);
+           break;
+         case T_LONG:
+           long_prev = true;
+           break;
+         default: ShouldNotReachHere();
+       }
+     });
+ 
+     if (long_prev) {
+       btarray.append(T_OBJECT);
+     }
+ 
+     nargs = btarray.length();
+     BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, nargs);
+     int index = 0;
+     GrowableArrayIterator<BasicType> iter = btarray.begin();
+     while (iter != btarray.end()) {
+       sig_bt[index++] = *iter;
+       ++iter;
+     }
+     assert(index == btarray.length(), "sanity check");
+ #ifdef ASSERT
+     {
+       AdapterFingerPrint* compare_fp = AdapterFingerPrint::allocate(nargs, sig_bt);
+       assert(this->equals(compare_fp), "sanity check");
+       AdapterFingerPrint::deallocate(compare_fp);
+     }
+ #endif
+     return sig_bt;
+   }
  
    bool equals(AdapterFingerPrint* other) {
      if (other->_length != _length) {
        return false;
      } else {
        for (int i = 0; i < _length; i++) {
!         if (_value[i] != other->_value[i]) {
            return false;
          }
        }
      }
      return true;
    }
  
+   // methods required by virtue of being a MetaspaceObj
+   void metaspace_pointers_do(MetaspaceClosure* it) { return; /* nothing to do here */ }
+   int size() const { return (int)heap_word_size(sizeof(AdapterFingerPrint) + (_length > _compact_int_count ? (_length - _compact_int_count) * sizeof(int) : 0)); }
+   MetaspaceObj::Type type() const { return AdapterFingerPrintType; }
+ 
    static bool equals(AdapterFingerPrint* const& fp1, AdapterFingerPrint* const& fp2) {
      NOT_PRODUCT(_equals++);
      return fp1->equals(fp2);
    }
  
    static unsigned int compute_hash(AdapterFingerPrint* const& fp) {
      return fp->compute_hash();
    }
  };
  
+ #if INCLUDE_CDS
+ static inline bool adapter_fp_equals_compact_hashtable_entry(AdapterHandlerEntry* entry, AdapterFingerPrint* fp, int len_unused) {
+   return AdapterFingerPrint::equals(entry->fingerprint(), fp);
+ }
+ 
+ class ArchivedAdapterTable : public OffsetCompactHashtable<
+   AdapterFingerPrint*,
+   AdapterHandlerEntry*,
+   adapter_fp_equals_compact_hashtable_entry> {};
+ #endif // INCLUDE_CDS
+ 
  // A hashtable mapping from AdapterFingerPrints to AdapterHandlerEntries
  using AdapterHandlerTable = ResourceHashtable<AdapterFingerPrint*, AdapterHandlerEntry*, 293,
                    AnyObj::C_HEAP, mtCode,
                    AdapterFingerPrint::compute_hash,
                    AdapterFingerPrint::equals>;
  static AdapterHandlerTable* _adapter_handler_table;
+ static GrowableArray<AdapterHandlerEntry*>* _adapter_handler_list = nullptr;
  
  // Find a entry with the same fingerprint if it exists
! AdapterHandlerEntry* AdapterHandlerLibrary::lookup(AdapterFingerPrint* fp) {
    NOT_PRODUCT(_lookups++);
+   AdapterHandlerEntry* entry = nullptr;
+ #if INCLUDE_CDS
+   // if we are building the archive then the archived adapter table is
+   // not valid and we need to use the ones added to the runtime table
+   if (!CDSConfig::is_dumping_adapters()) {
+     // Search archived table first. It is read-only table so can be searched without lock
+     entry = _archived_adapter_handler_table.lookup(fp, fp->compute_hash(), 0 /* unused */);
+     if (entry != nullptr) {
+ #ifndef PRODUCT
+       if (fp->is_compact()) {
+         _compact++;
+       }
+       _archived_hits++;
+ #endif
+       return entry;
+     }
+   }
+ #endif // INCLUDE_CDS
    assert_lock_strong(AdapterHandlerLibrary_lock);
!   AdapterHandlerEntry** entry_p = _adapter_handler_table->get(fp);
!   if (entry_p != nullptr) {
!     entry = *entry_p;
+     assert(entry->fingerprint()->equals(fp), "fingerprint mismatch key fp %s %s (hash=%d) != found fp %s %s (hash=%d)",
+            entry->fingerprint()->as_basic_args_string(), entry->fingerprint()->as_string(), entry->fingerprint()->compute_hash(),
+            fp->as_basic_args_string(), fp->as_string(), fp->compute_hash());
  #ifndef PRODUCT
!     if (fp->is_compact()) _compact++;
!     _runtime_hits++;
  #endif
!     return entry;
    }
    return nullptr;
  }
  
  #ifndef PRODUCT
! void AdapterHandlerLibrary::print_statistics_on(outputStream* st) {
    auto size = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
      return sizeof(*key) + sizeof(*a);
    };
    TableStatistics ts = _adapter_handler_table->statistics_calculate(size);
!   ts.print(st, "AdapterHandlerTable");
!   st->print_cr("AdapterHandlerTable (table_size=%d, entries=%d)",
!                _adapter_handler_table->table_size(), _adapter_handler_table->number_of_entries());
!   int total_hits = _archived_hits + _runtime_hits;
!   st->print_cr("AdapterHandlerTable: lookups %d equals %d hits %d (archived=%d+runtime=%d) compact %d",
+                _lookups, _equals, total_hits, _archived_hits, _runtime_hits, _compact);
  }
! #endif // !PRODUCT
  
  // ---------------------------------------------------------------------------
  // Implementation of AdapterHandlerLibrary
  AdapterHandlerEntry* AdapterHandlerLibrary::_abstract_method_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_no_arg_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_int_arg_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_obj_arg_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_obj_int_arg_handler = nullptr;
  AdapterHandlerEntry* AdapterHandlerLibrary::_obj_obj_arg_handler = nullptr;
+ #if INCLUDE_CDS
+ ArchivedAdapterTable AdapterHandlerLibrary::_archived_adapter_handler_table;
+ #endif // INCLUDE_CDS
  const int AdapterHandlerLibrary_size = 16*K;
  BufferBlob* AdapterHandlerLibrary::_buffer = nullptr;
  
  BufferBlob* AdapterHandlerLibrary::buffer_blob() {
    return _buffer;

*** 2456,52 ***
      // are never compiled so an i2c entry is somewhat meaningless, but
      // throw AbstractMethodError just in case.
      // Pass wrong_method_abstract for the c2i transitions to return
      // AbstractMethodError for invalid invocations.
      address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub();
!     _abstract_method_handler = AdapterHandlerLibrary::new_entry(new AdapterFingerPrint(0, nullptr),
                                                                  SharedRuntime::throw_AbstractMethodError_entry(),
                                                                  wrong_method_abstract, wrong_method_abstract);
  
      _buffer = BufferBlob::create("adapters", AdapterHandlerLibrary_size);
!     _no_arg_handler = create_adapter(no_arg_blob, 0, nullptr, true);
  
      BasicType obj_args[] = { T_OBJECT };
!     _obj_arg_handler = create_adapter(obj_arg_blob, 1, obj_args, true);
  
      BasicType int_args[] = { T_INT };
!     _int_arg_handler = create_adapter(int_arg_blob, 1, int_args, true);
  
      BasicType obj_int_args[] = { T_OBJECT, T_INT };
!     _obj_int_arg_handler = create_adapter(obj_int_arg_blob, 2, obj_int_args, true);
  
      BasicType obj_obj_args[] = { T_OBJECT, T_OBJECT };
!     _obj_obj_arg_handler = create_adapter(obj_obj_arg_blob, 2, obj_obj_args, true);
  
      assert(no_arg_blob != nullptr &&
!           obj_arg_blob != nullptr &&
!           int_arg_blob != nullptr &&
!           obj_int_arg_blob != nullptr &&
!           obj_obj_arg_blob != nullptr, "Initial adapters must be properly created");
    }
  
    // Outside of the lock
    post_adapter_creation(no_arg_blob, _no_arg_handler);
    post_adapter_creation(obj_arg_blob, _obj_arg_handler);
    post_adapter_creation(int_arg_blob, _int_arg_handler);
    post_adapter_creation(obj_int_arg_blob, _obj_int_arg_handler);
    post_adapter_creation(obj_obj_arg_blob, _obj_obj_arg_handler);
  }
  
  AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
                                                        address i2c_entry,
                                                        address c2i_entry,
                                                        address c2i_unverified_entry,
                                                        address c2i_no_clinit_check_entry) {
    // Insert an entry into the table
!   return new AdapterHandlerEntry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry,
!                                  c2i_no_clinit_check_entry);
  }
  
  AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandle& method) {
    if (method->is_abstract()) {
      return _abstract_method_handler;
--- 2636,73 ---
      // are never compiled so an i2c entry is somewhat meaningless, but
      // throw AbstractMethodError just in case.
      // Pass wrong_method_abstract for the c2i transitions to return
      // AbstractMethodError for invalid invocations.
      address wrong_method_abstract = SharedRuntime::get_handle_wrong_method_abstract_stub();
!     _abstract_method_handler = AdapterHandlerLibrary::new_entry(AdapterFingerPrint::allocate(0, nullptr),
                                                                  SharedRuntime::throw_AbstractMethodError_entry(),
                                                                  wrong_method_abstract, wrong_method_abstract);
  
      _buffer = BufferBlob::create("adapters", AdapterHandlerLibrary_size);
!     _no_arg_handler = create_simple_adapter(no_arg_blob, 0, nullptr);
  
      BasicType obj_args[] = { T_OBJECT };
!     _obj_arg_handler = create_simple_adapter(obj_arg_blob, 1, obj_args);
  
      BasicType int_args[] = { T_INT };
!     _int_arg_handler = create_simple_adapter(int_arg_blob, 1, int_args);
  
      BasicType obj_int_args[] = { T_OBJECT, T_INT };
!     _obj_int_arg_handler = create_simple_adapter(obj_int_arg_blob, 2, obj_int_args);
  
      BasicType obj_obj_args[] = { T_OBJECT, T_OBJECT };
!     _obj_obj_arg_handler = create_simple_adapter(obj_obj_arg_blob, 2, obj_obj_args);
  
      assert(no_arg_blob != nullptr &&
!            obj_arg_blob != nullptr &&
!            int_arg_blob != nullptr &&
!            obj_int_arg_blob != nullptr &&
!            obj_obj_arg_blob != nullptr, "Initial adapters must be properly created");
    }
  
    // Outside of the lock
    post_adapter_creation(no_arg_blob, _no_arg_handler);
    post_adapter_creation(obj_arg_blob, _obj_arg_handler);
    post_adapter_creation(int_arg_blob, _int_arg_handler);
    post_adapter_creation(obj_int_arg_blob, _obj_int_arg_handler);
    post_adapter_creation(obj_obj_arg_blob, _obj_obj_arg_handler);
  }
  
+ AdapterHandlerEntry* AdapterHandlerLibrary::create_simple_adapter(AdapterBlob*& adapter_blob,
+                                                                   int total_args_passed,
+                                                                   BasicType* sig_bt) {
+   AdapterFingerPrint* fp = AdapterFingerPrint::allocate(total_args_passed, sig_bt);
+   // We may find the adapter in the table if it is loaded from the AOT cache
+   AdapterHandlerEntry* entry = lookup(fp);
+   if (entry != nullptr) {
+     assert(entry->is_shared() && !entry->is_linked(), "Non null AdapterHandlerEntry should be in the AOT cache in unlinked state");
+     if (!link_adapter_handler(entry, adapter_blob)) {
+       if (!generate_adapter_code(adapter_blob, entry, total_args_passed, sig_bt, /* is_transient */ false)) {
+         return nullptr;
+       }
+     }
+     // AdapterFingerPrint is already in the cache, no need to keep this one
+     AdapterFingerPrint::deallocate(fp);
+   } else {
+     entry = create_adapter(adapter_blob, fp, total_args_passed, sig_bt, /* is_transient */ false);
+   }
+   return entry;
+ }
+ 
  AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* fingerprint,
                                                        address i2c_entry,
                                                        address c2i_entry,
                                                        address c2i_unverified_entry,
                                                        address c2i_no_clinit_check_entry) {
    // Insert an entry into the table
!   return AdapterHandlerEntry::allocate(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry,
!                                        c2i_no_clinit_check_entry);
  }
  
  AdapterHandlerEntry* AdapterHandlerLibrary::get_simple_adapter(const methodHandle& method) {
    if (method->is_abstract()) {
      return _abstract_method_handler;

*** 2607,117 ***
    BasicType* sig_bt = si.basic_types();
    {
      MutexLocker mu(AdapterHandlerLibrary_lock);
  
      // Lookup method signature's fingerprint
!     entry = lookup(total_args_passed, sig_bt);
  
      if (entry != nullptr) {
  #ifdef ASSERT
        if (VerifyAdapterSharing) {
          AdapterBlob* comparison_blob = nullptr;
!         AdapterHandlerEntry* comparison_entry = create_adapter(comparison_blob, total_args_passed, sig_bt, false);
          assert(comparison_blob == nullptr, "no blob should be created when creating an adapter for comparison");
          assert(comparison_entry->compare_code(entry), "code must match");
          // Release the one just created and return the original
!         delete comparison_entry;
        }
  #endif
        return entry;
      }
  
!     entry = create_adapter(new_adapter, total_args_passed, sig_bt, /* allocate_code_blob */ true);
    }
  
    // Outside of the lock
    if (new_adapter != nullptr) {
      post_adapter_creation(new_adapter, entry);
    }
    return entry;
  }
  
! AdapterHandlerEntry* AdapterHandlerLibrary::create_adapter(AdapterBlob*& new_adapter,
!                                                            int total_args_passed,
!                                                            BasicType* sig_bt,
!                                                            bool allocate_code_blob) {
!   if (log_is_enabled(Info, perf, class, link)) {
!     ClassLoader::perf_method_adapters_count()->inc();
    }
  
!   // StubRoutines::_final_stubs_code is initialized after this function can be called. As a result,
!   // VerifyAdapterCalls and VerifyAdapterSharing can fail if we re-use code that generated prior
!   // to all StubRoutines::_final_stubs_code being set. Checks refer to runtime range checks generated
!   // in an I2C stub that ensure that an I2C stub is called from an interpreter frame or stubs.
!   bool contains_all_checks = StubRoutines::final_stubs_code() != nullptr;
  
!   VMRegPair stack_regs[16];
!   VMRegPair* regs = (total_args_passed <= 16) ? stack_regs : NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
  
-   // Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
-   int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed);
    BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache
    CodeBuffer buffer(buf);
    short buffer_locs[20];
    buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs,
!                                           sizeof(buffer_locs)/sizeof(relocInfo));
! 
!   // Make a C heap allocated version of the fingerprint to store in the adapter
!   AdapterFingerPrint* fingerprint = new AdapterFingerPrint(total_args_passed, sig_bt);
-   MacroAssembler _masm(&buffer);
-   AdapterHandlerEntry* entry = SharedRuntime::generate_i2c2i_adapters(&_masm,
-                                                 total_args_passed,
-                                                 comp_args_on_stack,
-                                                 sig_bt,
-                                                 regs,
-                                                 fingerprint);
  
  #ifdef ASSERT
    if (VerifyAdapterSharing) {
!     entry->save_code(buf->code_begin(), buffer.insts_size());
!     if (!allocate_code_blob) {
!       return entry;
      }
    }
  #endif
  
!   new_adapter = AdapterBlob::create(&buffer);
!   NOT_PRODUCT(int insts_size = buffer.insts_size());
-   if (new_adapter == nullptr) {
      // CodeCache is full, disable compilation
      // Ought to log this but compile log is only per compile thread
      // and we're some non descript Java thread.
!     return nullptr;
    }
!   entry->relocate(new_adapter->content_begin());
  #ifndef PRODUCT
    // debugging support
    if (PrintAdapterHandlers || PrintStubCode) {
!     ttyLocker ttyl;
-     entry->print_adapter_on(tty);
-     tty->print_cr("i2c argument handler #%d for: %s %s (%d bytes generated)",
-                   _adapter_handler_table->number_of_entries(), fingerprint->as_basic_args_string(),
-                   fingerprint->as_string(), insts_size);
-     tty->print_cr("c2i argument handler starts at " INTPTR_FORMAT, p2i(entry->get_c2i_entry()));
-     if (Verbose || PrintStubCode) {
-       address first_pc = entry->base_address();
-       if (first_pc != nullptr) {
-         Disassembler::decode(first_pc, first_pc + insts_size, tty
-                              NOT_PRODUCT(COMMA &new_adapter->asm_remarks()));
-         tty->cr();
-       }
-     }
    }
  #endif
  
!   // Add the entry only if the entry contains all required checks (see sharedRuntime_xxx.cpp)
!   // The checks are inserted only if -XX:+VerifyAdapterCalls is specified.
!   if (contains_all_checks || !VerifyAdapterCalls) {
      assert_lock_strong(AdapterHandlerLibrary_lock);
!     _adapter_handler_table->put(fingerprint, entry);
    }
!   return entry;
  }
  
  address AdapterHandlerEntry::base_address() {
    address base = _i2c_entry;
    if (base == nullptr)  base = _c2i_entry;
    assert(base <= _c2i_entry || _c2i_entry == nullptr, "");
--- 2808,237 ---
    BasicType* sig_bt = si.basic_types();
    {
      MutexLocker mu(AdapterHandlerLibrary_lock);
  
      // Lookup method signature's fingerprint
!     AdapterFingerPrint *fp = AdapterFingerPrint::allocate(total_args_passed, sig_bt);
+     entry = lookup(fp);
  
      if (entry != nullptr) {
  #ifdef ASSERT
        if (VerifyAdapterSharing) {
          AdapterBlob* comparison_blob = nullptr;
!         AdapterFingerPrint* comparison_fp = AdapterFingerPrint::allocate(total_args_passed, sig_bt);
+         AdapterHandlerEntry* comparison_entry = create_adapter(comparison_blob, comparison_fp, total_args_passed, sig_bt, true);
          assert(comparison_blob == nullptr, "no blob should be created when creating an adapter for comparison");
          assert(comparison_entry->compare_code(entry), "code must match");
+         AdapterFingerPrint::deallocate(comparison_fp);
          // Release the one just created and return the original
!         AdapterHandlerEntry::deallocate(comparison_entry);
        }
  #endif
+       AdapterFingerPrint::deallocate(fp);
        return entry;
      }
  
!     entry = create_adapter(new_adapter, fp, total_args_passed, sig_bt, /* is_transient */ false);
    }
  
    // Outside of the lock
    if (new_adapter != nullptr) {
      post_adapter_creation(new_adapter, entry);
    }
    return entry;
  }
  
! bool AdapterHandlerLibrary::lookup_aot_cache(AdapterHandlerEntry* handler, CodeBuffer* buffer) {
!   ResourceMark rm;
!   const char* name = AdapterHandlerLibrary::name(handler->fingerprint());
!   const uint32_t id = AdapterHandlerLibrary::id(handler->fingerprint());
!   uint32_t offsets[4];
!   if (SCCache::load_adapter(buffer, id, name, offsets)) {
+     address i2c_entry = buffer->insts_begin();
+     assert(offsets[0] == 0, "sanity check");
+     handler->set_entry_points(i2c_entry, i2c_entry + offsets[1], i2c_entry + offsets[2], i2c_entry + offsets[3]);
+     return true;
    }
+   return false;
+ }
  
! #ifndef PRODUCT
! void AdapterHandlerLibrary::print_adapter_handler_info(AdapterHandlerEntry* handler, AdapterBlob* adapter_blob) {
!   ttyLocker ttyl;
!   ResourceMark rm;
!   int insts_size = adapter_blob->code_size();
+   handler->print_adapter_on(tty);
+   tty->print_cr("i2c argument handler for: %s %s (%d bytes generated)",
+                 handler->fingerprint()->as_basic_args_string(),
+                 handler->fingerprint()->as_string(), insts_size);
+   tty->print_cr("c2i argument handler starts at " INTPTR_FORMAT, p2i(handler->get_c2i_entry()));
+   if (Verbose || PrintStubCode) {
+     address first_pc = handler->base_address();
+     if (first_pc != nullptr) {
+       Disassembler::decode(first_pc, first_pc + insts_size, tty, &adapter_blob->asm_remarks());
+       tty->cr();
+     }
+   }
+ }
+ #endif // PRODUCT
  
! bool AdapterHandlerLibrary::generate_adapter_code(AdapterBlob*& adapter_blob,
!                                                   AdapterHandlerEntry* handler,
+                                                   int total_args_passed,
+                                                   BasicType* sig_bt,
+                                                   bool is_transient) {
+   if (log_is_enabled(Info, perf, class, link)) {
+     ClassLoader::perf_method_adapters_count()->inc();
+   }
  
    BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache
    CodeBuffer buffer(buf);
    short buffer_locs[20];
    buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs,
!                                          sizeof(buffer_locs)/sizeof(relocInfo));
!   MacroAssembler masm(&buffer);
!   VMRegPair stack_regs[16];
!   VMRegPair* regs = (total_args_passed <= 16) ? stack_regs : NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed);
  
+   // Get a description of the compiled java calling convention and the largest used (VMReg) stack slot usage
+   int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed);
+   SharedRuntime::generate_i2c2i_adapters(&masm,
+                                          total_args_passed,
+                                          comp_args_on_stack,
+                                          sig_bt,
+                                          regs,
+                                          handler);
+   if (CDSConfig::is_dumping_adapters()) {
+     // try to save generated code
+     const char* name = AdapterHandlerLibrary::name(handler->fingerprint());
+     const uint32_t id = AdapterHandlerLibrary::id(handler->fingerprint());
+     uint32_t offsets[4];
+     offsets[0] = 0;
+     offsets[1] = handler->get_c2i_entry() - handler->get_i2c_entry();
+     offsets[2] = handler->get_c2i_unverified_entry() - handler->get_i2c_entry();
+     offsets[3] = handler->get_c2i_no_clinit_check_entry() - handler->get_i2c_entry();
+     SCCache::store_adapter(&buffer, id, name, offsets);
+   }
  #ifdef ASSERT
    if (VerifyAdapterSharing) {
!     handler->save_code(buf->code_begin(), buffer.insts_size());
!     if (is_transient) {
!       return true;
      }
    }
  #endif
  
!   adapter_blob = AdapterBlob::create(&buffer);
!   if (adapter_blob == nullptr) {
      // CodeCache is full, disable compilation
      // Ought to log this but compile log is only per compile thread
      // and we're some non descript Java thread.
!     return false;
    }
!   handler->relocate(adapter_blob->content_begin());
  #ifndef PRODUCT
    // debugging support
    if (PrintAdapterHandlers || PrintStubCode) {
!     print_adapter_handler_info(handler, adapter_blob);
    }
  #endif
+   return true;
+ }
  
! AdapterHandlerEntry* AdapterHandlerLibrary::create_adapter(AdapterBlob*& adapter_blob,
!                                                            AdapterFingerPrint* fingerprint,
!                                                            int total_args_passed,
+                                                            BasicType* sig_bt,
+                                                            bool is_transient) {
+   AdapterHandlerEntry* handler = AdapterHandlerLibrary::new_entry(fingerprint);
+   if (!generate_adapter_code(adapter_blob, handler, total_args_passed, sig_bt, is_transient)) {
+     return nullptr;
+   }
+   if (!is_transient) {
      assert_lock_strong(AdapterHandlerLibrary_lock);
!     _adapter_handler_table->put(fingerprint, handler);
    }
!   return handler;
+ }
+ 
+ #if INCLUDE_CDS
+ bool AdapterHandlerLibrary::link_adapter_handler(AdapterHandlerEntry* handler, AdapterBlob*& adapter_blob) {
+ #ifndef PRODUCT
+   if (TestAdapterLinkFailure) {
+     return false;
+   }
+ #endif
+   BufferBlob* buf = buffer_blob(); // the temporary code buffer in CodeCache
+   CodeBuffer buffer(buf);
+   short buffer_locs[20];
+   buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs,
+                                          sizeof(buffer_locs)/sizeof(relocInfo));
+ 
+   if (!lookup_aot_cache(handler, &buffer)) {
+     return false;
+   }
+   adapter_blob = AdapterBlob::create(&buffer);
+   if (adapter_blob == nullptr) {
+     // CodeCache is full, disable compilation
+     // Ought to log this but compile log is only per compile thread
+     // and we're some non descript Java thread.
+     return false;
+   }
+   handler->relocate(adapter_blob->content_begin());
+ #ifndef PRODUCT
+   // debugging support
+   if (PrintAdapterHandlers || PrintStubCode) {
+     print_adapter_handler_info(handler, adapter_blob);
+   }
+ #endif
+   return true;
+ }
+ 
+ class CopyAdapterTableToArchive : StackObj {
+ private:
+   CompactHashtableWriter* _writer;
+   ArchiveBuilder* _builder;
+ public:
+   CopyAdapterTableToArchive(CompactHashtableWriter* writer) : _writer(writer),
+                                                              _builder(ArchiveBuilder::current())
+   {}
+ 
+   bool do_entry(AdapterFingerPrint* fp, AdapterHandlerEntry* entry) {
+     LogStreamHandle(Trace, cds) lsh;
+     if (ArchiveBuilder::current()->has_been_archived((address)entry)) {
+       assert(ArchiveBuilder::current()->has_been_archived((address)fp), "must be");
+       AdapterFingerPrint* buffered_fp = ArchiveBuilder::current()->get_buffered_addr(fp);
+       assert(buffered_fp != nullptr,"sanity check");
+       AdapterHandlerEntry* buffered_entry = ArchiveBuilder::current()->get_buffered_addr(entry);
+       assert(buffered_entry != nullptr,"sanity check");
+ 
+       uint hash = fp->compute_hash();
+       u4 delta = _builder->buffer_to_offset_u4((address)buffered_entry);
+       _writer->add(hash, delta);
+       if (lsh.is_enabled()) {
+         address fp_runtime_addr = (address)buffered_fp + ArchiveBuilder::current()->buffer_to_requested_delta();
+         address entry_runtime_addr = (address)buffered_entry + ArchiveBuilder::current()->buffer_to_requested_delta();
+         log_trace(cds)("Added fp=%p (%s), entry=%p to the archived adater table", buffered_fp, buffered_fp->as_basic_args_string(), buffered_entry);
+       }
+     } else {
+       if (lsh.is_enabled()) {
+         log_trace(cds)("Skipping adapter handler %p (fp=%s) as it is not archived", entry, fp->as_basic_args_string());
+       }
+     }
+     return true;
+   }
+ };
+ 
+ size_t AdapterHandlerLibrary::estimate_size_for_archive() {
+   return CompactHashtableWriter::estimate_size(_adapter_handler_table->number_of_entries());
+ }
+ 
+ void AdapterHandlerLibrary::archive_adapter_table() {
+   CompactHashtableStats stats;
+   CompactHashtableWriter writer(_adapter_handler_table->number_of_entries(), &stats);
+   CopyAdapterTableToArchive copy(&writer);
+   _adapter_handler_table->iterate(&copy);
+   writer.dump(&_archived_adapter_handler_table, "archived adapter table");
+ }
+ 
+ void AdapterHandlerLibrary::serialize_shared_table_header(SerializeClosure* soc) {
+   _archived_adapter_handler_table.serialize_header(soc);
  }
+ #endif // INCLUDE_CDS
  
  address AdapterHandlerEntry::base_address() {
    address base = _i2c_entry;
    if (base == nullptr)  base = _c2i_entry;
    assert(base <= _c2i_entry || _c2i_entry == nullptr, "");

*** 2739,16 ***
    if (_c2i_no_clinit_check_entry != nullptr)
      _c2i_no_clinit_check_entry += delta;
    assert(base_address() == new_base, "");
  }
  
  
  AdapterHandlerEntry::~AdapterHandlerEntry() {
-   delete _fingerprint;
  #ifdef ASSERT
    FREE_C_HEAP_ARRAY(unsigned char, _saved_code);
  #endif
  }
  
  
  #ifdef ASSERT
  // Capture the code before relocation so that it can be compared
--- 3060,70 ---
    if (_c2i_no_clinit_check_entry != nullptr)
      _c2i_no_clinit_check_entry += delta;
    assert(base_address() == new_base, "");
  }
  
+ void AdapterHandlerEntry::metaspace_pointers_do(MetaspaceClosure* it) {
+   LogStreamHandle(Trace, cds) lsh;
+   if (lsh.is_enabled()) {
+     lsh.print("Iter(AdapterHandlerEntry): %p(%s)", this, _fingerprint->as_basic_args_string());
+     lsh.cr();
+   }
+   it->push(&_fingerprint);
+ }
+ 
+ #if INCLUDE_CDS
+ void AdapterHandlerEntry::remove_unshareable_info() {
+   set_entry_points(nullptr, nullptr, nullptr, nullptr, false);
+ }
+ 
+ void AdapterHandlerEntry::restore_unshareable_info(TRAPS) {
+   PerfTraceElapsedTime timer(ClassLoader::perf_method_adapters_time());
+   // A fixed set of simple adapters are eagerly linked during JVM initialization
+   // in AdapterHandlerTable::initialize().
+   // Others may already have been linked because they are shared by other methods.
+   if (is_linked()) {
+     return;
+   }
+   AdapterBlob* adapter_blob = nullptr;
+   {
+     MutexLocker mu(AdapterHandlerLibrary_lock);
+     assert(_fingerprint != nullptr, "_fingerprint must not be null");
+ #ifdef ASSERT
+     AdapterHandlerEntry* entry = AdapterHandlerLibrary::lookup(_fingerprint);
+     assert(entry == this, "sanity check");
+ #endif
+     if (!AdapterHandlerLibrary::link_adapter_handler(this, adapter_blob)) {
+       ResourceMark rm;
+       log_warning(cds)("Failed to link AdapterHandlerEntry to its code in the AOT code cache");
+       int nargs;
+       BasicType* bt = _fingerprint->as_basic_type(nargs);
+       if (!AdapterHandlerLibrary::generate_adapter_code(adapter_blob, this, nargs, bt, /* is_transient */ false)) {
+         if (!is_init_completed()) {
+           // Don't throw exceptions during VM initialization because java.lang.* classes
+           // might not have been initialized, causing problems when constructing the
+           // Java exception object.
+           vm_exit_during_initialization("Out of space in CodeCache for adapters");
+         } else {
+           THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Out of space in CodeCache for adapters");
+         }
+       }
+     }
+   }
+   // Outside of the lock
+   if (adapter_blob != nullptr) {
+     post_adapter_creation(adapter_blob, this);
+   }
+   assert(_linked, "AdapterHandlerEntry must now be linked");
+ }
+ #endif // INCLUDE_CDS
  
  AdapterHandlerEntry::~AdapterHandlerEntry() {
  #ifdef ASSERT
    FREE_C_HEAP_ARRAY(unsigned char, _saved_code);
  #endif
+   FreeHeap(this);
  }
  
  
  #ifdef ASSERT
  // Capture the code before relocation so that it can be compared

*** 3049,32 ***
    FREE_C_HEAP_ARRAY(intptr_t, buf);
  JRT_END
  
  bool AdapterHandlerLibrary::contains(const CodeBlob* b) {
    bool found = false;
!   auto findblob = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
!     return (found = (b == CodeCache::find_blob(a->get_i2c_entry())));
    };
!   assert_locked_or_safepoint(AdapterHandlerLibrary_lock);
!   _adapter_handler_table->iterate(findblob);
    return found;
  }
  
  void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b) {
    bool found = false;
!   auto findblob = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
!     if (b == CodeCache::find_blob(a->get_i2c_entry())) {
        found = true;
        st->print("Adapter for signature: ");
!       a->print_adapter_on(st);
        return true;
      } else {
        return false; // keep looking
      }
    };
!   assert_locked_or_safepoint(AdapterHandlerLibrary_lock);
!   _adapter_handler_table->iterate(findblob);
    assert(found, "Should have found handler");
  }
  
  void AdapterHandlerEntry::print_adapter_on(outputStream* st) const {
    st->print("AHE@" INTPTR_FORMAT ": %s", p2i(this), fingerprint()->as_string());
--- 3424,65 ---
    FREE_C_HEAP_ARRAY(intptr_t, buf);
  JRT_END
  
  bool AdapterHandlerLibrary::contains(const CodeBlob* b) {
    bool found = false;
! #if INCLUDE_CDS
!   auto findblob_archived_table = [&] (AdapterHandlerEntry* handler) {
+     return (found = (b == CodeCache::find_blob(handler->get_i2c_entry())));
    };
!   _archived_adapter_handler_table.iterate(findblob_archived_table);
! #endif // INCLUDE_CDS
+   if (!found) {
+     auto findblob_runtime_table = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
+       return (found = (b == CodeCache::find_blob(a->get_i2c_entry())));
+     };
+     assert_locked_or_safepoint(AdapterHandlerLibrary_lock);
+     _adapter_handler_table->iterate(findblob_runtime_table);
+   }
    return found;
  }
  
+ const char* AdapterHandlerLibrary::name(AdapterFingerPrint* fingerprint) {
+   return fingerprint->as_basic_args_string();
+ }
+ 
+ uint32_t AdapterHandlerLibrary::id(AdapterFingerPrint* fingerprint) {
+   unsigned int hash = fingerprint->compute_hash();
+   return hash;
+ }
+ 
  void AdapterHandlerLibrary::print_handler_on(outputStream* st, const CodeBlob* b) {
    bool found = false;
! #if INCLUDE_CDS
!   auto findblob_archived_table = [&] (AdapterHandlerEntry* handler) {
+     if (b == CodeCache::find_blob(handler->get_i2c_entry())) {
        found = true;
        st->print("Adapter for signature: ");
!       handler->print_adapter_on(st);
        return true;
      } else {
        return false; // keep looking
+ 
      }
    };
!   _archived_adapter_handler_table.iterate(findblob_archived_table);
! #endif // INCLUDE_CDS
+   if (!found) {
+     auto findblob_runtime_table = [&] (AdapterFingerPrint* key, AdapterHandlerEntry* a) {
+       if (b == CodeCache::find_blob(a->get_i2c_entry())) {
+         found = true;
+         st->print("Adapter for signature: ");
+         a->print_adapter_on(st);
+         return true;
+       } else {
+         return false; // keep looking
+       }
+     };
+     assert_locked_or_safepoint(AdapterHandlerLibrary_lock);
+     _adapter_handler_table->iterate(findblob_runtime_table);
+   }
    assert(found, "Should have found handler");
  }
  
  void AdapterHandlerEntry::print_adapter_on(outputStream* st) const {
    st->print("AHE@" INTPTR_FORMAT ": %s", p2i(this), fingerprint()->as_string());

*** 3091,18 ***
      st->print(" c2iNCI: " INTPTR_FORMAT, p2i(get_c2i_no_clinit_check_entry()));
    }
    st->cr();
  }
  
! #ifndef PRODUCT
! 
! void AdapterHandlerLibrary::print_statistics() {
!   print_table_statistics();
  }
  
- #endif /* PRODUCT */
- 
  JRT_LEAF(void, SharedRuntime::enable_stack_reserved_zone(JavaThread* current))
    assert(current == JavaThread::current(), "pre-condition");
    StackOverflow* overflow_state = current->stack_overflow_state();
    overflow_state->enable_stack_reserved_zone(/*check_if_disabled*/true);
    overflow_state->set_reserved_stack_activation(current->stack_base());
--- 3499,17 ---
      st->print(" c2iNCI: " INTPTR_FORMAT, p2i(get_c2i_no_clinit_check_entry()));
    }
    st->cr();
  }
  
! bool AdapterHandlerLibrary::is_abstract_method_adapter(AdapterHandlerEntry* entry) {
!   if (entry == _abstract_method_handler) {
!     return true;
!   }
+   return false;
  }
  
  JRT_LEAF(void, SharedRuntime::enable_stack_reserved_zone(JavaThread* current))
    assert(current == JavaThread::current(), "pre-condition");
    StackOverflow* overflow_state = current->stack_overflow_state();
    overflow_state->enable_stack_reserved_zone(/*check_if_disabled*/true);
    overflow_state->set_reserved_stack_activation(current->stack_base());
< prev index next >