changeset 47254:af6b6ab06876 condy-folding

import changes from condy-folding/hotspot
author mcimadamore
date Mon, 25 Sep 2017 11:46:09 +0100
parents 570a43f46092
children f49cbe81e0da
files src/hotspot/cpu/x86/interp_masm_x86.cpp src/hotspot/cpu/x86/macroAssembler_x86.cpp src/hotspot/cpu/x86/templateTable_x86.cpp src/hotspot/share/c1/c1_GraphBuilder.cpp src/hotspot/share/ci/ciEnv.cpp src/hotspot/share/ci/ciReplay.cpp src/hotspot/share/ci/ciStreams.cpp src/hotspot/share/classfile/classFileParser.cpp src/hotspot/share/classfile/systemDictionary.cpp src/hotspot/share/classfile/systemDictionary.hpp src/hotspot/share/classfile/verifier.cpp src/hotspot/share/classfile/vmSymbols.cpp src/hotspot/share/classfile/vmSymbols.hpp src/hotspot/share/interpreter/bytecode.cpp src/hotspot/share/interpreter/bytecodeInterpreter.cpp src/hotspot/share/interpreter/bytecodeTracer.cpp src/hotspot/share/interpreter/interpreterRuntime.cpp src/hotspot/share/interpreter/linkResolver.cpp src/hotspot/share/interpreter/linkResolver.hpp src/hotspot/share/interpreter/rewriter.cpp src/hotspot/share/interpreter/templateTable.cpp src/hotspot/share/interpreter/templateTable.hpp src/hotspot/share/memory/universe.cpp src/hotspot/share/memory/universe.hpp src/hotspot/share/oops/constantPool.cpp src/hotspot/share/oops/constantPool.hpp src/hotspot/share/oops/generateOopMap.cpp src/hotspot/share/opto/parse2.cpp src/hotspot/share/prims/jvm.h src/hotspot/share/prims/jvmtiRedefineClasses.cpp src/hotspot/share/prims/methodHandles.cpp src/hotspot/share/runtime/globals.hpp src/hotspot/share/runtime/reflection.cpp src/hotspot/share/runtime/signature.cpp src/hotspot/share/runtime/signature.hpp src/hotspot/share/runtime/vmStructs.cpp src/hotspot/share/utilities/constantTag.cpp src/hotspot/share/utilities/constantTag.hpp src/hotspot/share/utilities/exceptions.cpp src/hotspot/share/utilities/exceptions.hpp src/hotspot/share/utilities/globalDefinitions.hpp src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java
diffstat 47 files changed, 1172 insertions(+), 182 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/interp_masm_x86.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -515,6 +515,8 @@
   // Add in the index
   addptr(result, tmp);
   load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
+  // The resulting oop is null if the reference is not yet resolved.
+  // It is Universe::the_null_sentinel() if the reference resolved to NULL via condy.
 }
 
 // load cpool->resolved_klass_at(index)
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -834,7 +834,8 @@
   andq(rsp, -16);     // align stack as required by push_CPU_state and call
   push_CPU_state();   // keeps alignment at 16 bytes
   lea(c_rarg0, ExternalAddress((address) msg));
-  call_VM_leaf(CAST_FROM_FN_PTR(address, warning), c_rarg0);
+  lea(rax, ExternalAddress(CAST_FROM_FN_PTR(address, warning)));
+  call(rax);
   pop_CPU_state();
   mov(rsp, rbp);
   pop(rbp);
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/cpu/x86/templateTable_x86.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -419,7 +419,7 @@
 void TemplateTable::ldc(bool wide) {
   transition(vtos, vtos);
   Register rarg = NOT_LP64(rcx) LP64_ONLY(c_rarg1);
-  Label call_ldc, notFloat, notClass, Done;
+  Label call_ldc, notFloat, notClass, notInt, Done;
 
   if (wide) {
     __ get_unsigned_2_byte_index_at_bcp(rbx, 1);
@@ -465,19 +465,18 @@
   __ jmp(Done);
 
   __ bind(notFloat);
-#ifdef ASSERT
-  {
-    Label L;
-    __ cmpl(rdx, JVM_CONSTANT_Integer);
-    __ jcc(Assembler::equal, L);
-    // String and Object are rewritten to fast_aldc
-    __ stop("unexpected tag type in ldc");
-    __ bind(L);
-  }
-#endif
-  // itos JVM_CONSTANT_Integer only
+  __ cmpl(rdx, JVM_CONSTANT_Integer);
+  __ jccb(Assembler::notEqual, notInt);
+
+  // itos
   __ movl(rax, Address(rcx, rbx, Address::times_ptr, base_offset));
   __ push(itos);
+  __ jmp(Done);
+
+  // assume the tag is for condy; if not, the VM runtime will tell us
+  __ bind(notInt);
+  condy_helper(Done);
+
   __ bind(Done);
 }
 
@@ -487,6 +486,7 @@
 
   Register result = rax;
   Register tmp = rdx;
+  Register rarg = NOT_LP64(rcx) LP64_ONLY(c_rarg1);
   int index_size = wide ? sizeof(u2) : sizeof(u1);
 
   Label resolved;
@@ -496,17 +496,28 @@
   assert_different_registers(result, tmp);
   __ get_cache_index_at_bcp(tmp, 1, index_size);
   __ load_resolved_reference_at_index(result, tmp);
-  __ testl(result, result);
+  __ testptr(result, result);
   __ jcc(Assembler::notZero, resolved);
 
   address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc);
 
   // first time invocation - must resolve first
-  __ movl(tmp, (int)bytecode());
-  __ call_VM(result, entry, tmp);
-
+  __ movl(rarg, (int)bytecode());
+  __ call_VM(result, entry, rarg);
   __ bind(resolved);
 
+  { // Check for the null sentinel.
+    // If we just called the VM, that already did the mapping for us,
+    // but it's harmless to retry.
+    Label notNull;
+    ExternalAddress null_sentinel((address)Universe::the_null_sentinel_addr());
+    __ movptr(tmp, null_sentinel);
+    __ cmpptr(tmp, result);
+    __ jccb(Assembler::notEqual, notNull);
+    __ xorptr(result, result);  // NULL object reference
+    __ bind(notNull);
+  }
+
   if (VerifyOops) {
     __ verify_oop(result);
   }
@@ -514,7 +525,7 @@
 
 void TemplateTable::ldc2_w() {
   transition(vtos, vtos);
-  Label Long, Done;
+  Label notDouble, notLong, Done;
   __ get_unsigned_2_byte_index_at_bcp(rbx, 1);
 
   __ get_cpool_and_tags(rcx, rax);
@@ -522,25 +533,143 @@
   const int tags_offset = Array<u1>::base_offset_in_bytes();
 
   // get type
-  __ cmpb(Address(rax, rbx, Address::times_1, tags_offset),
-          JVM_CONSTANT_Double);
-  __ jccb(Assembler::notEqual, Long);
+  __ movzbl(rdx, Address(rax, rbx, Address::times_1, tags_offset));
+  __ cmpl(rdx, JVM_CONSTANT_Double);
+  __ jccb(Assembler::notEqual, notDouble);
 
   // dtos
   __ load_double(Address(rcx, rbx, Address::times_ptr, base_offset));
   __ push(dtos);
 
-  __ jmpb(Done);
-  __ bind(Long);
+  __ jmp(Done);
+  __ bind(notDouble);
+  __ cmpl(rdx, JVM_CONSTANT_Long);
+  __ jccb(Assembler::notEqual, notLong);
 
   // ltos
   __ movptr(rax, Address(rcx, rbx, Address::times_ptr, base_offset + 0 * wordSize));
   NOT_LP64(__ movptr(rdx, Address(rcx, rbx, Address::times_ptr, base_offset + 1 * wordSize)));
   __ push(ltos);
+  __ jmp(Done);
+
+  __ bind(notLong);
+  condy_helper(Done);
 
   __ bind(Done);
 }
 
+void TemplateTable::condy_helper(Label& Done) {
+  const Register obj = rax;
+  const Register off = rbx;
+  const Register flags = rcx;
+  const Register rarg = NOT_LP64(rcx) LP64_ONLY(c_rarg1);
+  __ movl(rarg, (int)bytecode());
+  call_VM(obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc), rarg);
+#ifndef _LP64
+  // borrow rdi from locals
+  __ get_thread(rdi);
+  __ get_vm_result_2(flags, rdi);
+  __ restore_locals();
+#else
+  __ get_vm_result_2(flags, r15_thread);
+#endif
+  // VMr = obj = base address to find primitive value to push
+  // VMr2 = flags = (tos, off) using format of CPCE::_flags
+  __ movl(off, flags);
+  __ andl(off, ConstantPoolCacheEntry::field_index_mask);
+  const Address field(obj, off, Address::times_1, 0*wordSize);
+
+  // What sort of thing are we loading?
+  __ shrl(flags, ConstantPoolCacheEntry::tos_state_shift);
+  __ andl(flags, ConstantPoolCacheEntry::tos_state_mask);
+
+  switch (bytecode()) {
+  case Bytecodes::_ldc:
+  case Bytecodes::_ldc_w:
+    {
+      // tos in (itos, ftos, stos, btos, ctos, ztos)
+      Label notInt, notFloat, notShort, notByte, notChar, notBool;
+      __ cmpl(flags, itos);
+      __ jcc(Assembler::notEqual, notInt);
+      // itos
+      __ movl(rax, field);
+      __ push(itos);
+      __ jmp(Done);
+
+      __ bind(notInt);
+      __ cmpl(flags, ftos);
+      __ jcc(Assembler::notEqual, notFloat);
+      // ftos
+      __ load_float(field);
+      __ push(ftos);
+      __ jmp(Done);
+
+      __ bind(notFloat);
+      __ cmpl(flags, stos);
+      __ jcc(Assembler::notEqual, notShort);
+      // stos
+      __ load_signed_short(rax, field);
+      __ push(stos);
+      __ jmp(Done);
+
+      __ bind(notShort);
+      __ cmpl(flags, btos);
+      __ jcc(Assembler::notEqual, notByte);
+      // btos
+      __ load_signed_byte(rax, field);
+      __ push(btos);
+      __ jmp(Done);
+
+      __ bind(notByte);
+      __ cmpl(flags, ctos);
+      __ jcc(Assembler::notEqual, notChar);
+      // ctos
+      __ load_unsigned_short(rax, field);
+      __ push(ctos);
+      __ jmp(Done);
+
+      __ bind(notChar);
+      __ cmpl(flags, ztos);
+      __ jcc(Assembler::notEqual, notBool);
+      // ztos
+      __ load_signed_byte(rax, field);
+      __ push(ztos);
+      __ jmp(Done);
+
+      __ bind(notBool);
+      break;
+    }
+
+  case Bytecodes::_ldc2_w:
+    {
+      Label notLong, notDouble;
+      __ cmpl(flags, ltos);
+      __ jcc(Assembler::notEqual, notLong);
+      // ltos
+      __ movptr(rax, field);
+      NOT_LP64(__ movptr(rdx, field.plus_disp(4)));
+      __ push(ltos);
+      __ jmp(Done);
+
+      __ bind(notLong);
+      __ cmpl(flags, dtos);
+      __ jcc(Assembler::notEqual, notDouble);
+      // dtos
+      __ load_double(field);
+      __ push(dtos);
+      __ jmp(Done);
+
+      __ bind(notDouble);
+      break;
+    }
+
+  default:
+    ShouldNotReachHere();
+  }
+
+  __ stop("bad ldc/condy");
+}
+
 void TemplateTable::locals_index(Register reg, int offset) {
   __ load_unsigned_byte(reg, at_bcp(offset));
   __ negptr(reg);
--- a/src/hotspot/share/c1/c1_GraphBuilder.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -874,6 +874,8 @@
 void GraphBuilder::load_constant() {
   ciConstant con = stream()->get_constant();
   if (con.basic_type() == T_ILLEGAL) {
+    // FIXME: an unresolved ConstantDynamic can get here,
+    // and that should not terminate the whole compilation.
     BAILOUT("could not resolve a constant");
   } else {
     ValueType* t = illegalType;
@@ -893,11 +895,19 @@
         ciObject* obj = con.as_object();
         if (!obj->is_loaded()
             || (PatchALot && obj->klass() != ciEnv::current()->String_klass())) {
+          // A Class, MethodType, MethodHandle, or String.
+          // Unloaded condy nodes show up as T_ILLEGAL, above.
           patch_state = copy_state_before();
           t = new ObjectConstant(obj);
         } else {
-          assert(obj->is_instance(), "must be java_mirror of klass");
-          t = new InstanceConstant(obj->as_instance());
+          // Might be a Class, MethodType, MethodHandle, or ConstantDynamic
+          // result, which might turn out to be an array.
+          if (obj->is_null_object())
+            t = objectNull;
+          else if (obj->is_array())
+            t = new ArrayConstant(obj->as_array());
+          else
+            t = new InstanceConstant(obj->as_instance());
         }
         break;
        }
--- a/src/hotspot/share/ci/ciEnv.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/ci/ciEnv.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -584,8 +584,34 @@
   int index = pool_index;
   if (cache_index >= 0) {
     assert(index < 0, "only one kind of index at a time");
+    index = cpool->object_to_cp_index(cache_index);
     oop obj = cpool->resolved_references()->obj_at(cache_index);
     if (obj != NULL) {
+      if (obj == Universe::the_null_sentinel()) {
+        return ciConstant(T_OBJECT, get_object(NULL));
+      }
+      BasicType bt = T_OBJECT;
+      if (cpool->tag_at(index).is_constant_dynamic())
+        bt = FieldType::basic_type(cpool->uncached_signature_ref_at(index));
+      if (is_reference_type(bt)) {
+      } else {
+        // we have to unbox the primitive value
+        if (!is_java_primitive(bt))  return ciConstant();
+        jvalue value;
+        BasicType bt2 = java_lang_boxing_object::get_value(obj, &value);
+        assert(bt2 == bt, "");
+        switch (bt2) {
+        case T_DOUBLE:  return ciConstant(value.d);
+        case T_FLOAT:   return ciConstant(value.f);
+        case T_LONG:    return ciConstant(value.j);
+        case T_INT:     return ciConstant(bt2, value.i);
+        case T_SHORT:   return ciConstant(bt2, value.s);
+        case T_BYTE:    return ciConstant(bt2, value.b);
+        case T_CHAR:    return ciConstant(bt2, value.c);
+        case T_BOOLEAN: return ciConstant(bt2, value.z);
+        default:  return ciConstant();
+        }
+      }
       ciObject* ciobj = get_object(obj);
       if (ciobj->is_array()) {
         return ciConstant(T_ARRAY, ciobj);
@@ -594,7 +620,6 @@
         return ciConstant(T_OBJECT, ciobj);
       }
     }
-    index = cpool->object_to_cp_index(cache_index);
   }
   constantTag tag = cpool->tag_at(index);
   if (tag.is_int()) {
@@ -650,6 +675,8 @@
     ciSymbol* signature = get_symbol(cpool->method_handle_signature_ref_at(index));
     ciObject* ciobj     = get_unloaded_method_handle_constant(callee, name, signature, ref_kind);
     return ciConstant(T_OBJECT, ciobj);
+  } else if (tag.is_constant_dynamic()) {
+    return ciConstant();
   } else {
     ShouldNotReachHere();
     return ciConstant();
--- a/src/hotspot/share/ci/ciReplay.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/ci/ciReplay.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -721,6 +721,7 @@
         case JVM_CONSTANT_Float:
         case JVM_CONSTANT_MethodHandle:
         case JVM_CONSTANT_MethodType:
+        case JVM_CONSTANT_ConstantDynamic:
         case JVM_CONSTANT_InvokeDynamic:
           if (tag != cp->tag_at(i).value()) {
             report_error("tag mismatch: wrong class files?");
--- a/src/hotspot/share/ci/ciStreams.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/ci/ciStreams.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -254,7 +254,8 @@
 // constant.
 constantTag ciBytecodeStream::get_constant_pool_tag(int index) const {
   VM_ENTRY_MARK;
-  return _method->get_Method()->constants()->tag_at(index);
+  BasicType bt = _method->get_Method()->constants()->basic_type_for_constant_at(index);
+  return constantTag::ofBasicType(bt);
 }
 
 // ------------------------------------------------------------------
--- a/src/hotspot/share/classfile/classFileParser.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -202,6 +202,22 @@
         }
         break;
       }
+      case JVM_CONSTANT_ConstantDynamic : {
+        // TODO major version check
+        if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
+          classfile_parse_error(
+              "Class file version does not support constant tag %u in class file %s",
+              tag, CHECK);
+        }
+        cfs->guarantee_more(5, CHECK);  // bsm_index, nt, tag/access_flags
+        const u2 bootstrap_specifier_index = cfs->get_u2_fast();
+        const u2 name_and_type_index = cfs->get_u2_fast();
+        if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) {
+          _max_bootstrap_specifier_index = (int) bootstrap_specifier_index;  // collect for later
+        }
+        cp->constant_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index);
+        break;
+      }
       case JVM_CONSTANT_InvokeDynamic : {
         if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
           classfile_parse_error(
@@ -534,6 +550,18 @@
           ref_index, CHECK);
         break;
       }
