Top


定義場所(file name)

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

名前(function name)

jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) {

本体部(body)

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      // For consistency allocate memory using os::malloc wrapper.
      _scratch_classes = (instanceKlassHandle *)
        os::malloc(sizeof(instanceKlassHandle) * _class_count);
      if (_scratch_classes == NULL) {
        return JVMTI_ERROR_OUT_OF_MEMORY;
      }

  {- -------------------------------------------
  (1) (変数宣言など)
      ---------------------------------------- -}

      ResourceMark rm(THREAD);

  {- -------------------------------------------
  (1) 
      ---------------------------------------- -}

      JvmtiThreadState *state = JvmtiThreadState::state_for(JavaThread::current());
      // state can only be NULL if the current thread is exiting which
      // should not happen since we're trying to do a RedefineClasses
      guarantee(state != NULL, "exiting thread calling load_new_class_versions");
      for (int i = 0; i < _class_count; i++) {
        oop mirror = JNIHandles::resolve_non_null(_class_defs[i].klass);
        // classes for primitives cannot be redefined
        if (!is_modifiable_class(mirror)) {
          return JVMTI_ERROR_UNMODIFIABLE_CLASS;
        }
        klassOop the_class_oop = java_lang_Class::as_klassOop(mirror);
        instanceKlassHandle the_class = instanceKlassHandle(THREAD, the_class_oop);
        Symbol*  the_class_sym = the_class->name();

        // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
        RC_TRACE_WITH_THREAD(0x00000001, THREAD,
          ("loading name=%s (avail_mem=" UINT64_FORMAT "K)",
          the_class->external_name(), os::available_memory() >> 10));

        ClassFileStream st((u1*) _class_defs[i].class_bytes,
          _class_defs[i].class_byte_count, (char *)"__VM_RedefineClasses__");

        // Parse the stream.
        Handle the_class_loader(THREAD, the_class->class_loader());
        Handle protection_domain(THREAD, the_class->protection_domain());
        // Set redefined class handle in JvmtiThreadState class.
        // This redefined class is sent to agent event handler for class file
        // load hook event.
        state->set_class_being_redefined(&the_class, _class_load_kind);

        klassOop k = SystemDictionary::parse_stream(the_class_sym,
                                                    the_class_loader,
                                                    protection_domain,
                                                    &st,
                                                    THREAD);
        // Clear class_being_redefined just to be sure.
        state->clear_class_being_redefined();

        // TODO: if this is retransform, and nothing changed we can skip it

        instanceKlassHandle scratch_class (THREAD, k);

        if (HAS_PENDING_EXCEPTION) {
          Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
          // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
          RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("parse_stream exception: '%s'",
            ex_name->as_C_string()));
          CLEAR_PENDING_EXCEPTION;

          if (ex_name == vmSymbols::java_lang_UnsupportedClassVersionError()) {
            return JVMTI_ERROR_UNSUPPORTED_VERSION;
          } else if (ex_name == vmSymbols::java_lang_ClassFormatError()) {
            return JVMTI_ERROR_INVALID_CLASS_FORMAT;
          } else if (ex_name == vmSymbols::java_lang_ClassCircularityError()) {
            return JVMTI_ERROR_CIRCULAR_CLASS_DEFINITION;
          } else if (ex_name == vmSymbols::java_lang_NoClassDefFoundError()) {
            // The message will be "XXX (wrong name: YYY)"
            return JVMTI_ERROR_NAMES_DONT_MATCH;
          } else if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
            return JVMTI_ERROR_OUT_OF_MEMORY;
          } else {  // Just in case more exceptions can be thrown..
            return JVMTI_ERROR_FAILS_VERIFICATION;
          }
        }

        // Ensure class is linked before redefine
        if (!the_class->is_linked()) {
          the_class->link_class(THREAD);
          if (HAS_PENDING_EXCEPTION) {
            Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
            // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
            RC_TRACE_WITH_THREAD(0x00000002, THREAD, ("link_class exception: '%s'",
              ex_name->as_C_string()));
            CLEAR_PENDING_EXCEPTION;
            if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
              return JVMTI_ERROR_OUT_OF_MEMORY;
            } else {
              return JVMTI_ERROR_INTERNAL;
            }
          }
        }

        // Do the validity checks in compare_and_normalize_class_versions()
        // before verifying the byte codes. By doing these checks first, we
        // limit the number of functions that require redirection from
        // the_class to scratch_class. In particular, we don't have to
        // modify JNI GetSuperclass() and thus won't change its performance.
        jvmtiError res = compare_and_normalize_class_versions(the_class,
                           scratch_class);
        if (res != JVMTI_ERROR_NONE) {
          return res;
        }

        // verify what the caller passed us
        {
          // The bug 6214132 caused the verification to fail.
          // Information about the_class and scratch_class is temporarily
          // recorded into jvmtiThreadState. This data is used to redirect
          // the_class to scratch_class in the JVM_* functions called by the
          // verifier. Please, refer to jvmtiThreadState.hpp for the detailed
          // description.
          RedefineVerifyMark rvm(&the_class, &scratch_class, state);
          Verifier::verify(
            scratch_class, Verifier::ThrowException, true, THREAD);
        }

        if (HAS_PENDING_EXCEPTION) {
          Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
          // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
          RC_TRACE_WITH_THREAD(0x00000002, THREAD,
            ("verify_byte_codes exception: '%s'", ex_name->as_C_string()));
          CLEAR_PENDING_EXCEPTION;
          if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
            return JVMTI_ERROR_OUT_OF_MEMORY;
          } else {
            // tell the caller the bytecodes are bad
            return JVMTI_ERROR_FAILS_VERIFICATION;
          }
        }

        res = merge_cp_and_rewrite(the_class, scratch_class, THREAD);
        if (res != JVMTI_ERROR_NONE) {
          return res;
        }

        if (VerifyMergedCPBytecodes) {
          // verify what we have done during constant pool merging
          {
            RedefineVerifyMark rvm(&the_class, &scratch_class, state);
            Verifier::verify(scratch_class, Verifier::ThrowException, true, THREAD);
          }

          if (HAS_PENDING_EXCEPTION) {
            Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
            // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
            RC_TRACE_WITH_THREAD(0x00000002, THREAD,
              ("verify_byte_codes post merge-CP exception: '%s'",
              ex_name->as_C_string()));
            CLEAR_PENDING_EXCEPTION;
            if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
              return JVMTI_ERROR_OUT_OF_MEMORY;
            } else {
              // tell the caller that constant pool merging screwed up
              return JVMTI_ERROR_INTERNAL;
            }
          }
        }

        Rewriter::rewrite(scratch_class, THREAD);
        if (!HAS_PENDING_EXCEPTION) {
          Rewriter::relocate_and_link(scratch_class, THREAD);
        }
        if (HAS_PENDING_EXCEPTION) {
          Symbol* ex_name = PENDING_EXCEPTION->klass()->klass_part()->name();
          CLEAR_PENDING_EXCEPTION;
          if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
            return JVMTI_ERROR_OUT_OF_MEMORY;
          } else {
            return JVMTI_ERROR_INTERNAL;
          }
        }

        _scratch_classes[i] = scratch_class;

        // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
        RC_TRACE_WITH_THREAD(0x00000001, THREAD,
          ("loaded name=%s (avail_mem=" UINT64_FORMAT "K)",
          the_class->external_name(), os::available_memory() >> 10));
      }

  {- -------------------------------------------
  (1) リターン
      ---------------------------------------- -}

      return JVMTI_ERROR_NONE;
    }

This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.