< prev index next >

src/hotspot/share/prims/jvmtiRedefineClasses.cpp

Print this page
rev 50604 : imported patch jep181-rev1
rev 50605 : imported patch jep181-rev2

*** 681,690 **** --- 681,779 ---- _operands_index_map_p = NULL; _operands_cur_length = 0; _operands_index_map_count = 0; } // end finalize_operands_merge() + // Symbol* comparator for qsort + // The caller must have an active ResourceMark. + static int symcmp(const void* a, const void* b) { + char* astr = (*(Symbol**)a)->as_C_string(); + char* bstr = (*(Symbol**)b)->as_C_string(); + return strcmp(astr, bstr); + } + + static jvmtiError check_nest_attributes(InstanceKlass* the_class, + InstanceKlass* scratch_class) { + // Check whether the class NestHost attribute has been changed. + Thread* thread = Thread::current(); + ResourceMark rm(thread); + JvmtiThreadState *state = JvmtiThreadState::state_for((JavaThread*)thread); + u2 the_nest_host_idx = the_class->nest_host_index(); + u2 scr_nest_host_idx = scratch_class->nest_host_index(); + + if (the_nest_host_idx != 0 && scr_nest_host_idx != 0) { + Symbol* the_sym = the_class->constants()->klass_name_at(the_nest_host_idx); + Symbol* scr_sym = scratch_class->constants()->klass_name_at(scr_nest_host_idx); + if (the_sym != scr_sym) { + log_trace(redefine, class, nestmates) + ("redefined class %s attribute change error: NestHost class: %s replaced with: %s", + the_class->external_name(), the_sym->as_C_string(), scr_sym->as_C_string()); + return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED; + } + } else if ((the_nest_host_idx == 0) ^ (scr_nest_host_idx == 0)) { + const char* action_str = (the_nest_host_idx != 0) ? "removed" : "added"; + log_trace(redefine, class, nestmates) + ("redefined class %s attribute change error: NestHost attribute %s", + the_class->external_name(), action_str); + return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED; + } + + // Check whether the class NestMembers attribute has been changed. + Array<u2>* the_nest_members = the_class->nest_members(); + Array<u2>* scr_nest_members = scratch_class->nest_members(); + bool the_members_exists = the_nest_members != Universe::the_empty_short_array(); + bool scr_members_exists = scr_nest_members != Universe::the_empty_short_array(); + + int members_len = the_nest_members->length(); + if (the_members_exists && scr_members_exists) { + if (members_len != scr_nest_members->length()) { + log_trace(redefine, class, nestmates) + ("redefined class %s attribute change error: NestMember len=%d changed to len=%d", + the_class->external_name(), members_len, scr_nest_members->length()); + return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED; + } + + // The order of entries in the NestMembers array is not specified so we + // have to explicitly check for the same contents. We do this by copying + // the referenced symbols into their own arrays, sorting them and then + // comparing each element pair. + + Symbol** the_syms = NEW_RESOURCE_ARRAY_RETURN_NULL(Symbol*, members_len); + Symbol** scr_syms = NEW_RESOURCE_ARRAY_RETURN_NULL(Symbol*, members_len); + + if (the_syms == NULL || scr_syms == NULL) { + return JVMTI_ERROR_OUT_OF_MEMORY; + } + + for (int i = 0; i < members_len; i++) { + int the_cp_index = the_nest_members->at(i); + int scr_cp_index = scr_nest_members->at(i); + the_syms[i] = the_class->constants()->klass_name_at(the_cp_index); + scr_syms[i] = scratch_class->constants()->klass_name_at(scr_cp_index); + } + + qsort(the_syms, members_len, sizeof(Symbol*), symcmp); + qsort(scr_syms, members_len, sizeof(Symbol*), symcmp); + + for (int i = 0; i < members_len; i++) { + if (the_syms[i] != scr_syms[i]) { + log_trace(redefine, class, nestmates) + ("redefined class %s attribute change error: NestMembers[%d]: %s changed to %s", + the_class->external_name(), i, the_syms[i]->as_C_string(), scr_syms[i]->as_C_string()); + return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED; + } + } + } else if (the_members_exists ^ scr_members_exists) { + const char* action_str = (the_members_exists) ? "removed" : "added"; + log_trace(redefine, class, nestmates) + ("redefined class %s attribute change error: NestMembers attribute %s", + the_class->external_name(), action_str); + return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED; + } + + return JVMTI_ERROR_NONE; + } jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions( InstanceKlass* the_class, InstanceKlass* scratch_class) { int i;
*** 723,732 **** --- 812,827 ---- if (the_class->is_in_error_state()) { // TBD #5057930: special error code is needed in 1.6 return JVMTI_ERROR_INVALID_CLASS; } + // Check whether the nest-related attributes have been changed. + jvmtiError err = check_nest_attributes(the_class, scratch_class); + if (err != JVMTI_ERROR_NONE) { + return err; + } + // Check whether class modifiers are the same. jushort old_flags = (jushort) the_class->access_flags().get_flags(); jushort new_flags = (jushort) scratch_class->access_flags().get_flags(); if (old_flags != new_flags) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED;
*** 1596,1605 **** --- 1691,1706 ---- // Rewrite constant pool references in klass scratch_class. bool VM_RedefineClasses::rewrite_cp_refs(InstanceKlass* scratch_class, TRAPS) { + // rewrite constant pool references in the nest attributes: + if (!rewrite_cp_refs_in_nest_attributes(scratch_class)) { + // propagate failure back to caller + return false; + } + // rewrite constant pool references in the methods: if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) { // propagate failure back to caller return false; }
*** 1678,1687 **** --- 1779,1804 ---- } return true; } // end rewrite_cp_refs() + // Rewrite constant pool references in the NestHost and NestMembers attributes. + bool VM_RedefineClasses::rewrite_cp_refs_in_nest_attributes( + InstanceKlass* scratch_class) { + + u2 cp_index = scratch_class->nest_host_index(); + if (cp_index != 0) { + scratch_class->set_nest_host_index(find_new_index(cp_index)); + } + Array<u2>* nest_members = scratch_class->nest_members(); + for (int i = 0; i < nest_members->length(); i++) { + u2 cp_index = nest_members->at(i); + nest_members->at_put(i, find_new_index(cp_index)); + } + return true; + } + // Rewrite constant pool references in the methods. bool VM_RedefineClasses::rewrite_cp_refs_in_methods( InstanceKlass* scratch_class, TRAPS) { Array<Method*>* methods = scratch_class->methods();
< prev index next >