Top


定義場所(file name)

hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp

名前(function name)

void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
       BitMap *emcp_methods, int * emcp_method_count_p) {

本体部(body)

  {- -------------------------------------------
  (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.