Mercurial > hg > truffle
diff src/share/vm/oops/constantPoolOop.cpp @ 1913:3b2dea75431e
6984311: JSR 292 needs optional bootstrap method parameters
Summary: Allow CONSTANT_InvokeDynamic nodes to have any number of extra operands.
Reviewed-by: twisti
author | jrose |
---|---|
date | Sat, 30 Oct 2010 13:08:23 -0700 |
parents | d1896d1dda3e |
children | f95d63e2154a |
line wrap: on
line diff
--- a/src/share/vm/oops/constantPoolOop.cpp Sat Oct 30 12:19:07 2010 -0700 +++ b/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; } }