8007037: JSR 292: the VM_RedefineClasses::append_entry() should do cross-checks with indy operands

References from operands to CP entries and back must be correct after CP merge

Reviewed-by: coleenp, twisti
This commit is contained in:
Serguei Spitsyn 2013-04-25 03:58:53 -07:00 committed by Serguei Spitsyn
parent db8bc15dd2
commit 333cf9a756
4 changed files with 344 additions and 30 deletions

View file

@ -415,20 +415,26 @@ void VM_RedefineClasses::append_entry(constantPoolHandle scratch_cp,
// 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,
// Index of the bootstrap specifier in the operands array
int old_bs_i = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i);
int new_bs_i = find_or_append_operand(scratch_cp, old_bs_i, merge_cp_p,
merge_cp_length_p, THREAD);
// The bootstrap method NameAndType_info index
int old_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, old_ref_i, merge_cp_p,
merge_cp_length_p, THREAD);
if (new_ref_i != ref_i) {
if (new_bs_i != old_bs_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));
("InvokeDynamic entry@%d bootstrap_method_attr_index change: %d to %d",
*merge_cp_length_p, old_bs_i, new_bs_i));
}
if (new_ref_i != old_ref_i) {
RC_TRACE(0x00080000,
("InvokeDynamic entry@%d name_and_type_index change: %d to %d",
*merge_cp_length_p, old_ref_i, new_ref_i));
}
(*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, bss_idx, new_ref_i);
(*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, new_bs_i, 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.
@ -492,6 +498,105 @@ int VM_RedefineClasses::find_or_append_indirect_entry(constantPoolHandle scratch
} // end find_or_append_indirect_entry()
// Append a bootstrap specifier into the merge_cp operands that is semantically equal
// to the scratch_cp operands bootstrap specifier passed by the old_bs_i index.
// Recursively append new merge_cp entries referenced by the new bootstrap specifier.
void VM_RedefineClasses::append_operand(constantPoolHandle scratch_cp, int old_bs_i,
constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
int old_ref_i = scratch_cp->operand_bootstrap_method_ref_index_at(old_bs_i);
int new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p,
merge_cp_length_p, THREAD);
if (new_ref_i != old_ref_i) {
RC_TRACE(0x00080000,
("operands entry@%d bootstrap method ref_index change: %d to %d",
_operands_cur_length, old_ref_i, new_ref_i));
}
Array<u2>* merge_ops = (*merge_cp_p)->operands();
int new_bs_i = _operands_cur_length;
// We have _operands_cur_length == 0 when the merge_cp operands is empty yet.
// However, the operand_offset_at(0) was set in the extend_operands() call.
int new_base = (new_bs_i == 0) ? (*merge_cp_p)->operand_offset_at(0)
: (*merge_cp_p)->operand_next_offset_at(new_bs_i - 1);
int argc = scratch_cp->operand_argument_count_at(old_bs_i);
ConstantPool::operand_offset_at_put(merge_ops, _operands_cur_length, new_base);
merge_ops->at_put(new_base++, new_ref_i);
merge_ops->at_put(new_base++, argc);
for (int i = 0; i < argc; i++) {
int old_arg_ref_i = scratch_cp->operand_argument_index_at(old_bs_i, i);
int new_arg_ref_i = find_or_append_indirect_entry(scratch_cp, old_arg_ref_i, merge_cp_p,
merge_cp_length_p, THREAD);
merge_ops->at_put(new_base++, new_arg_ref_i);
if (new_arg_ref_i != old_arg_ref_i) {
RC_TRACE(0x00080000,
("operands entry@%d bootstrap method argument ref_index change: %d to %d",
_operands_cur_length, old_arg_ref_i, new_arg_ref_i));
}
}
if (old_bs_i != _operands_cur_length) {
// The bootstrap specifier in *merge_cp_p is at a different index than
// that in scratch_cp so we need to map the index values.
map_operand_index(old_bs_i, new_bs_i);
}
_operands_cur_length++;
} // end append_operand()
int VM_RedefineClasses::find_or_append_operand(constantPoolHandle scratch_cp,
int old_bs_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
int new_bs_i = old_bs_i; // bootstrap specifier index
bool match = (old_bs_i < _operands_cur_length) &&
scratch_cp->compare_operand_to(old_bs_i, *merge_cp_p, old_bs_i, THREAD);
if (!match) {
// forward reference in *merge_cp_p or not a direct match
int found_i = scratch_cp->find_matching_operand(old_bs_i, *merge_cp_p,
_operands_cur_length, THREAD);
if (found_i != -1) {
guarantee(found_i != old_bs_i, "compare_operand_to() and find_matching_operand() disagree");
// found a matching operand somewhere else in *merge_cp_p so just need a mapping
new_bs_i = found_i;
map_operand_index(old_bs_i, found_i);
} else {
// no match found so we have to append this bootstrap specifier to *merge_cp_p
append_operand(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p, THREAD);
new_bs_i = _operands_cur_length - 1;
}
}
return new_bs_i;
} // end find_or_append_operand()
void VM_RedefineClasses::finalize_operands_merge(constantPoolHandle merge_cp, TRAPS) {
if (merge_cp->operands() == NULL) {
return;
}
// Shrink the merge_cp operands
merge_cp->shrink_operands(_operands_cur_length, CHECK);
if (RC_TRACE_ENABLED(0x00040000)) {
// don't want to loop unless we are tracing
int count = 0;
for (int i = 1; i < _operands_index_map_p->length(); i++) {
int value = _operands_index_map_p->at(i);
if (value != -1) {
RC_TRACE_WITH_THREAD(0x00040000, THREAD,
("operands_index_map[%d]: old=%d new=%d", count, i, value));
count++;
}
}
}
// Clean-up
_operands_index_map_p = NULL;
_operands_cur_length = 0;
_operands_index_map_count = 0;
} // end finalize_operands_merge()
jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
instanceKlassHandle the_class,
instanceKlassHandle scratch_class) {
@ -765,6 +870,31 @@ int VM_RedefineClasses::find_new_index(int old_index) {
} // end find_new_index()
// Find new bootstrap specifier index value for old bootstrap specifier index
// value by seaching the index map. Returns unused index (-1) if there is
// no mapped value for the old bootstrap specifier index.
int VM_RedefineClasses::find_new_operand_index(int old_index) {
if (_operands_index_map_count == 0) {
// map is empty so nothing can be found
return -1;
}
if (old_index == -1 || old_index >= _operands_index_map_p->length()) {
// The old_index is out of range so it is not mapped.
// This should not happen in regular constant pool merging use.
return -1;
}
int value = _operands_index_map_p->at(old_index);
if (value == -1) {
// the old_index is not mapped
return -1;
}
return value;
} // end find_new_operand_index()
// Returns true if the current mismatch is due to a resolved/unresolved
// class pair. Otherwise, returns false.
bool VM_RedefineClasses::is_unresolved_class_mismatch(constantPoolHandle cp1,
@ -1014,6 +1144,25 @@ void VM_RedefineClasses::map_index(constantPoolHandle scratch_cp,
} // end map_index()
// Map old_index to new_index as needed.
void VM_RedefineClasses::map_operand_index(int old_index, int new_index) {
if (find_new_operand_index(old_index) != -1) {
// old_index is already mapped
return;
}
if (old_index == new_index) {
// no mapping is needed
return;
}
_operands_index_map_p->at_put(old_index, new_index);
_operands_index_map_count++;
RC_TRACE(0x00040000, ("mapped bootstrap specifier at index %d to %d", old_index, new_index));
} // end map_index()
// Merge old_cp and scratch_cp and return the results of the merge via
// merge_cp_p. The number of entries in *merge_cp_p is returned via
// merge_cp_length_p. The entries in old_cp occupy the same locations
@ -1086,6 +1235,7 @@ bool VM_RedefineClasses::merge_constant_pools(constantPoolHandle old_cp,
} // end for each old_cp entry
ConstantPool::copy_operands(old_cp, *merge_cp_p, CHECK_0);
(*merge_cp_p)->extend_operands(scratch_cp, CHECK_0);
// We don't need to sanity check that *merge_cp_length_p is within
// *merge_cp_p bounds since we have the minimum on-entry check above.
@ -1198,6 +1348,8 @@ bool VM_RedefineClasses::merge_constant_pools(constantPoolHandle old_cp,
CHECK_0);
}
finalize_operands_merge(*merge_cp_p, THREAD);
RC_TRACE_WITH_THREAD(0x00020000, THREAD,
("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d",
*merge_cp_length_p, scratch_i, _index_map_count));
@ -1270,6 +1422,11 @@ jvmtiError VM_RedefineClasses::merge_cp_and_rewrite(
_index_map_count = 0;
_index_map_p = new intArray(scratch_cp->length(), -1);
_operands_cur_length = ConstantPool::operand_array_length(old_cp->operands());
_operands_index_map_count = 0;
_operands_index_map_p = new intArray(
ConstantPool::operand_array_length(scratch_cp->operands()), -1);
// reference to the cp holder is needed for copy_operands()
merge_cp->set_pool_holder(scratch_class());
bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp,
@ -1400,7 +1557,6 @@ bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class,
return true;
} // end rewrite_cp_refs()
// Rewrite constant pool references in the methods.
bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
instanceKlassHandle scratch_class, TRAPS) {