+      case JVM_CONSTANT_ConstantDynamic: {
+        const int name_and_type_ref_index =
+          cp->invoke_dynamic_name_and_type_ref_index_at(index);
+
+        check_property(valid_cp_range(name_and_type_ref_index, length) &&
+          cp->tag_at(name_and_type_ref_index).is_name_and_type(),
+          "Invalid constant pool index %u in class file %s",
+          name_and_type_ref_index, CHECK);
+        // bootstrap specifier index must be checked later,
+        // when BootstrapMethods attr is available
+        break;
+      }
       case JVM_CONSTANT_InvokeDynamic: {
         const int name_and_type_ref_index =
           cp->invoke_dynamic_name_and_type_ref_index_at(index);
@@ -626,6 +654,27 @@
         }
         break;
       }
+      case JVM_CONSTANT_ConstantDynamic: {
+        const int name_and_type_ref_index =
+          cp->name_and_type_ref_index_at(index);
+        // already verified to be utf8
+        const int name_ref_index =
+          cp->name_ref_index_at(name_and_type_ref_index);
+        // already verified to be utf8
+        const int signature_ref_index =
+          cp->signature_ref_index_at(name_and_type_ref_index);
+        const Symbol* const name = cp->symbol_at(name_ref_index);
+        const Symbol* const signature = cp->symbol_at(signature_ref_index);
+        if (_need_verify) {
+          // ConstantDynamic name and signature are verified above, when iterating NameAndType_info.
+          // Need only to be sure signature is non-zero length and the right type.
+          if (signature->utf8_length() == 0 ||
+              signature->byte_at(0) == JVM_SIGNATURE_FUNC) {
+            throwIllegalSignature("ConstantDynamic", name, signature, CHECK);
+          }
+        }
+        break;
+      }
       case JVM_CONSTANT_InvokeDynamic:
       case JVM_CONSTANT_Fieldref:
       case JVM_CONSTANT_Methodref:
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -2636,6 +2636,92 @@
           InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::MethodHandle_klass()));  // java.lang.invoke
 }
 
+
+// Return the Java mirror (java.lang.Class instance) for a single-character
+// descriptor.  This result, when available, is the same as produced by the
+// heavier API point of the same name that takes a Symbol.
+oop SystemDictionary::find_java_mirror_for_type(char signature_char) {
+  return java_lang_Class::primitive_mirror(char2type(signature_char));
+}
+
+// Find or construct the Java mirror (java.lang.Class instance) for a
+// for the given field type signature, as interpreted relative to the
+// given class loader.  Handles primitives, void, references, arrays,
+// and all other reflectable types, except method types.
+// N.B.  Code in reflection should use this entry point.
+Handle SystemDictionary::find_java_mirror_for_type(Symbol* signature,
+                                                   Klass* accessing_klass,
+                                                   Handle class_loader,
+                                                   Handle protection_domain,
+                                                   SignatureStream::FailureMode failure_mode,
+                                                   TRAPS) {
+  Handle empty;
+
+  assert(accessing_klass == NULL || (class_loader.is_null() && protection_domain.is_null()),
+         "one or the other, or perhaps neither");
+
+  Symbol* type = signature;
+  TempNewSymbol type_buf;
+  if (type->utf8_length() > 1 && type->byte_at(0) == ';') {
+    // Strip the quote, which may have come from CONSTANT_Class[";"+FD].
+    // (This logic corresponds to the use of "FieldType::is_obj"
+    // in resolve_or_null.  A field type can be unwrapped to a class
+    // type and vice versa.)
+    type = SymbolTable::new_symbol(type->as_C_string() + 1,
+                                   type->utf8_length() - 1, CHECK_(empty));
+    type_buf = type;  // will free later
+  }
+
+  // What we have here must be a valid field descriptor,
+  // and all valid field descriptors are supported.
+  // Produce the same java.lang.Class that reflection reports.
+  if (type->utf8_length() == 1) {
+
+    // It's a primitive.  (Void has a primitive mirror too.)
+    char ch = (char) type->byte_at(0);
+    assert(is_java_primitive(char2type(ch)) || ch == 'V', "");
+    return Handle(THREAD, find_java_mirror_for_type(ch));
+
+  } else if (FieldType::is_obj(type) || FieldType::is_array(type)) {
+
+    // It's a reference type.
+    if (accessing_klass != NULL) {
+      class_loader      = Handle(THREAD, accessing_klass->class_loader());
+      protection_domain = Handle(THREAD, accessing_klass->protection_domain());
+    }
+    Klass* constant_type_klass;
+    if (failure_mode == SignatureStream::ReturnNull) {
+      constant_type_klass = resolve_or_null(type, class_loader, protection_domain,
+                                            CHECK_(empty));
+    } else {
+      bool throw_error = (failure_mode == SignatureStream::NCDFError);
+      constant_type_klass = resolve_or_fail(type, class_loader, protection_domain,
+                                            throw_error, CHECK_(empty));
+    }
+    if (constant_type_klass == NULL) {
+      return Handle();  // report failure this way
+    }
+    Handle mirror(THREAD, constant_type_klass->java_mirror());
+
+    // Check accessibility, emulating ConstantPool::verify_constant_pool_resolve.
+    if (accessing_klass != NULL) {
+      Klass* sel_klass = constant_type_klass;
+      bool fold_type_to_class = true;
+      LinkResolver::check_klass_accessability(accessing_klass, sel_klass,
+                                              fold_type_to_class, CHECK_(empty));
+    }
+
+    return mirror;
+
+  }
+  // New cases like "QFoo;" would go here.
+
+  // Fall through to an error.
+  assert(false, "unsupported mirror syntax");
+  THROW_MSG_(vmSymbols::java_lang_InternalError(), "unsupported mirror syntax", empty);
+}
+
+
 // Ask Java code to find or construct a java.lang.invoke.MethodType for the given
 // signature, as interpreted relative to the given class loader.
 // Because of class loader constraints, all method handle usage must be
@@ -2690,15 +2776,13 @@
       pts->obj_at_put(arg++, mirror);
 
     // Check accessibility.
-    if (ss.is_object() && accessing_klass != NULL) {
+    if (!java_lang_Class::is_primitive(mirror) && accessing_klass != NULL) {
       Klass* sel_klass = java_lang_Class::as_Klass(mirror);
       mirror = NULL;  // safety
       // Emulate ConstantPool::verify_constant_pool_resolve.
-      if (sel_klass->is_objArray_klass())
-        sel_klass = ObjArrayKlass::cast(sel_klass)->bottom_klass();
-      if (sel_klass->is_instance_klass()) {
-        LinkResolver::check_klass_accessability(accessing_klass, sel_klass, CHECK_(empty));
-      }
+      bool fold_type_to_class = true;
+      LinkResolver::check_klass_accessability(accessing_klass, sel_klass,
+                                              fold_type_to_class, CHECK_(empty));
     }
   }
   assert(arg == npts, "");
@@ -2776,9 +2860,60 @@
   return Handle(THREAD, (oop) result.get_jobject());
 }
 
+// Ask Java to compute a constant by invoking a BSM given a ConstantDynamic_info CP entry
+Handle SystemDictionary::link_constant_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");
+
+  // This should not happen.  JDK code should take care of that.
+  if (caller == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_InternalError(), "bad constantdynamic", empty);
+  }
+
+  Handle constant_name = java_lang_String::create_from_symbol(name, CHECK_(empty));
+
+  // 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)
+  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);
+  JavaValue result(T_OBJECT);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::MethodHandleNatives_klass(),
+                         vmSymbols::linkConstantDynamic_name(),
+                         vmSymbols::linkConstantDynamic_signature(),
+                         &args, CHECK_(empty));
+
+  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,
@@ -2790,17 +2925,10 @@
   if (java_lang_invoke_MethodHandle::is_instance(bootstrap_specifier())) {
     bsm = bootstrap_specifier;
   } else {
-    assert(bootstrap_specifier->is_objArray(), "");
-    objArrayHandle args(THREAD, (objArrayOop) bootstrap_specifier());
-    int len = args->length();
-    assert(len >= 1, "");
-    bsm = Handle(THREAD, args->obj_at(0));
-    if (len > 1) {
-      objArrayOop args1 = oopFactory::new_objArray(SystemDictionary::Object_klass(), len-1, CHECK_(empty));
-      for (int i = 1; i < len; i++)
-        args1->obj_at_put(i-1, args->obj_at(i));
-      info = Handle(THREAD, args1);
-    }
+    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");
@@ -2816,9 +2944,10 @@
   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, bsm, name, mtype, info, &appendix)
