changeset 58354:4cf6af46e13b records

Summary: Add support for class redefinition of classes with Record attributes
author hseigel
date Fri, 18 Oct 2019 11:49:23 +0000
parents 5b80d7a64254
children 4cbc18406d31
files src/hotspot/share/classfile/javaClasses.cpp src/hotspot/share/logging/logTag.hpp src/hotspot/share/oops/instanceKlass.cpp src/hotspot/share/oops/recordComponent.hpp src/hotspot/share/prims/jvm.cpp src/hotspot/share/prims/jvmti.xml src/hotspot/share/prims/jvmtiRedefineClasses.cpp src/hotspot/share/prims/jvmtiRedefineClasses.hpp src/java.instrument/share/native/libinstrument/JavaExceptions.c test/hotspot/jtreg/runtime/records/RedefineRecord.java test/jdk/java/lang/instrument/RedefineRecordAttr/Host/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/Host/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostA/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostA/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostAB/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostAB/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostABC/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostABC/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostABCD/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostABD/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostAC/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostACB/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostB/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostBA/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostBAC/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostBCA/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostCAB/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/HostCBA/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttr/TestRecordAttr.java test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/Host/Host.java test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/Host/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/HostA/Host.java test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/HostA/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/HostB/redef/Host.java test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/TestRecordAttrGenericSig.java
diffstat 35 files changed, 1484 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/classfile/javaClasses.cpp	Thu Oct 17 13:42:17 2019 -0700
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Fri Oct 18 11:49:23 2019 +0000
@@ -3055,7 +3055,7 @@
     accessor_method = holder->find_instance_method(name, full_sig);
   }
 
-  if (accessor_method != NULL) { // TBD should a null accessor method be an error?
+  if (accessor_method != NULL) {
     methodHandle method(THREAD, accessor_method);
     oop m = Reflection::new_method(method, false, CHECK_0);
     java_lang_reflect_RecordComponent::set_accessor(element(), m);
@@ -3065,7 +3065,7 @@
 
   int sig_index = component->generic_signature_index();
   if (sig_index > 0) {
-    Symbol* sig = holder->constants()->symbol_at(sig_index); // name_index is a utf8
+    Symbol* sig = holder->constants()->symbol_at(sig_index); // sig_index is a utf8
     oop component_sig = StringTable::intern(sig, CHECK_0);
     java_lang_reflect_RecordComponent::set_signature(element(), component_sig);
   } else {
--- a/src/hotspot/share/logging/logTag.hpp	Thu Oct 17 13:42:17 2019 -0700
+++ b/src/hotspot/share/logging/logTag.hpp	Fri Oct 18 11:49:23 2019 +0000
@@ -136,6 +136,7 @@
   LOG_TAG(parser) \
   LOG_TAG(ptrqueue) \
   LOG_TAG(purge) \
+  LOG_TAG(record) \
   LOG_TAG(resolve) \
   LOG_TAG(safepoint) \
   LOG_TAG(sampling) \
--- a/src/hotspot/share/oops/instanceKlass.cpp	Thu Oct 17 13:42:17 2019 -0700
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Fri Oct 18 11:49:23 2019 +0000
@@ -3245,8 +3245,9 @@
   }
   st->print(BULLET"inner classes:     "); inner_classes()->print_value_on(st);     st->cr();
   st->print(BULLET"nest members:     "); nest_members()->print_value_on(st);     st->cr();
-  // TBD - need to check for NULL?
-  st->print(BULLET"record components:     "); record_components()->print_value_on(st);     st->cr();
+  if (record_components() != NULL) {
+    st->print(BULLET"record components:     "); record_components()->print_value_on(st);     st->cr();
+  }
   if (java_mirror() != NULL) {
     st->print(BULLET"java mirror:       ");
     java_mirror()->print_value_on(st);
--- a/src/hotspot/share/oops/recordComponent.hpp	Thu Oct 17 13:42:17 2019 -0700
+++ b/src/hotspot/share/oops/recordComponent.hpp	Fri Oct 18 11:49:23 2019 +0000
@@ -63,12 +63,19 @@
     void deallocate_contents(ClassLoaderData* loader_data);
 
     u2 name_index() const { return _name_index; }
+    void set_name_index(u2 name_index) { _name_index = name_index; }
 
     u2 descriptor_index() const { return _descriptor_index; }
+    void set_descriptor_index(u2 descriptor_index) {
+      _descriptor_index = descriptor_index;
+    }
 
     u2 attributes_count() const { return _attributes_count; }
 
     u2 generic_signature_index() const { return _generic_signature_index; }
+    void set_generic_signature_index(u2 generic_signature_index) {
+      _generic_signature_index = generic_signature_index;
+    }
 
     AnnotationArray* annotations() const { return _annotations; }
     AnnotationArray* type_annotations() const { return _type_annotations; }
--- a/src/hotspot/share/prims/jvm.cpp	Thu Oct 17 13:42:17 2019 -0700
+++ b/src/hotspot/share/prims/jvm.cpp	Fri Oct 18 11:49:23 2019 +0000
@@ -1682,9 +1682,16 @@
 JVM_END
 
 JVM_ENTRY(jboolean, JVM_IsRecord(JNIEnv *env, jclass cls))
+{
   JVMWrapper("JVM_IsRecord");
-  InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)));
-  return k->is_record();
+  Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls));
+  if (k != NULL && k->is_instance_klass()) {
+    InstanceKlass* ik = InstanceKlass::cast(k);
+    return ik->is_record();
+  } else {
+    return false;
+  }
+}
 JVM_END
 
 JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass))
