--- 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;
}
}