hotspot/src/share/vm/oops/constantPoolOop.cpp
changeset 7114 65d21c4c6337
parent 7111 ac1a0346bc0f
child 7397 5b173b4ca846
--- a/hotspot/src/share/vm/oops/constantPoolOop.cpp	Sat Oct 30 12:19:07 2010 -0700
+++ b/hotspot/src/share/vm/oops/constantPoolOop.cpp	Sat Oct 30 13:08:23 2010 -0700
@@ -267,7 +267,7 @@
     if (constantPoolCacheOopDesc::is_secondary_index(which)) {
       // Invokedynamic index.
       int pool_index = cache()->main_entry_at(which)->constant_pool_index();
-      if (tag_at(pool_index).is_invoke_dynamic())
+      if (!AllowTransitionalJSR292 || tag_at(pool_index).is_invoke_dynamic())
         pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index);
       assert(tag_at(pool_index).is_name_and_type(), "");
       return pool_index;
@@ -275,11 +275,17 @@
     // change byte-ordering and go via cache
     i = remap_instruction_operand_from_cache(which);
   } else {
-    if (tag_at(which).is_name_and_type())
+    if (AllowTransitionalJSR292 && tag_at(which).is_name_and_type())
       // invokedynamic index is a simple name-and-type
       return which;
+    if (tag_at(which).is_invoke_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;
+    }
   }
   assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
+  assert(!tag_at(i).is_invoke_dynamic(), "Must be handled above");
   jint ref_index = *int_at_addr(i);
   return extract_high_short_from_int(ref_index);
 }
@@ -393,18 +399,61 @@
   }
 }
 
+// A resolved constant value in the CP cache is represented as a non-null
+// value.  As a special case, this value can be a 'systemObjArray'
+// which masks an exception object to throw.
+// This allows a MethodHandle constant reference to throw a consistent
+// exception every time, if it fails to resolve.
+static oop decode_exception_from_f1(oop result_oop, TRAPS) {
+  if (result_oop->klass() != Universe::systemObjArrayKlassObj())
+    return result_oop;
+
+  // Special cases here:  Masked null, saved exception.
+  objArrayOop sys_array = (objArrayOop) result_oop;
+  assert(sys_array->length() == 1, "bad system array");
+  if (sys_array->length() == 1) {
+    THROW_OOP_(sys_array->obj_at(0), NULL);
+  }
+  return NULL;
+}
+
 oop constantPoolOopDesc::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, 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 CP cache.
+    // We'll do a linear search.  This should be OK because this usage is rare.
+    assert(index > 0, "valid index");
+    constantPoolCacheOop cache = this_oop()->cache();
+    for (int i = 0, len = cache->length(); i < len; i++) {
+      ConstantPoolCacheEntry* cpc_entry = cache->entry_at(i);
+      if (!cpc_entry->is_secondary_entry() && cpc_entry->constant_pool_index() == index) {
+        // Switch the query to use this CPC entry.
+        cache_index = i;
+        index = _no_index_sentinel;
+        break;
+      }
+    }
+    if (cache_index == _possible_index_sentinel)
+      cache_index = _no_index_sentinel;  // not found
+  }
+  assert(cache_index == _no_index_sentinel || cache_index >= 0, "");
+  assert(index == _no_index_sentinel || index >= 0, "");
+
   if (cache_index >= 0) {
-    assert(index < 0, "only one kind of index at a time");
+    assert(index == _no_index_sentinel, "only one kind of index at a time");
     ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index);
     result_oop = cpc_entry->f1();
     if (result_oop != NULL) {
-      return result_oop;  // that was easy...
+      return decode_exception_from_f1(result_oop, THREAD);
+      // That was easy...
     }
     index = cpc_entry->constant_pool_index();
   }
 
+  jvalue prim_value;  // temp used only in a few cases below
+
   int tag_value = this_oop->tag_at(index).value();
   switch (tag_value) {
 
@@ -448,9 +497,14 @@
       KlassHandle klass(THREAD, this_oop->pool_holder());
       Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
                                                                    callee, name, signature,
-                                                                   CHECK_NULL);
+                                                                   THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        throw_exception = Handle(THREAD, PENDING_EXCEPTION);
+        CLEAR_PENDING_EXCEPTION;
+        break;
+      }
       result_oop = value();
