changeset 54600:69cfd80f8706

8218994: Consolidate indy and condy JVM information within a BootstrapInfo data structure Summary: Introduce BootstrapInfo data structure and merge invocation of a bootstrap method for condy and indy into invoke_bootstrap_method. Reviewed-by: acorn, coleenp Contributed-by: john.r.rose@oracle.com, lois.foltan@oracle.com
author lfoltan
date Tue, 23 Apr 2019 14:09:54 -0400
parents f5657f30bb01
children c40b2a190173
files src/hotspot/share/classfile/systemDictionary.cpp src/hotspot/share/classfile/systemDictionary.hpp src/hotspot/share/interpreter/bootstrapInfo.cpp src/hotspot/share/interpreter/bootstrapInfo.hpp src/hotspot/share/interpreter/linkResolver.cpp src/hotspot/share/interpreter/linkResolver.hpp src/hotspot/share/oops/constantPool.cpp src/hotspot/share/oops/constantPool.hpp
diffstat 8 files changed, 534 insertions(+), 325 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Tue Apr 23 08:11:38 2019 -0700
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Tue Apr 23 14:09:54 2019 -0400
@@ -2750,106 +2750,61 @@
   return Handle(THREAD, (oop) result.get_jobject());
 }
 
-// Ask Java to compute a constant by invoking a BSM given a Dynamic_info CP entry
-Handle SystemDictionary::link_dynamic_constant(Klass* caller,
-                                               int condy_index,
-                                               Handle bootstrap_specifier,
-                                               Symbol* name,
-                                               Symbol* type,
-                                               TRAPS) {
-  Handle empty;
-  Handle bsm, info;
-  if (java_lang_invoke_MethodHandle::is_instance(bootstrap_specifier())) {
-    bsm = bootstrap_specifier;
-  } else {
-    assert(bootstrap_specifier->is_objArray(), "");
-    objArrayOop args = (objArrayOop) bootstrap_specifier();
-    assert(args->length() == 2, "");
-    bsm  = Handle(THREAD, args->obj_at(0));
-    info = Handle(THREAD, args->obj_at(1));
-  }
-  guarantee(java_lang_invoke_MethodHandle::is_instance(bsm()),
-            "caller must supply a valid BSM");
+// Ask Java to run a bootstrap method, in order to create a dynamic call site
+// while linking an invokedynamic op, or compute a constant for Dynamic_info CP entry
+// with linkage results being stored back into the bootstrap specifier.
+void SystemDictionary::invoke_bootstrap_method(BootstrapInfo& bootstrap_specifier, TRAPS) {
+  // Resolve the bootstrap specifier, its name, type, and static arguments
+  bootstrap_specifier.resolve_bsm(CHECK);
 
   // This should not happen.  JDK code should take care of that.
-  if (caller == NULL) {
-    THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad dynamic constant", empty);
+  if (bootstrap_specifier.caller() == NULL || bootstrap_specifier.type_arg().is_null()) {
+    THROW_MSG(vmSymbols::java_lang_InternalError(), "Invalid bootstrap method invocation with no caller or type argument");
   }
 
-  Handle constant_name = java_lang_String::create_from_symbol(name, CHECK_(empty));
+  bool is_indy = bootstrap_specifier.is_method_call();
+  objArrayHandle appendix_box;
+  if (is_indy) {
+    // Some method calls may require an appendix argument.  Arrange to receive it.
+    appendix_box = oopFactory::new_objArray_handle(SystemDictionary::Object_klass(), 1, CHECK);
+    assert(appendix_box->obj_at(0) == NULL, "");
+  }
 
-  // Resolve the constant type in the context of the caller class
-  Handle type_mirror = find_java_mirror_for_type(type, caller, SignatureStream::NCDFError,
-                                                 CHECK_(empty));
-
-  // call java.lang.invoke.MethodHandleNatives::linkConstantDyanmic(caller, condy_index, bsm, type, info)
+  // call condy: java.lang.invoke.MethodHandleNatives::linkDynamicConstant(caller, condy_index, bsm, type, info)
+  //       indy: java.lang.invoke.MethodHandleNatives::linkCallSite(caller, indy_index, bsm, name, mtype, info, &appendix)
   JavaCallArguments args;
-  args.push_oop(Handle(THREAD, caller->java_mirror()));
-  args.push_int(condy_index);
-  args.push_oop(bsm);
-  args.push_oop(constant_name);
-  args.push_oop(type_mirror);
-  args.push_oop(info);
+  args.push_oop(Handle(THREAD, bootstrap_specifier.caller_mirror()));
+  args.push_int(bootstrap_specifier.bss_index());
+  args.push_oop(bootstrap_specifier.bsm());
+  args.push_oop(bootstrap_specifier.name_arg());
+  args.push_oop(bootstrap_specifier.type_arg());
+  args.push_oop(bootstrap_specifier.arg_values());
+  if (is_indy) {
+    args.push_oop(appendix_box);
+  }
   JavaValue result(T_OBJECT);
   JavaCalls::call_static(&result,
                          SystemDictionary::MethodHandleNatives_klass(),
-                         vmSymbols::linkDynamicConstant_name(),
-                         vmSymbols::linkDynamicConstant_signature(),
-                         &args, CHECK_(empty));
+                         is_indy ? vmSymbols::linkCallSite_name() : vmSymbols::linkDynamicConstant_name(),
+                         is_indy ? vmSymbols::linkCallSite_signature() : vmSymbols::linkDynamicConstant_signature(),
+                         &args, CHECK);
 
-  return Handle(THREAD, (oop) result.get_jobject());
-}
-
-// Ask Java code to find or construct a java.lang.invoke.CallSite for the given
-// name and signature, as interpreted relative to the given class loader.
-methodHandle SystemDictionary::find_dynamic_call_site_invoker(Klass* caller,
-                                                              int indy_index,
-                                                              Handle bootstrap_specifier,
-                                                              Symbol* name,
-                                                              Symbol* type,
-                                                              Handle *appendix_result,
-                                                              TRAPS) {
-  methodHandle empty;
-  Handle bsm, info;
-  if (java_lang_invoke_MethodHandle::is_instance(bootstrap_specifier())) {
-    bsm = bootstrap_specifier;
+  Handle value(THREAD, (oop) result.get_jobject());
+  if (is_indy) {
+    Handle appendix;
+    methodHandle method = unpack_method_and_appendix(value,
+                                                     bootstrap_specifier.caller(),
+                                                     appendix_box,
+                                                     &appendix, CHECK);
+    bootstrap_specifier.set_resolved_method(method, appendix);
   } else {
-    objArrayOop args = (objArrayOop) bootstrap_specifier();
-    assert(args->length() == 2, "");
-    bsm  = Handle(THREAD, args->obj_at(0));
-    info = Handle(THREAD, args->obj_at(1));
-  }
-  guarantee(java_lang_invoke_MethodHandle::is_instance(bsm()),
-            "caller must supply a valid BSM");
-
-  Handle method_name = java_lang_String::create_from_symbol(name, CHECK_(empty));
-  Handle method_type = find_method_handle_type(type, caller, CHECK_(empty));
-
-  // This should not happen.  JDK code should take care of that.
-  if (caller == NULL || method_type.is_null()) {
-    THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad invokedynamic", empty);
+    bootstrap_specifier.set_resolved_value(value);
   }
 
-  objArrayHandle appendix_box = oopFactory::new_objArray_handle(SystemDictionary::Object_klass(), 1, CHECK_(empty));
-  assert(appendix_box->obj_at(0) == NULL, "");
-
-  // call java.lang.invoke.MethodHandleNatives::linkCallSite(caller, indy_index, bsm, name, mtype, info, &appendix)
-  JavaCallArguments args;
-  args.push_oop(Handle(THREAD, caller->java_mirror()));
-  args.push_int(indy_index);
-  args.push_oop(bsm);
-  args.push_oop(method_name);
-  args.push_oop(method_type);
-  args.push_oop(info);
-  args.push_oop(appendix_box);
-  JavaValue result(T_OBJECT);
-  JavaCalls::call_static(&result,
-                         SystemDictionary::MethodHandleNatives_klass(),
-                         vmSymbols::linkCallSite_name(),
-                         vmSymbols::linkCallSite_signature(),
-                         &args, CHECK_(empty));
-  Handle mname(THREAD, (oop) result.get_jobject());
-  return unpack_method_and_appendix(mname, caller, appendix_box, appendix_result, THREAD);
+  // sanity check
+  assert(bootstrap_specifier.is_resolved() ||
+         (bootstrap_specifier.is_method_call() &&
+          bootstrap_specifier.resolved_method().not_null()), "bootstrap method call failed");
 }
 
 // Protection domain cache table handling
--- a/src/hotspot/share/classfile/systemDictionary.hpp	Tue Apr 23 08:11:38 2019 -0700
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Tue Apr 23 14:09:54 2019 -0400
@@ -74,6 +74,7 @@
 // of placeholders must hold the SystemDictionary_lock.
 //
 
+class BootstrapInfo;
 class ClassFileStream;
 class Dictionary;
 class PlaceholderTable;
@@ -221,6 +222,7 @@
 
 
 class SystemDictionary : AllStatic {
+  friend class BootstrapInfo;
   friend class VMStructs;
   friend class SystemDictionaryHandles;
 
@@ -531,21 +533,7 @@
                                                TRAPS);
 
   // ask Java to compute a constant by invoking a BSM given a Dynamic_info CP entry
-  static Handle    link_dynamic_constant(Klass* caller,
-                                         int condy_index,
-                                         Handle bootstrap_specifier,
-                                         Symbol* name,
-                                         Symbol* type,
-                                         TRAPS);
-
-  // ask Java to create a dynamic call site, while linking an invokedynamic op
-  static methodHandle find_dynamic_call_site_invoker(Klass* caller,
-                                                     int indy_index,
-                                                     Handle bootstrap_method,
-                                                     Symbol* name,
-                                                     Symbol* type,
-                                                     Handle *appendix_result,
-                                                     TRAPS);
+  static void      invoke_bootstrap_method(BootstrapInfo& bootstrap_specifier, TRAPS);
 
   // Record the error when the first attempt to resolve a reference from a constant
   // pool entry to a class fails.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/interpreter/bootstrapInfo.cpp	Tue Apr 23 14:09:54 2019 -0400
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "classfile/javaClasses.inline.hpp"
+#include "classfile/resolutionErrors.hpp"
+#include "interpreter/bootstrapInfo.hpp"
+#include "interpreter/linkResolver.hpp"
+#include "logging/log.hpp"
+#include "logging/logStream.hpp"
+#include "memory/oopFactory.hpp"
+#include "oops/cpCache.inline.hpp"
+#include "oops/objArrayOop.inline.hpp"
+#include "oops/typeArrayOop.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/vmThread.hpp"
+
+//------------------------------------------------------------------------------------------------------------------------
+// Implementation of BootstrapInfo
+
+BootstrapInfo::BootstrapInfo(const constantPoolHandle& pool, int bss_index, int indy_index)
+  : _pool(pool),
+    _bss_index(bss_index),
+    _indy_index(indy_index),
+    // derived and eagerly cached:
+    _argc(      pool->bootstrap_argument_count_at(bss_index) ),
+    _name(      pool->uncached_name_ref_at(bss_index) ),
+    _signature( pool->uncached_signature_ref_at(bss_index) )
+{
+  _is_resolved = false;
+  assert(pool->tag_at(bss_index).has_bootstrap(), "");
+  assert(indy_index == -1 || pool->invokedynamic_bootstrap_ref_index_at(indy_index) == bss_index, "invalid bootstrap specifier index");
+}
+
+// If there is evidence this call site was already linked, set the
+// existing linkage data into result, or throw previous exception.
+// Return true if either action is taken, else false.
+bool BootstrapInfo::resolve_previously_linked_invokedynamic(CallInfo& result, TRAPS) {
+  assert(_indy_index != -1, "");
+  ConstantPoolCacheEntry* cpce = invokedynamic_cp_cache_entry();
+  if (!cpce->is_f1_null()) {
+    methodHandle method(     THREAD, cpce->f1_as_method());
+    Handle       appendix(   THREAD, cpce->appendix_if_resolved(_pool));
+    result.set_handle(method, appendix, THREAD);
+    Exceptions::wrap_dynamic_exception(CHECK_false);
+    return true;
+  } else if (cpce->indy_resolution_failed()) {
+    int encoded_index = ResolutionErrorTable::encode_cpcache_index(_indy_index);
+    ConstantPool::throw_resolution_error(_pool, encoded_index, CHECK_false);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+// Resolve the bootstrap specifier in 3 steps:
+// - unpack the BSM by resolving the MH constant
+// - obtain the NameAndType description for the condy/indy
+// - prepare the BSM's static arguments
+Handle BootstrapInfo::resolve_bsm(TRAPS) {
+  if (_bsm.not_null())  return _bsm;
+  // The tag at the bootstrap method index must be a valid method handle or a method handle in error.
+  // If it is a MethodHandleInError, a resolution error will be thrown which will be wrapped if necessary
+  // with a BootstrapMethodError.
+  assert(_pool->tag_at(bsm_index()).is_method_handle() ||
+         _pool->tag_at(bsm_index()).is_method_handle_in_error(), "MH not present, classfile structural constraint");
+  oop bsm_oop = _pool->resolve_possibly_cached_constant_at(bsm_index(), THREAD);
+  Exceptions::wrap_dynamic_exception(CHECK_NH);
+  guarantee(java_lang_invoke_MethodHandle::is_instance(bsm_oop), "classfile must supply a valid BSM");
+  _bsm = Handle(THREAD, bsm_oop);
+
+  // Obtain NameAndType information
+  resolve_bss_name_and_type(THREAD);
+  Exceptions::wrap_dynamic_exception(CHECK_NH);
+
+  // Prepare static arguments
+  resolve_args(THREAD);
+  Exceptions::wrap_dynamic_exception(CHECK_NH);
+
+  return _bsm;
+}
+
+// Resolve metadata from the JVM_Dynamic_info or JVM_InvokeDynamic_info's name and type information.
+void BootstrapInfo::resolve_bss_name_and_type(TRAPS) {
+  assert(_bsm.not_null(), "resolve_bsm first");
+  Symbol* name = this->name();
+  Symbol* type = this->signature();
+  _name_arg = java_lang_String::create_from_symbol(name, CHECK);
+  if (type->char_at(0) == '(') {
+    _type_arg = SystemDictionary::find_method_handle_type(type, caller(), CHECK);
+  } else {
+    _type_arg = SystemDictionary::find_java_mirror_for_type(type, caller(), SignatureStream::NCDFError, CHECK);
+  }
+}
+
+// Resolve the bootstrap method's static arguments and store the result in _arg_values.
+void BootstrapInfo::resolve_args(TRAPS) {
+  assert(_bsm.not_null(), "resolve_bsm first");
+
+  // if there are no static arguments, return leaving _arg_values as null
+  if (_argc == 0 && UseBootstrapCallInfo < 2) return;
+
+  bool use_BSCI;
+  switch (UseBootstrapCallInfo) {
+  default: use_BSCI = true;  break;  // stress mode
+  case 0:  use_BSCI = false; break;  // stress mode
+  case 1:                            // normal mode
+    // If we were to support an alternative mode of BSM invocation,
+    // we'd convert to pull mode here if the BSM could be a candidate
+    // for that alternative mode.  We can't easily test for things
+    // like varargs here, but we can get away with approximate testing,
+    // since the JDK runtime will make up the difference either way.
+    // For now, exercise the pull-mode path if the BSM is of arity 2,
+    // or if there is a potential condy loop (see below).
+    oop mt_oop = java_lang_invoke_MethodHandle::type(_bsm());
+    use_BSCI = (java_lang_invoke_MethodType::ptype_count(mt_oop) == 2);
+    break;
+  }
+
+  // Here's a reason to use BSCI even if it wasn't requested:
+  // If a condy uses a condy argument, we want to avoid infinite
+  // recursion (condy loops) in the C code.  It's OK in Java,
+  // because Java has stack overflow checking, so we punt
+  // potentially cyclic cases from C to Java.
+  if (!use_BSCI && _pool->tag_at(_bss_index).is_dynamic_constant()) {
+    bool found_unresolved_condy = false;
+    for (int i = 0; i < _argc; i++) {
+      int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);
+      if (_pool->tag_at(arg_index).is_dynamic_constant()) {
+        // potential recursion point condy -> condy
+        bool found_it = false;
+        _pool->find_cached_constant_at(arg_index, found_it, CHECK);
+        if (!found_it) { found_unresolved_condy = true; break; }
+      }
+    }
+    if (found_unresolved_condy)
+      use_BSCI = true;
+  }
+
+  const int SMALL_ARITY = 5;
+  if (use_BSCI && _argc <= SMALL_ARITY && UseBootstrapCallInfo <= 2) {
+    // If there are only a few arguments, and none of them need linking,
+    // push them, instead of asking the JDK runtime to turn around and
+    // pull them, saving a JVM/JDK transition in some simple cases.
+    bool all_resolved = true;
+    for (int i = 0; i < _argc; i++) {
+      bool found_it = false;
+      int arg_index = _pool->bootstrap_argument_index_at(_bss_index, i);
+      _pool->find_cached_constant_at(arg_index, found_it, CHECK);
+      if (!found_it) { all_resolved = false; break; }
+    }
+    if (all_resolved)
+      use_BSCI = false;
+  }
+
+  if (!use_BSCI) {
+    // return {arg...}; resolution of arguments is done immediately, before JDK code is called
+    objArrayOop args_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), _argc, CHECK);
+    objArrayHandle args(THREAD, args_oop);
+    _pool->copy_bootstrap_arguments_at(_bss_index, 0, _argc, args, 0, true, Handle(), CHECK);
+    oop arg_oop = ((_argc == 1) ? args->obj_at(0) : (oop)NULL);
+    // try to discard the singleton array
+    if (arg_oop != NULL && !arg_oop->is_array()) {
+      // JVM treats arrays and nulls specially in this position,
+      // but other things are just single arguments
+      _arg_values = Handle(THREAD, arg_oop);
+    } else {
+      _arg_values = args;
+    }
+  } else {
+    // return {arg_count, pool_index}; JDK code must pull the arguments as needed
+    typeArrayOop ints_oop = oopFactory::new_typeArray(T_INT, 2, CHECK);
+    ints_oop->int_at_put(0, _argc);
+    ints_oop->int_at_put(1, _bss_index);
+    _arg_values = Handle(THREAD, ints_oop);
+  }
+}
+
+// there must be a LinkageError pending; try to save it and then throw
+bool BootstrapInfo::save_and_throw_indy_exc(TRAPS) {
+  assert(HAS_PENDING_EXCEPTION, "");
+  assert(_indy_index != -1, "");
+  ConstantPoolCacheEntry* cpce = invokedynamic_cp_cache_entry();
+  int encoded_index = ResolutionErrorTable::encode_cpcache_index(_indy_index);
+  bool recorded_res_status = cpce->save_and_throw_indy_exc(_pool, _bss_index,
+                                                           encoded_index,
+                                                           pool()->tag_at(_bss_index),
+                                                           CHECK_false);
+  return recorded_res_status;
+}
+
+void BootstrapInfo::resolve_newly_linked_invokedynamic(CallInfo& result, TRAPS) {
+  assert(is_resolved(), "");
+  result.set_handle(resolved_method(), resolved_appendix(), CHECK);
+}
+
+void BootstrapInfo::print_msg_on(outputStream* st, const char* msg) {
+  ResourceMark rm;
+  char what[20];
+  st = st ? st : tty;
+
+  if (_indy_index != -1)
+    sprintf(what, "indy#%d", decode_indy_index());
+  else
+    sprintf(what, "condy");
+  bool have_msg = (msg != NULL && strlen(msg) > 0);
+  st->print_cr("%s%sBootstrap in %s %s@CP[%d] %s:%s%s BSMS[%d] BSM@CP[%d]%s argc=%d%s",
+                (have_msg ? msg : ""), (have_msg ? " " : ""),
+                caller()->name()->as_C_string(),
+                what,  // "indy#42" or "condy"
+                _bss_index,
+                _name->as_C_string(),
+                _signature->as_C_string(),
+                (_type_arg.is_null() ? "" : "(resolved)"),
+                bsms_attr_index(),
+                bsm_index(), (_bsm.is_null() ? "" : "(resolved)"),
+                _argc, (_arg_values.is_null() ? "" : "(resolved)"));
+  if (_argc > 0) {
+    char argbuf[80];
+    argbuf[0] = 0;
+    for (int i = 0; i < _argc; i++) {
+      int pos = (int) strlen(argbuf);
+      if (pos + 20 > (int)sizeof(argbuf)) {
+        sprintf(argbuf + pos, "...");
+        break;
+      }
+      if (i > 0)  argbuf[pos++] = ',';
+      sprintf(argbuf+pos, "%d", arg_index(i));
+    }
+    st->print_cr("  argument indexes: {%s}", argbuf);
+  }
+  if (_bsm.not_null()) {
+    st->print("  resolved BSM: "); _bsm->print();
+  }
+
+  // How the array of resolved arguments is printed depends highly
+  // on how BootstrapInfo::resolve_args structures the array based on
+  // the use_BSCI setting.
+  if (_arg_values.not_null()) {
+    // Find the static arguments within the first element of _arg_values.
+    objArrayOop static_args = (objArrayOop)_arg_values();
+    if (!static_args->is_array()) {
+      assert(_argc == 1, "Invalid BSM _arg_values for non-array");
+      st->print("  resolved arg[0]: "); static_args->print();
+    } else if (static_args->is_objArray()) {
+      int lines = 0;
+      for (int i = 0; i < _argc; i++) {
+        oop x = static_args->obj_at(i);
+        if (x != NULL) {
+          if (++lines > 6) {
+            st->print_cr("  resolved arg[%d]: ...", i);
+            break;
+          }
+          st->print("  resolved arg[%d]: ", i); x->print();
+        }
+      }
+    } else if (static_args->is_typeArray()) {
+      typeArrayOop tmp_array = (typeArrayOop) static_args;
+      assert(tmp_array->length() == 2, "Invalid BSM _arg_values type array");
+      st->print_cr("  resolved arg[0]: %d", tmp_array->int_at(0));
+      st->print_cr("  resolved arg[1]: %d", tmp_array->int_at(1));
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/interpreter/bootstrapInfo.hpp	Tue Apr 23 14:09:54 2019 -0400
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_INTERPRETER_BOOTSTRAPINFO_HPP
+#define SHARE_INTERPRETER_BOOTSTRAPINFO_HPP
+
+#include "oops/constantPool.hpp"
+#include "oops/instanceKlass.hpp"
+
+// BootstrapInfo provides condensed information from the constant pool
+// necessary to invoke a bootstrap method.
+class BootstrapInfo : public StackObj {
+  constantPoolHandle _pool;     // constant pool containing the bootstrap specifier
+  const int   _bss_index;       // index of bootstrap specifier in CP (condy or indy)
+  const int   _indy_index;      // internal index of indy call site, or -1 if a condy call
+  const int   _argc;            // number of static arguments
+  Symbol*     _name;            // extracted from JVM_CONSTANT_NameAndType
+  Symbol*     _signature;
+
+  // pre-bootstrap resolution state:
+  Handle      _bsm;             // resolved bootstrap method
+  Handle      _name_arg;        // resolved String
+  Handle      _type_arg;        // resolved Class or MethodType
+  Handle      _arg_values;      // array of static arguments; null implies either
+                                // uresolved or zero static arguments are specified
+
+  // post-bootstrap resolution state:
+  bool        _is_resolved;       // set true when any of the next fields are set
+  Handle      _resolved_value;    // bind this as condy constant
+  methodHandle _resolved_method;  // bind this as indy behavior
+  Handle      _resolved_appendix; // extra opaque static argument for _resolved_method
+
+ public:
+  BootstrapInfo(const constantPoolHandle& pool, int bss_index, int indy_index = -1);
+
+  // accessors
+  const constantPoolHandle& pool() const{ return _pool; }
+  int bss_index() const                 { return _bss_index; }
+  int indy_index() const                { return _indy_index; }
+  int argc() const                      { return _argc; }
+  bool is_method_call() const           { return (_indy_index != -1); }
+  Symbol* name() const                  { return _name; }
+  Symbol* signature() const             { return _signature; }
+
+  // accessors to lazy state
+  Handle bsm() const                    { return _bsm; }
+  Handle name_arg() const               { return _name_arg; }
+  Handle type_arg() const               { return _type_arg; }
+  Handle arg_values() const             { return _arg_values; }
+  bool is_resolved() const              { return _is_resolved; }
+  Handle resolved_value() const         { assert(!is_method_call(), ""); return _resolved_value; }
+  methodHandle resolved_method() const  { assert(is_method_call(), "");  return _resolved_method; }
+  Handle resolved_appendix() const      { assert(is_method_call(), "");  return _resolved_appendix; }
+
+  // derived accessors
+  InstanceKlass* caller() const         { return _pool->pool_holder(); }
+  oop caller_mirror() const             { return caller()->java_mirror(); }
+  int decode_indy_index() const         { return ConstantPool::decode_invokedynamic_index(_indy_index); }
+  int bsms_attr_index() const           { return _pool->bootstrap_methods_attribute_index(_bss_index); }
+  int bsm_index() const                 { return _pool->bootstrap_method_ref_index_at(_bss_index); }
+  //int argc() is eagerly cached in _argc
+  int arg_index(int i) const            { return _pool->bootstrap_argument_index_at(_bss_index, i); }
+
+  // CP cache entry for call site (indy only)
+  ConstantPoolCacheEntry* invokedynamic_cp_cache_entry() const {
+    assert(is_method_call(), "");
+    return _pool->invokedynamic_cp_cache_entry_at(_indy_index);
+  }
+
+  // If there is evidence this call site was already linked, set the
+  // existing linkage data into result, or throw previous exception.
+  // Return true if either action is taken, else false.
+  bool resolve_previously_linked_invokedynamic(CallInfo& result, TRAPS);
+  bool save_and_throw_indy_exc(TRAPS);
+  void resolve_newly_linked_invokedynamic(CallInfo& result, TRAPS);
+
+  // pre-bootstrap resolution actions:
+  Handle resolve_bsm(TRAPS); // lazily compute _bsm and return it
+  void resolve_bss_name_and_type(TRAPS); // lazily compute _name/_type
+  void resolve_args(TRAPS);  // compute arguments
+
+  // setters for post-bootstrap results:
+  void set_resolved_value(Handle value) {
+    assert(!is_resolved() && !is_method_call(), "");
+    _is_resolved = true;
+    _resolved_value = value;
+  }
+  void set_resolved_method(methodHandle method, Handle appendix) {
+    assert(!is_resolved() && is_method_call(), "");
+    _is_resolved = true;
+    _resolved_method = method;
+    _resolved_appendix = appendix;
+  }
+
+  void print() { print_msg_on(tty); }
+  void print_msg_on(outputStream* st, const char* msg = NULL);
+};
+
+#endif // SHARE_INTERPRETER_BOOTSTRAPINFO_HPP
--- a/src/hotspot/share/interpreter/linkResolver.cpp	Tue Apr 23 08:11:38 2019 -0700
+++ b/src/hotspot/share/interpreter/linkResolver.cpp	Tue Apr 23 14:09:54 2019 -0400
@@ -32,6 +32,7 @@
 #include "classfile/vmSymbols.hpp"
 #include "compiler/compileBroker.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
+#include "interpreter/bootstrapInfo.hpp"
 #include "interpreter/bytecode.hpp"
 #include "interpreter/interpreterRuntime.hpp"
 #include "interpreter/linkResolver.hpp"
@@ -1694,99 +1695,80 @@
   result.set_handle(resolved_klass, resolved_method, resolved_appendix, CHECK);
 }
 
-void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) {
-  Symbol* method_name       = pool->name_ref_at(index);
-  Symbol* method_signature  = pool->signature_ref_at(index);
-  Klass* current_klass = pool->pool_holder();
+void LinkResolver::resolve_invokedynamic(CallInfo& result, const constantPoolHandle& pool, int indy_index, TRAPS) {
+  ConstantPoolCacheEntry* cpce = pool->invokedynamic_cp_cache_entry_at(indy_index);
+  int pool_index = cpce->constant_pool_index();
 
   // Resolve the bootstrap specifier (BSM + optional arguments).
-  Handle bootstrap_specifier;
-  // Check if CallSite has been bound already:
-  ConstantPoolCacheEntry* cpce = pool->invokedynamic_cp_cache_entry_at(index);
-  int pool_index = cpce->constant_pool_index();
+  BootstrapInfo bootstrap_specifier(pool, pool_index, indy_index);
 
-  if (cpce->is_f1_null()) {
-    if (cpce->indy_resolution_failed()) {
-      ConstantPool::throw_resolution_error(pool,
-                                           ResolutionErrorTable::encode_cpcache_index(index),
-                                           CHECK);
-    }
-
-    // The initial step in Call Site Specifier Resolution is to resolve the symbolic
-    // reference to a method handle which will be the bootstrap method for a dynamic
-    // call site.  If resolution for the java.lang.invoke.MethodHandle for the bootstrap
-    // method fails, then a MethodHandleInError is stored at the corresponding bootstrap
-    // method's CP index for the CONSTANT_MethodHandle_info.  So, there is no need to
-    // set the indy_rf flag since any subsequent invokedynamic instruction which shares
-    // this bootstrap method will encounter the resolution of MethodHandleInError.
-    oop bsm_info = pool->resolve_bootstrap_specifier_at(pool_index, THREAD);
-    Exceptions::wrap_dynamic_exception(CHECK);
-    assert(bsm_info != NULL, "");
-    // FIXME: Cache this once per BootstrapMethods entry, not once per CONSTANT_InvokeDynamic.
-    bootstrap_specifier = Handle(THREAD, bsm_info);
-  }
-  if (!cpce->is_f1_null()) {
-    methodHandle method(     THREAD, cpce->f1_as_method());
-    Handle       appendix(   THREAD, cpce->appendix_if_resolved(pool));
-    result.set_handle(method, appendix, THREAD);
-    Exceptions::wrap_dynamic_exception(CHECK);
-    return;
+  // Check if CallSite has been bound already or failed already, and short circuit:
+  {
+    bool is_done = bootstrap_specifier.resolve_previously_linked_invokedynamic(result, CHECK);
+    if (is_done) return;
   }
 
+  // The initial step in Call Site Specifier Resolution is to resolve the symbolic
+  // reference to a method handle which will be the bootstrap method for a dynamic
+  // call site.  If resolution for the java.lang.invoke.MethodHandle for the bootstrap
+  // method fails, then a MethodHandleInError is stored at the corresponding bootstrap
+  // method's CP index for the CONSTANT_MethodHandle_info.  So, there is no need to
+  // set the indy_rf flag since any subsequent invokedynamic instruction which shares
+  // this bootstrap method will encounter the resolution of MethodHandleInError.
+
+  resolve_dynamic_call(result, bootstrap_specifier, CHECK);
+
   if (TraceMethodHandles) {
-    ResourceMark rm(THREAD);
-    tty->print_cr("resolve_invokedynamic #%d %s %s in %s",
-                  ConstantPool::decode_invokedynamic_index(index),
-                  method_name->as_C_string(), method_signature->as_C_string(),
-                  current_klass->name()->as_C_string());
-    tty->print("  BSM info: "); bootstrap_specifier->print();
+    bootstrap_specifier.print_msg_on(tty, "resolve_invokedynamic");
   }
 
-  resolve_dynamic_call(result, pool_index, bootstrap_specifier, method_name,
-                       method_signature, current_klass, THREAD);
-  if (HAS_PENDING_EXCEPTION && PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {
-    int encoded_index = ResolutionErrorTable::encode_cpcache_index(index);
-    bool recorded_res_status = cpce->save_and_throw_indy_exc(pool, pool_index,
-                                                             encoded_index,
-                                                             pool()->tag_at(pool_index),
-                                                             CHECK);
-    if (!recorded_res_status) {
-      // Another thread got here just before we did.  So, either use the method
-      // that it resolved or throw the LinkageError exception that it threw.
-      if (!cpce->is_f1_null()) {
-        methodHandle method(     THREAD, cpce->f1_as_method());
-        Handle       appendix(   THREAD, cpce->appendix_if_resolved(pool));
-        result.set_handle(method, appendix, THREAD);
-        Exceptions::wrap_dynamic_exception(CHECK);
-      } else {
-        assert(cpce->indy_resolution_failed(), "Resolution failure flag not set");
-        ConstantPool::throw_resolution_error(pool, encoded_index, CHECK);
-      }
-      return;
-    }
-    assert(cpce->indy_resolution_failed(), "Resolution failure flag wasn't set");
-  }
+  // The returned linkage result is provisional up to the moment
+  // the interpreter or runtime performs a serialized check of
+  // the relevant CPCE::f1 field.  This is done by the caller
+  // of this method, via CPCE::set_dynamic_call, which uses
+  // an ObjectLocker to do the final serialization of updates
+  // to CPCE state, including f1.
 }
 
 void LinkResolver::resolve_dynamic_call(CallInfo& result,
-                                        int pool_index,
-                                        Handle bootstrap_specifier,
-                                        Symbol* method_name, Symbol* method_signature,
-                                        Klass* current_klass,
+                                        BootstrapInfo& bootstrap_specifier,
                                         TRAPS) {
-  // JSR 292:  this must resolve to an implicitly generated method MH.linkToCallSite(*...)
+  // JSR 292:  this must resolve to an implicitly generated method
+  // such as MH.linkToCallSite(*...) or some other call-site shape.
   // The appendix argument is likely to be a freshly-created CallSite.
-  Handle       resolved_appendix;
-  methodHandle resolved_method =
-    SystemDictionary::find_dynamic_call_site_invoker(current_klass,
-                                                     pool_index,
-                                                     bootstrap_specifier,
-                                                     method_name, method_signature,
-                                                     &resolved_appendix,
-                                                     THREAD);
-  Exceptions::wrap_dynamic_exception(CHECK);
-  result.set_handle(resolved_method, resolved_appendix, THREAD);
-  Exceptions::wrap_dynamic_exception(CHECK);
+  // It may also be a MethodHandle from an unwrapped ConstantCallSite,
+  // or any other reference.  The resolved_method as well as the appendix
+  // are both recorded together via CallInfo::set_handle.
+  SystemDictionary::invoke_bootstrap_method(bootstrap_specifier, THREAD);
+  Exceptions::wrap_dynamic_exception(THREAD);
+
+  if (HAS_PENDING_EXCEPTION) {
+    if (!PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {
+      // Let any random low-level IE or SOE or OOME just bleed through.
+      // Basically we pretend that the bootstrap method was never called,
+      // if it fails this way:  We neither record a successful linkage,
+      // nor do we memorize a LE for posterity.
+      return;
+    }
+    // JVMS 5.4.3 says: If an attempt by the Java Virtual Machine to resolve
+    // a symbolic reference fails because an error is thrown that is an
+    // instance of LinkageError (or a subclass), then subsequent attempts to
+    // resolve the reference always fail with the same error that was thrown
+    // as a result of the initial resolution attempt.
+     bool recorded_res_status = bootstrap_specifier.save_and_throw_indy_exc(CHECK);
+     if (!recorded_res_status) {
+       // Another thread got here just before we did.  So, either use the method
+       // that it resolved or throw the LinkageError exception that it threw.
+       bool is_done = bootstrap_specifier.resolve_previously_linked_invokedynamic(result, CHECK);
+       if (is_done) return;
+     }
+     assert(bootstrap_specifier.invokedynamic_cp_cache_entry()->indy_resolution_failed(),
+            "Resolution failure flag wasn't set");
+  }
+
+  bootstrap_specifier.resolve_newly_linked_invokedynamic(result, CHECK);
+  // Exceptions::wrap_dynamic_exception not used because
+  // set_handle doesn't throw linkage errors
 }
 
 // Selected method is abstract.
--- a/src/hotspot/share/interpreter/linkResolver.hpp	Tue Apr 23 08:11:38 2019 -0700
+++ b/src/hotspot/share/interpreter/linkResolver.hpp	Tue Apr 23 14:09:54 2019 -0400
@@ -25,6 +25,7 @@
 #ifndef SHARE_INTERPRETER_LINKRESOLVER_HPP
 #define SHARE_INTERPRETER_LINKRESOLVER_HPP
 
+#include "interpreter/bootstrapInfo.hpp"
 #include "oops/method.hpp"
 
 // All the necessary definitions for run-time link resolution.
@@ -77,6 +78,7 @@
                   CallKind kind,
                   int index, TRAPS);
 
+  friend class BootstrapInfo;
   friend class LinkResolver;
 
  public:
@@ -311,9 +313,8 @@
                                      bool check_null_and_abstract, TRAPS);
   static void resolve_handle_call   (CallInfo& result,
                                      const LinkInfo& link_info, TRAPS);
-  static void resolve_dynamic_call  (CallInfo& result, int pool_index, Handle bootstrap_specifier,
-                                     Symbol* method_name, Symbol* method_signature,
-                                     Klass* current_klass, TRAPS);
+  static void resolve_dynamic_call  (CallInfo& result,
+                                     BootstrapInfo& bootstrap_specifier, TRAPS);
 
   // same as above for compile-time resolution; but returns null handle instead of throwing
   // an exception on error also, does not initialize klass (i.e., no side effects)
--- a/src/hotspot/share/oops/constantPool.cpp	Tue Apr 23 08:11:38 2019 -0700
+++ b/src/hotspot/share/oops/constantPool.cpp	Tue Apr 23 14:09:54 2019 -0400
@@ -30,6 +30,7 @@
 #include "classfile/stringTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
+#include "interpreter/bootstrapInfo.hpp"
 #include "interpreter/linkResolver.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/heapInspection.hpp"
@@ -909,9 +910,8 @@
 
   case JVM_CONSTANT_Dynamic:
     {
-      Klass* current_klass  = this_cp->pool_holder();
-      Symbol* constant_name = this_cp->uncached_name_ref_at(index);
-      Symbol* constant_type = this_cp->uncached_signature_ref_at(index);
+      // Resolve the Dynamically-Computed constant to invoke the BSM in order to obtain the resulting oop.
+      BootstrapInfo bootstrap_specifier(this_cp, index);
 
       // The initial step in resolving an unresolved symbolic reference to a
       // dynamically-computed constant is to resolve the symbolic reference to a
@@ -921,27 +921,18 @@
       // bootstrap method's CP index for the CONSTANT_MethodHandle_info. No need to
       // set a DynamicConstantInError here since any subsequent use of this
       // bootstrap method will encounter the resolution of MethodHandleInError.
-      oop bsm_info = this_cp->resolve_bootstrap_specifier_at(index, THREAD);
-      Exceptions::wrap_dynamic_exception(CHECK_NULL);
-      assert(bsm_info != NULL, "");
-      // FIXME: Cache this once per BootstrapMethods entry, not once per CONSTANT_Dynamic.
-      Handle bootstrap_specifier = Handle(THREAD, bsm_info);
-
-      // Resolve the Dynamically-Computed constant to invoke the BSM in order to obtain the resulting oop.
-      Handle value = SystemDictionary::link_dynamic_constant(current_klass,
-                                                             index,
-                                                             bootstrap_specifier,
-                                                             constant_name,
-                                                             constant_type,
-                                                             THREAD);
-      result_oop = value();
+      // Both the first, (resolution of the BSM and its static arguments), and the second tasks,
+      // (invocation of the BSM), of JVMS Section 5.4.3.6 occur within invoke_bootstrap_method()
+      // for the bootstrap_specifier created above.
+      SystemDictionary::invoke_bootstrap_method(bootstrap_specifier, THREAD);
       Exceptions::wrap_dynamic_exception(THREAD);
       if (HAS_PENDING_EXCEPTION) {
         // Resolution failure of the dynamically-computed constant, save_and_throw_exception
         // will check for a LinkageError and store a DynamicConstantInError.
         save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
       }
-      BasicType type = FieldType::basic_type(constant_type);
+      result_oop = bootstrap_specifier.resolved_value()();
+      BasicType type = FieldType::basic_type(bootstrap_specifier.signature());
       if (!is_reference_type(type)) {
         // Make sure the primitive value is properly boxed.
         // This is a JDK responsibility.
@@ -961,6 +952,10 @@
           THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), fail);
         }
       }
+
+      if (TraceMethodHandles) {
+        bootstrap_specifier.print_msg_on(tty, "resolve_constant_at_impl");
+      }
       break;
     }
 
@@ -1102,119 +1097,6 @@
   return str;
 }
 
