hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp
jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) {
{- -------------------------------------------
(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.