-      // FIXME: Uniquify errors, using SystemDictionary::find_resolution_error.
+      assert(result_oop != NULL, "");
       break;
     }
 
@@ -467,20 +521,36 @@
                                                                klass,
                                                                false,
                                                                ignore_is_on_bcp,
-                                                               CHECK_NULL);
+                                                               THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        throw_exception = Handle(THREAD, PENDING_EXCEPTION);
+        CLEAR_PENDING_EXCEPTION;
+        break;
+      }
       result_oop = value();
-      // FIXME: Uniquify errors, using SystemDictionary::find_resolution_error.
+      assert(result_oop != NULL, "");
       break;
     }
 
-    /* maybe some day
   case JVM_CONSTANT_Integer:
+    prim_value.i = this_oop->int_at(index);
+    result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL);
+    break;
+
   case JVM_CONSTANT_Float:
+    prim_value.f = this_oop->float_at(index);
+    result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL);
+    break;
+
   case JVM_CONSTANT_Long:
+    prim_value.j = this_oop->long_at(index);
+    result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL);
+    break;
+
   case JVM_CONSTANT_Double:
-    result_oop = java_lang_boxing_object::create(...);
+    prim_value.d = this_oop->double_at(index);
+    result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL);
     break;
-    */
 
   default:
     DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
@@ -491,18 +561,31 @@
 
   if (cache_index >= 0) {
     // Cache the oop here also.
-    Handle result(THREAD, result_oop);
+    if (throw_exception.not_null()) {
+      objArrayOop sys_array = oopFactory::new_system_objArray(1, CHECK_NULL);
+      sys_array->obj_at_put(0, throw_exception());
+      result_oop = sys_array;
+      throw_exception = Handle();  // be tidy
+    }
+    Handle result_handle(THREAD, result_oop);
     result_oop = NULL;  // safety
     ObjectLocker ol(this_oop, THREAD);
     ConstantPoolCacheEntry* cpc_entry = this_oop->cache()->entry_at(cache_index);
-    oop result_oop2 = cpc_entry->f1();
-    if (result_oop2 != NULL) {
-      // Race condition:  May already be filled in while we were trying to lock.
-      return result_oop2;
+    result_oop = cpc_entry->f1();
+    // Benign race condition:  f1 may already be filled in while we were trying to lock.
+    // 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.
+    // That result may be either a resolved constant or a failure exception.
+    if (result_oop == NULL) {
+      result_oop = result_handle();
+      cpc_entry->set_f1(result_oop);
     }
-    cpc_entry->set_f1(result());
-    return result();
+    return decode_exception_from_f1(result_oop, THREAD);
   } else {
+    if (throw_exception.not_null()) {
+      THROW_HANDLE_(throw_exception, NULL);
+    }
     return result_oop;
   }
 }
@@ -620,6 +703,7 @@
 
 void constantPoolOopDesc::shared_tags_iterate(OopClosure* closure) {
   closure->do_oop(tags_addr());
+  closure->do_oop(operands_addr());
 }
 
 
@@ -837,13 +921,19 @@
 
   case JVM_CONSTANT_InvokeDynamic:
   {
-    int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1);
-    int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2);
-    if (k1 == k2) {
-      int i1 = invoke_dynamic_name_and_type_ref_index_at(index1);
-      int i2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
-      if (i1 == i2) {
-        return true;
+    int op_count = multi_operand_count_at(index1);
+    if (op_count == cp2->multi_operand_count_at(index2)) {
+      bool all_equal = true;
+      for (int op_i = 0; op_i < op_count; op_i++) {
+        int k1 = multi_operand_ref_at(index1, op_i);
+        int k2 = cp2->multi_operand_ref_at(index2, op_i);
+        if (k1 != k2) {
+          all_equal = false;
+          break;
+        }
+      }
+      if (all_equal) {
+        return true;           // got through loop; all elements equal
       }
     }
   } break;
@@ -880,6 +970,25 @@
 } // end compare_entry_to()
 
 
