src/hotspot/share/oops/constantPool.cpp
changeset 48826 c4d9d1b08e2e
parent 48785 4d1970962ee9
child 49036 bc92debe57e4
--- a/src/hotspot/share/oops/constantPool.cpp	Wed Jan 31 10:55:49 2018 -0800
+++ b/src/hotspot/share/oops/constantPool.cpp	Fri Sep 08 10:46:46 2017 -0700
@@ -607,7 +607,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) {
@@ -621,14 +620,18 @@
     // 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_dynamic_constant() ||
+        tag_at(which).is_dynamic_constant_in_error()) {
       int pool_index = invoke_dynamic_name_and_type_ref_index_at(which);
       assert(tag_at(pool_index).is_name_and_type(), "");
       return pool_index;
     }
   }
   assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
-  assert(!tag_at(i).is_invoke_dynamic(), "Must be handled above");
+  assert(!tag_at(i).is_invoke_dynamic() &&
+         !tag_at(i).is_dynamic_constant() &&
+         !tag_at(i).is_dynamic_constant_in_error(), "Must be handled above");
   jint ref_index = *int_at_addr(i);
   return extract_high_short_from_int(ref_index);
 }
@@ -672,16 +675,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);
 }
 
 
@@ -769,8 +768,8 @@
   THROW_MSG(error, message->as_C_string());
 }
 
-// If resolution for Class, MethodHandle or MethodType fails, save the exception
-// in the resolution error table, so that the same exception is thrown again.
+// If resolution for Class, Dynamic constant, MethodHandle or MethodType fails, save the
+// exception in the resolution error table, so that the same exception is thrown again.
 void ConstantPool::save_and_throw_exception(const constantPoolHandle& this_cp, int which,
                                             constantTag tag, TRAPS) {
   Symbol* error = PENDING_EXCEPTION->klass()->name();
@@ -806,16 +805,31 @@
   }
 }
 
+BasicType ConstantPool::basic_type_for_constant_at(int which) {
+  constantTag tag = tag_at(which);
+  if (tag.is_dynamic_constant() ||
+      tag.is_dynamic_constant_in_error()) {
+    // 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);
   }
@@ -825,6 +839,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_dynamic_constant(), "only condy uses the null sentinel");
+        result_oop = NULL;
+      }
+      if (status_return != NULL)  (*status_return) = true;
       return result_oop;
       // That was easy...
     }
@@ -835,6 +855,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:
@@ -848,6 +897,63 @@
       break;
     }
 
+  case JVM_CONSTANT_Dynamic:
+    {
+      Klass* current_klass  = this_cp->pool_holder();
+      Symbol* constant_name = this_cp->uncached_name_ref_at(index);
+      Symbol* constant_type = this_cp->uncached_signature_ref_at(index);
+
+      // The initial step in resolving an unresolved symbolic reference to a
+      // dynamically-computed constant is to resolve the symbolic reference to a
+      // method handle which will be the bootstrap method for the dynamically-computed
+      // constant. If resolution of the java.lang.invoke.MethodHandle for the bootstrap
+      // method fails, then a MethodHandleInError is stored at the corresponding
+      // bootstrap method's CP index for the CONSTANT_MethodHandle_info. No need to
+      // set a DynamicConstantInError here since any subsequent use of this
+      // bootstrap method will encounter the resolution of MethodHandleInError.
+      oop bsm_info = this_cp->resolve_bootstrap_specifier_at(index, THREAD);
+      Exceptions::wrap_dynamic_exception(CHECK_NULL);
+      assert(bsm_info != NULL, "");
+      // FIXME: Cache this once per BootstrapMethods entry, not once per CONSTANT_Dynamic.
+      Handle bootstrap_specifier = Handle(THREAD, bsm_info);
+
+      // Resolve the Dynamically-Computed constant to invoke the BSM in order to obtain the resulting oop.
+      Handle value = SystemDictionary::link_dynamic_constant(current_klass,
+                                                             index,
+                                                             bootstrap_specifier,
+                                                             constant_name,
+                                                             constant_type,
+                                                             THREAD);
+      result_oop = value();
+      Exceptions::wrap_dynamic_exception(THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        // Resolution failure of the dynamically-computed constant, save_and_throw_exception
+        // will check for a LinkageError and store a DynamicConstantInError.
+        save_and_throw_exception(this_cp, index, tag, CHECK_NULL);
+      }
+      BasicType type = FieldType::basic_type(constant_type);
+      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) {
+          // Since this exception is not a LinkageError, throw exception
+          // but do not save a DynamicInError resolution result.
+          // See section 5.4.3 of the VM spec.
+          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)) {
@@ -857,6 +963,7 @@
     result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL);
     break;
 