-
-oop ConstantPool::resolve_bootstrap_specifier_at_impl(const constantPoolHandle& this_cp, int index, TRAPS) {
-  assert((this_cp->tag_at(index).is_invoke_dynamic() ||
-          this_cp->tag_at(index).is_dynamic_constant()), "Corrupted constant pool");
-  Handle bsm;
-  int argc;
-  {
-    // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&mtype], plus optional arguments
-    // JVM_CONSTANT_Dynamic is an ordered pair of [bootm, name&ftype], plus optional arguments
-    // In both cases, the bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry.
-    // It is accompanied by the optional arguments.
-    int bsm_index = this_cp->bootstrap_method_ref_index_at(index);
-    oop bsm_oop = this_cp->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL);
-    if (!java_lang_invoke_MethodHandle::is_instance(bsm_oop)) {
-      THROW_MSG_NULL(vmSymbols::java_lang_LinkageError(), "BSM not an MethodHandle");
-    }
-
-    // Extract the optional static arguments.
-    argc = this_cp->bootstrap_argument_count_at(index);
-
-    // if there are no static arguments, return the bsm by itself:
-    if (argc == 0 && UseBootstrapCallInfo < 2)  return bsm_oop;
-
-    bsm = Handle(THREAD, bsm_oop);
-  }
-
-  // We are going to return an ordered pair of {bsm, info}, using a 2-array.
-  objArrayHandle info;
-  {
-    objArrayOop info_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), 2, CHECK_NULL);
-    info = objArrayHandle(THREAD, info_oop);
-  }
-
-  info->obj_at_put(0, bsm());
-
-  bool use_BSCI;
-  switch (UseBootstrapCallInfo) {
-  default: use_BSCI = true;  break;  // stress mode
-  case 0:  use_BSCI = false; break;  // stress mode
-  case 1:                            // normal mode
-    // If we were to support an alternative mode of BSM invocation,
-    // we'd convert to pull mode here if the BSM could be a candidate
-    // for that alternative mode.  We can't easily test for things
-    // like varargs here, but we can get away with approximate testing,
-    // since the JDK runtime will make up the difference either way.
-    // For now, exercise the pull-mode path if the BSM is of arity 2,
-    // or if there is a potential condy loop (see below).
-    oop mt_oop = java_lang_invoke_MethodHandle::type(bsm());
-    use_BSCI = (java_lang_invoke_MethodType::ptype_count(mt_oop) == 2);
-    break;
-  }
-
-  // Here's a reason to use BSCI even if it wasn't requested:
-  // If a condy uses a condy argument, we want to avoid infinite
-  // recursion (condy loops) in the C code.  It's OK in Java,
-  // because Java has stack overflow checking, so we punt
-  // potentially cyclic cases from C to Java.
-  if (!use_BSCI && this_cp->tag_at(index).is_dynamic_constant()) {
-    bool found_unresolved_condy = false;
-    for (int i = 0; i < argc; i++) {
-      int arg_index = this_cp->bootstrap_argument_index_at(index, i);
-      if (this_cp->tag_at(arg_index).is_dynamic_constant()) {
-        // potential recursion point condy -> condy
-        bool found_it = false;
-        this_cp->find_cached_constant_at(arg_index, found_it, CHECK_NULL);
-        if (!found_it) { found_unresolved_condy = true; break; }
-      }
-    }
-    if (found_unresolved_condy)
-      use_BSCI = true;
-  }
-
-  const int SMALL_ARITY = 5;
-  if (use_BSCI && argc <= SMALL_ARITY && UseBootstrapCallInfo <= 2) {
-    // If there are only a few arguments, and none of them need linking,
-    // push them, instead of asking the JDK runtime to turn around and
-    // pull them, saving a JVM/JDK transition in some simple cases.
-    bool all_resolved = true;
-    for (int i = 0; i < argc; i++) {
-      bool found_it = false;
-      int arg_index = this_cp->bootstrap_argument_index_at(index, i);
-      this_cp->find_cached_constant_at(arg_index, found_it, CHECK_NULL);
-      if (!found_it) { all_resolved = false; break; }
-    }
-    if (all_resolved)
-      use_BSCI = false;
-  }
-
-  if (!use_BSCI) {
-    // return {bsm, {arg...}}; resolution of arguments is done immediately, before JDK code is called
-    objArrayOop args_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), argc, CHECK_NULL);
-    info->obj_at_put(1, args_oop);   // may overwrite with args[0] below
-    objArrayHandle args(THREAD, args_oop);
-    copy_bootstrap_arguments_at_impl(this_cp, index, 0, argc, args, 0, true, Handle(), CHECK_NULL);
-    if (argc == 1) {
-      // try to discard the singleton array
-      oop arg_oop = args->obj_at(0);
-      if (arg_oop != NULL && !arg_oop->is_array()) {
-        // JVM treats arrays and nulls specially in this position,
-        // but other things are just single arguments
-        info->obj_at_put(1, arg_oop);
-      }
-    }
-  } else {
-    // return {bsm, {arg_count, pool_index}}; JDK code must pull the arguments as needed
-    typeArrayOop ints_oop = oopFactory::new_typeArray(T_INT, 2, CHECK_NULL);
-    ints_oop->int_at_put(0, argc);
-    ints_oop->int_at_put(1, index);
-    info->obj_at_put(1, ints_oop);
-  }
-  return info();
-}
-
 void ConstantPool::copy_bootstrap_arguments_at_impl(const constantPoolHandle& this_cp, int index,
                                                     int start_arg, int end_arg,
                                                     objArrayHandle info, int pos,
@@ -1848,8 +1730,8 @@
 } // end compare_operand_to()
 
 // Search constant pool search_cp for a bootstrap specifier that matches