--- a/src/hotspot/share/prims/jvmti.xml	Thu Oct 17 13:42:17 2019 -0700
+++ b/src/hotspot/share/prims/jvmti.xml	Fri Oct 18 11:49:23 2019 +0000
@@ -7633,8 +7633,8 @@
         (unless explicitly prohibited).
         The retransformation must not add, remove or rename fields or methods, change the
         signatures of methods, change modifiers, or change inheritance.
-        The retransformation must not change the <code>NestHost</code> or
-        <code>NestMembers</code> attributes.
+        The retransformation must not change the <code>NestHost</code>,
+        <code>NestMembers</code>, or <code>Record</code> attributes.
         These restrictions may be lifted in future versions.
         See the error return description below for information on error codes
         returned if an unsupported retransformation is attempted.
@@ -7786,8 +7786,8 @@
         (unless explicitly prohibited).
         The redefinition must not add, remove or rename fields or methods, change the
         signatures of methods, change modifiers, or change inheritance.
-        The retransformation must not change the <code>NestHost</code> or
-        <code>NestMembers</code> attributes.
+        The retransformation must not change the <code>NestHost</code>,
+        <code>NestMembers</code>, or <code>Record</code> attributes.
         These restrictions may be lifted in future versions.
 	See the error return description below for information on error codes
 	returned if an unsupported redefinition is attempted.
@@ -14974,6 +14974,11 @@
         - The specified thread must be suspended or must be the current thread.
           (It was not allowed to be the current thread before.)
   </change>
+  <change date="10 October 2019" version="14.0.0">
+      Minor update for new class file Record attribute:
+        - Specify that RedefineClasses and RetransformClasses are not allowed
+          to change the class file Record attribute.
+  </change>
 </changehistory>
 
 </specification>
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp	Thu Oct 17 13:42:17 2019 -0700
+++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp	Fri Oct 18 11:49:23 2019 +0000
@@ -40,10 +40,12 @@
 #include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
+#include "oops/annotations.hpp"
 #include "oops/constantPool.hpp"
 #include "oops/fieldStreams.hpp"
 #include "oops/klassVtable.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/recordComponent.hpp"
 #include "prims/jvmtiImpl.hpp"
 #include "prims/jvmtiRedefineClasses.hpp"
 #include "prims/jvmtiThreadState.inline.hpp"
@@ -293,10 +295,6 @@
     return false;
   }
 
-  // Cannot redefine or retransform a record.
-  if (InstanceKlass::cast(k)->is_record()) {
-    /* TBD: can we support redefining a record with annotations ? */  return false;
-  }
   return true;
 }
 
@@ -790,6 +788,69 @@
   return JVMTI_ERROR_NONE;
 }
 
