Mercurial > hg > graal-compiler
comparison src/share/vm/prims/jvmtiRedefineClasses.cpp @ 10151:15a99ca4ee34
8007037: JSR 292: the VM_RedefineClasses::append_entry() should do cross-checks with indy operands
Summary: References from operands to CP entries and back must be correct after CP merge
Reviewed-by: coleenp, twisti
Contributed-by: serguei.spitsyn@oracle.com
author | sspitsyn |
---|---|
date | Thu, 25 Apr 2013 03:58:53 -0700 |
parents | 6337ca4dcad8 |
children | 712a1e9c91f3 |
comparison
equal
deleted
inserted
replaced
10150:d66a24adbe3f | 10151:15a99ca4ee34 |
---|---|
413 } break; | 413 } break; |
414 | 414 |
415 // this is an indirect CP entry so it needs special handling | 415 // this is an indirect CP entry so it needs special handling |
416 case JVM_CONSTANT_InvokeDynamic: | 416 case JVM_CONSTANT_InvokeDynamic: |
417 { | 417 { |
418 // TBD: cross-checks and possible extra appends into CP and bsm operands | 418 // Index of the bootstrap specifier in the operands array |
419 // are needed as well. This issue is tracked by a separate bug 8007037. | 419 int old_bs_i = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i); |
420 int bss_idx = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i); | 420 int new_bs_i = find_or_append_operand(scratch_cp, old_bs_i, merge_cp_p, |
421 | 421 merge_cp_length_p, THREAD); |
422 int ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i); | 422 // The bootstrap method NameAndType_info index |
423 int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p, | 423 int old_ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i); |
424 int new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p, | |
424 merge_cp_length_p, THREAD); | 425 merge_cp_length_p, THREAD); |
425 if (new_ref_i != ref_i) { | 426 if (new_bs_i != old_bs_i) { |
426 RC_TRACE(0x00080000, | 427 RC_TRACE(0x00080000, |
427 ("InvokeDynamic entry@%d name_and_type ref_index change: %d to %d", | 428 ("InvokeDynamic entry@%d bootstrap_method_attr_index change: %d to %d", |
428 *merge_cp_length_p, ref_i, new_ref_i)); | 429 *merge_cp_length_p, old_bs_i, new_bs_i)); |
429 } | 430 } |
430 | 431 if (new_ref_i != old_ref_i) { |
431 (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, bss_idx, new_ref_i); | 432 RC_TRACE(0x00080000, |
433 ("InvokeDynamic entry@%d name_and_type_index change: %d to %d", | |
434 *merge_cp_length_p, old_ref_i, new_ref_i)); | |
435 } | |
436 | |
437 (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, new_bs_i, new_ref_i); | |
432 if (scratch_i != *merge_cp_length_p) { | 438 if (scratch_i != *merge_cp_length_p) { |
433 // The new entry in *merge_cp_p is at a different index than | 439 // The new entry in *merge_cp_p is at a different index than |
434 // the new entry in scratch_cp so we need to map the index values. | 440 // the new entry in scratch_cp so we need to map the index values. |
435 map_index(scratch_cp, scratch_i, *merge_cp_length_p); | 441 map_index(scratch_cp, scratch_i, *merge_cp_length_p); |
436 } | 442 } |
488 } | 494 } |
489 } | 495 } |
490 | 496 |
491 return new_ref_i; | 497 return new_ref_i; |
492 } // end find_or_append_indirect_entry() | 498 } // end find_or_append_indirect_entry() |
499 | |
500 | |
501 // Append a bootstrap specifier into the merge_cp operands that is semantically equal | |
502 // to the scratch_cp operands bootstrap specifier passed by the old_bs_i index. | |
503 // Recursively append new merge_cp entries referenced by the new bootstrap specifier. | |
504 void VM_RedefineClasses::append_operand(constantPoolHandle scratch_cp, int old_bs_i, | |
505 constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) { | |
506 | |
507 int old_ref_i = scratch_cp->operand_bootstrap_method_ref_index_at(old_bs_i); | |
508 int new_ref_i = find_or_append_indirect_entry(scratch_cp, old_ref_i, merge_cp_p, | |
509 merge_cp_length_p, THREAD); | |
510 if (new_ref_i != old_ref_i) { | |
511 RC_TRACE(0x00080000, | |
512 ("operands entry@%d bootstrap method ref_index change: %d to %d", | |
513 _operands_cur_length, old_ref_i, new_ref_i)); | |
514 } | |
515 | |
516 Array<u2>* merge_ops = (*merge_cp_p)->operands(); | |
517 int new_bs_i = _operands_cur_length; | |
518 // We have _operands_cur_length == 0 when the merge_cp operands is empty yet. | |
519 // However, the operand_offset_at(0) was set in the extend_operands() call. | |
520 int new_base = (new_bs_i == 0) ? (*merge_cp_p)->operand_offset_at(0) | |
521 : (*merge_cp_p)->operand_next_offset_at(new_bs_i - 1); | |
522 int argc = scratch_cp->operand_argument_count_at(old_bs_i); | |
523 | |
524 ConstantPool::operand_offset_at_put(merge_ops, _operands_cur_length, new_base); | |
525 merge_ops->at_put(new_base++, new_ref_i); | |
526 merge_ops->at_put(new_base++, argc); | |
527 | |
528 for (int i = 0; i < argc; i++) { | |
529 int old_arg_ref_i = scratch_cp->operand_argument_index_at(old_bs_i, i); | |
530 int new_arg_ref_i = find_or_append_indirect_entry(scratch_cp, old_arg_ref_i, merge_cp_p, | |
531 merge_cp_length_p, THREAD); | |
532 merge_ops->at_put(new_base++, new_arg_ref_i); | |
533 if (new_arg_ref_i != old_arg_ref_i) { | |
534 RC_TRACE(0x00080000, | |
535 ("operands entry@%d bootstrap method argument ref_index change: %d to %d", | |
536 _operands_cur_length, old_arg_ref_i, new_arg_ref_i)); | |
537 } | |
538 } | |
539 if (old_bs_i != _operands_cur_length) { | |
540 // The bootstrap specifier in *merge_cp_p is at a different index than | |
541 // that in scratch_cp so we need to map the index values. | |
542 map_operand_index(old_bs_i, new_bs_i); | |
543 } | |
544 _operands_cur_length++; | |
545 } // end append_operand() | |
546 | |
547 | |
548 int VM_RedefineClasses::find_or_append_operand(constantPoolHandle scratch_cp, | |
549 int old_bs_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) { | |
550 | |
551 int new_bs_i = old_bs_i; // bootstrap specifier index | |
552 bool match = (old_bs_i < _operands_cur_length) && | |
553 scratch_cp->compare_operand_to(old_bs_i, *merge_cp_p, old_bs_i, THREAD); | |
554 | |
555 if (!match) { | |
556 // forward reference in *merge_cp_p or not a direct match | |
557 int found_i = scratch_cp->find_matching_operand(old_bs_i, *merge_cp_p, | |
558 _operands_cur_length, THREAD); | |
559 if (found_i != -1) { | |
560 guarantee(found_i != old_bs_i, "compare_operand_to() and find_matching_operand() disagree"); | |
561 // found a matching operand somewhere else in *merge_cp_p so just need a mapping | |
562 new_bs_i = found_i; | |
563 map_operand_index(old_bs_i, found_i); | |
564 } else { | |
565 // no match found so we have to append this bootstrap specifier to *merge_cp_p | |
566 append_operand(scratch_cp, old_bs_i, merge_cp_p, merge_cp_length_p, THREAD); | |
567 new_bs_i = _operands_cur_length - 1; | |
568 } | |
569 } | |
570 return new_bs_i; | |
571 } // end find_or_append_operand() | |
572 | |
573 | |
574 void VM_RedefineClasses::finalize_operands_merge(constantPoolHandle merge_cp, TRAPS) { | |
575 if (merge_cp->operands() == NULL) { | |
576 return; | |
577 } | |
578 // Shrink the merge_cp operands | |
579 merge_cp->shrink_operands(_operands_cur_length, CHECK); | |
580 | |
581 if (RC_TRACE_ENABLED(0x00040000)) { | |
582 // don't want to loop unless we are tracing | |
583 int count = 0; | |
584 for (int i = 1; i < _operands_index_map_p->length(); i++) { | |
585 int value = _operands_index_map_p->at(i); | |
586 if (value != -1) { | |
587 RC_TRACE_WITH_THREAD(0x00040000, THREAD, | |
588 ("operands_index_map[%d]: old=%d new=%d", count, i, value)); | |
589 count++; | |
590 } | |
591 } | |
592 } | |
593 // Clean-up | |
594 _operands_index_map_p = NULL; | |
595 _operands_cur_length = 0; | |
596 _operands_index_map_count = 0; | |
597 } // end finalize_operands_merge() | |
493 | 598 |
494 | 599 |
495 jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( | 600 jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( |
496 instanceKlassHandle the_class, | 601 instanceKlassHandle the_class, |
497 instanceKlassHandle scratch_class) { | 602 instanceKlassHandle scratch_class) { |
763 | 868 |
764 return value; | 869 return value; |
765 } // end find_new_index() | 870 } // end find_new_index() |
766 | 871 |
767 | 872 |
873 // Find new bootstrap specifier index value for old bootstrap specifier index | |
874 // value by seaching the index map. Returns unused index (-1) if there is | |
875 // no mapped value for the old bootstrap specifier index. | |
876 int VM_RedefineClasses::find_new_operand_index(int old_index) { | |
877 if (_operands_index_map_count == 0) { | |
878 // map is empty so nothing can be found | |
879 return -1; | |
880 } | |
881 | |
882 if (old_index == -1 || old_index >= _operands_index_map_p->length()) { | |
883 // The old_index is out of range so it is not mapped. | |
884 // This should not happen in regular constant pool merging use. | |
885 return -1; | |
886 } | |
887 | |
888 int value = _operands_index_map_p->at(old_index); | |
889 if (value == -1) { | |
890 // the old_index is not mapped | |
891 return -1; | |
892 } | |
893 | |
894 return value; | |
895 } // end find_new_operand_index() | |
896 | |
897 | |
768 // Returns true if the current mismatch is due to a resolved/unresolved | 898 // Returns true if the current mismatch is due to a resolved/unresolved |
769 // class pair. Otherwise, returns false. | 899 // class pair. Otherwise, returns false. |
770 bool VM_RedefineClasses::is_unresolved_class_mismatch(constantPoolHandle cp1, | 900 bool VM_RedefineClasses::is_unresolved_class_mismatch(constantPoolHandle cp1, |
771 int index1, constantPoolHandle cp2, int index2) { | 901 int index1, constantPoolHandle cp2, int index2) { |
772 | 902 |
1012 RC_TRACE(0x00040000, ("mapped tag %d at index %d to %d", | 1142 RC_TRACE(0x00040000, ("mapped tag %d at index %d to %d", |
1013 scratch_cp->tag_at(old_index).value(), old_index, new_index)); | 1143 scratch_cp->tag_at(old_index).value(), old_index, new_index)); |
1014 } // end map_index() | 1144 } // end map_index() |
1015 | 1145 |
1016 | 1146 |
1147 // Map old_index to new_index as needed. | |
1148 void VM_RedefineClasses::map_operand_index(int old_index, int new_index) { | |
1149 if (find_new_operand_index(old_index) != -1) { | |
1150 // old_index is already mapped | |
1151 return; | |
1152 } | |
1153 | |
1154 if (old_index == new_index) { | |
1155 // no mapping is needed | |
1156 return; | |
1157 } | |
1158 | |
1159 _operands_index_map_p->at_put(old_index, new_index); | |
1160 _operands_index_map_count++; | |
1161 | |
1162 RC_TRACE(0x00040000, ("mapped bootstrap specifier at index %d to %d", old_index, new_index)); | |
1163 } // end map_index() | |
1164 | |
1165 | |
1017 // Merge old_cp and scratch_cp and return the results of the merge via | 1166 // Merge old_cp and scratch_cp and return the results of the merge via |
1018 // merge_cp_p. The number of entries in *merge_cp_p is returned via | 1167 // merge_cp_p. The number of entries in *merge_cp_p is returned via |
1019 // merge_cp_length_p. The entries in old_cp occupy the same locations | 1168 // merge_cp_length_p. The entries in old_cp occupy the same locations |
1020 // in *merge_cp_p. Also creates a map of indices from entries in | 1169 // in *merge_cp_p. Also creates a map of indices from entries in |
1021 // scratch_cp to the corresponding entry in *merge_cp_p. Index map | 1170 // scratch_cp to the corresponding entry in *merge_cp_p. Index map |
1084 break; | 1233 break; |
1085 } | 1234 } |
1086 } // end for each old_cp entry | 1235 } // end for each old_cp entry |
1087 | 1236 |
1088 ConstantPool::copy_operands(old_cp, *merge_cp_p, CHECK_0); | 1237 ConstantPool::copy_operands(old_cp, *merge_cp_p, CHECK_0); |
1238 (*merge_cp_p)->extend_operands(scratch_cp, CHECK_0); | |
1089 | 1239 |
1090 // We don't need to sanity check that *merge_cp_length_p is within | 1240 // We don't need to sanity check that *merge_cp_length_p is within |
1091 // *merge_cp_p bounds since we have the minimum on-entry check above. | 1241 // *merge_cp_p bounds since we have the minimum on-entry check above. |
1092 (*merge_cp_length_p) = old_i; | 1242 (*merge_cp_length_p) = old_i; |
1093 } | 1243 } |
1196 // referenced entries to *merge_cp_p. | 1346 // referenced entries to *merge_cp_p. |
1197 append_entry(scratch_cp, scratch_i, merge_cp_p, merge_cp_length_p, | 1347 append_entry(scratch_cp, scratch_i, merge_cp_p, merge_cp_length_p, |
1198 CHECK_0); | 1348 CHECK_0); |
1199 } | 1349 } |
1200 | 1350 |
1351 finalize_operands_merge(*merge_cp_p, THREAD); | |
1352 | |
1201 RC_TRACE_WITH_THREAD(0x00020000, THREAD, | 1353 RC_TRACE_WITH_THREAD(0x00020000, THREAD, |
1202 ("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d", | 1354 ("after pass 1b: merge_cp_len=%d, scratch_i=%d, index_map_len=%d", |
1203 *merge_cp_length_p, scratch_i, _index_map_count)); | 1355 *merge_cp_length_p, scratch_i, _index_map_count)); |
1204 } | 1356 } |
1205 | 1357 |
1268 | 1420 |
1269 ResourceMark rm(THREAD); | 1421 ResourceMark rm(THREAD); |
1270 _index_map_count = 0; | 1422 _index_map_count = 0; |
1271 _index_map_p = new intArray(scratch_cp->length(), -1); | 1423 _index_map_p = new intArray(scratch_cp->length(), -1); |
1272 | 1424 |
1425 _operands_cur_length = ConstantPool::operand_array_length(old_cp->operands()); | |
1426 _operands_index_map_count = 0; | |
1427 _operands_index_map_p = new intArray( | |
1428 ConstantPool::operand_array_length(scratch_cp->operands()), -1); | |
1429 | |
1273 // reference to the cp holder is needed for copy_operands() | 1430 // reference to the cp holder is needed for copy_operands() |
1274 merge_cp->set_pool_holder(scratch_class()); | 1431 merge_cp->set_pool_holder(scratch_class()); |
1275 bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp, | 1432 bool result = merge_constant_pools(old_cp, scratch_cp, &merge_cp, |
1276 &merge_cp_length, THREAD); | 1433 &merge_cp_length, THREAD); |
1277 merge_cp->set_pool_holder(NULL); | 1434 merge_cp->set_pool_holder(NULL); |
1397 return false; | 1554 return false; |
1398 } | 1555 } |
1399 | 1556 |
1400 return true; | 1557 return true; |
1401 } // end rewrite_cp_refs() | 1558 } // end rewrite_cp_refs() |
1402 | |
1403 | 1559 |
1404 // Rewrite constant pool references in the methods. | 1560 // Rewrite constant pool references in the methods. |
1405 bool VM_RedefineClasses::rewrite_cp_refs_in_methods( | 1561 bool VM_RedefineClasses::rewrite_cp_refs_in_methods( |
1406 instanceKlassHandle scratch_class, TRAPS) { | 1562 instanceKlassHandle scratch_class, TRAPS) { |
1407 | 1563 |