-// this constant pool's bootstrap specifier at pattern_i index.
-// Return the index of a matching bootstrap specifier or (-1) if there is no match.
+// this constant pool's bootstrap specifier data at pattern_i index.
+// Return the index of a matching bootstrap attribute record or (-1) if there is no match.
 int ConstantPool::find_matching_operand(int pattern_i,
                     const constantPoolHandle& search_cp, int search_len, TRAPS) {
   for (int i = 0; i < search_len; i++) {
@@ -1858,7 +1740,7 @@
       return i;
     }
   }
-  return -1;  // bootstrap specifier not found; return unused index (-1)
+  return -1;  // bootstrap specifier data not found; return unused index (-1)
 } // end find_matching_operand()
 
 
--- a/src/hotspot/share/oops/constantPool.hpp	Tue Apr 23 08:11:38 2019 -0700
+++ b/src/hotspot/share/oops/constantPool.hpp	Tue Apr 23 14:09:54 2019 -0400
@@ -746,11 +746,6 @@
     return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, &found_it, THREAD);
   }
 
-  oop resolve_bootstrap_specifier_at(int index, TRAPS) {
-    constantPoolHandle h_this(THREAD, this);
-    return resolve_bootstrap_specifier_at_impl(h_this, index, THREAD);
-  }
-
   void copy_bootstrap_arguments_at(int index,
                                    int start_arg, int end_arg,
                                    objArrayHandle info, int pos,
@@ -871,7 +866,6 @@
 
   static oop resolve_constant_at_impl(const constantPoolHandle& this_cp, int index, int cache_index,
                                       bool* status_return, TRAPS);
-  static oop resolve_bootstrap_specifier_at_impl(const constantPoolHandle& this_cp, int index, TRAPS);
   static void copy_bootstrap_arguments_at_impl(const constantPoolHandle& this_cp, int index,
                                                int start_arg, int end_arg,
                                                objArrayHandle info, int pos,