+// Return an error status if the class Record attribute was changed.
+static jvmtiError check_record_attribute(InstanceKlass* the_class, InstanceKlass* scratch_class) {
+  // Get lists of record components.
+  Array<RecordComponent*>* the_record = the_class->record_components();
+  Array<RecordComponent*>* scr_record = scratch_class->record_components();
+  bool the_record_exists = the_record != NULL;
+  bool scr_record_exists = scr_record != NULL;
+
+  if (the_record_exists && scr_record_exists) {
+    int the_num_components = the_record->length();
+    int scr_num_components = scr_record->length();
+    if (the_num_components != scr_num_components) {
+      log_trace(redefine, class, record)
+        ("redefined class %s attribute change error: Record num_components=%d changed to num_components=%d",
+         the_class->external_name(), the_num_components, scr_num_components);
+      return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+    }
+
+    // Compare each field in each record component.
+    ConstantPool* the_cp =  the_class->constants();
+    ConstantPool* scr_cp =  scratch_class->constants();
+    for (int x = 0; x < the_num_components; x++) {
+      RecordComponent* the_component = the_record->at(x);
+      RecordComponent* scr_component = scr_record->at(x);
+      const Symbol* const the_name = the_cp->symbol_at(the_component->name_index());
+      const Symbol* const scr_name = scr_cp->symbol_at(scr_component->name_index());
+      const Symbol* const the_descr = the_cp->symbol_at(the_component->descriptor_index());
+      const Symbol* const scr_descr = scr_cp->symbol_at(scr_component->descriptor_index());
+      if (the_name != scr_name || the_descr != scr_descr) {
+        log_trace(redefine, class, record)
+          ("redefined class %s attribute change error: Record name_index, descriptor_index, and/or attributes_count changed",
+           the_class->external_name());
+        return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+      }
+
+      int the_gen_sig = the_component->generic_signature_index();
+      int scr_gen_sig = scr_component->generic_signature_index();
+      const Symbol* const the_gen_sig_sym = (the_gen_sig == 0 ? NULL :
+        the_cp->symbol_at(the_component->generic_signature_index()));
+      const Symbol* const scr_gen_sig_sym = (scr_gen_sig == 0 ? NULL :
+        scr_cp->symbol_at(scr_component->generic_signature_index()));
+      if (the_gen_sig_sym != scr_gen_sig_sym) {
+        log_trace(redefine, class, record)
+          ("redefined class %s attribute change error: Record generic_signature attribute changed",
+           the_class->external_name());
+        return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+      }
+
+      // It's okay of a record component's annotations were changed.
+    }
+
+  } else if (the_record_exists ^ scr_record_exists) {
+    const char* action_str = (the_record_exists) ? "removed" : "added";
+    log_trace(redefine, class, record)
+      ("redefined class %s attribute change error: Record attribute %s",
+       the_class->external_name(), action_str);
+    return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
+  }
+
+  return JVMTI_ERROR_NONE;
+}
+
+
 static bool can_add_or_delete(Method* m) {
       // Compatibility mode
   return (AllowRedefinitionToAddDeleteMethods &&
@@ -843,6 +904,12 @@
     return err;
   }
 
+  // Check whether the Record attribute has been changed.
+  err = check_record_attribute(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();
@@ -1716,6 +1783,12 @@
     return false;
   }
 
+  // rewrite constant pool references in the Record attribute:
+  if (!rewrite_cp_refs_in_record_attribute(scratch_class, THREAD)) {
+    // 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
@@ -1814,6 +1887,46 @@
   return true;
 }
 
+// Rewrite constant pool references in the Record attribute.
+bool VM_RedefineClasses::rewrite_cp_refs_in_record_attribute(
+       InstanceKlass* scratch_class, TRAPS) {
+  Array<RecordComponent*>* components = scratch_class->record_components();
+  if (components != NULL) {
+    for (int i = 0; i < components->length(); i++) {
+      RecordComponent* component = components->at(i);
+      u2 cp_index = component->name_index();
+      component->set_name_index(find_new_index(cp_index));
+      cp_index = component->descriptor_index();
+      component->set_descriptor_index(find_new_index(cp_index));
+      cp_index = component->generic_signature_index();
+      if (cp_index != 0) {
+        component->set_generic_signature_index(find_new_index(cp_index));
+      }
+
+      AnnotationArray* annotations = component->annotations();
+      if (annotations != NULL && annotations->length() != 0) {
+        int byte_i = 0;  // byte index into annotations
+        if (!rewrite_cp_refs_in_annotations_typeArray(annotations, byte_i, THREAD)) {
+          log_debug(redefine, class, annotation)("bad record_component_annotations at %d", i);
+          // propagate failure back to caller
+          return false;
+        }
+      }
+
+      AnnotationArray* type_annotations = component->type_annotations();
+      if (type_annotations != NULL && type_annotations->length() != 0) {
+        int byte_i = 0;  // byte index into annotations
+        if (!rewrite_cp_refs_in_annotations_typeArray(type_annotations, byte_i, THREAD)) {
+          log_debug(redefine, class, annotation)("bad record_component_type_annotations at %d", i);
+          // propagate failure back to caller
+          return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
 // Rewrite constant pool references in the methods.
 bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
        InstanceKlass* scratch_class, TRAPS) {
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.hpp	Thu Oct 17 13:42:17 2019 -0700
+++ b/src/hotspot/share/prims/jvmtiRedefineClasses.hpp	Fri Oct 18 11:49:23 2019 +0000
@@ -472,6 +472,7 @@
   bool rewrite_cp_refs_in_fields_annotations(
     InstanceKlass* scratch_class, TRAPS);
   bool rewrite_cp_refs_in_nest_attributes(InstanceKlass* scratch_class);
+  bool rewrite_cp_refs_in_record_attribute(InstanceKlass* scratch_class, TRAPS);
   void rewrite_cp_refs_in_method(methodHandle method,
     methodHandle * new_method_p, TRAPS);
   bool rewrite_cp_refs_in_methods(InstanceKlass* scratch_class, TRAPS);
--- a/src/java.instrument/share/native/libinstrument/JavaExceptions.c	Thu Oct 17 13:42:17 2019 -0700
+++ b/src/java.instrument/share/native/libinstrument/JavaExceptions.c	Fri Oct 18 11:49:23 2019 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -216,7 +216,7 @@
 
         case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED:
                 throwableClassName = "java/lang/UnsupportedOperationException";
-                message = "class redefinition failed: attempted to change the class NestHost or NestMembers attribute";
+                message = "class redefinition failed: attempted to change the class NestHost, NestMembers, or Record attribute";
                 break;
 
         case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/records/RedefineRecord.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @library /test/lib
+ * @summary Test that a class that is a record can be redefined.
+ * @modules java.base/jdk.internal.misc
+ * @modules java.instrument
+ *          jdk.jartool/sun.tools.jar
+ * @run main RedefineRecord buildagent
+ * @run main/othervm/timeout=6000  RedefineRecord runtest
+ */
+
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.lang.RuntimeException;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.Instrumentation;
+import java.security.ProtectionDomain;
+import java.lang.instrument.IllegalClassFormatException;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class RedefineRecord {
+
+    record Tester(int x, String y, long z) { }
+
+    static class LoggingTransformer implements ClassFileTransformer {
+
+        public LoggingTransformer() {}
+
+        public byte[] transform(ClassLoader loader, String className,
+                                Class classBeingRedefined, ProtectionDomain protectionDomain,
+                                byte[] classfileBuffer) throws IllegalClassFormatException {
+            return null;
+        }
+    }
+
+    public static void premain(String agentArgs, Instrumentation inst) throws Exception {
+        LoggingTransformer t = new LoggingTransformer();
+        inst.addTransformer(t, true);
+        {
+            Class demoClass = Class.forName("RedefineRecord$Tester");
+            inst.retransformClasses(demoClass);
+        }
+    }
+    private static void buildAgent() {
+        try {
+            ClassFileInstaller.main("RedefineRecord");
+        } catch (Exception e) {
+            throw new RuntimeException("Could not write agent classfile", e);
+        }
+
+        try {
+            PrintWriter pw = new PrintWriter("MANIFEST.MF");
+            pw.println("Premain-Class: RedefineRecord");
+            pw.println("Agent-Class: RedefineRecord");
+            pw.println("Can-Redefine-Classes: true");
+            pw.println("Can-Retransform-Classes: true");
+            pw.close();
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException("Could not write manifest file for the agent", e);
+        }
+
+        sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
+        if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineRecord.class" })) {
+            throw new RuntimeException("Could not write the agent jar file");
+        }
+    }
+    public static void main(String argv[]) throws Exception {
+        if (argv.length == 1 && argv[0].equals("buildagent")) {
+            buildAgent();
+            return;
+        }
+        if (argv.length == 1 && argv[0].equals("runtest")) {
+            String[] javaArgs1 = { "-XX:MetaspaceSize=12m", "-XX:MaxMetaspaceSize=12m",
+                                   "-javaagent:redefineagent.jar", "RedefineRecord"};
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(javaArgs1);
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+            output.shouldNotContain("processing of -javaagent failed");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/Host/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host() {
+    public static String getID() { return "Host/Host.java";}
+    public int m() {
+        return 1; // original class
+    }
+    public Host(int A, long B, char C) {
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/Host/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host() {
+    public static String getID() { return "Host/redef/Host.java";}
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostA/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A) {
+    public static String getID() { return "HostA/Host.java";}
+    public int m() {
+        return 1; // original class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostA/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A) {
+    public static String getID() { return "HostA/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostAB/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A, long B) {
+    public static String getID() { return "HostAB/Host.java";}
+    public int m() {
+        return 1; // original class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+        this.B = B;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostAB/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A, long B) {
+    public static String getID() { return "HostAB/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+        this.B = B;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostABC/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A, long B, char C) {
+    public static String getID() { return "HostABC/Host.java";}
+    public int m() {
+        return 1; // original class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+        this.B = B;
+        this.C = C;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostABC/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A, long B, char C) {
+    public static String getID() { return "HostABC/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+        this.B = B;
+        this.C = C;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostABCD/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A, long B, char C, String D) {
+    public static String getID() { return "HostABCD/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+        this.B = B;
+        this.C = C;
+        this.D = "abc";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostABD/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A, long B, String D) {
+    public static String getID() { return "HostABD/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+        this.B = B;
+        this.D = "abc";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostAC/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A, char C) {
+    public static String getID() { return "HostAC/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+        this.C = C;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostACB/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(int A, char C, long B) {
+    public static String getID() { return "HostACB/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+        this.C = C;
+        this.B = B;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostB/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(long B) {
+    public static String getID() { return "HostB/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.B = B;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostBA/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(long B, int A) {
+    public static String getID() { return "HostBA/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.A = A;
+        this.B = B;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostBAC/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(long B, int A, char C) {
+    public static String getID() { return "HostBAC/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.B = B;
+        this.A = A;
+        this.C = C;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostBCA/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(long B, char C, int A) {
+    public static String getID() { return "HostBCA/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.B = B;
+        this.C = C;
+        this.A = A;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostCAB/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(char C, int A, long B) {
+    public static String getID() { return "HostCAB/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.C = C;
+        this.A = A;
+        this.B = B;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/HostCBA/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(char C, long B, int A) {
+    public static String getID() { return "HostCBA/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+    public Host(int A, long B, char C) {
+        this.C = C;
+        this.B = B;
+        this.A = A;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/TestRecordAttr.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Class redefinition must preclude changes to Record attributes
+ * @comment This is a copy of test/jdk/java/lang/instrument/RedefineNestmateAttr/
+ * @comment modified for records and the Record attribute.
+ *
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @modules java.compiler
+ *          java.instrument
+ *          jdk.jartool/sun.tools.jar
+ * @compile ../NamedBuffer.java
+ * @run main RedefineClassHelper
+ * @compile Host/Host.java
+ * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttr Host
+ * @compile HostA/Host.java
+ * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttr HostA
+ * @compile HostAB/Host.java
+ * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttr HostAB
+ * @compile HostABC/Host.java
+ * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttr HostABC
+ */
+
+/* Test Description
+
+The basic test class is call Host and we have variants that have zero or more
+record components.  Each variant of Host is defined in source code in its own
+directory i.e.
+
+Host/Host.java defines zero record components
+Record HostA/Host.java has record component "int A"
+Record HostAB/Host.java has record components "int A" and "long B" (in that order)
+Record HostABC/Host.java has record components "int A", "long B", and "char C" (in that order)
+etc.
+
+Each Host class has the form:
+
+  public record Host <zero or more record components> {
+    public static String getID() { return "<directory name>/Host.java"; }
+
+    public int m() {
+        return 1; // original class
+    }
+
+    public Host(int A, long B, char C) {
+         ...
+    }
+  }
+
+Under each directory is a directory "redef" with a modified version of the Host
+class that changes the ID to e.g. Host/redef/Host.java, and the method m()
+returns 2. This allows us to check we have the redefined class loaded.
+
+Using Host' to represent the redefined version we test redefinition
+combinations as follows:
+
+Host:
+  Host -> Host'  - succeeds m() returns 2
+  Host -> HostA' - fails - added a record component
+
+HostA:
+  HostA -> HostA'  - succeeds m() returns 2
+  HostA -> Host'   - fails - removed a record component
+  HostA -> HostAB' - fails - added a record component
+  HostA -> HostB'  - fails - replaced a record component
+
+HostAB:
+  HostAB -> HostAB'  - succeeds m() returns 2
+  HostAB -> HostBA'  - fails - reordered record components
+  HostAB -> HostA'   - fails - removed a record component
+  HostAB -> HostABC' - fails - added a record component
+  HostAB -> HostAC'  - fails - replaced a record component
+
+HostABC:
+  HostABC -> HostABC'  - succeeds m() returns 2
+  HostABC -> HostACB'  - fails - reordered record components
+  HostABC -> HostBAC'  - fails - reordered record components
+  HostABC -> HostBCA'  - fails - reordered record components
+  HostABC -> HostCAB'  - fails - reordered record components
+  HostABC -> HostCBA'  - fails - reordered record components
+  HostABC -> HostAB'   - fails - removed a record component
+  HostABC -> HostABCD' - fails - added a record component
+  HostABC -> HostABD'  - fails - replaced a record component
+
+More than three record components doesn't add to the code coverage so
+we stop here.
+
+Note that we always try to load the redefined version even when we expect it
+to fail.
+
+We can only directly load one class Host per classloader, so to run all the
+groups we either need to use new classloaders, or we reinvoke the test
+requesting a different primary directory. We chose the latter using
+multiple @run tags. So we preceed as follows:
+
+ @compile Host/Host.java
+ @run TestRecordAttr Host
+ @compile HostA/Host.java  - replaces previous Host.class
+ @run TestRecordAttr HostA
+ @compile HostAB/Host.java  - replaces previous Host.class
+ @run TestRecordAttr HostAB
+etc.
+
+Within the test we directly compile redefined versions of the classes,
+using CompilerUtil, and then read the .class file directly as a byte[]
+to use with the RedefineClassHelper.
+
+*/
+
+import java.io.File;
+import java.io.FileInputStream;
+import jdk.test.lib.ByteCodeLoader;
+import jdk.test.lib.compiler.CompilerUtils;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+import static jdk.test.lib.Asserts.assertTrue;
+
+public class TestRecordAttr {
+
+    static final String SRC = System.getProperty("test.src");
+    static final String DEST = System.getProperty("test.classes");
+    static final boolean VERBOSE = Boolean.getBoolean("verbose");
+
+    public static void main(String[] args) throws Throwable {
+        String origin = args[0];
+        System.out.println("Testing original Host class from " + origin);
+
+        // Make sure the Host class loaded directly is an original version
+        // and from the expected location. Use a ctor common to all Host
+        // classes.
+        Host h = new Host(3, 4, 'a');
+        assertTrue(h.m() == 1);
+        assertTrue(Host.getID().startsWith(origin + "/"));
+
+        String[] badTransforms;  // directories of bad classes
+        String[] goodTransforms; // directories of good classes
+
+        switch (origin) {
+        case "Host":
+            badTransforms = new String[] {
+                "HostA" // add record component
+            };
+            goodTransforms = new String[] {
+                origin
+            };
+            break;
+
+        case "HostA":
+            badTransforms = new String[] {
+                "Host",   // remove record component
+                "HostAB", // add record component
+                "HostB"   // change record component
+            };
+            goodTransforms = new String[] {
+                origin
+            };
+            break;
+
+        case "HostAB":
+            badTransforms = new String[] {
+                "HostA",   // remove record component
+                "HostABC", // add record component
+                "HostAC",  // change record component
+                "HostBA"   // reorder record components
+            };
+            goodTransforms = new String[] {
+                origin,
+            };
+            break;
+
+        case "HostABC":
+            badTransforms = new String[] {
+                "HostAB",   // remove record component
+                "HostABCD", // add record component
+                "HostABD",  // change record component
+                "HostACB",  // reorder record components
+                "HostBAC",  // reorder record components
+                "HostBCA",  // reorder record components
+                "HostCAB",  // reorder record components
+                "HostCBA"   // reorder record components
+            };
+            goodTransforms = new String[] {
+                origin
+            };
+            break;
+
+        default: throw new Error("Unknown test directory: " + origin);
+        }
+
+        // Compile and check bad transformations
+        checkBadTransforms(Host.class, badTransforms);
+
+        // Compile and check good transformations
+        checkGoodTransforms(Host.class, goodTransforms);
+    }
+
+    static void checkGoodTransforms(Class<?> c, String[] dirs) throws Throwable {
+        for (String dir : dirs) {
+            dir += "/redef";
+            System.out.println("Trying good retransform from " + dir);
+            byte[] buf = bytesForHostClass(dir);
+            RedefineClassHelper.redefineClass(c, buf);
+
+            // Test redefintion worked
+            Host h = new Host(3, 4, 'a');
+            assertTrue(h.m() == 2);
+            if (VERBOSE) System.out.println("Redefined ID: " + Host.getID());
+            assertTrue(Host.getID().startsWith(dir));
+        }
+    }
+
+    static void checkBadTransforms(Class<?> c, String[] dirs) throws Throwable {
+        for (String dir : dirs) {
+            dir += "/redef";
+            System.out.println("Trying bad retransform from " + dir);
+            byte[] buf = bytesForHostClass(dir);
+            try {
+                RedefineClassHelper.redefineClass(c, buf);
+                throw new Error("Retransformation from directory " + dir +
+                                " succeeded unexpectedly");
+            }
+            catch (UnsupportedOperationException uoe) {
+                if (uoe.getMessage().contains("attempted to change the class") &&
+                    uoe.getMessage().contains(" Record")) {
+                    System.out.println("Got expected exception " + uoe);
+                }
+                else throw new Error("Wrong UnsupportedOperationException", uoe);
+            }
+        }
+    }
+
+    static byte[] bytesForHostClass(String dir) throws Throwable {
+        compile("/" + dir);
+        File clsfile = new File(DEST + "/" + dir + "/Host.class");
+        if (VERBOSE) System.out.println("Reading bytes from " + clsfile);
+        byte[] buf = null;
+        try (FileInputStream str = new FileInputStream(clsfile)) {
+            return buf = NamedBuffer.loadBufferFromStream(str);
+        }
+    }
+
+    static void compile(String dir) throws Throwable {
+        File src = new File(SRC + dir);
+        File dst = new File(DEST + dir);
+        if (VERBOSE) System.out.println("Compiling from: " + src + "\n" +
+                                        "            to: " + dst);
+        CompilerUtils.compile(src.toPath(),
+                              dst.toPath(),
+                              false /* don't recurse */,
+                              new String[0]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/Host/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(java.lang.Object a, java.lang.String b) {
+    public static String getID() { return "Host/redef/Host.java";}
+    public int m() {
+        return 1; // redefined class
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/Host/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host(java.lang.Object a, java.lang.String b) {
+    public static String getID() { return "Host/redef/Host.java";}
+    public int m() {
+        return 2; // redefined class
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/HostA/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host<T>(T a, java.lang.String b) {
+    public static String getID() { return "HostA/Host.java";}
+    public int m() {
+        return 1; // original class
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/HostA/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host<T>(T a, java.lang.String b) {
+    public static String getID() { return "HostA/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/HostB/redef/Host.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+public record Host<X>(X a, java.lang.String b) {
+    public static String getID() { return "HostB/redef/Host.java"; }
+    public int m() {
+        return 2; // redefined class
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/TestRecordAttrGenericSig.java	Fri Oct 18 11:49:23 2019 +0000
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Class redefinition must preclude changes to Record attributes
+ * @comment This is a copy of test/jdk/java/lang/instrument/RedefineNestmateAttr/
+ * @comment modified for records and the Record attribute.
+ *
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @modules java.compiler
+ *          java.instrument
+ *          jdk.jartool/sun.tools.jar
+ * @compile ../NamedBuffer.java
+ * @run main RedefineClassHelper
+ * @compile Host/Host.java
+ * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttrGenericSig Host
+ * @compile HostA/Host.java
+ * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttrGenericSig HostA
+ */
+
+/* Test Description
+
+The basic test class is call Host and we have variants that have record components
+with no or different generic_signature attributes.  Each variant of Host is defined
+in source code in its own directory i.e.
+
+Host/Host.java has record components with no generic signature attributes.
+HostA/Host.java has a record component with generic signature "TT".
+HostB/Host.java has a record component with generic signature "TX".
+
+Each Host class has the form:
+
+  public record Host <possible generic>(<java.lang.Object or generic> a, java.lang.String b) {
+    public static String getID() { return "<directory name>/Host.java"; }
+
+    public int m() {
+        return 1; // original class
+    }
+
+  }
+
+Under each directory is a directory "redef" with a modified version of the Host
+class that changes the ID to e.g. Host/redef/Host.java, and the method m()
+returns 2. This allows us to check we have the redefined class loaded.
+
+Using Host' to represent the redefined version we test redefinition
+combinations as follows:
+
+Host:
+  Host -> Host'  - succeeds m() returns 2
+  Host -> HostA' - fails - added a generic signature
+
+HostA:
+  HostA -> HostA'  - succeeds m() returns 2
+  HostA -> Host'   - fails - removed a generic signature
+  HostA -> HostB'  - fails - replaced a generic signature
+
+Note that we always try to load the redefined version even when we expect it
+to fail.
+
+We can only directly load one class Host per classloader, so to run all the
+groups we either need to use new classloaders, or we reinvoke the test
+requesting a different primary directory. We chose the latter using
+multiple @run tags. So we preceed as follows:
+
+ @compile Host/Host.java
+ @run TestRecordAttrGenericSig Host
+ @compile HostA/Host.java  - replaces previous Host.class
+ @run TestRecordAttrGenericSig HostA
+etc.
+
+Within the test we directly compile redefined versions of the classes,
+using CompilerUtil, and then read the .class file directly as a byte[]
+to use with the RedefineClassHelper.
+
+*/
+
+import java.io.File;
+import java.io.FileInputStream;
+import jdk.test.lib.ByteCodeLoader;
+import jdk.test.lib.compiler.CompilerUtils;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+import static jdk.test.lib.Asserts.assertTrue;
+
+public class TestRecordAttrGenericSig {
+
+    static final String SRC = System.getProperty("test.src");
+    static final String DEST = System.getProperty("test.classes");
+    static final boolean VERBOSE = Boolean.getBoolean("verbose");
+
+    public static void main(String[] args) throws Throwable {
+        String origin = args[0];
+        System.out.println("Testing original Host class from " + origin);
+
+        // Make sure the Host class loaded directly is an original version
+        // and from the expected location. Use a ctor common to all Host
+        // classes.
+        Host h = new Host("abc", "def");
+        assertTrue(h.m() == 1);
+        assertTrue(Host.getID().startsWith(origin + "/"));
+
+        String[] badTransforms;  // directories of bad classes
+        String[] goodTransforms; // directories of good classes
+
+        switch (origin) {
+        case "Host":
+            badTransforms = new String[] {
+                "HostA" // add a generic signature to a record component
+            };
+            goodTransforms = new String[] {
+                origin
+            };
+            break;
+
+        case "HostA":
+            badTransforms = new String[] {
+                "Host",   // remove a generic signature from a record component
+                "HostB"   // change a record component generic signature
+            };
+            goodTransforms = new String[] {
+                origin
+            };
+            break;
+
+        default: throw new Error("Unknown test directory: " + origin);
+        }
+
+        // Compile and check bad transformations
+        checkBadTransforms(Host.class, badTransforms);
+
+        // Compile and check good transformations
+        checkGoodTransforms(Host.class, goodTransforms);
+    }
+
+    static void checkGoodTransforms(Class<?> c, String[] dirs) throws Throwable {
+        for (String dir : dirs) {
+            dir += "/redef";
+            System.out.println("Trying good retransform from " + dir);
+            byte[] buf = bytesForHostClass(dir);
+            RedefineClassHelper.redefineClass(c, buf);
+
+            // Test redefintion worked
+            Host h = new Host("abc", "def");
+            assertTrue(h.m() == 2);
+            if (VERBOSE) System.out.println("Redefined ID: " + Host.getID());
+            assertTrue(Host.getID().startsWith(dir));
+        }
+    }
+
+    static void checkBadTransforms(Class<?> c, String[] dirs) throws Throwable {
+        for (String dir : dirs) {
+            dir += "/redef";
+            System.out.println("Trying bad retransform from " + dir);
+            byte[] buf = bytesForHostClass(dir);
+            try {
+                RedefineClassHelper.redefineClass(c, buf);
+                throw new Error("Retransformation from directory " + dir +
+                                " succeeded unexpectedly");
+            }
+            catch (UnsupportedOperationException uoe) {
+                if (uoe.getMessage().contains("attempted to change the class") &&
+                    uoe.getMessage().contains(" Record")) {
+                    System.out.println("Got expected exception " + uoe);
+                }
+                else throw new Error("Wrong UnsupportedOperationException", uoe);
+            }
+        }
+    }
+
+    static byte[] bytesForHostClass(String dir) throws Throwable {
+        compile("/" + dir);
+        File clsfile = new File(DEST + "/" + dir + "/Host.class");
+        if (VERBOSE) System.out.println("Reading bytes from " + clsfile);
+        byte[] buf = null;
+        try (FileInputStream str = new FileInputStream(clsfile)) {
+            return buf = NamedBuffer.loadBufferFromStream(str);
+        }
+    }
+
+    static void compile(String dir) throws Throwable {
+        File src = new File(SRC + dir);
+        File dst = new File(DEST + dir);
+        if (VERBOSE) System.out.println("Compiling from: " + src + "\n" +
+                                        "            to: " + dst);
+        CompilerUtils.compile(src.toPath(),
+                              dst.toPath(),
+                              false /* don't recurse */,
+                              new String[0]);
+    }
+}