+  case JVM_CONSTANT_DynamicInError:
   case JVM_CONSTANT_MethodHandleInError:
   case JVM_CONSTANT_MethodTypeInError:
     {
@@ -957,15 +1064,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;
   }
 }
@@ -979,13 +1091,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_dynamic_constant()), "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_Dynamic is an ordered pair of [bootm, name&ftype], plus optional arguments
+    // In both cases, the bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry.
     // It is accompanied by the optional arguments.
     int bsm_index = this_cp->invoke_dynamic_bootstrap_method_ref_index_at(index);
     oop bsm_oop = this_cp->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL);
@@ -995,30 +1108,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_dynamic_constant()) {
+    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_dynamic_constant()) {
+        // potential recursion point condy -> condy
+        bool found_it = false;
+        this_cp->find_cached_constant_at(arg_index, found_it, CHECK_NULL);
+        if (!found_it) { found_unresolved_condy = true; break; }
+      }
+    }
+    if (found_unresolved_condy)
+      use_BSCI = true;
+  }
+
+  const int SMALL_ARITY = 5;
+  if (use_BSCI && argc <= SMALL_ARITY && UseBootstrapCallInfo <= 2) {
+    // If there are only a few arguments, and none of them need linking,
+    // push them, instead of asking the JDK runtime to turn around and
+    // pull them, saving a JVM/JDK transition in some simple cases.
+    bool all_resolved = true;
+    for (int i = 0; i < argc; i++) {
+      bool found_it = false;
+      int arg_index = this_cp->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 = 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_dynamic_constant()) ||
+      (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));
@@ -1199,6 +1424,18 @@
     }
   } break;
 
+  case JVM_CONSTANT_Dynamic:
+  {
+    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);
@@ -1525,6 +1762,15 @@
     to_cp->method_handle_index_at_put(to_i, k1, k2);
   } break;
 
+  case JVM_CONSTANT_Dynamic:
+  case JVM_CONSTANT_DynamicInError:
+  {
+    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->dynamic_constant_at_put(to_i, k1, k2);
+  } break;
+
   case JVM_CONSTANT_InvokeDynamic:
   {
     int k1 = from_cp->invoke_dynamic_bootstrap_specifier_index(from_i);
@@ -1786,6 +2032,8 @@
     case JVM_CONSTANT_NameAndType:
       return 5;
 
+    case JVM_CONSTANT_Dynamic:
+    case JVM_CONSTANT_DynamicInError:
     case JVM_CONSTANT_InvokeDynamic:
       // u1 tag, u2 bsm, u2 nt
       return 5;
@@ -1971,6 +2219,17 @@
         DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1));
         break;
       }
+      case JVM_CONSTANT_Dynamic:
+      case JVM_CONSTANT_DynamicInError: {
+        *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_Dynamic: %hd %hd", idx1, idx2));
+        break;
+      }
       case JVM_CONSTANT_InvokeDynamic: {
         *bytes = tag;
         idx1 = extract_low_short_from_int(*int_at_addr(idx));
@@ -2176,6 +2435,21 @@
     case JVM_CONSTANT_MethodTypeInError :
       st->print("signature_index=%d", method_type_index_at(index));
       break;
+    case JVM_CONSTANT_Dynamic :
+    case JVM_CONSTANT_DynamicInError :
+      {
+        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));