hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
BitMap *emcp_methods, int * emcp_method_count_p) {
{- -------------------------------------------
(1) emcp_method_count_p 引数の int 値を 0 に初期化しておく.
---------------------------------------- -}
*emcp_method_count_p = 0;
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
int obsolete_count = 0;
int old_index = 0;
{- -------------------------------------------
(1)
---------------------------------------- -}
for (int j = 0; j < _matching_methods_length; ++j, ++old_index) {
{- -------------------------------------------
(1.1)
---------------------------------------- -}
methodOop old_method = _matching_old_methods[j];
methodOop new_method = _matching_new_methods[j];
methodOop old_array_method;
// Maintain an old_index into the _old_methods array by skipping
// deleted methods
while ((old_array_method = (methodOop) _old_methods->obj_at(old_index))
!= old_method) {
++old_index;
}
{- -------------------------------------------
(1.1) もし古いメソッドと (Redefine 後に) 新しいメソッドが EMCP であれば,
BitMap::set_bit() で emcp_methods 引数で指定された BitMap にチェックを付け,
さらに emcp_method_count_p 引数で指定された int 値もインクリメントしておく.
逆に, EMCP でなかった場合には
methodOopDesc::set_is_obsolete() で古いメソッドに obsolete だということを記録しておく
(ついでに obsolete_count 変数の値もインクリメントしておく).
また, (obsolete になったメソッドにはそれぞれにユニークな IDNUM が必要なので)
instanceKlass::next_method_idnum() で新しい IDNUM を生成し,
それを methodOopDesc::set_method_idnum() で古いメソッドにセットしておく.
---------------------------------------- -}
if (MethodComparator::methods_EMCP(old_method, new_method)) {
// The EMCP definition from JSR-163 requires the bytecodes to be
// the same with the exception of constant pool indices which may
// differ. However, the constants referred to by those indices
// must be the same.
//
// We use methods_EMCP() for comparison since constant pool
// merging can remove duplicate constant pool entries that were
// present in the old method and removed from the rewritten new
// method. A faster binary comparison function would consider the
// old and new methods to be different when they are actually
// EMCP.
//
// The old and new methods are EMCP and you would think that we
// could get rid of one of them here and now and save some space.
// However, the concept of EMCP only considers the bytecodes and
// the constant pool entries in the comparison. Other things,
// e.g., the line number table (LNT) or the local variable table
// (LVT) don't count in the comparison. So the new (and EMCP)
// method can have a new LNT that we need so we can't just
// overwrite the new method with the old method.
//
// When this routine is called, we have already attached the new
// methods to the_class so the old methods are effectively
// overwritten. However, if an old method is still executing,
// then the old method cannot be collected until sometime after
// the old method call has returned. So the overwriting of old
// methods by new methods will save us space except for those
// (hopefully few) old methods that are still executing.
//
// A method refers to a constMethodOop and this presents another
// possible avenue to space savings. The constMethodOop in the
// new method contains possibly new attributes (LNT, LVT, etc).
// At first glance, it seems possible to save space by replacing
// the constMethodOop in the old method with the constMethodOop
// from the new method. The old and new methods would share the
// same constMethodOop and we would save the space occupied by
// the old constMethodOop. However, the constMethodOop contains
// a back reference to the containing method. Sharing the
// constMethodOop between two methods could lead to confusion in
// the code that uses the back reference. This would lead to
// brittle code that could be broken in non-obvious ways now or
// in the future.
//
// Another possibility is to copy the constMethodOop from the new
// method to the old method and then overwrite the new method with
// the old method. Since the constMethodOop contains the bytecodes
// for the method embedded in the oop, this option would change
// the bytecodes out from under any threads executing the old
// method and make the thread's bcp invalid. Since EMCP requires
// that the bytecodes be the same modulo constant pool indices, it
// is straight forward to compute the correct new bcp in the new
// constMethodOop from the old bcp in the old constMethodOop. The
// time consuming part would be searching all the frames in all
// of the threads to find all of the calls to the old method.
//
// It looks like we will have to live with the limited savings
// that we get from effectively overwriting the old methods
// when the new methods are attached to the_class.
// track which methods are EMCP for add_previous_version() call
emcp_methods->set_bit(old_index);
(*emcp_method_count_p)++;
// An EMCP method is _not_ obsolete. An obsolete method has a
// different jmethodID than the current method. An EMCP method
// has the same jmethodID as the current method. Having the
// same jmethodID for all EMCP versions of a method allows for
// a consistent view of the EMCP methods regardless of which
// EMCP method you happen to have in hand. For example, a
// breakpoint set in one EMCP method will work for all EMCP
// versions of the method including the current one.
} else {
// mark obsolete methods as such
old_method->set_is_obsolete();
obsolete_count++;
// obsolete methods need a unique idnum
u2 num = instanceKlass::cast(_the_class_oop)->next_method_idnum();
if (num != constMethodOopDesc::UNSET_IDNUM) {
// u2 old_num = old_method->method_idnum();
old_method->set_method_idnum(num);
// TO DO: attach obsolete annotations to obsolete method's new idnum
}
// With tracing we try not to "yack" too much. The position of
// this trace assumes there are fewer obsolete methods than
// EMCP methods.
RC_TRACE(0x00000100, ("mark %s(%s) as obsolete",
old_method->name()->as_C_string(),
old_method->signature()->as_C_string()));
}
{- -------------------------------------------
(1)
---------------------------------------- -}
old_method->set_is_old();
}
{- -------------------------------------------
(1)
---------------------------------------- -}
for (int i = 0; i < _deleted_methods_length; ++i) {
methodOop old_method = _deleted_methods[i];
assert(old_method->vtable_index() < 0,
"cannot delete methods with vtable entries");;
// Mark all deleted methods as old and obsolete
old_method->set_is_old();
old_method->set_is_obsolete();
++obsolete_count;
// With tracing we try not to "yack" too much. The position of
// this trace assumes there are fewer obsolete methods than
// EMCP methods.
RC_TRACE(0x00000100, ("mark deleted %s(%s) as obsolete",
old_method->name()->as_C_string(),
old_method->signature()->as_C_string()));
}
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert((*emcp_method_count_p + obsolete_count) == _old_methods->length(),
"sanity check");
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
RC_TRACE(0x00000100, ("EMCP_cnt=%d, obsolete_cnt=%d", *emcp_method_count_p,
obsolete_count));
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.