# HG changeset patch # User sspitsyn # Date 1359691638 28800 # Node ID 9bf5f643d1cfc97451a8a86d671242e88960c7bc # Parent 7885e162c30f75b8cc4c17d3597828bde99721d6 8006542: JSR 292: the VM_RedefineClasses::append_entry() must support invokedynamic entry kinds Summary: Need a support for invokedynamic entry kinds when new and old constant pools are merged. Reviewed-by: coleenp, twisti Contributed-by: serguei.spitsyn@oracle.com diff -r 7885e162c30f -r 9bf5f643d1cf src/share/vm/prims/jvmtiRedefineClasses.cpp --- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Mon Jan 28 09:33:55 2013 -0800 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Jan 31 20:07:18 2013 -0800 @@ -278,76 +278,23 @@ case JVM_CONSTANT_NameAndType: { int name_ref_i = scratch_cp->name_ref_index_at(scratch_i); - int new_name_ref_i = 0; - bool match = (name_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(name_ref_i, *merge_cp_p, name_ref_i, - THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(name_ref_i, *merge_cp_p, - THREAD); - if (found_i != 0) { - guarantee(found_i != name_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_name_ref_i = found_i; - map_index(scratch_cp, name_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, name_ref_i, merge_cp_p, merge_cp_length_p, - THREAD); - // The above call to append_entry() can only append one entry - // so the post call query of *merge_cp_length_p is only for - // the sake of consistency. - new_name_ref_i = *merge_cp_length_p - 1; - } - } + int new_name_ref_i = find_or_append_indirect_entry(scratch_cp, name_ref_i, merge_cp_p, + merge_cp_length_p, THREAD); int signature_ref_i = scratch_cp->signature_ref_index_at(scratch_i); - int new_signature_ref_i = 0; - match = (signature_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(signature_ref_i, *merge_cp_p, - signature_ref_i, THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(signature_ref_i, - *merge_cp_p, THREAD); - if (found_i != 0) { - guarantee(found_i != signature_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_signature_ref_i = found_i; - map_index(scratch_cp, signature_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, signature_ref_i, merge_cp_p, - merge_cp_length_p, THREAD); - // The above call to append_entry() can only append one entry - // so the post call query of *merge_cp_length_p is only for - // the sake of consistency. - new_signature_ref_i = *merge_cp_length_p - 1; - } - } + int new_signature_ref_i = find_or_append_indirect_entry(scratch_cp, signature_ref_i, + merge_cp_p, merge_cp_length_p, + THREAD); // If the referenced entries already exist in *merge_cp_p, then // both new_name_ref_i and new_signature_ref_i will both be 0. // In that case, all we are appending is the current entry. - if (new_name_ref_i == 0) { - new_name_ref_i = name_ref_i; - } else { + if (new_name_ref_i != name_ref_i) { RC_TRACE(0x00080000, ("NameAndType entry@%d name_ref_index change: %d to %d", *merge_cp_length_p, name_ref_i, new_name_ref_i)); } - if (new_signature_ref_i == 0) { - new_signature_ref_i = signature_ref_i; - } else { + if (new_signature_ref_i != signature_ref_i) { RC_TRACE(0x00080000, ("NameAndType entry@%d signature_ref_index change: %d to %d", *merge_cp_length_p, signature_ref_i, new_signature_ref_i)); @@ -369,76 +316,12 @@ case JVM_CONSTANT_Methodref: { int klass_ref_i = scratch_cp->uncached_klass_ref_index_at(scratch_i); - int new_klass_ref_i = 0; - bool match = (klass_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(klass_ref_i, *merge_cp_p, klass_ref_i, - THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(klass_ref_i, *merge_cp_p, - THREAD); - if (found_i != 0) { - guarantee(found_i != klass_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_klass_ref_i = found_i; - map_index(scratch_cp, klass_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, klass_ref_i, merge_cp_p, merge_cp_length_p, - THREAD); - // The above call to append_entry() can only append one entry - // so the post call query of *merge_cp_length_p is only for - // the sake of consistency. Without the optimization where we - // use JVM_CONSTANT_UnresolvedClass, then up to two entries - // could be appended. - new_klass_ref_i = *merge_cp_length_p - 1; - } - } - - int name_and_type_ref_i = - scratch_cp->uncached_name_and_type_ref_index_at(scratch_i); - int new_name_and_type_ref_i = 0; - match = (name_and_type_ref_i < *merge_cp_length_p) && - scratch_cp->compare_entry_to(name_and_type_ref_i, *merge_cp_p, - name_and_type_ref_i, THREAD); - if (!match) { - // forward reference in *merge_cp_p or not a direct match - - int found_i = scratch_cp->find_matching_entry(name_and_type_ref_i, - *merge_cp_p, THREAD); - if (found_i != 0) { - guarantee(found_i != name_and_type_ref_i, - "compare_entry_to() and find_matching_entry() do not agree"); - - // Found a matching entry somewhere else in *merge_cp_p so - // just need a mapping entry. - new_name_and_type_ref_i = found_i; - map_index(scratch_cp, name_and_type_ref_i, found_i); - } else { - // no match found so we have to append this entry to *merge_cp_p - append_entry(scratch_cp, name_and_type_ref_i, merge_cp_p, - merge_cp_length_p, THREAD); - // The above call to append_entry() can append more than - // one entry so the post call query of *merge_cp_length_p - // is required in order to get the right index for the - // JVM_CONSTANT_NameAndType entry. - new_name_and_type_ref_i = *merge_cp_length_p - 1; - } - } - - // If the referenced entries already exist in *merge_cp_p, then - // both new_klass_ref_i and new_name_and_type_ref_i will both be - // 0. In that case, all we are appending is the current entry. - if (new_klass_ref_i == 0) { - new_klass_ref_i = klass_ref_i; - } - if (new_name_and_type_ref_i == 0) { - new_name_and_type_ref_i = name_and_type_ref_i; - } + int new_klass_ref_i = find_or_append_indirect_entry(scratch_cp, klass_ref_i, + merge_cp_p, merge_cp_length_p, THREAD); + + int name_and_type_ref_i = scratch_cp->uncached_name_and_type_ref_index_at(scratch_i); + int new_name_and_type_ref_i = find_or_append_indirect_entry(scratch_cp, name_and_type_ref_i, + merge_cp_p, merge_cp_length_p, THREAD); const char *entry_name; switch (scratch_cp->tag_at(scratch_i).value()) { @@ -481,6 +364,72 @@ (*merge_cp_length_p)++; } break; + // this is an indirect CP entry so it needs special handling + case JVM_CONSTANT_MethodType: + { + int ref_i = scratch_cp->method_type_index_at(scratch_i); + int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, + merge_cp_length_p, THREAD); + if (new_ref_i != ref_i) { + RC_TRACE(0x00080000, + ("MethodType entry@%d ref_index change: %d to %d", + *merge_cp_length_p, ref_i, new_ref_i)); + } + (*merge_cp_p)->method_type_index_at_put(*merge_cp_length_p, 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. + map_index(scratch_cp, scratch_i, *merge_cp_length_p); + } + (*merge_cp_length_p)++; + } break; + + // this is an indirect CP entry so it needs special handling + case JVM_CONSTANT_MethodHandle: + { + int ref_kind = scratch_cp->method_handle_ref_kind_at(scratch_i); + int ref_i = scratch_cp->method_handle_index_at(scratch_i); + int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, + merge_cp_length_p, THREAD); + if (new_ref_i != ref_i) { + RC_TRACE(0x00080000, + ("MethodHandle entry@%d ref_index change: %d to %d", + *merge_cp_length_p, ref_i, new_ref_i)); + } + (*merge_cp_p)->method_handle_index_at_put(*merge_cp_length_p, ref_kind, 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. + map_index(scratch_cp, scratch_i, *merge_cp_length_p); + } + (*merge_cp_length_p)++; + } break; + + // this is an indirect CP entry so it needs special handling + case JVM_CONSTANT_InvokeDynamic: + { + // TBD: cross-checks and possible extra appends into CP and bsm operands + // are needed as well. This issue is tracked by a separate bug 8007037. + int bss_idx = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i); + + int ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i); + int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, + merge_cp_length_p, THREAD); + if (new_ref_i != ref_i) { + RC_TRACE(0x00080000, + ("InvokeDynamic entry@%d name_and_type ref_index change: %d to %d", + *merge_cp_length_p, ref_i, new_ref_i)); + } + + (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, bss_idx, 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. + map_index(scratch_cp, scratch_i, *merge_cp_length_p); + } + (*merge_cp_length_p)++; + } break; + // At this stage, Class or UnresolvedClass could be here, but not // ClassIndex case JVM_CONSTANT_ClassIndex: // fall through @@ -507,6 +456,35 @@ } // end append_entry() +int VM_RedefineClasses::find_or_append_indirect_entry(constantPoolHandle scratch_cp, + int ref_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) { + + int new_ref_i = ref_i; + bool match = (ref_i < *merge_cp_length_p) && + scratch_cp->compare_entry_to(ref_i, *merge_cp_p, ref_i, THREAD); + + if (!match) { + // forward reference in *merge_cp_p or not a direct match + int found_i = scratch_cp->find_matching_entry(ref_i, *merge_cp_p, THREAD); + if (found_i != 0) { + guarantee(found_i != ref_i, "compare_entry_to() and find_matching_entry() do not agree"); + // Found a matching entry somewhere else in *merge_cp_p so just need a mapping entry. + new_ref_i = found_i; + map_index(scratch_cp, ref_i, found_i); + } else { + // no match found so we have to append this entry to *merge_cp_p + append_entry(scratch_cp, ref_i, merge_cp_p, merge_cp_length_p, THREAD); + // The above call to append_entry() can only append one entry + // so the post call query of *merge_cp_length_p is only for + // the sake of consistency. + new_ref_i = *merge_cp_length_p - 1; + } + } + + return new_ref_i; +} // end find_or_append_indirect_entry() + + void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class, TRAPS) { AnnotationArray* save; diff -r 7885e162c30f -r 9bf5f643d1cf src/share/vm/prims/jvmtiRedefineClasses.hpp --- a/src/share/vm/prims/jvmtiRedefineClasses.hpp Mon Jan 28 09:33:55 2013 -0800 +++ b/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Jan 31 20:07:18 2013 -0800 @@ -421,10 +421,11 @@ // and in all direct and indirect subclasses. void increment_class_counter(InstanceKlass *ik, TRAPS); - // Support for constant pool merging (these routines are in alpha - // order): + // Support for constant pool merging (these routines are in alpha order): void append_entry(constantPoolHandle scratch_cp, int scratch_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS); + int find_or_append_indirect_entry(constantPoolHandle scratch_cp, int scratch_i, + constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS); int find_new_index(int old_index); bool is_unresolved_class_mismatch(constantPoolHandle cp1, int index1, constantPoolHandle cp2, int index2);