+  // 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);
--- a/src/hotspot/share/classfile/systemDictionary.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -32,6 +32,7 @@
 #include "oops/symbol.hpp"
 #include "runtime/java.hpp"
 #include "runtime/reflectionUtils.hpp"
+#include "runtime/signature.hpp"
 #include "utilities/hashtable.hpp"
 #include "utilities/hashtable.inline.hpp"
 
@@ -523,6 +524,28 @@
   static methodHandle find_method_handle_intrinsic(vmIntrinsics::ID iid,
                                                    Symbol* signature,
                                                    TRAPS);
+
+  // compute java_mirror (java.lang.Class instance) for a type ("I", "[[B", "LFoo;", etc.)
+  // Either the accessing_klass or the CL/PD can be non-null, but not both.
+  static Handle    find_java_mirror_for_type(Symbol* signature,
+                                             Klass* accessing_klass,
+                                             Handle class_loader,
+                                             Handle protection_domain,
+                                             SignatureStream::FailureMode failure_mode,
+                                             TRAPS);
+  static Handle    find_java_mirror_for_type(Symbol* signature,
+                                             Klass* accessing_klass,
+                                             SignatureStream::FailureMode failure_mode,
+                                             TRAPS) {
+    // callee will fill in CL/PD from AK, if they are needed
+    return find_java_mirror_for_type(signature, accessing_klass, Handle(), Handle(),
+                                     failure_mode, THREAD);
+  }
+                                             
+
+  // fast short-cut for the one-character case:
+  static oop       find_java_mirror_for_type(char signature_char);
+
   // find a java.lang.invoke.MethodType object for a given signature
   // (asks Java to compute it if necessary, except in a compiler thread)
   static Handle    find_method_handle_type(Symbol* signature,
@@ -537,8 +560,17 @@
                                                Symbol* signature,
                                                TRAPS);
 