+// Grow this->operands() to the indicated length, unless it is already at least that long.
+void constantPoolOopDesc::multi_operand_buffer_grow(int min_length, TRAPS) {
+  int old_length = multi_operand_buffer_fill_pointer();
+  if (old_length >= min_length)  return;
+  int new_length = min_length;
+  assert(new_length > _multi_operand_buffer_fill_pointer_offset, "");
+  typeArrayHandle new_operands = oopFactory::new_permanent_intArray(new_length, CHECK);
+  if (operands() == NULL) {
+    new_operands->int_at_put(_multi_operand_buffer_fill_pointer_offset, old_length);
+  } else {
+    // copy fill pointer and everything else
+    for (int i = 0; i < old_length; i++) {
+      new_operands->int_at_put(i, operands()->int_at(i));
+    }
+  }
+  set_operands(new_operands());
+}
+
+
 // Copy this constant pool's entries at start_i to end_i (inclusive)
 // to the constant pool to_cp's entries starting at to_i. A total of
 // (end_i - start_i) + 1 entries are copied.
@@ -888,6 +997,13 @@
 
   int dest_i = to_i;  // leave original alone for debug purposes
 
+  if (operands() != NULL) {
+    // pre-grow the target CP's operand buffer
+    int nops = this->multi_operand_buffer_fill_pointer();
+    nops   += to_cp->multi_operand_buffer_fill_pointer();
+    to_cp->multi_operand_buffer_grow(nops, CHECK);
+  }
+
   for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) {
     copy_entry_to(src_i, to_cp, dest_i, CHECK);
 
@@ -1036,9 +1152,26 @@
 
   case JVM_CONSTANT_InvokeDynamic:
   {
+    int op_count = multi_operand_count_at(from_i);
+    int fillp = to_cp->multi_operand_buffer_fill_pointer();
+    int to_op_base = fillp - _multi_operand_count_offset;  // fillp is count offset; get to base
+    to_cp->multi_operand_buffer_grow(to_op_base + op_count, CHECK);
+    to_cp->operands()->int_at_put(fillp++, op_count);
+    assert(fillp == to_op_base + _multi_operand_base_offset, "just wrote count, will now write args");
+    for (int op_i = 0; op_i < op_count; op_i++) {
+      int op = multi_operand_ref_at(from_i, op_i);
+      to_cp->operands()->int_at_put(fillp++, op);
+    }
+    assert(fillp <= to_cp->operands()->length(), "oob");
+    to_cp->set_multi_operand_buffer_fill_pointer(fillp);
+    to_cp->invoke_dynamic_at_put(to_i, to_op_base, op_count);
+#ifdef ASSERT
     int k1 = invoke_dynamic_bootstrap_method_ref_index_at(from_i);
     int k2 = invoke_dynamic_name_and_type_ref_index_at(from_i);
-    to_cp->invoke_dynamic_at_put(to_i, k1, k2);
+    int k3 = invoke_dynamic_argument_count_at(from_i);
+    assert(to_cp->check_invoke_dynamic_at(to_i, k1, k2, k3),
+           "indy structure is OK");
+#endif //ASSERT
   } break;
 
   // Invalid is used as the tag for the second constant pool entry
@@ -1256,8 +1389,11 @@
     case JVM_CONSTANT_Methodref:
     case JVM_CONSTANT_InterfaceMethodref:
     case JVM_CONSTANT_NameAndType:
+      return 5;
+
     case JVM_CONSTANT_InvokeDynamic:
-      return 5;
+      // u1 tag, u2 bsm, u2 nt, u2 argc, u2 argv[argc]
+      return 7 + 2 * invoke_dynamic_argument_count_at(idx);
 
     case JVM_CONSTANT_Long:
     case JVM_CONSTANT_Double:
@@ -1474,9 +1610,15 @@
         *bytes = JVM_CONSTANT_InvokeDynamic;
         idx1 = invoke_dynamic_bootstrap_method_ref_index_at(idx);
         idx2 = invoke_dynamic_name_and_type_ref_index_at(idx);
+        int argc = invoke_dynamic_argument_count_at(idx);
         Bytes::put_Java_u2((address) (bytes+1), idx1);
         Bytes::put_Java_u2((address) (bytes+3), idx2);
-        DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd", idx1, idx2));
+        Bytes::put_Java_u2((address) (bytes+5), argc);
+        for (int arg_i = 0; arg_i < argc; arg_i++) {
+          int arg = invoke_dynamic_argument_index_at(idx, arg_i);
+          Bytes::put_Java_u2((address) (bytes+7+2*arg_i), arg);
+        }
+        DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd [%d]", idx1, idx2, argc));
         break;
       }
     }