FieldStreamBase(instanceKlassHandle klass) { _fields = klass->fields(); _constants = klass->constants(); _index = 0; _limit = klass->java_fields_count(); init_generic_signature_start_slot(); }
// Field names and signatures are referenced via constantpool indexes. In the new class // version, the layout of the constantpool can be different, so these indexes should be // patched. void patch_indexes_for_fields(instanceKlassHandle k_h, instanceKlassHandle k_h_new) { typeArrayOop k_fields = k_h->fields(); typeArrayOop k_new_fields = k_h_new->fields(); int n_fields = k_fields->length(); for (int i = 0; i < n_fields; i += instanceKlass::next_offset) { // name and signature k_fields->short_at_put( i + instanceKlass::name_index_offset, k_new_fields->short_at(i + instanceKlass::name_index_offset) ); k_fields->short_at_put( i + instanceKlass::signature_index_offset, k_new_fields->short_at(i + instanceKlass::signature_index_offset) ); } }
AllFieldStream(instanceKlassHandle k): FieldStreamBase(k->fields(), k->constants()) {}
InternalFieldStream(instanceKlassHandle k): FieldStreamBase(k->fields(), k->constants(), k->java_fields_count(), 0) {}
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; }
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; }