+  // ask Java to compute a constant by invoking a BSM given a ConstantDynamic_info CP entry
+  static Handle    link_constant_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,
--- a/src/hotspot/share/classfile/verifier.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/classfile/verifier.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -2054,19 +2054,21 @@
     const constantPoolHandle& cp, u2 bci, TRAPS) {
   verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
   constantTag tag = cp->tag_at(index);
-  unsigned int types;
+  unsigned int types = 0;
   if (opcode == Bytecodes::_ldc || opcode == Bytecodes::_ldc_w) {
     if (!tag.is_unresolved_klass()) {
       types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float)
             | (1 << JVM_CONSTANT_String)  | (1 << JVM_CONSTANT_Class)
-            | (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType);
+            | (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType)
+            | (1 << JVM_CONSTANT_ConstantDynamic);
       // Note:  The class file parser already verified the legality of
       // MethodHandle and MethodType constants.
       verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));
     }
   } else {
     assert(opcode == Bytecodes::_ldc2_w, "must be ldc2_w");
-    types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long);
+    types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long)
+          | (1 << JVM_CONSTANT_ConstantDynamic);
     verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));
   }
   if (tag.is_string() && cp->is_pseudo_string_at(index)) {
@@ -2101,6 +2103,30 @@
     current_frame->push_stack(
       VerificationType::reference_type(
         vmSymbols::java_lang_invoke_MethodType()), CHECK_VERIFY(this));
+  } else if (tag.is_constant_dynamic()) {
+    Symbol* constant_type = cp->uncached_signature_ref_at(index);
+    if (!SignatureVerifier::is_valid_type_signature(constant_type)) {
+      class_format_error(
+        "Invalid type for constant dynamic in class %s referenced "
+        "from constant pool index %d", _klass->external_name(), index);
+      return;
+    }
+    assert(sizeof(VerificationType) == sizeof(uintptr_t),
+          "buffer type must match VerificationType size");
+    uintptr_t constant_type_buffer[2];
+    VerificationType* v_constant_type = (VerificationType*)constant_type_buffer;
+    SignatureStream sig_stream(constant_type, false);
+    int n = change_sig_to_verificationType(
+      &sig_stream, v_constant_type, CHECK_VERIFY(this));
+    int opcode_n = (opcode == Bytecodes::_ldc2_w ? 2 : 1);
+    if (n != opcode_n) {
+      // wrong kind of ldc; reverify against updated type mask
+      types &= ~(1 << JVM_CONSTANT_ConstantDynamic);
+      verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));
+    }
+    for (int i = 0; i < n; i++) {
+      current_frame->push_stack(v_constant_type[i], CHECK_VERIFY(this));
+    }
   } else {
     /* Unreachable? verify_cp_type has already validated the cp type. */
     verify_error(
@@ -2665,7 +2691,7 @@
   // Make sure the constant pool item is the right type
   u2 index = bcs->get_index_u2();
   Bytecodes::Code opcode = bcs->raw_code();
-  unsigned int types;
+  unsigned int types = 0;
   switch (opcode) {
     case Bytecodes::_invokeinterface:
       types = 1 << JVM_CONSTANT_InterfaceMethodref;
--- a/src/hotspot/share/classfile/vmSymbols.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/classfile/vmSymbols.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -98,6 +98,14 @@
     _type_signatures[T_BOOLEAN] = bool_signature();
     _type_signatures[T_VOID]    = void_signature();
     // no single signatures for T_OBJECT or T_ARRAY
+#ifdef ASSERT
+    for (int i = (int)T_BOOLEAN; i < (int)T_VOID+1; i++) {
+      Symbol* s = _type_signatures[i];
+      if (s == NULL)  continue;
+      BasicType st = signature_type(s);
+      assert(st == i, "");
+    }
+#endif
   }
 
 #ifdef ASSERT
@@ -202,9 +210,11 @@
 
 BasicType vmSymbols::signature_type(const Symbol* s) {
   assert(s != NULL, "checking");
-  for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
-    if (s == _type_signatures[i]) {
-      return (BasicType)i;
+  if (s->utf8_length() == 1) {
+    BasicType result = char2type(s->byte_at(0));
+    if (is_java_primitive(result) || result == T_VOID) {
+      assert(s == _type_signatures[result], "");
+      return result;
     }
   }
   return T_OBJECT;
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -309,8 +309,10 @@
   template(linkMethodHandleConstant_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;") \
   template(linkMethod_name,                           "linkMethod")                               \
   template(linkMethod_signature, "(Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/invoke/MemberName;") \
+  template(linkConstantDynamic_name,                  "linkConstantDynamic")                      \
+  template(linkConstantDynamic_signature, "(Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \
   template(linkCallSite_name,                         "linkCallSite")                             \
-  template(linkCallSite_signature, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/invoke/MemberName;") \
+  template(linkCallSite_signature, "(Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/invoke/MemberName;") \
   template(setTargetNormal_name,                      "setTargetNormal")                          \
   template(setTargetVolatile_name,                    "setTargetVolatile")                        \
   template(setTarget_signature,                       "(Ljava/lang/invoke/MethodHandle;)V")       \
--- a/src/hotspot/share/interpreter/bytecode.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/interpreter/bytecode.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -207,8 +207,7 @@
 
 BasicType Bytecode_loadconstant::result_type() const {
   int index = pool_index();
-  constantTag tag = _method->constants()->tag_at(index);
-  return tag.basic_type();
+  return _method->constants()->basic_type_for_constant_at(index);
 }
 
 oop Bytecode_loadconstant::resolve_constant(TRAPS) const {
@@ -217,6 +216,8 @@
   ConstantPool* constants = _method->constants();
   if (has_cache_index()) {
     return constants->resolve_cached_constant_at(index, THREAD);
+  } else if (_method->constants()->tag_at(index).is_constant_dynamic()) {
+    return constants->resolve_possibly_cached_constant_at(index, THREAD);
   } else {
     return constants->resolve_constant_at(index, THREAD);
   }
--- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -2371,6 +2371,30 @@
             THREAD->set_vm_result(NULL);
             break;
 
+          case JVM_CONSTANT_ConstantDynamic:
+            {
+              oop result = constants->resolved_references()->obj_at(index);
+              if (result == NULL) {
+                CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception);
+                result = THREAD->vm_result();
+              }
+              VERIFY_OOP(result);
+
+              jvalue value;
+              BasicType type = java_lang_boxing_object::get_value(result, &value);
+              switch (type) {
+              case T_FLOAT:   SET_STACK_FLOAT(value.f, 0); break;
+              case T_INT:     SET_STACK_INT(value.i, 0); break;
+              case T_SHORT:   SET_STACK_INT(value.s, 0); break;
+              case T_BYTE:    SET_STACK_INT(value.b, 0); break;
+              case T_CHAR:    SET_STACK_INT(value.c, 0); break;
+              case T_BOOLEAN: SET_STACK_INT(value.z, 0); break;
+              default:  ShouldNotReachHere();
+              }
+
+              break;
+            }
+
           default:  ShouldNotReachHere();
           }
           UPDATE_PC_AND_TOS_AND_CONTINUE(incr, 1);
@@ -2390,6 +2414,27 @@
           case JVM_CONSTANT_Double:
              SET_STACK_DOUBLE(constants->double_at(index), 1);
             break;
+
+          case JVM_CONSTANT_ConstantDynamic:
+            {
+              oop result = constants->resolved_references()->obj_at(index);
+              if (result == NULL) {
+                CALL_VM(InterpreterRuntime::resolve_ldc(THREAD, (Bytecodes::Code) opcode), handle_exception);
+                result = THREAD->vm_result();
+              }
+              VERIFY_OOP(result);
+
+              jvalue value;
+              BasicType type = java_lang_boxing_object::get_value(result, &value);
+              switch (type) {
+              case T_DOUBLE: SET_STACK_DOUBLE(value.d, 1); break;
+              case T_LONG:   SET_STACK_LONG(value.j, 1); break;
+              default:  ShouldNotReachHere();
+              }
+
+              break;
+            }
+
           default:  ShouldNotReachHere();
           }
           UPDATE_PC_AND_TOS_AND_CONTINUE(3, 2);
@@ -2407,7 +2452,7 @@
           incr = 3;
         }
 
-        // We are resolved if the f1 field contains a non-null object (CallSite, etc.)
+        // We are resolved if the resolved_references array contains a non-null object (CallSite, etc.)
         // This kind of CP cache entry does not need to match the flags byte, because
         // there is a 1-1 relation between bytecode type and CP entry type.
         ConstantPool* constants = METHOD->constants();
@@ -2417,6 +2462,8 @@
                   handle_exception);
           result = THREAD->vm_result();
         }
+        if (result == Universe::the_null_sentinel())
+          result = NULL;
 
         VERIFY_OOP(result);
         SET_STACK_OBJECT(result, 0);
@@ -2428,7 +2475,7 @@
         u4 index = Bytes::get_native_u4(pc+1);
         ConstantPoolCacheEntry* cache = cp->constant_pool()->invokedynamic_cp_cache_entry_at(index);
 
-        // We are resolved if the resolved_references field contains a non-null object (CallSite, etc.)
+        // We are resolved if the resolved_references array contains a non-null object (CallSite, etc.)
         // This kind of CP cache entry does not need to match the flags byte, because
         // there is a 1-1 relation between bytecode type and CP entry type.
         if (! cache->is_resolved((Bytecodes::Code) opcode)) {
--- a/src/hotspot/share/interpreter/bytecodeTracer.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/interpreter/bytecodeTracer.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -367,6 +367,7 @@
   case JVM_CONSTANT_Fieldref:
     break;
   case JVM_CONSTANT_NameAndType:
+  case JVM_CONSTANT_ConstantDynamic:
   case JVM_CONSTANT_InvokeDynamic:
     has_klass = false;
     break;
@@ -382,7 +383,7 @@
     Symbol* klass = constants->klass_name_at(constants->uncached_klass_ref_index_at(i));
     st->print_cr(" %d <%s.%s%s%s> ", i, klass->as_C_string(), name->as_C_string(), sep, signature->as_C_string());
   } else {
-    if (tag.is_invoke_dynamic()) {
+    if (tag.is_constant_dynamic() || tag.is_invoke_dynamic()) {
       int bsm = constants->invoke_dynamic_bootstrap_method_ref_index_at(i);
       st->print(" bsm=%d", bsm);
     }
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -116,25 +116,56 @@
 IRT_END
 
 IRT_ENTRY(void, InterpreterRuntime::resolve_ldc(JavaThread* thread, Bytecodes::Code bytecode)) {
-  assert(bytecode == Bytecodes::_fast_aldc ||
+  assert(bytecode == Bytecodes::_ldc ||
+         bytecode == Bytecodes::_ldc_w ||
+         bytecode == Bytecodes::_ldc2_w ||
+         bytecode == Bytecodes::_fast_aldc ||
          bytecode == Bytecodes::_fast_aldc_w, "wrong bc");
   ResourceMark rm(thread);
+  const bool is_fast_aldc = (bytecode == Bytecodes::_fast_aldc ||
+                             bytecode == Bytecodes::_fast_aldc_w);
   methodHandle m (thread, method(thread));
   Bytecode_loadconstant ldc(m, bci(thread));
+
+  // Double-check the size.  (Condy can have any type.)
+  BasicType type = ldc.result_type();
+  switch (type2size[type]) {
+  case 2: guarantee(bytecode == Bytecodes::_ldc2_w, ""); break;
+  case 1: guarantee(bytecode != Bytecodes::_ldc2_w, ""); break;
+  default: ShouldNotReachHere();
+  }
+
+  // Resolve the constant.  This does not do unboxing.
+  // But it does replace Universe::the_null_sentinel by null.
   oop result = ldc.resolve_constant(CHECK);
+  assert(result != NULL || is_fast_aldc, "null result only valid for fast_aldc");
+
 #ifdef ASSERT
   {
     // The bytecode wrappers aren't GC-safe so construct a new one
     Bytecode_loadconstant ldc2(m, bci(thread));
-    oop coop = m->constants()->resolved_references()->obj_at(ldc2.cache_index());
-    assert(result == coop, "expected result for assembly code");
+    int rindex = ldc2.cache_index();
+    if (rindex < 0)
+      rindex = m->constants()->cp_to_object_index(ldc2.pool_index());
+    if (rindex >= 0) {
+      oop coop = m->constants()->resolved_references()->obj_at(rindex);
+      oop roop = (result == NULL ? Universe::the_null_sentinel() : result);
+      assert(roop == coop, "expected result for assembly code");
+    }
   }
 #endif
   thread->set_vm_result(result);
+  if (!is_fast_aldc) {
+    // Tell the interpreter how to unbox the primitive.
+    guarantee(java_lang_boxing_object::is_instance(result, type), "");
+    int offset = java_lang_boxing_object::value_offset_in_bytes(type);
+    intptr_t flags = ((as_TosState(type) << ConstantPoolCacheEntry::tos_state_shift)
+                      | (offset & ConstantPoolCacheEntry::field_index_mask));
+    thread->set_vm_result_2((Metadata*)flags);
+  }
 }
 IRT_END
 
-
 //------------------------------------------------------------------------------------------------------------------------
 // Allocation
 
--- a/src/hotspot/share/interpreter/linkResolver.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/interpreter/linkResolver.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -39,6 +39,7 @@
 #include "memory/universe.inline.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/method.hpp"
+#include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.hpp"
 #include "oops/oop.inline.hpp"
 #include "prims/jvm.h"
@@ -53,7 +54,6 @@
 #include "runtime/thread.inline.hpp"
 #include "runtime/vmThread.hpp"
 
-
 //------------------------------------------------------------------------------------------------------------------------
 // Implementation of CallInfo
 
@@ -283,9 +283,21 @@
 //------------------------------------------------------------------------------------------------------------------------
 // Klass resolution
 
-void LinkResolver::check_klass_accessability(Klass* ref_klass, Klass* sel_klass, TRAPS) {
+void LinkResolver::check_klass_accessability(Klass* ref_klass, Klass* sel_klass,
+                                             bool fold_type_to_class, TRAPS) {
+  Klass* base_klass = sel_klass;
+  if (fold_type_to_class) {
+    if (sel_klass->is_objArray_klass()) {
+      base_klass = ObjArrayKlass::cast(sel_klass)->bottom_klass();
+    }
+    // The element type could be a typeArray - we only need the access
+    // check if it is an reference to another class.
+    if (!base_klass->is_instance_klass()) {
+      return;  // no relevant check to do
+    }
+  }
   Reflection::VerifyClassAccessResults vca_result =
-    Reflection::verify_class_access(ref_klass, InstanceKlass::cast(sel_klass), true);
+    Reflection::verify_class_access(ref_klass, InstanceKlass::cast(base_klass), true);
   if (vca_result != Reflection::ACCESS_OK) {
     ResourceMark rm(THREAD);
     char* msg = Reflection::verify_class_access_msg(ref_klass,
@@ -1662,31 +1674,6 @@
   result.set_handle(resolved_klass, resolved_method, resolved_appendix, resolved_method_type, CHECK);
 }
 
-static void wrap_invokedynamic_exception(TRAPS) {
-  if (HAS_PENDING_EXCEPTION) {
-    // See the "Linking Exceptions" section for the invokedynamic instruction
-    // in JVMS 6.5.
-    if (PENDING_EXCEPTION->is_a(SystemDictionary::Error_klass())) {
-      // Pass through an Error, including BootstrapMethodError, any other form
-      // of linkage error, or say ThreadDeath/OutOfMemoryError
-      if (TraceMethodHandles) {
-        tty->print_cr("invokedynamic passes through an Error for " INTPTR_FORMAT, p2i((void *)PENDING_EXCEPTION));
-        PENDING_EXCEPTION->print();
-      }
-      return;
-    }
-
-    // Otherwise wrap the exception in a BootstrapMethodError
-    if (TraceMethodHandles) {
-      tty->print_cr("invokedynamic throws BSME for " INTPTR_FORMAT, p2i((void *)PENDING_EXCEPTION));
-      PENDING_EXCEPTION->print();
-    }
-    Handle nested_exception(THREAD, PENDING_EXCEPTION);
-    CLEAR_PENDING_EXCEPTION;
-    THROW_CAUSE(vmSymbols::java_lang_BootstrapMethodError(), nested_exception)
-  }
-}
-
 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);
@@ -1696,10 +1683,11 @@
   Handle bootstrap_specifier;
   // Check if CallSite has been bound already:
   ConstantPoolCacheEntry* cpce = pool->invokedynamic_cp_cache_entry_at(index);
+  int pool_index = -1;
   if (cpce->is_f1_null()) {
-    int pool_index = cpce->constant_pool_index();
+    pool_index = cpce->constant_pool_index();
     oop bsm_info = pool->resolve_bootstrap_specifier_at(pool_index, THREAD);
-    wrap_invokedynamic_exception(CHECK);
+    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);
@@ -1709,7 +1697,7 @@
     Handle       appendix(   THREAD, cpce->appendix_if_resolved(pool));
     Handle       method_type(THREAD, cpce->method_type_if_resolved(pool));
     result.set_handle(method, appendix, method_type, THREAD);
-    wrap_invokedynamic_exception(CHECK);
+    Exceptions::wrap_dynamic_exception(CHECK);
     return;
   }
 
@@ -1722,10 +1710,11 @@
     tty->print("  BSM info: "); bootstrap_specifier->print();
   }
 
-  resolve_dynamic_call(result, bootstrap_specifier, method_name, method_signature, current_klass, CHECK);
+  resolve_dynamic_call(result, pool_index, bootstrap_specifier, method_name, method_signature, current_klass, CHECK);
 }
 
 void LinkResolver::resolve_dynamic_call(CallInfo& result,
+                                        int pool_index,
                                         Handle bootstrap_specifier,
                                         Symbol* method_name, Symbol* method_signature,
                                         Klass* current_klass,
@@ -1736,12 +1725,13 @@
   Handle       resolved_method_type;
   methodHandle resolved_method =
     SystemDictionary::find_dynamic_call_site_invoker(current_klass,
+                                                     pool_index,
                                                      bootstrap_specifier,
                                                      method_name, method_signature,
                                                      &resolved_appendix,
                                                      &resolved_method_type,
                                                      THREAD);
-  wrap_invokedynamic_exception(CHECK);
+  Exceptions::wrap_dynamic_exception(CHECK);
   result.set_handle(resolved_method, resolved_appendix, resolved_method_type, THREAD);
-  wrap_invokedynamic_exception(CHECK);
+  Exceptions::wrap_dynamic_exception(CHECK);
 }
--- a/src/hotspot/share/interpreter/linkResolver.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/interpreter/linkResolver.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -275,7 +275,16 @@
                                       const constantPoolHandle& pool, int index, TRAPS);
  public:
   // constant pool resolving
-  static void check_klass_accessability(Klass* ref_klass, Klass* sel_klass, TRAPS);
+  static void check_klass_accessability(Klass* ref_klass, Klass* sel_klass,
+                                        bool fold_type_to_class, TRAPS);
+  // The optional 'fold_type_to_class' means that a derived type (array)
+  // is first converted to the class it is derived from (element type).
+  // If this element type is not a class, then the check passes quietly.
+  // This is usually what is needed, but a few existing uses might break
+  // if this flag were always turned on.  FIXME: See if it can be, always.
+  static void check_klass_accessability(Klass* ref_klass, Klass* sel_klass, TRAPS) {
+    return check_klass_accessability(ref_klass, sel_klass, false, THREAD);
+  }
 
   // static resolving calls (will not run any Java code);
   // used only from Bytecode_invoke::static_target
@@ -307,7 +316,7 @@
                                      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, Handle bootstrap_specifier,
+  static void resolve_dynamic_call  (CallInfo& result, int pool_index, Handle bootstrap_specifier,
                                      Symbol* method_name, Symbol* method_signature,
                                      Klass* current_klass, TRAPS);
 
--- a/src/hotspot/share/interpreter/rewriter.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/interpreter/rewriter.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -49,7 +49,8 @@
       case JVM_CONSTANT_Methodref         : // fall through
         add_cp_cache_entry(i);
         break;
-      case JVM_CONSTANT_String:
+      case JVM_CONSTANT_ConstantDynamic:
+      case JVM_CONSTANT_String            : // fall through
       case JVM_CONSTANT_MethodHandle      : // fall through
       case JVM_CONSTANT_MethodType        : // fall through
         add_resolved_references_entry(i);
@@ -322,7 +323,14 @@
     address p = bcp + offset;
     int cp_index = is_wide ? Bytes::get_Java_u2(p) : (u1)(*p);
     constantTag tag = _pool->tag_at(cp_index).value();
-    if (tag.is_method_handle() || tag.is_method_type() || tag.is_string()) {
+
+    if (tag.is_method_handle() ||
+        tag.is_method_type() ||
+        tag.is_string() ||
+        (tag.is_constant_dynamic() &&
+         // keep regular ldc interpreter logic for condy primitives
+         is_reference_type(FieldType::basic_type(_pool->uncached_signature_ref_at(cp_index))))
+        ) {
       int ref_index = cp_entry_to_resolved_references(cp_index);
       if (is_wide) {
         (*bcp) = Bytecodes::_fast_aldc_w;
--- a/src/hotspot/share/interpreter/templateTable.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/interpreter/templateTable.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -278,7 +278,7 @@
   def(Bytecodes::_sipush              , ubcp|____|____|____, vtos, itos, sipush              ,  _           );
   def(Bytecodes::_ldc                 , ubcp|____|clvm|____, vtos, vtos, ldc                 ,  false       );
   def(Bytecodes::_ldc_w               , ubcp|____|clvm|____, vtos, vtos, ldc                 ,  true        );
-  def(Bytecodes::_ldc2_w              , ubcp|____|____|____, vtos, vtos, ldc2_w              ,  _           );
+  def(Bytecodes::_ldc2_w              , ubcp|____|clvm|____, vtos, vtos, ldc2_w              ,  _           );
   def(Bytecodes::_iload               , ubcp|____|clvm|____, vtos, itos, iload               ,  _           );
   def(Bytecodes::_lload               , ubcp|____|____|____, vtos, ltos, lload               ,  _           );
   def(Bytecodes::_fload               , ubcp|____|____|____, vtos, ftos, fload               ,  _           );
--- a/src/hotspot/share/interpreter/templateTable.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/interpreter/templateTable.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -295,6 +295,7 @@
   static void getstatic(int byte_no);
   static void putstatic(int byte_no);
   static void pop_and_check_object(Register obj);
+  static void condy_helper(Label& Done);  // shared by ldc instances
 
   static void _new();
   static void newarray();
--- a/src/hotspot/share/memory/universe.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/memory/universe.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -118,6 +118,7 @@
 oop Universe::_system_thread_group                    = NULL;
 objArrayOop Universe::_the_empty_class_klass_array    = NULL;
 Array<Klass*>* Universe::_the_array_interfaces_array = NULL;
+oop Universe::_the_null_sentinel                      = NULL;
 oop Universe::_the_null_string                        = NULL;
 oop Universe::_the_min_jint_string                   = NULL;
 LatestMethodCache* Universe::_finalizer_register_cache = NULL;
@@ -202,6 +203,7 @@
   assert(_mirrors[0] == NULL && _mirrors[T_BOOLEAN - 1] == NULL, "checking");
 
   f->do_oop((oop*)&_the_empty_class_klass_array);
+  f->do_oop((oop*)&_the_null_sentinel);
   f->do_oop((oop*)&_the_null_string);
   f->do_oop((oop*)&_the_min_jint_string);
   f->do_oop((oop*)&_out_of_memory_error_java_heap);
@@ -388,6 +390,11 @@
     initialize_basic_type_klass(longArrayKlassObj(), CHECK);
   } // end of core bootstrapping
 
+  {
+    Handle tns = java_lang_String::create_from_str("<null_sentinel>", CHECK);
+    _the_null_sentinel = tns();
+  }
+
   // Maybe this could be lifted up now that object array can be initialized
   // during the bootstrapping.
 
--- a/src/hotspot/share/memory/universe.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/memory/universe.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -141,6 +141,7 @@
   static oop          _system_thread_group;           // Reference to the system thread group object
 
   static objArrayOop  _the_empty_class_klass_array;   // Canonicalized obj array of type java.lang.Class
+  static oop          _the_null_sentinel;             // A unique object pointer unused except as a sentinel for null.
   static oop          _the_null_string;               // A cache of "null" as a Java string
   static oop          _the_min_jint_string;          // A cache of "-2147483648" as a Java string
   static LatestMethodCache* _finalizer_register_cache; // static method for registering finalizable objects
@@ -323,6 +324,9 @@
 
   static Method*      do_stack_walk_method()          { return _do_stack_walk_cache->get_method(); }
 
+  static oop          the_null_sentinel()             { return _the_null_sentinel;             }
+  static address      the_null_sentinel_addr()        { return (address) &_the_null_sentinel;  }
+
   // Function to initialize these
   static void initialize_known_methods(TRAPS);
 
--- a/src/hotspot/share/oops/constantPool.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/oops/constantPool.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -587,7 +587,6 @@
   return symbol_at(signature_index);
 }
 
-
 int ConstantPool::impl_name_and_type_ref_index_at(int which, bool uncached) {
   int i = which;
   if (!uncached && cache() != NULL) {
@@ -601,7 +600,7 @@
     // change byte-ordering and go via cache
     i = remap_instruction_operand_from_cache(which);
   } else {
-    if (tag_at(which).is_invoke_dynamic()) {
+    if (tag_at(which).is_invoke_dynamic() || tag_at(which).is_constant_dynamic()) {
       int pool_index = invoke_dynamic_name_and_type_ref_index_at(which);
       assert(tag_at(pool_index).is_name_and_type(), "");
       return pool_index;
@@ -652,16 +651,12 @@
 
 
 void ConstantPool::verify_constant_pool_resolve(const constantPoolHandle& this_cp, Klass* k, TRAPS) {
- if (k->is_instance_klass() || k->is_objArray_klass()) {
-    InstanceKlass* holder = this_cp->pool_holder();
-    Klass* elem = k->is_instance_klass() ? k : ObjArrayKlass::cast(k)->bottom_klass();
-
-    // The element type could be a typeArray - we only need the access check if it is
-    // an reference to another class
-    if (elem->is_instance_klass()) {
-      LinkResolver::check_klass_accessability(holder, elem, CHECK);
-    }
+  if (!(k->is_instance_klass() || k->is_objArray_klass())) {
+    return;  // short cut, typeArray klass is always accessible
   }
+  Klass* holder = this_cp->pool_holder();
+  bool fold_type_to_class = true;
+  LinkResolver::check_klass_accessability(holder, k, fold_type_to_class, CHECK);
 }
 
 
@@ -802,16 +797,30 @@
   }
 }
 
+BasicType ConstantPool::basic_type_for_constant_at(int which) {
+  constantTag tag = tag_at(which);
+  if (tag.is_constant_dynamic()) {
+    // have to look at the signature for this one
+    Symbol* constant_type = uncached_signature_ref_at(which);
+    return FieldType::basic_type(constant_type);
+  }
+  return tag.basic_type();
+}
+
 // Called to resolve constants in the constant pool and return an oop.
 // Some constant pool entries cache their resolved oop. This is also
 // called to create oops from constants to use in arguments for invokedynamic
-oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp, int index, int cache_index, TRAPS) {
+oop ConstantPool::resolve_constant_at_impl(const constantPoolHandle& this_cp,
+                                           int index, int cache_index,
+                                           bool* status_return, TRAPS) {
   oop result_oop = NULL;
   Handle throw_exception;
 
   if (cache_index == _possible_index_sentinel) {
     // It is possible that this constant is one which is cached in the objects.
     // We'll do a linear search.  This should be OK because this usage is rare.
+    // FIXME: If bootstrap specifiers stress this code, consider putting in
+    // a reverse index.  Binary search over a short array should do it.
     assert(index > 0, "valid index");
     cache_index = this_cp->cp_to_object_index(index);
   }
@@ -821,6 +830,12 @@
   if (cache_index >= 0) {
     result_oop = this_cp->resolved_references()->obj_at(cache_index);
     if (result_oop != NULL) {
+      if (result_oop == Universe::the_null_sentinel()) {
+        DEBUG_ONLY(int temp_index = (index >= 0 ? index : this_cp->object_to_cp_index(cache_index)));
+        assert(this_cp->tag_at(temp_index).is_constant_dynamic(), "only condy uses the null sentinel");
+        result_oop = NULL;
+      }
+      if (status_return != NULL)  (*status_return) = true;
       return result_oop;
       // That was easy...
     }
@@ -831,6 +846,35 @@
 
   constantTag tag = this_cp->tag_at(index);
 
+  if (status_return != NULL) {
+    // don't trigger resolution if the constant might need it
+    switch (tag.value()) {
+    case JVM_CONSTANT_Class:
+    {
+      CPKlassSlot kslot = this_cp->klass_slot_at(index);
+      int resolved_klass_index = kslot.resolved_klass_index();
+      if (this_cp->resolved_klasses()->at(resolved_klass_index) == NULL) {
+        (*status_return) = false;
+        return NULL;
+      }
+      // the klass is waiting in the CP; go get it
+      break;
+    }
+    case JVM_CONSTANT_String:
+    case JVM_CONSTANT_Integer:
+    case JVM_CONSTANT_Float:
+    case JVM_CONSTANT_Long:
+    case JVM_CONSTANT_Double:
+      // these guys trigger OOM at worst
+      break;
+    default:
+      (*status_return) = false;
+      return NULL;
+    }
+    // from now on there is either success or an OOME
+    (*status_return) = true;
+  }
+
   switch (tag.value()) {
 
   case JVM_CONSTANT_UnresolvedClass:
@@ -844,6 +888,48 @@
       break;
     }
 
+  case JVM_CONSTANT_ConstantDynamic:
+    {
+      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);
+
+      Handle bootstrap_specifier;
+      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_ConstantDynamic.
+      bootstrap_specifier = Handle(THREAD, bsm_info);
+    
+      // Resolve the ConstantDynamic to invoke the BSM in order to obtain the resulting oop.
+      Handle value = SystemDictionary::link_constant_dynamic_constant(current_klass,
+                                                                      index,
+                                                                      bootstrap_specifier,
+                                                                      constant_name,
+                                                                      constant_type,
+                                                                      THREAD);
+      result_oop = value();
+      Exceptions::wrap_dynamic_exception(CHECK_NULL);
+      BasicType type = FieldType::basic_type(constant_type);
+      if (!is_reference_type(type)) {
+        // Make sure the primitive value is properly boxed.
+        // This is a JDK responsibility.
+        const char* fail = NULL;
+        if (result_oop == NULL) {
+          fail = "null result instead of box";
+        } else if (!is_java_primitive(type)) {
+          // FIXME: support value types via unboxing
+          fail = "can only handle references and primitives";
+        } else if (!java_lang_boxing_object::is_instance(result_oop, type)) {
+          fail = "primitive is not properly boxed";
+        }
+        if (fail != NULL) {
+          THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), fail);
+        }
+      }
+      break;
+    }
+
   case JVM_CONSTANT_String:
     assert(cache_index != _no_index_sentinel, "should have been set");
     if (this_cp->is_pseudo_string_at(index)) {
@@ -953,15 +1039,20 @@
     // The important thing here is that all threads pick up the same result.
     // It doesn't matter which racing thread wins, as long as only one
     // result is used by all threads, and all future queries.
-    oop old_result = this_cp->resolved_references()->atomic_compare_exchange_oop(cache_index, result_oop, NULL);
+    oop new_result = (result_oop == NULL ? Universe::the_null_sentinel() : result_oop);
+    oop old_result = this_cp->resolved_references()
+      ->atomic_compare_exchange_oop(cache_index, new_result, NULL);
     if (old_result == NULL) {
       return result_oop;  // was installed
     } else {
       // Return the winning thread's result.  This can be different than
       // the result here for MethodHandles.
+      if (old_result == Universe::the_null_sentinel())
+        old_result = NULL;
       return old_result;
     }
   } else {
+    assert(result_oop != Universe::the_null_sentinel(), "");
     return result_oop;
   }
 }
@@ -975,13 +1066,14 @@
 
 
 oop ConstantPool::resolve_bootstrap_specifier_at_impl(const constantPoolHandle& this_cp, int index, TRAPS) {
-  assert(this_cp->tag_at(index).is_invoke_dynamic(), "Corrupted constant pool");
-
+  assert((this_cp->tag_at(index).is_invoke_dynamic() ||
+          this_cp->tag_at(index).is_constant_dynamic()), "Corrupted constant pool");
   Handle bsm;
   int argc;
   {
-    // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type], plus optional arguments
-    // The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry.
+    // JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&mtype], plus optional arguments
+    // JVM_CONSTANT_ConstantDynamic 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->invoke_dynamic_bootstrap_method_ref_index_at(index);
     oop bsm_oop = this_cp->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL);
@@ -991,30 +1083,142 @@
 
     // Extract the optional static arguments.
     argc = this_cp->invoke_dynamic_argument_count_at(index);
-    if (argc == 0)  return bsm_oop;
+
+    // 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(), 1+argc, CHECK_NULL);
+    objArrayOop info_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), 2, CHECK_NULL);
     info = objArrayHandle(THREAD, info_oop);
   }
 
   info->obj_at_put(0, bsm());
-  for (int i = 0; i < argc; i++) {
-    int arg_index = this_cp->invoke_dynamic_argument_index_at(index, i);
-    oop arg_oop = this_cp->resolve_possibly_cached_constant_at(arg_index, CHECK_NULL);
-    info->obj_at_put(1+i, arg_oop);
+
+  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_constant_dynamic()) {
+    bool found_unresolved_condy = false;
+    for (int i = 0; i < argc; i++) {
+      int arg_index = this_cp->invoke_dynamic_argument_index_at(index, i);
+      if (this_cp->tag_at(arg_index).is_constant_dynamic()) {
+        // 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->invoke_dynamic_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,
+                                                    bool must_resolve, Handle if_not_available,
+                                                    TRAPS) {
+  int argc;
+  int limit = java_add(pos, end_arg - start_arg);
+  // checks: index in range [0..this_cp->length),
+  // tag at index, start..end in range [0..argc],
+  // info array non-null, pos..limit in [0..info.length]
+  if ((0 >= index    || index >= this_cp->length())  ||
+      !(this_cp->tag_at(index).is_invoke_dynamic()    ||
+        this_cp->tag_at(index).is_constant_dynamic()) ||
+      (0 > start_arg || start_arg > end_arg) ||
+      (end_arg > (argc = this_cp->invoke_dynamic_argument_count_at(index))) ||
+      (0 > pos       || pos > limit)         ||
+      (info.is_null() || limit > info->length())) {
+    // An index or something else went wrong; throw an error.
+    // Since this is an internal API, we don't expect this,
+    // so we don't bother to craft a nice message.
+    THROW_MSG(vmSymbols::java_lang_LinkageError(), "bad BSM argument access");
+  }
+  // now we can loop safely
+  int info_i = pos;
+  for (int i = start_arg; i < end_arg; i++) {
+    int arg_index = this_cp->invoke_dynamic_argument_index_at(index, i);
+    oop arg_oop;
+    if (must_resolve) {
+      arg_oop = this_cp->resolve_possibly_cached_constant_at(arg_index, CHECK);
+    } else {
+      bool found_it = false;
+      arg_oop = this_cp->find_cached_constant_at(arg_index, found_it, CHECK);
+      if (!found_it)  arg_oop = if_not_available();
+    }
+    info->obj_at_put(info_i++, arg_oop);
+  }
+}
+
 oop ConstantPool::string_at_impl(const constantPoolHandle& this_cp, int which, int obj_index, TRAPS) {
   // If the string has already been interned, this entry will be non-null
   oop str = this_cp->resolved_references()->obj_at(obj_index);
+  assert(str != Universe::the_null_sentinel(), "");
   if (str != NULL) return str;
   Symbol* sym = this_cp->unresolved_string_at(which);
   str = StringTable::intern(sym, CHECK_(NULL));
@@ -1195,6 +1399,18 @@
     }
   } break;
 
+  case JVM_CONSTANT_ConstantDynamic:
+  {
+    int k1 = invoke_dynamic_name_and_type_ref_index_at(index1);
+    int k2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
+    int i1 = invoke_dynamic_bootstrap_specifier_index(index1);
+    int i2 = cp2->invoke_dynamic_bootstrap_specifier_index(index2);
+    // separate statements and variables because CHECK_false is used
+    bool match_entry = compare_entry_to(k1, cp2, k2, CHECK_false);
+    bool match_operand = compare_operand_to(i1, cp2, i2, CHECK_false);
+    return (match_entry && match_operand);
+  } break;
+
   case JVM_CONSTANT_InvokeDynamic:
   {
     int k1 = invoke_dynamic_name_and_type_ref_index_at(index1);
@@ -1521,6 +1737,14 @@
     to_cp->method_handle_index_at_put(to_i, k1, k2);
   } break;
 
+  case JVM_CONSTANT_ConstantDynamic:
+  {
+    int k1 = from_cp->invoke_dynamic_bootstrap_specifier_index(from_i);
+    int k2 = from_cp->invoke_dynamic_name_and_type_ref_index_at(from_i);
+    k1 += operand_array_length(to_cp->operands());  // to_cp might already have operands
+    to_cp->constant_dynamic_at_put(to_i, k1, k2);
+  } break;
+
   case JVM_CONSTANT_InvokeDynamic:
   {
     int k1 = from_cp->invoke_dynamic_bootstrap_specifier_index(from_i);
@@ -1782,6 +2006,7 @@
     case JVM_CONSTANT_NameAndType:
       return 5;
 
+    case JVM_CONSTANT_ConstantDynamic:
     case JVM_CONSTANT_InvokeDynamic:
       // u1 tag, u2 bsm, u2 nt
       return 5;
@@ -1967,6 +2192,16 @@
         DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1));
         break;
       }
+      case JVM_CONSTANT_ConstantDynamic: {
+        *bytes = tag;
+        idx1 = extract_low_short_from_int(*int_at_addr(idx));
+        idx2 = extract_high_short_from_int(*int_at_addr(idx));
+        assert(idx2 == invoke_dynamic_name_and_type_ref_index_at(idx), "correct half of u4");
+        Bytes::put_Java_u2((address) (bytes+1), idx1);
+        Bytes::put_Java_u2((address) (bytes+3), idx2);
+        DBG(printf("JVM_CONSTANT_ConstantDynamic: %hd %hd", idx1, idx2));
+        break;
+      }
       case JVM_CONSTANT_InvokeDynamic: {
         *bytes = tag;
         idx1 = extract_low_short_from_int(*int_at_addr(idx));
@@ -2172,6 +2407,20 @@
     case JVM_CONSTANT_MethodTypeInError :
       st->print("signature_index=%d", method_type_index_at(index));
       break;
+    case JVM_CONSTANT_ConstantDynamic :
+      {
+        st->print("bootstrap_method_index=%d", invoke_dynamic_bootstrap_method_ref_index_at(index));
+        st->print(" type_index=%d", invoke_dynamic_name_and_type_ref_index_at(index));
+        int argc = invoke_dynamic_argument_count_at(index);
+        if (argc > 0) {
+          for (int arg_i = 0; arg_i < argc; arg_i++) {
+            int arg = invoke_dynamic_argument_index_at(index, arg_i);
+            st->print((arg_i == 0 ? " arguments={%d" : ", %d"), arg);
+          }
+          st->print("}");
+        }
+      }
+      break;
     case JVM_CONSTANT_InvokeDynamic :
       {
         st->print("bootstrap_method_index=%d", invoke_dynamic_bootstrap_method_ref_index_at(index));
--- a/src/hotspot/share/oops/constantPool.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/oops/constantPool.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -295,6 +295,11 @@
     *int_at_addr(which) = ref_index;
   }
 
+  void constant_dynamic_at_put(int which, int bootstrap_specifier_index, int name_and_type_index) {
+    tag_at_put(which, JVM_CONSTANT_ConstantDynamic);
+    *int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_specifier_index;
+  }
+
   void invoke_dynamic_at_put(int which, int bootstrap_specifier_index, int name_and_type_index) {
     tag_at_put(which, JVM_CONSTANT_InvokeDynamic);
     *int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_specifier_index;
@@ -552,11 +557,13 @@
   }
 
   int invoke_dynamic_name_and_type_ref_index_at(int which) {
-    assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
+    assert(tag_at(which).is_invoke_dynamic() ||
+           tag_at(which).is_constant_dynamic(), "Corrupted constant pool");
     return extract_high_short_from_int(*int_at_addr(which));
   }
   int invoke_dynamic_bootstrap_specifier_index(int which) {
-    assert(tag_at(which).value() == JVM_CONSTANT_InvokeDynamic, "Corrupted constant pool");
+    assert(tag_at(which).is_invoke_dynamic() ||
+           tag_at(which).is_constant_dynamic(), "Corrupted constant pool");
     return extract_low_short_from_int(*int_at_addr(which));
   }
   int invoke_dynamic_operand_base(int which) {
@@ -606,7 +613,7 @@
   }
 #endif //ASSERT
 
-  // layout of InvokeDynamic bootstrap method specifier (in second part of operands array):
+  // layout of InvokeDynamic and ConstantDynamic bootstrap method specifier (in second part of operands array):
   enum {
          _indy_bsm_offset  = 0,  // CONSTANT_MethodHandle bsm
          _indy_argc_offset = 1,  // u2 argc
@@ -652,14 +659,15 @@
   // Shrink the operands array to a smaller array with new_len length
   void shrink_operands(int new_len, TRAPS);
 
-
   int invoke_dynamic_bootstrap_method_ref_index_at(int which) {
-    assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
+    assert(tag_at(which).is_invoke_dynamic() ||
+           tag_at(which).is_constant_dynamic(), "Corrupted constant pool");
     int op_base = invoke_dynamic_operand_base(which);
     return operands()->at(op_base + _indy_bsm_offset);
   }
   int invoke_dynamic_argument_count_at(int which) {
-    assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
+    assert(tag_at(which).is_invoke_dynamic() ||
+           tag_at(which).is_constant_dynamic(), "Corrupted constant pool");
     int op_base = invoke_dynamic_operand_base(which);
     int argc = operands()->at(op_base + _indy_argc_offset);
     DEBUG_ONLY(int end_offset = op_base + _indy_argv_offset + argc;
@@ -729,20 +737,27 @@
   enum { _no_index_sentinel = -1, _possible_index_sentinel = -2 };
  public:
 
+  BasicType basic_type_for_constant_at(int which);
+
   // Resolve late bound constants.
   oop resolve_constant_at(int index, TRAPS) {
     constantPoolHandle h_this(THREAD, this);
-    return resolve_constant_at_impl(h_this, index, _no_index_sentinel, THREAD);
+    return resolve_constant_at_impl(h_this, index, _no_index_sentinel, NULL, THREAD);
   }
 
   oop resolve_cached_constant_at(int cache_index, TRAPS) {
     constantPoolHandle h_this(THREAD, this);
-    return resolve_constant_at_impl(h_this, _no_index_sentinel, cache_index, THREAD);
+    return resolve_constant_at_impl(h_this, _no_index_sentinel, cache_index, NULL, THREAD);
   }
 
   oop resolve_possibly_cached_constant_at(int pool_index, TRAPS) {
     constantPoolHandle h_this(THREAD, this);
-    return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, THREAD);
+    return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, NULL, THREAD);
+  }
+
+  oop find_cached_constant_at(int pool_index, bool& found_it, TRAPS) {
+    constantPoolHandle h_this(THREAD, this);
+    return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, &found_it, THREAD);
   }
 
   oop resolve_bootstrap_specifier_at(int index, TRAPS) {
@@ -750,6 +765,15 @@
     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,
+                                   bool must_resolve, Handle if_not_available, TRAPS) {
+    constantPoolHandle h_this(THREAD, this);
+    copy_bootstrap_arguments_at_impl(h_this, index, start_arg, end_arg,
+                                     info, pos, must_resolve, if_not_available, THREAD);
+  }
+
   // Klass name matches name at offset
   bool klass_name_at_matches(const InstanceKlass* k, int which);
 
@@ -831,6 +855,7 @@
 
   Symbol* impl_name_ref_at(int which, bool uncached);
   Symbol* impl_signature_ref_at(int which, bool uncached);
+
   int       impl_klass_ref_index_at(int which, bool uncached);
   int       impl_name_and_type_ref_index_at(int which, bool uncached);
   constantTag impl_tag_ref_at(int which, bool uncached);
@@ -860,8 +885,13 @@
   // Resolve string constants (to prevent allocation during compilation)
   static void resolve_string_constants_impl(const constantPoolHandle& this_cp, TRAPS);
 
-  static oop resolve_constant_at_impl(const constantPoolHandle& this_cp, int index, int cache_index, TRAPS);
+  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,
+                                               bool must_resolve, Handle if_not_available, TRAPS);
 
   // Exception handling
   static void throw_resolution_error(const constantPoolHandle& this_cp, int which, TRAPS);
--- a/src/hotspot/share/oops/generateOopMap.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/oops/generateOopMap.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -1871,13 +1871,15 @@
   ConstantPool* cp  = method()->constants();
   constantTag tag = cp->tag_at(ldc.pool_index()); // idx is index in resolved_references
   BasicType       bt  = ldc.result_type();
+#ifdef ASSERT
+  BasicType   tag_bt = tag.is_constant_dynamic() ? bt : tag.basic_type();
+  assert(bt == tag_bt, "same result");
+#endif
   CellTypeState   cts;
-  if (tag.basic_type() == T_OBJECT) {
+  if (is_reference_type(bt)) {  // could be T_ARRAY with condy
     assert(!tag.is_string_index() && !tag.is_klass_index(), "Unexpected index tag");
-    assert(bt == T_OBJECT, "Guard is incorrect");
     cts = CellTypeState::make_line_ref(bci);
   } else {
-    assert(bt != T_OBJECT, "Guard is incorrect");
     cts = valCTS;
   }
   ppush1(cts);
--- a/src/hotspot/share/opto/parse2.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/opto/parse2.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -1483,8 +1483,9 @@
     // If the constant is unresolved, run this BC once in the interpreter.
     {
       ciConstant constant = iter().get_constant();
-      if (constant.basic_type() == T_OBJECT &&
-          !constant.as_object()->is_loaded()) {
+      if (!constant.is_valid() ||
+          (constant.basic_type() == T_OBJECT &&
+           !constant.as_object()->is_loaded())) {
         int index = iter().get_constant_pool_index();
         constantTag tag = iter().get_constant_pool_tag(index);
         uncommon_trap(Deoptimization::make_trap_request
--- a/src/hotspot/share/prims/jvm.h	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/prims/jvm.h	Mon Sep 25 11:46:09 2017 +0100
@@ -1007,7 +1007,7 @@
     JVM_CONSTANT_NameAndType,
     JVM_CONSTANT_MethodHandle           = 15,  // JSR 292
     JVM_CONSTANT_MethodType             = 16,  // JSR 292
-    //JVM_CONSTANT_(unused)             = 17,  // JSR 292 early drafts only
+    JVM_CONSTANT_ConstantDynamic        = 17,  // JSR 292 early drafts only
     JVM_CONSTANT_InvokeDynamic          = 18,  // JSR 292
     JVM_CONSTANT_ExternalMax            = 18   // Last tag found in classfiles
 };
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -491,6 +491,7 @@
     } break;
 
     // this is an indirect CP entry so it needs special handling
+    case JVM_CONSTANT_ConstantDynamic:  // fall through
     case JVM_CONSTANT_InvokeDynamic:
     {
       // Index of the bootstrap specifier in the operands array
@@ -503,15 +504,18 @@
                                                     merge_cp_length_p, THREAD);
       if (new_bs_i != old_bs_i) {
         log_trace(redefine, class, constantpool)
-          ("InvokeDynamic entry@%d bootstrap_method_attr_index change: %d to %d",
+          ("Dynamic entry@%d bootstrap_method_attr_index change: %d to %d",
            *merge_cp_length_p, old_bs_i, new_bs_i);
       }
       if (new_ref_i != old_ref_i) {
         log_trace(redefine, class, constantpool)
-          ("InvokeDynamic entry@%d name_and_type_index change: %d to %d", *merge_cp_length_p, old_ref_i, new_ref_i);
+          ("Dynamic entry@%d name_and_type_index change: %d to %d", *merge_cp_length_p, old_ref_i, new_ref_i);
       }
 
-      (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, new_bs_i, new_ref_i);
+      if (scratch_cp->tag_at(scratch_i).is_constant_dynamic())
+        (*merge_cp_p)->constant_dynamic_at_put(*merge_cp_length_p, new_bs_i, new_ref_i);
+      else
+        (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, new_bs_i, new_ref_i);
       if (scratch_i != *merge_cp_length_p) {
         // The new entry in *merge_cp_p is at a different index than
         // the new entry in scratch_cp so we need to map the index values.
--- a/src/hotspot/share/prims/methodHandles.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/prims/methodHandles.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -1297,6 +1297,88 @@
 }
 JVM_END
 
+JVM_ENTRY(void, MHN_copyOutBootstrapArguments(JNIEnv* env, jobject igcls,
+                                              jobject caller_jh, jintArray index_info_jh,
+                                              jint start, jint end,
+                                              jobjectArray buf_jh, jint pos,
+                                              jboolean resolve, jobject ifna_jh)) {
+  Klass* caller_k = java_lang_Class::as_Klass(JNIHandles::resolve(caller_jh));
+  if (caller_k == NULL || !caller_k->is_instance_klass()) {
+      THROW_MSG(vmSymbols::java_lang_InternalError(), "bad caller");
+  }
+  InstanceKlass* caller = InstanceKlass::cast(caller_k);
+  typeArrayOop index_info_oop = (typeArrayOop) JNIHandles::resolve(index_info_jh);
+  if (index_info_oop == NULL ||
+      index_info_oop->klass() != Universe::intArrayKlassObj() ||
+      typeArrayOop(index_info_oop)->length() < 2) {
+      THROW_MSG(vmSymbols::java_lang_InternalError(), "bad index info (0)");
+  }
+  typeArrayHandle index_info(THREAD, index_info_oop);
+  int bss_index_in_pool = index_info->int_at(1);
+  // While we are here, take a quick look at the index info:
+  if (bss_index_in_pool <= 0 ||
+      bss_index_in_pool >= caller->constants()->length() ||
+      index_info->int_at(0)
+      != caller->constants()->invoke_dynamic_argument_count_at(bss_index_in_pool)) {
+      THROW_MSG(vmSymbols::java_lang_InternalError(), "bad index info (1)");
+  }
+  objArrayHandle buf(THREAD, (objArrayOop) JNIHandles::resolve(buf_jh));
+  if (start < 0) {
+    for (int pseudo_index = -4; pseudo_index < 0; pseudo_index++) {
+      if (start == pseudo_index) {
+        if (start >= end || 0 > pos || pos >= buf->length())  break;
+        oop pseudo_arg = NULL;
+        switch (pseudo_index) {
+        case -4:  // bootstrap method
+          {
+            int bsm_index = caller->constants()->invoke_dynamic_bootstrap_method_ref_index_at(bss_index_in_pool);
+            pseudo_arg = caller->constants()->resolve_possibly_cached_constant_at(bsm_index, CHECK);
+            break;
+          }
+        case -3:  // name
+          {
+            Symbol* name = caller->constants()->name_ref_at(bss_index_in_pool);
+            Handle str = java_lang_String::create_from_symbol(name, CHECK);
+            pseudo_arg = str();
+            break;
+          }
+        case -2:  // type
+          {
+            Symbol* type = caller->constants()->signature_ref_at(bss_index_in_pool);
+            Handle th;
+            if (type->byte_at(0) == '(') {
+              th = SystemDictionary::find_method_handle_type(type, caller, CHECK);
+              
+            } else {
+              th = SystemDictionary::find_java_mirror_for_type(type, caller, SignatureStream::NCDFError, CHECK);
+            }
+            pseudo_arg = th();
+            break;
+          }
+        case -1:  // argument count
+          {
+            int argc = caller->constants()->invoke_dynamic_argument_count_at(bss_index_in_pool);
+            jvalue argc_value; argc_value.i = (jint)argc;
+            pseudo_arg = java_lang_boxing_object::create(T_INT, &argc_value, CHECK);
+            break;
+          }
+        }
+
+        // Store the pseudo-argument, and advance the pointers.
+        buf->obj_at_put(pos++, pseudo_arg);
+        ++start;
+      }
+    }
+    // When we are done with this there may be regular arguments to process too.
+  }
+  Handle ifna(THREAD, JNIHandles::resolve(ifna_jh));
+  caller->constants()->
+    copy_bootstrap_arguments_at(bss_index_in_pool,
+                                start, end, buf, pos,
+                                resolve, ifna, CHECK);
+}
+JVM_END
+
 // It is called by a Cleaner object which ensures that dropped CallSites properly
 // deallocate their dependency information.
 JVM_ENTRY(void, MHN_clearCallSiteContext(JNIEnv* env, jobject igcls, jobject context_jh)) {
@@ -1376,6 +1458,7 @@
   {CC "objectFieldOffset",         CC "(" MEM ")J",                          FN_PTR(MHN_objectFieldOffset)},
   {CC "setCallSiteTargetNormal",   CC "(" CS "" MH ")V",                     FN_PTR(MHN_setCallSiteTargetNormal)},
   {CC "setCallSiteTargetVolatile", CC "(" CS "" MH ")V",                     FN_PTR(MHN_setCallSiteTargetVolatile)},
+  {CC "copyOutBootstrapArguments", CC "(" CLS "[III[" OBJ "IZ" OBJ ")V",     FN_PTR(MHN_copyOutBootstrapArguments)},
   {CC "clearCallSiteContext",      CC "(" CTX ")V",                          FN_PTR(MHN_clearCallSiteContext)},
   {CC "staticFieldOffset",         CC "(" MEM ")J",                          FN_PTR(MHN_staticFieldOffset)},
   {CC "staticFieldBase",           CC "(" MEM ")" OBJ,                        FN_PTR(MHN_staticFieldBase)},
--- a/src/hotspot/share/runtime/globals.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/runtime/globals.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -3959,6 +3959,17 @@
   develop(bool, TraceInvokeDynamic, false,                                  \
           "trace internal invoke dynamic operations")                       \
                                                                             \
+  develop(bool, TraceConstantDynamic, false,                                \
+          "trace internal constant dynamic operations")                     \
+                                                                            \
+  diagnostic(int, UseBootstrapCallInfo, 1,                                  \
+          "0: when resolving InDy or ConDy, force all BSM arguments to be " \
+          "resolved before the bootstrap method is called; 1: when a BSM "  \
+          "that may accept a BootstrapCallInfo is detected, use that API "  \
+          "to pass BSM arguments, which allows the BSM to delay their "     \
+          "resolution; 2+: stress test the BCI API by calling more BSMs "   \
+          "via that API, instead of with the eagerly-resolved array.")      \
+                                                                            \
   diagnostic(bool, PauseAtStartup,      false,                              \
           "Causes the VM to pause at startup time and wait for the pause "  \
           "file to be removed (default: ./vm.paused.<pid>)")                \
--- a/src/hotspot/share/runtime/reflection.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/runtime/reflection.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -765,27 +765,22 @@
 static oop get_mirror_from_signature(const methodHandle& method,
                                      SignatureStream* ss,
                                      TRAPS) {
+  oop mirror_oop = ss->as_java_mirror(method->method_holder(), SignatureStream::NCDFError, CHECK_NULL);
 
-
-  if (T_OBJECT == ss->type() || T_ARRAY == ss->type()) {
-    Symbol* name = ss->as_symbol(CHECK_NULL);
-    oop loader = method->method_holder()->class_loader();
-    oop protection_domain = method->method_holder()->protection_domain();
-    const Klass* k = SystemDictionary::resolve_or_fail(name,
-                                                       Handle(THREAD, loader),
-                                                       Handle(THREAD, protection_domain),
-                                                       true,
-                                                       CHECK_NULL);
-    if (log_is_enabled(Debug, class, resolve)) {
+  // Special tracing logic for resolution of class names during reflection.
+  if (log_is_enabled(Debug, class, resolve)) {
+    Klass* k = java_lang_Class::as_Klass(mirror_oop);
+    if (k != NULL)  {
+      mirror_oop = NULL;
       trace_class_resolution(k);
+      mirror_oop = k->java_mirror();
     }
-    return k->java_mirror();
   }
 
   assert(ss->type() != T_VOID || ss->at_return_type(),
     "T_VOID should only appear as return type");
 
-  return java_lang_Class::primitive_mirror(ss->type());
+  return mirror_oop;
 }
 
 static objArrayHandle get_parameter_types(const methodHandle& method,
@@ -819,24 +814,17 @@
 }
 
 static Handle new_type(Symbol* signature, Klass* k, TRAPS) {
-  // Basic types
-  BasicType type = vmSymbols::signature_type(signature);
-  if (type != T_OBJECT) {
-    return Handle(THREAD, Universe::java_mirror(type));
+  Handle mirror = SystemDictionary::find_java_mirror_for_type(signature, k, SignatureStream::NCDFError, CHECK_(Handle()));
+
+  // Special tracing logic for resolution of class names during reflection.
+  if (log_is_enabled(Debug, class, resolve)) {
+    Klass* result = java_lang_Class::as_Klass(mirror());
+    if (result != NULL) {
+      trace_class_resolution(result);
+    }
   }
 
-  Klass* result =
-    SystemDictionary::resolve_or_fail(signature,
-                                      Handle(THREAD, k->class_loader()),
-                                      Handle(THREAD, k->protection_domain()),
-                                      true, CHECK_(Handle()));
-
-  if (log_is_enabled(Debug, class, resolve)) {
-    trace_class_resolution(result);
-  }
-
-  oop nt = result->java_mirror();
-  return Handle(THREAD, nt);
+  return mirror;
 }
 
 
--- a/src/hotspot/share/runtime/signature.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/runtime/signature.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -392,11 +392,19 @@
 
 oop SignatureStream::as_java_mirror(Handle class_loader, Handle protection_domain,
                                     FailureMode failure_mode, TRAPS) {
-  if (!is_object())
-    return Universe::java_mirror(type());
-  Klass* klass = as_klass(class_loader, protection_domain, failure_mode, CHECK_NULL);
-  if (klass == NULL)  return NULL;
-  return klass->java_mirror();
+  if (raw_length() == 1) {
+    // short-cut in a common case
+    return SystemDictionary::find_java_mirror_for_type((char) raw_byte_at(0));
+  }
+  TempNewSymbol signature = SymbolTable::new_symbol(_signature, _begin, _end, CHECK_NULL);
+  Klass* no_accessing_klass = NULL;
+  Handle mirror = SystemDictionary::find_java_mirror_for_type(signature,
+                                                              no_accessing_klass,
+                                                              class_loader,
+                                                              protection_domain,
+                                                              failure_mode,
+                                                              CHECK_NULL);
+  return mirror();
 }
 
 Symbol* SignatureStream::as_symbol_or_null() {
--- a/src/hotspot/share/runtime/signature.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/runtime/signature.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -406,9 +406,23 @@
   enum FailureMode { ReturnNull, CNFException, NCDFError };
   Klass* as_klass(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS);
   oop as_java_mirror(Handle class_loader, Handle protection_domain, FailureMode failure_mode, TRAPS);
+  oop as_java_mirror(Klass* accessing_klass, FailureMode failure_mode, TRAPS) {
+    Handle class_loader;
+    Handle protection_domain;
+    if (accessing_klass != NULL) {
+      class_loader      = Handle(THREAD, accessing_klass->class_loader());
+      protection_domain = Handle(THREAD, accessing_klass->protection_domain());
+    }
+    return as_java_mirror(class_loader, protection_domain, failure_mode, THREAD);
+  }
   const jbyte* raw_bytes()  { return _signature->bytes() + _begin; }
   int          raw_length() { return _end - _begin; }
 
+  jbyte raw_byte_at(int index) {
+    assert(index >= 0 && index < raw_length(), "index overflow");
+    return _signature->byte_at(_begin + index);
+  }
+
   // return same as_symbol except allocation of new symbols is avoided.
   Symbol* as_symbol_or_null();
 
--- a/src/hotspot/share/runtime/vmStructs.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/runtime/vmStructs.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -2320,6 +2320,7 @@
   declare_constant(JVM_CONSTANT_NameAndType)                              \
   declare_constant(JVM_CONSTANT_MethodHandle)                             \
   declare_constant(JVM_CONSTANT_MethodType)                               \
+  declare_constant(JVM_CONSTANT_ConstantDynamic)                          \
   declare_constant(JVM_CONSTANT_InvokeDynamic)                            \
   declare_constant(JVM_CONSTANT_ExternalMax)                              \
                                                                           \
--- a/src/hotspot/share/utilities/constantTag.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/utilities/constantTag.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -56,6 +56,10 @@
     case JVM_CONSTANT_MethodType :
     case JVM_CONSTANT_MethodTypeInError :
       return T_OBJECT;
+
+    case JVM_CONSTANT_ConstantDynamic :
+      assert(false, "ConstantDynamic has no fixed basic type");
+
     default:
       ShouldNotReachHere();
       return T_ILLEGAL;
@@ -123,6 +127,8 @@
       return "MethodType";
     case JVM_CONSTANT_MethodTypeInError :
       return "MethodType Error";
+    case JVM_CONSTANT_ConstantDynamic :
+      return "ConstantDynamic";
     case JVM_CONSTANT_InvokeDynamic :
       return "InvokeDynamic";
     case JVM_CONSTANT_Utf8 :
--- a/src/hotspot/share/utilities/constantTag.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/utilities/constantTag.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -90,11 +90,12 @@
 
   bool is_method_type() const              { return _tag == JVM_CONSTANT_MethodType; }
   bool is_method_handle() const            { return _tag == JVM_CONSTANT_MethodHandle; }
+  bool is_constant_dynamic() const         { return _tag == JVM_CONSTANT_ConstantDynamic; }
   bool is_invoke_dynamic() const           { return _tag == JVM_CONSTANT_InvokeDynamic; }
 
   bool is_loadable_constant() const {
     return ((_tag >= JVM_CONSTANT_Integer && _tag <= JVM_CONSTANT_String) ||
-            is_method_type() || is_method_handle() ||
+            is_method_type() || is_method_handle() || is_constant_dynamic() ||
             is_unresolved_klass());
   }
 
@@ -108,6 +109,20 @@
     _tag = tag;
   }
 
+  static constantTag ofBasicType(BasicType bt) {
+    if (is_subword_type(bt))  bt = T_INT;
+    switch (bt) {
+      case T_OBJECT: return constantTag(JVM_CONSTANT_String);
+      case T_INT:    return constantTag(JVM_CONSTANT_Integer);
+      case T_LONG:   return constantTag(JVM_CONSTANT_Long);
+      case T_FLOAT:  return constantTag(JVM_CONSTANT_Float);
+      case T_DOUBLE: return constantTag(JVM_CONSTANT_Double);
+      default:       break;
+    }
+    assert(false, "bad basic type for tag");
+    return constantTag();
+  }
+
   jbyte value() const                { return _tag; }
   jbyte error_value() const;
   jbyte non_error_value() const;
--- a/src/hotspot/share/utilities/exceptions.cpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/utilities/exceptions.cpp	Mon Sep 25 11:46:09 2017 +0100
@@ -402,6 +402,37 @@
                                    h_prot, to_utf8_safe);
 }
 
+// invokedynamic uses wrap_dynamic_exception for:
+//    - bootstrap method resolution
+//    - post call to MethodHandleNatives::linkCallSite
+// constantdynamic uses wrap_dynamic_exception for:
+//    - bootstrap method resolution
+//    - post call to MethodHandleNatives::linkConstantDynamic
+void Exceptions::wrap_dynamic_exception(Thread* THREAD) {
+  if (THREAD->has_pending_exception()) {
+    oop exception = THREAD->pending_exception();
+    // See the "Linking Exceptions" section for the invokedynamic instruction
+    // in JVMS 6.5.
+    if (exception->is_a(SystemDictionary::Error_klass())) {
+      // Pass through an Error, including BootstrapMethodError, any other form
+      // of linkage error, or say ThreadDeath/OutOfMemoryError
+      if (TraceMethodHandles) {
+        tty->print_cr("[constant/invoke]dynamic passes through an Error for " INTPTR_FORMAT, p2i((void *)exception));
+        exception->print();
+      }
+      return;
+    }
+
+    // Otherwise wrap the exception in a BootstrapMethodError
+    if (TraceMethodHandles) {
+      tty->print_cr("[constant/invoke]dynamic throws BSME for " INTPTR_FORMAT, p2i((void *)exception));
+      exception->print();
+    }
+    Handle nested_exception(THREAD, exception);
+    THREAD->clear_pending_exception();
+    THROW_CAUSE(vmSymbols::java_lang_BootstrapMethodError(), nested_exception)
+  }
+}
 
 // Exception counting for hs_err file
 volatile int Exceptions::_stack_overflow_errors = 0;
--- a/src/hotspot/share/utilities/exceptions.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/utilities/exceptions.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -166,6 +166,8 @@
 
   static void throw_stack_overflow_exception(Thread* thread, const char* file, int line, const methodHandle& method);
 
+  static void wrap_dynamic_exception(Thread* thread);
+
   // Exception counting for error files of interesting exceptions that may have
   // caused a problem for the jvm
   static volatile int _stack_overflow_errors;
--- a/src/hotspot/share/utilities/globalDefinitions.hpp	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/hotspot/share/utilities/globalDefinitions.hpp	Mon Sep 25 11:46:09 2017 +0100
@@ -596,6 +596,10 @@
   return (t == T_BYTE || t == T_SHORT);
 }
 
+inline bool is_reference_type(BasicType t) {
+  return (t == T_OBJECT || t == T_ARRAY);
+}
+
 // Convert a char from a classfile signature to a BasicType
 inline BasicType char2type(char c) {
   switch( c ) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java	Mon Sep 25 11:46:09 2017 +0100
@@ -297,7 +297,7 @@
       // change byte-ordering and go via cache
       i = remapInstructionOperandFromCache(which);
     } else {
-      if (getTagAt(which).isInvokeDynamic()) {
+      if (getTagAt(which).isInvokeDynamic() || getTagAt(which).isConstantDynamic()) {
         int poolIndex = invokeDynamicNameAndTypeRefIndexAt(which);
         Assert.that(getTagAt(poolIndex).isNameAndType(), "");
         return poolIndex;
@@ -433,7 +433,7 @@
   /** Lookup for multi-operand (InvokeDynamic) entries. */
   public short[] getBootstrapSpecifierAt(int i) {
     if (Assert.ASSERTS_ENABLED) {
-      Assert.that(getTagAt(i).isInvokeDynamic(), "Corrupted constant pool");
+      Assert.that(getTagAt(i).isInvokeDynamic() || getTagAt(i).isConstantDynamic(), "Corrupted constant pool");
     }
     int bsmSpec = extractLowShortFromInt(this.getIntAt(i));
     U2Array operands = getOperands();
@@ -469,6 +469,7 @@
     case JVM_CONSTANT_NameAndType:        return "JVM_CONSTANT_NameAndType";
     case JVM_CONSTANT_MethodHandle:       return "JVM_CONSTANT_MethodHandle";
     case JVM_CONSTANT_MethodType:         return "JVM_CONSTANT_MethodType";
+    case JVM_CONSTANT_ConstantDynamic:    return "JVM_CONSTANT_ConstantDynamic";
     case JVM_CONSTANT_InvokeDynamic:      return "JVM_CONSTANT_InvokeDynamic";
     case JVM_CONSTANT_Invalid:            return "JVM_CONSTANT_Invalid";
     case JVM_CONSTANT_UnresolvedClass:    return "JVM_CONSTANT_UnresolvedClass";
@@ -525,6 +526,7 @@
         case JVM_CONSTANT_NameAndType:
         case JVM_CONSTANT_MethodHandle:
         case JVM_CONSTANT_MethodType:
+        case JVM_CONSTANT_ConstantDynamic:
         case JVM_CONSTANT_InvokeDynamic:
           visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
           break;
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java	Mon Sep 25 11:46:09 2017 +0100
@@ -42,7 +42,7 @@
     public static final int JVM_CONSTANT_NameAndType        = 12;
     public static final int JVM_CONSTANT_MethodHandle       = 15;
     public static final int JVM_CONSTANT_MethodType         = 16;
-    //     static final int JVM_CONSTANT_(unused)           = 17;
+    public static final int JVM_CONSTANT_ConstantDynamic    = 17;
     public static final int JVM_CONSTANT_InvokeDynamic      = 18;
 
     // JVM_CONSTANT_MethodHandle subtypes
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java	Mon Sep 25 11:46:09 2017 +0100
@@ -296,6 +296,18 @@
                      break;
                 }
 
+                case JVM_CONSTANT_ConstantDynamic: {
+                    dos.writeByte(cpConstType);
+                    int value = cpool.getIntAt(ci);
+                    short bsmIndex = (short) extractLowShortFromInt(value);
+                    short nameAndTypeIndex = (short) extractHighShortFromInt(value);
+                    dos.writeShort(bsmIndex);
+                    dos.writeShort(nameAndTypeIndex);
+                    if (DEBUG) debugMessage("CP[" + ci + "] = CONDY bsm = " +
+                                            bsmIndex + ", N&T = " + nameAndTypeIndex);
+                    break;
+                }
+
                 case JVM_CONSTANT_InvokeDynamic: {
                      dos.writeByte(cpConstType);
                      int value = cpool.getIntAt(ci);
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Mon Sep 25 11:46:09 2017 +0100
@@ -557,6 +557,12 @@
                buf.cell(Integer.toString(cpool.getIntAt(index)));
                break;
 
+           case JVM_CONSTANT_ConstantDynamic:
+               buf.cell("JVM_CONSTANT_ConstantDynamic");
+               buf.cell(genLowHighShort(cpool.getIntAt(index)) +
+                        genListOfShort(cpool.getBootstrapSpecifierAt(index)));
+             break;
+
             case JVM_CONSTANT_InvokeDynamic:
                buf.cell("JVM_CONSTANT_InvokeDynamic");
                buf.cell(genLowHighShort(cpool.getIntAt(index)) +
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/ConstantTag.java	Mon Sep 25 11:46:09 2017 +0100
@@ -42,7 +42,7 @@
   private static final int JVM_CONSTANT_NameAndType             = 12;
   private static final int JVM_CONSTANT_MethodHandle            = 15;  // JSR 292
   private static final int JVM_CONSTANT_MethodType              = 16;  // JSR 292
-  //      static final int JVM_CONSTANT_(unused)                = 17;  // JSR 292 early drafts only
+  private static final int JVM_CONSTANT_ConstantDynamic         = 17;  // JSR 292 early drafts only
   private static final int JVM_CONSTANT_InvokeDynamic           = 18;  // JSR 292
   private static final int JVM_CONSTANT_Invalid                 = 0;   // For bad value initialization
   private static final int JVM_CONSTANT_UnresolvedClass         = 100; // Temporary tag until actual use
@@ -84,6 +84,7 @@
   public boolean isUtf8()             { return tag == JVM_CONSTANT_Utf8; }
   public boolean isMethodHandle()     { return tag == JVM_CONSTANT_MethodHandle; }
   public boolean isMethodType()       { return tag == JVM_CONSTANT_MethodType; }
+  public boolean isConstantDynamic()  { return tag == JVM_CONSTANT_ConstantDynamic; }
   public boolean isInvokeDynamic()    { return tag == JVM_CONSTANT_InvokeDynamic; }
 
   public boolean isInvalid()          { return tag == JVM_CONSTANT_Invalid; }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Mon Sep 25 11:46:00 2017 +0100
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Mon Sep 25 11:46:09 2017 +0100
@@ -237,6 +237,8 @@
      */
     native HotSpotResolvedJavaMethodImpl lookupMethodInPool(HotSpotConstantPool constantPool, int cpi, byte opcode);
 
+    // TODO resolving ConstantDynamic
+
     /**
      * Ensures that the type referenced by the specified {@code JVM_CONSTANT_InvokeDynamic} entry at
      * index {@code cpi} in {@code constantPool} is loaded and initialized.