FieldStreamBase(instanceKlassHandle klass) { _fields = klass->fields(); _constants = klass->constants(); _index = 0; _limit = klass->java_fields_count(); init_generic_signature_start_slot(); }
// Calls to this constructor must be proceeded by a ResourceMark // and a HandleMark JvmtiConstantPoolReconstituter(instanceKlassHandle ikh){ set_error(JVMTI_ERROR_NONE); _ikh = ikh; _cpool = constantPoolHandle(Thread::current(), ikh->constants()); _symmap = new SymbolHashMap(); _classmap = new SymbolHashMap(); _cpool_size = _cpool->hash_entries_to(_symmap, _classmap); if (_cpool_size == 0) { set_error(JVMTI_ERROR_OUT_OF_MEMORY); } else if (_cpool_size < 0) { set_error(JVMTI_ERROR_INTERNAL); } }
AllFieldStream(instanceKlassHandle k): FieldStreamBase(k->fields(), k->constants()) {}
InternalFieldStream(instanceKlassHandle k): FieldStreamBase(k->fields(), k->constants(), k->java_fields_count(), 0) {}
void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) { ResourceMark rm(THREAD); Rewriter rw(klass, klass->constants(), klass->methods(), CHECK); // (That's all, folks.) }
jvmtiError VM_RedefineClasses::compare_class_versions(instanceKlassHandle k_h_old, instanceKlassHandle k_h_new) { int i; // Check superclasses, or rather their names, since superclasses themselves can be // requested to replace. // Check for NULL superclass first since this might be java.lang.Object if (k_h_old->super() != k_h_new->super() && (k_h_old->super() == NULL || k_h_new->super() == NULL || Klass::cast(k_h_old->super())->name() != Klass::cast(k_h_new->super())->name())) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; } // Check if the number, names and order of directly implemented interfaces are the same. // I think in principle we should just check if the sets of names of directly implemented // interfaces are the same, i.e. the order of declaration (which, however, if changed in the // .java file, also changes in .class file) should not matter. However, comparing sets is // technically a bit more difficult, and, more importantly, I am not sure at present that the // order of interfaces does not matter on the implementation level, i.e. that the VM does not // rely on it somewhere. objArrayOop k_interfaces = k_h_old->local_interfaces(); objArrayOop k_new_interfaces = k_h_new->local_interfaces(); int n_intfs = k_interfaces->length(); if (n_intfs != k_new_interfaces->length()) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; } for (i = 0; i < n_intfs; i++) { if (Klass::cast((klassOop) k_interfaces->obj_at(i))->name() != Klass::cast((klassOop) k_new_interfaces->obj_at(i))->name()) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED; } } // Check whether class is in the error init state. if (k_h_old->is_in_error_state()) { // TBD #5057930: special error code is needed in 1.6 return JVMTI_ERROR_INVALID_CLASS; } // Check whether class modifiers are the same. jushort old_flags = (jushort) k_h_old->access_flags().get_flags(); jushort new_flags = (jushort) k_h_new->access_flags().get_flags(); if (old_flags != new_flags) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_MODIFIERS_CHANGED; } // Check if the number, names, types and order of fields declared in these classes // are the same. typeArrayOop k_old_fields = k_h_old->fields(); typeArrayOop k_new_fields = k_h_new->fields(); int n_fields = k_old_fields->length(); if (n_fields != k_new_fields->length()) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED; } for (i = 0; i < n_fields; i += instanceKlass::next_offset) { // access old_flags = k_old_fields->ushort_at(i + instanceKlass::access_flags_offset); new_flags = k_new_fields->ushort_at(i + instanceKlass::access_flags_offset); if ((old_flags ^ new_flags) & JVM_RECOGNIZED_FIELD_MODIFIERS) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED; } // offset if (k_old_fields->short_at(i + instanceKlass::low_offset) != k_new_fields->short_at(i + instanceKlass::low_offset) || k_old_fields->short_at(i + instanceKlass::high_offset) != k_new_fields->short_at(i + instanceKlass::high_offset)) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED; } // name and signature jshort name_index = k_old_fields->short_at(i + instanceKlass::name_index_offset); jshort sig_index = k_old_fields->short_at(i +instanceKlass::signature_index_offset); symbolOop name_sym1 = k_h_old->constants()->symbol_at(name_index); symbolOop sig_sym1 = k_h_old->constants()->symbol_at(sig_index); name_index = k_new_fields->short_at(i + instanceKlass::name_index_offset); sig_index = k_new_fields->short_at(i + instanceKlass::signature_index_offset); symbolOop name_sym2 = k_h_new->constants()->symbol_at(name_index); symbolOop sig_sym2 = k_h_new->constants()->symbol_at(sig_index); if (name_sym1 != name_sym2 || sig_sym1 != sig_sym2) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED; } } // Check if the number, names, signatures and order of methods declared in these classes // are the same. objArrayOop k_methods = k_h_old->methods(); objArrayOop k_new_methods = k_h_new->methods(); int n_methods = k_methods->length(); if (n_methods < k_new_methods->length()) return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED; else if (n_methods > k_new_methods->length()) return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED; for (i = 0; i < n_methods; i++) { methodOop k_method = (methodOop) k_methods->obj_at(i); methodOop k_new_method = (methodOop) k_new_methods->obj_at(i); if (k_method->name() != k_new_method->name()) return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED; if (k_method->signature() != k_new_method->signature()) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_DELETED; } old_flags = (jushort) k_method->access_flags().get_flags(); new_flags = (jushort) k_new_method->access_flags().get_flags(); if (old_flags != new_flags) { return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED; } } return JVMTI_ERROR_NONE; }
// Install the redefinition of a class -- // The original instanceKlass object (k_h) always represents the latest // version of the respective class. However, during class redefinition we swap // or replace much of its content with that of the instanceKlass object created // from the bytes of the redefine (k_h_new). Specifically, k_h points to the new // constantpool and methods objects, which we take from k_h_new. k_h_new, in turn, // assumes the role of the previous class version, with the old constantpool and // methods (taken from k_h) attached to it. k_h links to k_h_new to create a // linked list of class versions. void VM_RedefineClasses::redefine_single_class(jclass j_clazz, instanceKlassHandle k_h_new, TRAPS) { oop mirror = JNIHandles::resolve_non_null(j_clazz); klassOop k_oop = java_lang_Class::as_klassOop(mirror); instanceKlassHandle k_h = instanceKlassHandle(THREAD, k_oop); // Remove all breakpoints in methods of this class JvmtiBreakpoints& jvmti_breakpoints = JvmtiCurrentBreakpoints::get_jvmti_breakpoints(); jvmti_breakpoints.clearall_in_class_at_safepoint(k_oop); // Deoptimize all compiled code that depends on this class NOT_CORE(Universe::flush_evol_dependents_on(k_h)); _old_methods = k_h->methods(); _new_methods = k_h_new->methods(); _evolving_koop = k_oop; _old_constants = k_h->constants(); // flush the cached jmethodID fields for _old_methods flush_method_jmethod_id_cache(); // Patch the indexes into the constantpool from the array of fields of the evolving // class. This is required, because the layout of the new constantpool can be different, // so old indexes corresponding to field names and signatures can become invalid. patch_indexes_for_fields(k_h, k_h_new); // Make new constantpool object (and methodOops via it) point to the original class object k_h_new->constants()->set_pool_holder(k_h()); // Replace methods and constantpool k_h->set_methods(_new_methods); k_h_new->set_methods(_old_methods); // To prevent potential GCing of the old methods, // and to be able to undo operation easily. constantPoolOop old_constants = k_h->constants(); k_h->set_constants(k_h_new->constants()); k_h_new->set_constants(old_constants); // See the previous comment. check_methods_and_mark_as_old(); transfer_old_native_function_registrations(); // Replace inner_classes typeArrayOop old_inner_classes = k_h->inner_classes(); k_h->set_inner_classes(k_h_new->inner_classes()); k_h_new->set_inner_classes(old_inner_classes); // Initialize the vtable and interface table after // methods have been rewritten { ResourceMark rm(THREAD); k_h->vtable()->initialize_vtable(THREAD); // No exception can happen here k_h->itable()->initialize_itable(); } // Copy the "source file name" attribute from new class version k_h->set_source_file_name(k_h_new->source_file_name()); // Copy the "source debug extension" attribute from new class version k_h->set_source_debug_extension(k_h_new->source_debug_extension()); // Use of javac -g could be different in the old and the new if (k_h_new->access_flags().has_localvariable_table() != k_h->access_flags().has_localvariable_table()) { AccessFlags flags = k_h->access_flags(); if (k_h_new->access_flags().has_localvariable_table()) { flags.set_has_localvariable_table(); } else { flags.clear_has_localvariable_table(); } k_h->set_access_flags(flags); } // Replace class annotation fields values typeArrayOop old_class_annotations = k_h->class_annotations(); k_h->set_class_annotations(k_h_new->class_annotations()); k_h_new->set_class_annotations(old_class_annotations); // Replace fields annotation fields values objArrayOop old_fields_annotations = k_h->fields_annotations(); k_h->set_fields_annotations(k_h_new->fields_annotations()); k_h_new->set_fields_annotations(old_fields_annotations); // Replace methods annotation fields values objArrayOop old_methods_annotations = k_h->methods_annotations(); k_h->set_methods_annotations(k_h_new->methods_annotations()); k_h_new->set_methods_annotations(old_methods_annotations); // Replace methods parameter annotation fields values objArrayOop old_methods_parameter_annotations = k_h->methods_parameter_annotations(); k_h->set_methods_parameter_annotations(k_h_new->methods_parameter_annotations()); k_h_new->set_methods_parameter_annotations(old_methods_parameter_annotations); // Replace methods default annotation fields values objArrayOop old_methods_default_annotations = k_h->methods_default_annotations(); k_h->set_methods_default_annotations(k_h_new->methods_default_annotations()); k_h_new->set_methods_default_annotations(old_methods_default_annotations); // Replace major version number of class file u2 old_major_version = k_h->major_version(); k_h->set_major_version(k_h_new->major_version()); k_h_new->set_major_version(old_major_version); // Replace CP indexes for class and name+type of enclosing method u2 old_class_idx = k_h->enclosing_method_class_index(); u2 old_method_idx = k_h->enclosing_method_method_index(); k_h->set_enclosing_method_indices(k_h_new->enclosing_method_class_index(), k_h_new->enclosing_method_method_index()); k_h_new->set_enclosing_method_indices(old_class_idx, old_method_idx); // Maintain a linked list of versions of this class. // List is in ascending age order. Current version (k_h) is the head. if (k_h->has_previous_version()) { k_h_new->set_previous_version(k_h->previous_version()); } k_h->set_previous_version(k_h_new); // Adjust constantpool caches and vtables for all classes // that reference methods of the evolved class. SystemDictionary::classes_do(adjust_cpool_cache_and_vtable); k_h->set_rewritten_by_redefine(true); }
jvmdiError compare_class_versions(instanceKlassHandle k_h_old, instanceKlassHandle k_h_new) { int i; // Check whether essential class modifiers are the same. The rest can probably differ, e.g. // why not allow substitute class to be synthetic, if it satisfies other conditions. AccessFlags old_flags = k_h_old->access_flags(); AccessFlags new_flags = k_h_new->access_flags(); if (old_flags.is_public() != new_flags.is_public() || old_flags.is_final() != new_flags.is_final() || old_flags.is_interface() != new_flags.is_interface() || old_flags.is_abstract() != new_flags.is_abstract()) { return JVMDI_ERROR_CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED; } // Check superclasses, or rather their names, since superclasses themselves can be // requested to replace if (Klass::cast(k_h_old->super())->name() != Klass::cast(k_h_new->super())->name()) { return JVMDI_ERROR_HIERARCHY_CHANGE_NOT_IMPLEMENTED; } // Check if the number, names and order of directly implemented interfaces are the same. // I think in principle we should just check if the sets of names of directly implemented // interfaces are the same, i.e. the order of declaration (which, however, if changed in the // .java file, also changes in .class file) should not matter. However, comparing sets is // technically a bit more difficult, and, more importantly, I am not sure at present that the // order of interfaces does not matter on the implementation level, i.e. that the VM does not // rely on it somewhere. objArrayOop k_interfaces = k_h_old->local_interfaces(); objArrayOop k_new_interfaces = k_h_new->local_interfaces(); int n_intfs = k_interfaces->length(); if (n_intfs != k_new_interfaces->length()) { return JVMDI_ERROR_HIERARCHY_CHANGE_NOT_IMPLEMENTED; } for (i = 0; i < n_intfs; i++) { if (Klass::cast((klassOop) k_interfaces->obj_at(i))->name() != Klass::cast((klassOop) k_new_interfaces->obj_at(i))->name()) { return JVMDI_ERROR_HIERARCHY_CHANGE_NOT_IMPLEMENTED; } } // Check if the number, names, types and order of fields declared in these classes // are the same. typeArrayOop k_old_fields = k_h_old->fields(); typeArrayOop k_new_fields = k_h_new->fields(); int n_fields = k_old_fields->length(); if (n_fields != k_new_fields->length()) { return JVMDI_ERROR_SCHEMA_CHANGE_NOT_IMPLEMENTED; } for (i = 0; i < n_fields; i += instanceKlass::next_offset) { // access if (k_old_fields->ushort_at(i + instanceKlass::access_flags_offset) != k_new_fields->ushort_at(i + instanceKlass::access_flags_offset)) { return JVMDI_ERROR_SCHEMA_CHANGE_NOT_IMPLEMENTED; } // offset if (k_old_fields->short_at(i + instanceKlass::low_offset) != k_new_fields->short_at(i + instanceKlass::low_offset) || k_old_fields->short_at(i + instanceKlass::high_offset) != k_new_fields->short_at(i + instanceKlass::high_offset)) { return JVMDI_ERROR_SCHEMA_CHANGE_NOT_IMPLEMENTED; } // name and signature jshort name_index = k_old_fields->short_at(i + instanceKlass::name_index_offset); jshort sig_index = k_old_fields->short_at(i +instanceKlass::signature_index_offset); symbolOop name_sym1 = k_h_old->constants()->symbol_at(name_index); symbolOop sig_sym1 = k_h_old->constants()->symbol_at(sig_index); name_index = k_new_fields->short_at(i + instanceKlass::name_index_offset); sig_index = k_new_fields->short_at(i + instanceKlass::signature_index_offset); symbolOop name_sym2 = k_h_new->constants()->symbol_at(name_index); symbolOop sig_sym2 = k_h_new->constants()->symbol_at(sig_index); if (name_sym1 != name_sym2 || sig_sym1 != sig_sym2) { return JVMDI_ERROR_SCHEMA_CHANGE_NOT_IMPLEMENTED; } } // Check if the number, names, signatures and order of methods declared in these classes // are the same. objArrayOop k_methods = k_h_old->methods(); objArrayOop k_new_methods = k_h_new->methods(); int n_methods = k_methods->length(); if (n_methods < k_new_methods->length()) return JVMDI_ERROR_ADD_METHOD_NOT_IMPLEMENTED; else if (n_methods > k_new_methods->length()) return JVMDI_ERROR_DELETE_METHOD_NOT_IMPLEMENTED; for (i = 0; i < n_methods; i++) { methodOop k_method = (methodOop) k_methods->obj_at(i); methodOop k_new_method = (methodOop) k_new_methods->obj_at(i); if (k_method->name() != k_new_method->name()) return JVMDI_ERROR_DELETE_METHOD_NOT_IMPLEMENTED; if (k_method->signature() != k_new_method->signature()) { return JVMDI_ERROR_DELETE_METHOD_NOT_IMPLEMENTED; } old_flags = k_method->access_flags(); new_flags = k_new_method->access_flags(); // It's probably safer to not compare the values of access_flags directly, since // some bits in them encode some implementation-specific information, e.g. // something about inlined tables. This may be different in the new version, // but should not affect method changeability. if (old_flags.is_public() != new_flags.is_public() || old_flags.is_protected() != new_flags.is_protected() || old_flags.is_private() != new_flags.is_private() || old_flags.is_static() != new_flags.is_static() || old_flags.is_final() != new_flags.is_final() || old_flags.is_synchronized() != new_flags.is_synchronized() || old_flags.is_strict() != new_flags.is_strict() || old_flags.is_interface() != new_flags.is_interface() || old_flags.is_abstract() != new_flags.is_abstract()) { return JVMDI_ERROR_METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED; } } return JVMDI_ERROR_NONE; }