changeset 58344:e7a60c0654d6 records

records implementation
author vromero
date Wed, 16 Oct 2019 17:02:29 -0400
parents 42f09686678d
children 24e7f63093ac 66452d80d350
files make/hotspot/symbols/symbols-unix src/hotspot/share/classfile/classFileParser.cpp src/hotspot/share/classfile/classFileParser.hpp src/hotspot/share/classfile/javaClasses.cpp src/hotspot/share/classfile/javaClasses.hpp src/hotspot/share/classfile/systemDictionary.hpp src/hotspot/share/classfile/vmSymbols.hpp src/hotspot/share/include/jvm.h src/hotspot/share/memory/allocation.hpp src/hotspot/share/memory/heapInspection.hpp src/hotspot/share/memory/metaspaceShared.cpp src/hotspot/share/oops/instanceKlass.cpp src/hotspot/share/oops/instanceKlass.hpp src/hotspot/share/oops/recordComponent.cpp src/hotspot/share/oops/recordComponent.hpp src/hotspot/share/prims/jvm.cpp src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp src/hotspot/share/prims/jvmtiClassFileReconstituter.hpp src/hotspot/share/prims/jvmtiRedefineClasses.cpp src/java.base/share/classes/java/io/ObjectInputStream.java src/java.base/share/classes/java/io/ObjectOutputStream.java src/java.base/share/classes/java/io/ObjectStreamClass.java src/java.base/share/classes/java/lang/Class.java src/java.base/share/classes/java/lang/Record.java src/java.base/share/classes/java/lang/annotation/ElementType.java src/java.base/share/classes/java/lang/reflect/RecordComponent.java src/java.base/share/classes/java/lang/runtime/ObjectMethods.java src/java.base/share/classes/module-info.java src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java src/java.base/share/native/libjava/Class.c src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java src/java.compiler/share/classes/javax/lang/model/SourceVersion.java src/java.compiler/share/classes/javax/lang/model/element/Element.java src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java src/java.compiler/share/classes/javax/lang/model/element/RecordComponentElement.java src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java src/java.compiler/share/classes/javax/lang/model/element/package-info.java src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor6.java src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor7.java src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor8.java src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor7.java src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor8.java src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java src/java.compiler/share/classes/javax/lang/model/util/Elements.java src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor7.java src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor8.java src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor9.java src/jdk.compiler/share/classes/com/sun/source/doctree/AccessorTree.java src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Accessors.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/SymbolMetadata.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolConstant.java src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PubapiVisitor.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ClassWriter.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Resources.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/AccessorTaglet.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/ClassUseMapper.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/TypeElementCatalog.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/VisibleMemberTable.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocMemberEnter.java src/jdk.jdeps/share/classes/com/sun/tools/classfile/Attribute.java src/jdk.jdeps/share/classes/com/sun/tools/classfile/ClassWriter.java src/jdk.jdeps/share/classes/com/sun/tools/classfile/Record_attribute.java src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java test/hotspot/jtreg/runtime/records/recordAttribute.jcod test/hotspot/jtreg/runtime/records/recordAttributeTest.java test/hotspot/jtreg/runtime/records/recordReflectionTest.java test/jdk/java/io/Serializable/records/AbsentStreamValuesTest.java test/jdk/java/io/Serializable/records/BadValues.java test/jdk/java/io/Serializable/records/BasicRecordSer.java test/jdk/java/io/Serializable/records/ConstructorAccessTest.java test/jdk/java/io/Serializable/records/ConstructorPermissionTest.java test/jdk/java/io/Serializable/records/CycleTest.java test/jdk/java/io/Serializable/records/ProhibitedMethods.java test/jdk/java/io/Serializable/records/ReadResolveTest.java test/jdk/java/io/Serializable/records/RecordClassTest.java test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java test/jdk/java/io/Serializable/records/StreamRefTest.java test/jdk/java/io/Serializable/records/ThrowingConstructorTest.java test/jdk/java/io/Serializable/records/WriteReplaceTest.java test/jdk/java/io/Serializable/records/empty_security.policy test/jdk/java/io/Serializable/records/migration/AbstractTest.java test/jdk/java/io/Serializable/records/migration/AssignableFrom.java test/jdk/java/io/Serializable/records/migration/AssignableFromTest.java test/jdk/java/io/Serializable/records/migration/DefaultValues.java test/jdk/java/io/Serializable/records/migration/DefaultValuesTest.java test/jdk/java/io/Serializable/records/migration/Point.java test/jdk/java/io/Serializable/records/migration/SuperStreamFields.java test/jdk/java/io/Serializable/records/migration/SuperStreamFieldsTest.java test/jdk/java/io/Serializable/records/migration/plain/AssignableFromImpl.java test/jdk/java/io/Serializable/records/migration/plain/DefaultValuesImpl.java test/jdk/java/io/Serializable/records/migration/plain/PointImpl.java test/jdk/java/io/Serializable/records/migration/plain/SuperStreamFieldsImpl.java test/jdk/java/io/Serializable/records/migration/record/AssignableFromImpl.java test/jdk/java/io/Serializable/records/migration/record/DefaultValuesImpl.java test/jdk/java/io/Serializable/records/migration/record/PointImpl.java test/jdk/java/io/Serializable/records/migration/record/SuperStreamFieldsImpl.java test/langtools/jdk/javadoc/doclet/testNewLanguageFeatures/TestNewLanguageFeatures.java test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/BinaryNode.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Coords.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Holder.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Node.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Point.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/SerializablePoint.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/SerializableProxy.java test/langtools/jdk/javadoc/doclet/testRecordTypes/jdk11/element-list test/langtools/jdk/javadoc/doclet/testTaglets/TestTaglets.out test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java test/langtools/jdk/javadoc/tool/api/basic/GetTask_DiagListenerTest.java test/langtools/jdk/javadoc/tool/modules/ModuleTestBase.java test/langtools/jdk/javadoc/tool/reporter_generates_warnings/pkg/MyDoclet.java test/langtools/jdk/jshell/CompletenessTest.java test/langtools/lib/annotations/annotations/classfile/ClassfileInspector.java test/langtools/lib/combo/tools/javac/combo/CompilationTestCase.java test/langtools/lib/combo/tools/javac/combo/Diagnostics.java test/langtools/lib/combo/tools/javac/combo/JavacTemplateTestBase.java test/langtools/lib/combo/tools/javac/combo/Template.java test/langtools/lib/combo/tools/javac/combo/TemplateTest.java test/langtools/tools/javac/6402516/CheckLocalElements.java test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java test/langtools/tools/javac/MethodParameters/AttributeVisitor.java test/langtools/tools/javac/annotations/repeatingAnnotations/NoTargetOnContainer.java test/langtools/tools/javac/annotations/repeatingAnnotations/NoTargetOnContainer2.java test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage1.out test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage2.out test/langtools/tools/javac/diags/examples.not-yet.txt test/langtools/tools/javac/diags/examples/Expected3.java test/langtools/tools/javac/diags/examples/IllegalStartOfStmt.java test/langtools/tools/javac/doctree/AccessorsTest.java test/langtools/tools/javac/doctree/DocCommentTester.java test/langtools/tools/javac/enum/EnumMembersOrder.out test/langtools/tools/javac/launcher/SourceLauncherTest.java test/langtools/tools/javac/lib/DPrinter.java test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java test/langtools/tools/javac/modules/AnnotationProcessing.java test/langtools/tools/javac/parser/JavacParserTest.java test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out test/langtools/tools/javac/parser/extend/TrialParser.java test/langtools/tools/javac/processing/model/TestSourceVersion.java test/langtools/tools/javac/processing/model/TestSymtabItems.java test/langtools/tools/javac/processing/model/element/TestElementKindPredicates.java test/langtools/tools/javac/processing/model/element/TestRecord.java test/langtools/tools/javac/processing/model/element/TestRecordDesugar.java test/langtools/tools/javac/records/BadRecord.java test/langtools/tools/javac/records/BadRecord.out test/langtools/tools/javac/records/MapAccessorToComponent.java test/langtools/tools/javac/records/OriginTest.java test/langtools/tools/javac/records/RecordCompilationTests.java test/langtools/tools/javac/records/RecordMemberTests.java test/langtools/tools/javac/records/RecordReflectionTest.java test/langtools/tools/javac/records/VarargsRecordsTest.java test/langtools/tools/javac/records/annotations/AnnoProcessorOnRecordsTest.java test/langtools/tools/javac/records/annotations/CheckingTypeAnnotationsOnRecords.java test/langtools/tools/javac/records/annotations/JavaxLangModelForRecords.java test/langtools/tools/javac/records/mandated_members/CheckRecordMembers.java test/langtools/tools/javac/records/mandated_members/read_resolve_method/CheckReadResolveMethodTest.java test/langtools/tools/javac/records/writeread/Record.java test/langtools/tools/javac/records/writeread/WriteReadTest.java test/langtools/tools/lib/toolbox/ToolBox.java test/lib/jdk/test/lib/ByteCodeLoader.java
diffstat 239 files changed, 15457 insertions(+), 713 deletions(-) [+]
line wrap: on
line diff
--- a/make/hotspot/symbols/symbols-unix	Wed Oct 16 17:00:39 2019 -0400
+++ b/make/hotspot/symbols/symbols-unix	Wed Oct 16 17:02:29 2019 -0400
@@ -122,6 +122,7 @@
 JVM_GetPrimitiveArrayElement
 JVM_GetProperties
 JVM_GetProtectionDomain
+JVM_GetRecordComponents
 JVM_GetSimpleBinaryName
 JVM_GetStackAccessControlContext
 JVM_GetSystemPackage
@@ -144,6 +145,7 @@
 JVM_IsInterface
 JVM_IsInterrupted
 JVM_IsPrimitiveClass
+JVM_IsRecord
 JVM_IsSameClassPackage
 JVM_IsSupportedJNIVersion
 JVM_IsThreadAlive
--- a/src/hotspot/share/classfile/classFileParser.cpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Wed Oct 16 17:02:29 2019 -0400
@@ -3223,6 +3223,159 @@
   return length;
 }
 
+u2 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* const cfs,
+                                                     const ConstantPool* cp,
+                                                     const u1* const record_attribute_start,
+                                                     TRAPS) {
+  const u1* const current_mark = cfs->current();
+  int components_count = 0;
+  unsigned int calculate_attr_size = 0;
+  if (record_attribute_start != NULL) {
+    cfs->set_current(record_attribute_start);
+    cfs->guarantee_more(2, CHECK_0);  // num of components
+    components_count = (int)cfs->get_u2_fast();
+    calculate_attr_size = 2;
+  }
+
+  Array<RecordComponent*>* const record_components =
+    MetadataFactory::new_array<RecordComponent*>(_loader_data, components_count, NULL, CHECK_0);
+  _record_components = record_components;
+
+  for (int x = 0; x < components_count; x++) {
+    cfs->guarantee_more(6, CHECK_0); // name_index, descriptor_index, attributes_count
+
+    const u2 name_index = cfs->get_u2_fast();
+    check_property(valid_symbol_at(name_index),
+      "Invalid constant pool index %u for name in Record attribute in class file %s",
+      name_index, CHECK_0);
+    const Symbol* const name = cp->symbol_at(name_index);
+    verify_legal_field_name(name, CHECK_0);
+
+    const u2 descriptor_index = cfs->get_u2_fast();
+    check_property(valid_symbol_at(descriptor_index),
+      "Invalid constant pool index %u for descriptor in Record attribute in class file %s",
+      descriptor_index, CHECK_0);
+    const Symbol* const descr = cp->symbol_at(descriptor_index);
+    verify_legal_field_signature(name, descr, CHECK_0);
+
+    const u2 attributes_count = cfs->get_u2_fast();
+    calculate_attr_size += 6;
+    u2 generic_sig_index = 0;
+    const u1* runtime_visible_annotations = NULL;
+    int runtime_visible_annotations_length = 0;
+    const u1* runtime_invisible_annotations = NULL;
+    int runtime_invisible_annotations_length = 0;
+    bool runtime_invisible_annotations_exists = false;
+    const u1* runtime_visible_type_annotations = NULL;
+    int runtime_visible_type_annotations_length = 0;
+    const u1* runtime_invisible_type_annotations = NULL;
+    int runtime_invisible_type_annotations_length = 0;
+    bool runtime_invisible_type_annotations_exists = false;
+
+    for (int y = 0; y < attributes_count; y++) {
+      cfs->guarantee_more(6, CHECK_0);  // attribute_name_index, attribute_length
+      const u2 attribute_name_index = cfs->get_u2_fast();
+      const u4 attribute_length = cfs->get_u4_fast();
+      calculate_attr_size += 6;
+      check_property(
+        valid_symbol_at(attribute_name_index),
+        "Invalid Record attribute name index %u in class file %s",
+        attribute_name_index, CHECK_0);
+
+      const Symbol* const attribute_name = cp->symbol_at(attribute_name_index);
+      if (attribute_name == vmSymbols::tag_signature()) {
+        if (generic_sig_index != 0) {
+          classfile_parse_error(
+            "Multiple Signature attributes for Record component in class file %s",
+            CHECK_0);
+        }
+        if (attribute_length != 2) {
+          classfile_parse_error(
+            "Invalid Signature attribute length %u in Record component in class file %s",
+            attribute_length, CHECK_0);
+        }
+        generic_sig_index = parse_generic_signature_attribute(cfs, CHECK_0);
+
+      } else if (attribute_name == vmSymbols::tag_runtime_visible_annotations()) {
+        if (runtime_visible_annotations != NULL) {
+          classfile_parse_error(
+            "Multiple RuntimeVisibleAnnotations attributes for Record component in class file %s", CHECK_0);
+        }
+        runtime_visible_annotations_length = attribute_length;
+        runtime_visible_annotations = cfs->current();
+
+        assert(runtime_visible_annotations != NULL, "null record component visible annotation");
+        cfs->guarantee_more(runtime_visible_annotations_length, CHECK_0);
+        cfs->skip_u1_fast(runtime_visible_annotations_length);
+
+      } else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
+        if (runtime_invisible_annotations_exists) {
+          classfile_parse_error(
+            "Multiple RuntimeInvisibleAnnotations attributes for Record component in class file %s", CHECK_0);
+        }
+        runtime_invisible_annotations_exists = true;
+        if (PreserveAllAnnotations) {
+          runtime_invisible_annotations_length = attribute_length;
+          runtime_invisible_annotations = cfs->current();
+          assert(runtime_invisible_annotations != NULL, "null record component invisible annotation");
+        }
+        cfs->skip_u1(attribute_length, CHECK_0);
+
+      } else if (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
+        if (runtime_visible_type_annotations != NULL) {
+          classfile_parse_error(
+            "Multiple RuntimeVisibleTypeAnnotations attributes for Record component in class file %s", CHECK_0);
+        }
+        runtime_visible_type_annotations_length = attribute_length;
+        runtime_visible_type_annotations = cfs->current();
+
+        assert(runtime_visible_type_annotations != NULL, "null record component visible type annotation");
+        cfs->guarantee_more(runtime_visible_type_annotations_length, CHECK_0);
+        cfs->skip_u1_fast(runtime_visible_type_annotations_length);
+
+      } else if (attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
+        if (runtime_invisible_type_annotations_exists) {
+          classfile_parse_error(
+            "Multiple RuntimeInvisibleTypeAnnotations attributes for Record component in class file %s", CHECK_0);
+        }
+        runtime_invisible_type_annotations_exists = true;
+        if (PreserveAllAnnotations) {
+          runtime_invisible_type_annotations_length = attribute_length;
+          runtime_invisible_type_annotations = cfs->current();
+          assert(runtime_invisible_type_annotations != NULL, "null record component invisible type annotation");
+        }
+        cfs->skip_u1(attribute_length, CHECK_0);
+
+      } else {
+        // Skip unknown attributes
+        cfs->skip_u1(attribute_length, CHECK_0);
+      }
+      calculate_attr_size += attribute_length;
+    } // End of attributes For loop
+
+    AnnotationArray* annotations = assemble_annotations(runtime_visible_annotations,
+                                                        runtime_visible_annotations_length,
+                                                        runtime_invisible_annotations,
+                                                        runtime_invisible_annotations_length,
+                                                        CHECK_0);
+    AnnotationArray* type_annotations = assemble_annotations(runtime_visible_type_annotations,
+                                                             runtime_visible_type_annotations_length,
+                                                             runtime_invisible_type_annotations,
+                                                             runtime_invisible_type_annotations_length,
+                                                             CHECK_0);
+
+    RecordComponent* record_component =
+      RecordComponent::allocate(_loader_data, name_index, descriptor_index,
+                                attributes_count, generic_sig_index,
+                                annotations, type_annotations, CHECK_0);
+    record_components->at_put(x, record_component);
+  }  // End of component processing loop
+
+  // Restore buffer's current position.
+  cfs->set_current(current_mark);
+  return calculate_attr_size;
+}
+
 void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) {
   set_class_synthetic_flag(true);
 }
@@ -3320,6 +3473,12 @@
                      CHECK);
 }
 
+bool ClassFileParser::supports_records() {
+  return _major_version == JAVA_14_VERSION /* TBD &&
+    _minor_version == JAVA_PREVIEW_MINOR_VERSION &&
+    Arguments::enable_preview() */ ;
+}
+
 void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
                                                  ConstantPool* cp,
                  ClassFileParser::ClassAnnotationCollector* parsed_annotations,
@@ -3338,6 +3497,7 @@
   bool parsed_innerclasses_attribute = false;
   bool parsed_nest_members_attribute = false;
   bool parsed_nest_host_attribute = false;
+  bool parsed_record_attribute = false;
   bool parsed_enclosingmethod_attribute = false;
   bool parsed_bootstrap_methods_attribute = false;
   const u1* runtime_visible_annotations = NULL;
@@ -3357,6 +3517,8 @@
   u2  enclosing_method_method_index = 0;
   const u1* nest_members_attribute_start = NULL;
   u4  nest_members_attribute_length = 0;
+  const u1* record_attribute_start = NULL;
+  u4  record_attribute_length = 0;
 
   // Iterate over attributes
   while (attributes_count--) {
@@ -3539,6 +3701,23 @@
                          "Nest-host class_info_index %u has bad constant type in class file %s",
                          class_info_index, CHECK);
           _nest_host = class_info_index;
+        } else if (tag == vmSymbols::tag_record()) {
+          // Skip over Record attribute if not supported or if super class is
+          // not java.lang.Record.
+          if (supports_records() &&
+              cp->klass_name_at(_super_class_index) == vmSymbols::java_lang_Record()) {
+            if (parsed_record_attribute) {
+              classfile_parse_error("Multiple Record attributes in class file %s", CHECK);
+            }
+            // Check that class is final and not abstract.
+            if (!_access_flags.is_final() || _access_flags.is_abstract()) {
+              classfile_parse_error("Record attribute in non-final or abstract class file %s", CHECK);
+            }
+            parsed_record_attribute = true;
+            record_attribute_start = cfs->current();
+            record_attribute_length = attribute_length;
+          }
+          cfs->skip_u1(attribute_length, CHECK);
         } else {
           // Unknown attribute
           cfs->skip_u1(attribute_length, CHECK);
@@ -3590,6 +3769,19 @@
     }
   }
 
+  if (parsed_record_attribute) {
+    const unsigned int calculated_attr_length = parse_classfile_record_attribute(
+                            cfs,
+                            cp,
+                            record_attribute_start,
+                            CHECK);
+    if (_need_verify) {
+      guarantee_property(record_attribute_length == calculated_attr_length,
+                         "Record attribute has wrong length in class file %s",
+                         CHECK);
+    }
+  }
+
   if (_max_bootstrap_specifier_index >= 0) {
     guarantee_property(parsed_bootstrap_methods_attribute,
                        "Missing BootstrapMethods attribute in class file %s", CHECK);
@@ -3644,7 +3836,8 @@
 // Transfer ownership of metadata allocated to the InstanceKlass.
 void ClassFileParser::apply_parsed_class_metadata(
                                             InstanceKlass* this_klass,
-                                            int java_fields_count, TRAPS) {
+                                            int java_fields_count,
+                                            TRAPS) {
   assert(this_klass != NULL, "invariant");
 
   _cp->set_pool_holder(this_klass);
@@ -3656,6 +3849,7 @@
   this_klass->set_nest_host_index(_nest_host);
   this_klass->set_local_interfaces(_local_interfaces);
   this_klass->set_annotations(_combined_annotations);
+  this_klass->set_record_components(_record_components);
   // Delay the setting of _transitive_interfaces until after initialize_supers() in
   // fill_instance_klass(). It is because the _transitive_interfaces may be shared with
   // its _super. If an OOM occurs while loading the current klass, its _super field
@@ -4526,6 +4720,7 @@
 static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
   assert(this_klass != NULL, "invariant");
   const Klass* const super = this_klass->super();
+
   if (super != NULL) {
 
     // If the loader is not the boot loader then throw an exception if its
@@ -4727,12 +4922,13 @@
   const bool is_super      = (flags & JVM_ACC_SUPER)      != 0;
   const bool is_enum       = (flags & JVM_ACC_ENUM)       != 0;
   const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0;
-  const bool major_gte_15  = _major_version >= JAVA_1_5_VERSION;
-
-  if ((is_abstract && is_final) ||
+  const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION;
+  const bool major_gte_14  = _major_version >= JAVA_14_VERSION;
+
+  if ((is_abstract && is_final && !major_gte_14) ||
       (is_interface && !is_abstract) ||
-      (is_interface && major_gte_15 && (is_super || is_enum)) ||
-      (!is_interface && major_gte_15 && is_annotation)) {
+      (is_interface && major_gte_1_5 && (is_super || is_enum)) ||
+      (!is_interface && major_gte_1_5 && is_annotation)) {
     ResourceMark rm(THREAD);
     Exceptions::fthrow(
       THREAD_AND_LOCATION,
@@ -5506,6 +5702,7 @@
   assert(NULL == _nest_members, "invariant");
   assert(NULL == _local_interfaces, "invariant");
   assert(NULL == _combined_annotations, "invariant");
+  assert(NULL == _record_components, "invariant");
 
   if (_has_final_method) {
     ik->set_has_final_method();
@@ -5787,6 +5984,7 @@
   _inner_classes(NULL),
   _nest_members(NULL),
   _nest_host(0),
+  _record_components(NULL),
   _local_interfaces(NULL),
   _transitive_interfaces(NULL),
   _combined_annotations(NULL),
@@ -5897,6 +6095,7 @@
   _combined_annotations = NULL;
   _class_annotations = _class_type_annotations = NULL;
   _fields_annotations = _fields_type_annotations = NULL;
+  _record_components = NULL;
 }
 
 // Destructor to clean up
@@ -5924,6 +6123,10 @@
     MetadataFactory::free_array<u2>(_loader_data, _nest_members);
   }
 
+  if (_record_components != NULL) {
+    InstanceKlass::deallocate_record_components(_loader_data, _record_components);
+  }
+
   // Free interfaces
   InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
                                        _local_interfaces, _transitive_interfaces);
--- a/src/hotspot/share/classfile/classFileParser.hpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/classfile/classFileParser.hpp	Wed Oct 16 17:02:29 2019 -0400
@@ -28,6 +28,7 @@
 #include "memory/referenceType.hpp"
 #include "oops/annotations.hpp"
 #include "oops/constantPool.hpp"
+#include "oops/recordComponent.hpp"
 #include "oops/typeArrayOop.hpp"
 #include "utilities/accessFlags.hpp"
 
@@ -98,6 +99,7 @@
   Array<u2>* _inner_classes;
   Array<u2>* _nest_members;
   u2 _nest_host;
+  Array<RecordComponent*>* _record_components;
   Array<InstanceKlass*>* _local_interfaces;
   Array<InstanceKlass*>* _transitive_interfaces;
   Annotations* _combined_annotations;
@@ -287,6 +289,13 @@
                                             const u1* const nest_members_attribute_start,
                                             TRAPS);
 
+  u2 parse_classfile_record_attribute(const ClassFileStream* const cfs,
+                                      const ConstantPool* cp,
+                                      const u1* const record_attribute_start,
+                                      TRAPS);
+
+  bool supports_records();
+
   void parse_classfile_attributes(const ClassFileStream* const cfs,
                                   ConstantPool* cp,
                                   ClassAnnotationCollector* parsed_annotations,
--- a/src/hotspot/share/classfile/javaClasses.cpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Wed Oct 16 17:02:29 2019 -0400
@@ -50,6 +50,7 @@
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
+#include "oops/recordComponent.hpp"
 #include "oops/typeArrayOop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/resolvedMethodTable.hpp"
@@ -3021,6 +3022,65 @@
   field->obj_field_put(annotations_offset, value);
 }
 
+oop java_lang_reflect_RecordComponent::create(InstanceKlass* holder, RecordComponent* component, TRAPS) {
+  // Allocate java.lang.reflect.RecordComponent instance
+  InstanceKlass* ik = SystemDictionary::RecordComponent_klass();
+  assert(ik != NULL, "must be loaded");
+  if (ik->should_be_initialized()) {
+    ik->initialize(CHECK_0);
+  }
+
+  Handle element = ik->allocate_instance_handle(CHECK_0);
+
+  Handle decl_class(THREAD, holder->java_mirror());
+  java_lang_reflect_RecordComponent::set_clazz(element(), decl_class());
+
+  Symbol* name = holder->constants()->symbol_at(component->name_index()); // name_index is a utf8
+  oop component_name = StringTable::intern(name, CHECK_0);
+  java_lang_reflect_RecordComponent::set_name(element(), component_name);
+
+  Symbol* type = holder->constants()->symbol_at(component->descriptor_index());
+  Handle component_type_h =
+    SystemDictionary::find_java_mirror_for_type(type, holder, SignatureStream::NCDFError, CHECK_0);
+  java_lang_reflect_RecordComponent::set_type(element(), component_type_h());
+
+  Method* accessor_method = NULL;
+  {
+    // Prepend "()" to type to create the full method signature.
+    ResourceMark rm(THREAD);
+    int sig_len = type->utf8_length() + 3; // "()" and null char
+    char* sig = NEW_RESOURCE_ARRAY(char, sig_len);
+    jio_snprintf(sig, sig_len, "()%s", type->as_C_string());
+    TempNewSymbol full_sig = SymbolTable::new_symbol(sig);
+    accessor_method = holder->find_instance_method(name, full_sig);
+  }
+
+  if (accessor_method != NULL) { // TBD should a null accessor method be an error?
+    methodHandle method(THREAD, accessor_method);
+    oop m = Reflection::new_method(method, false, CHECK_0);
+    java_lang_reflect_RecordComponent::set_accessor(element(), m);
+  } else {
+    java_lang_reflect_RecordComponent::set_accessor(element(), NULL);
+  }
+
+  int sig_index = component->generic_signature_index();
+  if (sig_index > 0) {
+    Symbol* sig = holder->constants()->symbol_at(sig_index); // name_index is a utf8
+    oop component_sig = StringTable::intern(sig, CHECK_0);
+    java_lang_reflect_RecordComponent::set_signature(element(), component_sig);
+  } else {
+    java_lang_reflect_RecordComponent::set_signature(element(), NULL);
+  }
+
+  typeArrayOop annotation_oop = Annotations::make_java_array(component->annotations(), CHECK_0);
+  java_lang_reflect_RecordComponent::set_annotations(element(), annotation_oop);
+
+  typeArrayOop type_annotation_oop = Annotations::make_java_array(component->type_annotations(), CHECK_0);
+  java_lang_reflect_RecordComponent::set_typeAnnotations(element(), type_annotation_oop);
+
+  return element();
+}
+
 #define CONSTANTPOOL_FIELDS_DO(macro) \
   macro(_oop_offset, k, "constantPoolOop", object_signature, false)
 
@@ -4163,6 +4223,13 @@
 int java_lang_Byte_ByteCache::_static_cache_offset;
 int java_lang_Boolean::_static_TRUE_offset;
 int java_lang_Boolean::_static_FALSE_offset;
+int java_lang_reflect_RecordComponent::clazz_offset;
+int java_lang_reflect_RecordComponent::name_offset;
+int java_lang_reflect_RecordComponent::type_offset;
+int java_lang_reflect_RecordComponent::accessor_offset;
+int java_lang_reflect_RecordComponent::signature_offset;
+int java_lang_reflect_RecordComponent::annotations_offset;
+int java_lang_reflect_RecordComponent::typeAnnotations_offset;
 
 
 
@@ -4514,6 +4581,55 @@
   return (hardcoded_offset * heapOopSize) + instanceOopDesc::base_offset_in_bytes();
 }
 
+#define RECORDCOMPONENT_FIELDS_DO(macro) \
+  macro(clazz_offset,       k, "clazz",       class_signature,  false); \
+  macro(name_offset,        k, "name",        string_signature, false); \
+  macro(type_offset,        k, "type",        class_signature,  false); \
+  macro(accessor_offset,    k, "accessor",    reflect_method_signature, false); \
+  macro(signature_offset,   k, "signature",   string_signature, false); \
+  macro(annotations_offset, k, "annotations", byte_array_signature,     false); \
+  macro(typeAnnotations_offset, k, "typeAnnotations", byte_array_signature, false);
+
+// Support for java_lang_reflect_RecordComponent
+void java_lang_reflect_RecordComponent::compute_offsets() {
+  InstanceKlass* k = SystemDictionary::RecordComponent_klass();
+  RECORDCOMPONENT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
+}
+
+#if INCLUDE_CDS
+void java_lang_reflect_RecordComponent::serialize_offsets(SerializeClosure* f) {
+  RECORDCOMPONENT_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
+}
+#endif
+
+void java_lang_reflect_RecordComponent::set_clazz(oop element, oop value) {
+  element->obj_field_put(clazz_offset, value);
+}
+
+void java_lang_reflect_RecordComponent::set_name(oop element, oop value) {
+  element->obj_field_put(name_offset, value);
+}
+
+void java_lang_reflect_RecordComponent::set_type(oop element, oop value) {
+  element->obj_field_put(type_offset, value);
+}
+
+void java_lang_reflect_RecordComponent::set_accessor(oop element, oop value) {
+  element->obj_field_put(accessor_offset, value);
+}
+
+void java_lang_reflect_RecordComponent::set_signature(oop element, oop value) {
+  element->obj_field_put(signature_offset, value);
+}
+
+void java_lang_reflect_RecordComponent::set_annotations(oop element, oop value) {
+  element->obj_field_put(annotations_offset, value);
+}
+
+void java_lang_reflect_RecordComponent::set_typeAnnotations(oop element, oop value) {
+  element->obj_field_put(typeAnnotations_offset, value);
+}
+
 // Compute hard-coded offsets
 // Invoked before SystemDictionary::initialize, so pre-loaded classes
 // are not available to determine the offset_of_static_fields.
--- a/src/hotspot/share/classfile/javaClasses.hpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Wed Oct 16 17:02:29 2019 -0400
@@ -28,6 +28,7 @@
 #include "classfile/systemDictionary.hpp"
 #include "jvmtifiles/jvmti.h"
 #include "oops/oop.hpp"
+#include "oops/recordComponent.hpp"
 #include "runtime/os.hpp"
 
 // Interface for manipulating the basic Java classes.
@@ -72,6 +73,7 @@
   f(java_lang_reflect_Method) \
   f(java_lang_reflect_Constructor) \
   f(java_lang_reflect_Field) \
+  f(java_lang_reflect_RecordComponent) \
   f(java_nio_Buffer) \
   f(reflect_ConstantPool) \
   f(reflect_UnsafeStaticFieldAccessorImpl) \
@@ -1442,6 +1444,39 @@
   friend class JavaClasses;
 };
 
+// Interface to java.lang.reflect.RecordComponent objects
+
+class java_lang_reflect_RecordComponent: AllStatic {
+ private:
+  static int clazz_offset;
+  static int name_offset;
+  static int type_offset;
+  static int accessor_offset;
+  static int signature_offset;
+  static int annotations_offset;
+  static int typeAnnotations_offset;
+
+  // Setters
+  static void set_clazz(oop element, oop value);
+  static void set_name(oop element, oop value);
+  static void set_type(oop element, oop value);
+  static void set_accessor(oop element, oop value);
+  static void set_signature(oop element, oop value);
+  static void set_annotations(oop element, oop value);
+  static void set_typeAnnotations(oop element, oop value);
+
+ public:
+  // Create an instance of RecordComponent
+  static oop create(InstanceKlass* holder, RecordComponent* component, TRAPS);
+
+  static void compute_offsets();
+  static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
+
+  // Debugging
+  friend class JavaClasses;
+};
+
+
 // Interface to java.lang.AssertionStatusDirectives objects
 
 class java_lang_AssertionStatusDirectives: AllStatic {
--- a/src/hotspot/share/classfile/systemDictionary.hpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Wed Oct 16 17:02:29 2019 -0400
@@ -119,6 +119,7 @@
   do_klass(AccessController_klass,                      java_security_AccessController                        ) \
   do_klass(SecureClassLoader_klass,                     java_security_SecureClassLoader                       ) \
   do_klass(ClassNotFoundException_klass,                java_lang_ClassNotFoundException                      ) \
+  do_klass(Record_klass,                                java_lang_Record                                      ) \
   do_klass(NoClassDefFoundError_klass,                  java_lang_NoClassDefFoundError                        ) \
   do_klass(LinkageError_klass,                          java_lang_LinkageError                                ) \
   do_klass(ClassCastException_klass,                    java_lang_ClassCastException                          ) \
@@ -216,6 +217,9 @@
   /* force inline of iterators */                                                                               \
   do_klass(Iterator_klass,                              java_util_Iterator                                    ) \
                                                                                                                 \
+  /* support for records */                                                                                     \
+  do_klass(RecordComponent_klass,                       java_lang_reflect_RecordComponent                     ) \
+                                                                                                                \
   /*end*/
 
 
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Wed Oct 16 17:02:29 2019 -0400
@@ -94,6 +94,7 @@
   template(java_lang_reflect_Field,                   "java/lang/reflect/Field")                  \
   template(java_lang_reflect_Parameter,               "java/lang/reflect/Parameter")              \
   template(java_lang_reflect_Array,                   "java/lang/reflect/Array")                  \
+  template(java_lang_reflect_RecordComponent,         "java/lang/reflect/RecordComponent")        \
   template(java_lang_StringBuffer,                    "java/lang/StringBuffer")                   \
   template(java_lang_StringBuilder,                   "java/lang/StringBuilder")                  \
   template(java_lang_CharSequence,                    "java/lang/CharSequence")                   \
@@ -127,6 +128,7 @@
   template(jdk_internal_vm_PostVMInitHook,            "jdk/internal/vm/PostVMInitHook")           \
   template(sun_net_www_ParseUtil,                     "sun/net/www/ParseUtil")                    \
   template(java_util_Iterator,                        "java/util/Iterator")                       \
+  template(java_lang_Record,                          "java/lang/Record")                       \
                                                                                                   \
   template(jdk_internal_loader_ClassLoaders_AppClassLoader,      "jdk/internal/loader/ClassLoaders$AppClassLoader")      \
   template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \
@@ -159,6 +161,7 @@
   template(tag_deprecated,                            "Deprecated")                               \
   template(tag_source_debug_extension,                "SourceDebugExtension")                     \
   template(tag_signature,                             "Signature")                                \
+  template(tag_record,                                "Record")                                   \
   template(tag_runtime_visible_annotations,           "RuntimeVisibleAnnotations")                \
   template(tag_runtime_invisible_annotations,         "RuntimeInvisibleAnnotations")              \
   template(tag_runtime_visible_parameter_annotations, "RuntimeVisibleParameterAnnotations")       \
@@ -559,6 +562,7 @@
   template(char_StringBuffer_signature,               "(C)Ljava/lang/StringBuffer;")                              \
   template(int_String_signature,                      "(I)Ljava/lang/String;")                                    \
   template(boolean_boolean_int_signature,             "(ZZ)I")                                                    \
+  template(reflect_method_signature,                  "Ljava/lang/reflect/Method;")                                                    \
   /* signature symbols needed by intrinsics */                                                                    \
   VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE)            \
                                                                                                                   \
--- a/src/hotspot/share/include/jvm.h	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/include/jvm.h	Wed Oct 16 17:02:29 2019 -0400
@@ -522,6 +522,7 @@
 JNIEXPORT jobjectArray JNICALL
 JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly);
 
+
 /* Differs from JVM_GetClassModifiers in treatment of inner classes.
    This returns the access flags for the class as specified in the
    class file rather than searching the InnerClasses attribute (if
@@ -542,6 +543,14 @@
 JNIEXPORT jobjectArray JNICALL
 JVM_GetNestMembers(JNIEnv *env, jclass current);
 
+/* Records - since JDK 14 */
+
+JNIEXPORT jboolean JNICALL
+JVM_IsRecord(JNIEnv *env, jclass cls);
+
+JNIEXPORT jobjectArray JNICALL
+JVM_GetRecordComponents(JNIEnv *env, jclass ofClass);
+
 /* The following two reflection routines are still needed due to startup time issues */
 /*
  * java.lang.reflect.Method
--- a/src/hotspot/share/memory/allocation.hpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/memory/allocation.hpp	Wed Oct 16 17:02:29 2019 -0400
@@ -305,7 +305,8 @@
   f(ConstantPool) \
   f(ConstantPoolCache) \
   f(Annotations) \
-  f(MethodCounters)
+  f(MethodCounters) \
+  f(RecordComponent)
 
 #define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type,
 #define METASPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name;
--- a/src/hotspot/share/memory/heapInspection.hpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/memory/heapInspection.hpp	Wed Oct 16 17:02:29 2019 -0400
@@ -88,6 +88,8 @@
         "Number of bytes used by the InstanceKlass::inner_classes() array") \
     f(nest_members_bytes, IK_nest_members, \
         "Number of bytes used by the InstanceKlass::nest_members() array") \
+    f(record_components_bytes, IK_record_components, \
+        "Number of bytes used by the InstanceKlass::record_components() array") \
     f(signers_bytes, IK_signers, \
         "Number of bytes used by the InstanceKlass::singers() array") \
     f(class_annotations_bytes, class_annotations, \
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Wed Oct 16 17:02:29 2019 -0400
@@ -835,6 +835,7 @@
   case MetaspaceObj::ConstantPoolCacheType:
   case MetaspaceObj::AnnotationsType:
   case MetaspaceObj::MethodCountersType:
+  case MetaspaceObj::RecordComponentType:
     // These have no vtables.
     break;
   case MetaspaceObj::ClassType:
--- a/src/hotspot/share/oops/instanceKlass.cpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Wed Oct 16 17:02:29 2019 -0400
@@ -435,6 +435,7 @@
   _nest_members(NULL),
   _nest_host_index(0),
   _nest_host(NULL),
+  _record_components(NULL),
   _static_field_size(parser.static_field_size()),
   _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
   _itable_len(parser.itable_size()),
@@ -497,6 +498,18 @@
   }
 }
 
+void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data,
+                                                 Array<RecordComponent*>* record_components) {
+  if (record_components != NULL && !record_components->is_shared()) {
+    for (int i = 0; i < record_components->length(); i++) {
+      RecordComponent* record_component = record_components->at(i);
+      if (record_component == NULL) continue;  // maybe null if error processing
+      MetadataFactory::free_metadata(loader_data, record_component);
+    }
+    MetadataFactory::free_array<RecordComponent*>(loader_data, record_components);
+  }
+}
+
 // This function deallocates the metadata and C heap pointers that the
 // InstanceKlass points to.
 void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
@@ -525,6 +538,9 @@
   deallocate_methods(loader_data, methods());
   set_methods(NULL);
 
+  deallocate_record_components(loader_data, record_components());
+  set_record_components(NULL);
+
   if (method_ordering() != NULL &&
       method_ordering() != Universe::the_empty_int_array() &&
       !method_ordering()->is_shared()) {
@@ -2313,6 +2329,7 @@
   }
 
   it->push(&_nest_members);
+  it->push(&_record_components);
 }
 
 void InstanceKlass::remove_unshareable_info() {
@@ -3228,6 +3245,8 @@
   }
   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 (java_mirror() != NULL) {
     st->print(BULLET"java mirror:       ");
     java_mirror()->print_value_on(st);
@@ -3490,6 +3509,7 @@
   n += (sz->_fields_bytes                = sz->count_array(fields()));
   n += (sz->_inner_classes_bytes         = sz->count_array(inner_classes()));
   n += (sz->_nest_members_bytes          = sz->count_array(nest_members()));
+  n += (sz->_record_components_bytes     = sz->count_array(record_components()));
   sz->_ro_bytes += n;
 
   const ConstantPool* cp = constants();
@@ -3512,6 +3532,17 @@
       }
     }
   }
+
+  const Array<RecordComponent*>* components = record_components();
+  if (components != NULL) {
+    for (int i = 0; i < components->length(); i++) {
+      RecordComponent* component = components->at(i);
+      if (component) {
+        component->collect_statistics(sz);
+      }
+    }
+  }
+
 }
 #endif // INCLUDE_SERVICES
 
--- a/src/hotspot/share/oops/instanceKlass.hpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/oops/instanceKlass.hpp	Wed Oct 16 17:02:29 2019 -0400
@@ -32,6 +32,7 @@
 #include "oops/fieldInfo.hpp"
 #include "oops/instanceOop.hpp"
 #include "oops/klassVtable.hpp"
+#include "oops/recordComponent.hpp"
 #include "runtime/handles.hpp"
 #include "runtime/os.hpp"
 #include "utilities/accessFlags.hpp"
@@ -182,6 +183,9 @@
   // By always being set it makes nest-member access checks simpler.
   InstanceKlass* _nest_host;
 
+  // The contents of the Record attribute.
+  Array<RecordComponent*>* _record_components;
+
   // the source debug extension for this klass, NULL if not specified.
   // Specified as UTF-8 string without terminating zero byte in the classfile,
   // it is stored in the instanceklass as a NULL-terminated UTF-8 string
@@ -446,9 +450,17 @@
   jushort nest_host_index() const { return _nest_host_index; }
   void set_nest_host_index(u2 i)  { _nest_host_index = i; }
 
+  // record components
+  Array<RecordComponent*>* record_components() const { return _record_components; }
+  void set_record_components(Array<RecordComponent*>* record_components) {
+    _record_components = record_components;
+  }
+  bool is_record() const { return _record_components != NULL; }
+
 private:
   // Called to verify that k is a member of this nest - does not look at k's nest-host
   bool has_nest_member(InstanceKlass* k, TRAPS) const;
+
 public:
   // Returns nest-host class, resolving and validating it if needed
   // Returns NULL if an exception occurs during loading, or validation fails
@@ -1142,6 +1154,8 @@
                                     const Klass* super_klass,
                                     Array<InstanceKlass*>* local_interfaces,
                                     Array<InstanceKlass*>* transitive_interfaces);
+  void static deallocate_record_components(ClassLoaderData* loader_data,
+                                           Array<RecordComponent*>* record_component);
 
   // The constant pool is on stack if any of the methods are executing or
   // referenced by handles.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/oops/recordComponent.cpp	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "logging/log.hpp"
+#include "memory/metadataFactory.hpp"
+#include "memory/metaspace.hpp"
+#include "memory/metaspaceClosure.hpp"
+#include "oops/annotations.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/recordComponent.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+RecordComponent* RecordComponent::allocate(ClassLoaderData* loader_data,
+                                           u2 name_index, u2 descriptor_index,
+                                           u2 attributes_count,
+                                           u2 generic_signature_index,
+                                           AnnotationArray* annotations,
+                                           AnnotationArray* type_annotations, TRAPS) {
+  return new (loader_data, size(), MetaspaceObj::RecordComponentType, THREAD)
+         RecordComponent(name_index, descriptor_index, attributes_count,
+                         generic_signature_index, annotations, type_annotations);
+}
+
+void RecordComponent::deallocate_contents(ClassLoaderData* loader_data) {
+  if (annotations() != NULL) {
+    MetadataFactory::free_array<u1>(loader_data, annotations());
+  }
+  if (type_annotations() != NULL) {
+    MetadataFactory::free_array<u1>(loader_data, type_annotations());
+  }
+}
+
+void RecordComponent::metaspace_pointers_do(MetaspaceClosure* it) {
+  log_trace(cds)("Iter(RecordComponent): %p", this);
+  it->push(&_annotations);
+  it->push(&_type_annotations);
+}
+
+void RecordComponent::print_value_on(outputStream* st) const {
+  st->print("RecordComponent(" INTPTR_FORMAT ")", p2i(this));
+}
+
+#ifndef PRODUCT
+void RecordComponent::print_on(outputStream* st) const {
+  st->print("name_index: %d", _name_index);
+  st->print(" - descriptor_index: %d", _descriptor_index);
+  st->print(" - attributes_count: %d", _attributes_count);
+  if (_generic_signature_index != 0) {
+    st->print(" - generic_signature_index: %d", _generic_signature_index);
+  }
+  st->cr();
+  if (_annotations != NULL) {
+    st->print_cr("record component annotations");
+    _annotations->print_value_on(st);
+  }
+  if (_type_annotations != NULL) {
+    st->print_cr("record component type annotations");
+    _type_annotations->print_value_on(st);
+  }
+}
+#endif // PRODUCT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/oops/recordComponent.hpp	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_OOPS_RECORDCOMPONENT_HPP
+#define SHARE_OOPS_RECORDCOMPONENT_HPP
+
+#include "memory/heapInspection.hpp"
+#include "oops/annotations.hpp"
+#include "oops/metadata.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+// This class stores information extracted from the Record class attribute.
+class RecordComponent: public MetaspaceObj {
+  private:
+    AnnotationArray* _annotations;
+    AnnotationArray* _type_annotations;
+    u2 _name_index;
+    u2 _descriptor_index;
+    u2 _attributes_count;
+
+    // generic_signature_index gets set if the Record component has a Signature
+    // attribute.  A zero value indicates that there was no Signature attribute.
+    u2 _generic_signature_index;
+
+  public:
+    RecordComponent(u2 name_index, u2 descriptor_index, u2 attributes_count,
+                    u2 generic_signature_index, AnnotationArray* annotations,
+                    AnnotationArray* type_annotations):
+                    _annotations(annotations), _type_annotations(type_annotations),
+                    _name_index(name_index), _descriptor_index(descriptor_index),
+                    _attributes_count(attributes_count),
+                    _generic_signature_index(generic_signature_index) { }
+
+    // Allocate instance of this class
+    static RecordComponent* allocate(ClassLoaderData* loader_data,
+                                     u2 name_index, u2 descriptor_index,
+                                     u2 attributes_count,
+                                     u2 generic_signature_index,
+                                     AnnotationArray* annotations,
+                                     AnnotationArray* type_annotations, TRAPS);
+
+    void deallocate_contents(ClassLoaderData* loader_data);
+
+    u2 name_index() const { return _name_index; }
+
+    u2 descriptor_index() const { return _descriptor_index; }
+
+    u2 attributes_count() const { return _attributes_count; }
+
+    u2 generic_signature_index() const { return _generic_signature_index; }
+
+    AnnotationArray* annotations() const { return _annotations; }
+    AnnotationArray* type_annotations() const { return _type_annotations; }
+
+    // Size of RecordComponent, not including size of any annotations.
+    static int size() { return sizeof(RecordComponent) / wordSize; }
+
+    void metaspace_pointers_do(MetaspaceClosure* it);
+    MetaspaceObj::Type type() const { return RecordComponentType; }
+
+    // Record_components should be stored in the read-only region of CDS archive.
+    static bool is_read_only_by_default() { return true; }
+    DEBUG_ONLY(bool on_stack() { return false; })  // for template
+
+#if INCLUDE_SERVICES
+    void collect_statistics(KlassSizeStats *sz) const {
+      // TBD is this right?
+      if (_annotations != NULL) {
+        sz->_annotations_bytes += sz->count(_annotations);
+        sz->_ro_bytes += sz->count(_annotations);
+      }
+      if (_type_annotations != NULL) {
+        sz->_annotations_bytes += sz->count(_type_annotations);
+        sz->_ro_bytes += sz->count(_type_annotations);
+      }
+    }
+#endif
+
+    bool is_klass() const { return false; }
+
+#ifndef PRODUCT
+    void print_on(outputStream* st) const;
+#endif
+    void print_value_on(outputStream* st) const;
+
+};
+
+#endif // SHARE_OOPS_RECORDCOMPONENT_HPP
--- a/src/hotspot/share/prims/jvm.cpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/prims/jvm.cpp	Wed Oct 16 17:02:29 2019 -0400
@@ -50,6 +50,7 @@
 #include "oops/fieldStreams.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/method.hpp"
+#include "oops/recordComponent.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
@@ -1680,6 +1681,46 @@
 }
 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();
+JVM_END
+
+JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass))
+{
+  JVMWrapper("JVM_GetRecordComponents");
+  Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass));
+  assert(c->is_instance_klass(), "must be");
+  InstanceKlass* ik = InstanceKlass::cast(c);
+
+  if (ik->is_record()) {
+    Array<RecordComponent*>* components = ik->record_components();
+    assert(components != NULL, "components should not be NULL");
+    {
+      JvmtiVMObjectAllocEventCollector oam;
+      constantPoolHandle cp(THREAD, ik->constants());
+      int length = components->length();
+      assert(length >= 0, "unexpected record_components length");
+      objArrayOop record_components =
+        oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), length, CHECK_NULL);
+      objArrayHandle components_h (THREAD, record_components);
+
+      for (int x = 0; x < length; x++) {
+        RecordComponent* component = components->at(x);
+        assert(component != NULL, "unexpected NULL record component");
+        oop component_oop = java_lang_reflect_RecordComponent::create(ik, component, CHECK_NULL);
+        components_h->obj_at_put(x, component_oop);
+      }
+      return (jobjectArray)JNIHandles::make_local(components_h());
+    }
+  }
+
+  objArrayOop result = oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), 0, CHECK_NULL);
+  return (jobjectArray)JNIHandles::make_local(env, result);
+}
+JVM_END
+
 static bool select_method(const methodHandle& method, bool want_constructor) {
   if (want_constructor) {
     return (method->is_initializer() && !method->is_static());
--- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp	Wed Oct 16 17:02:29 2019 -0400
@@ -27,6 +27,7 @@
 #include "interpreter/bytecodeStream.hpp"
 #include "memory/universe.hpp"
 #include "oops/fieldStreams.hpp"
+#include "oops/recordComponent.hpp"
 #include "prims/jvmtiClassFileReconstituter.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/signature.hpp"
@@ -423,6 +424,57 @@
   }
 }
 
+//  Record {
+//    u2 attribute_name_index;
+//    u4 attribute_length;
+//    u2 components_count;
+//    component_info components[components_count];
+//  }
+//  component_info {
+//    u2 name_index;
+//    u2 descriptor_index
+//    u2 attributs_count;
+//    attribute_info_attributes[attributes_count];
+//  }
+void JvmtiClassFileReconstituter::write_record_attribute() {
+  Array<RecordComponent*>* components = ik()->record_components();
+  int number_of_components = components->length();
+
+  // Each component has a u2 for name, descr, attribute count
+  int length = sizeof(u2) + (sizeof(u2) * 3 * number_of_components);
+  for (int x = 0; x < number_of_components; x++) {
+    RecordComponent* component = components->at(x);
+    if (component->generic_signature_index() != 0) {
+      length += 8; // Signature attribute size
+      assert(component->attributes_count() > 0, "Bad component attributes count");
+    }
+    if (component->annotations() != NULL) {
+      length += 6 + component->annotations()->length();
+    }
+    if (component->type_annotations() != NULL) {
+      length += 6 + component->type_annotations()->length();
+    }
+  }
+
+  write_attribute_name_index("Record");
+  write_u4(length);
+  write_u2(number_of_components);
+  for (int i = 0; i < number_of_components; i++) {
+    RecordComponent* component = components->at(i);
+    write_u2(component->name_index());
+    write_u2(component->descriptor_index());
+    write_u2(component->attributes_count());
+    if (component->generic_signature_index() != 0) {
+      write_signature_attribute(component->generic_signature_index());
+    }
+    if (component->annotations() != NULL) {
+      write_annotations_attribute("RuntimeVisibleAnnotations", component->annotations());
+    }
+    if (component->type_annotations() != NULL) {
+      write_annotations_attribute("RuntimeVisibleTypeAnnotations", component->type_annotations());
+    }
+  }
+}
 
 // Write InnerClasses attribute
 // JVMSpec|   InnerClasses_attribute {
@@ -699,6 +751,9 @@
   if (ik()->nest_members() != Universe::the_empty_short_array()) {
     ++attr_count;
   }
+  if (ik()->record_components() != NULL) {
+    ++attr_count;
+  }
 
   write_u2(attr_count);
 
@@ -729,6 +784,9 @@
   if (ik()->nest_members() != Universe::the_empty_short_array()) {
     write_nest_members_attribute();
   }
+  if (ik()->record_components() != NULL) {
+    write_record_attribute();
+  }
 }
 
 // Write the method information portion of ClassFile structure
--- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.hpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.hpp	Wed Oct 16 17:02:29 2019 -0400
@@ -118,6 +118,7 @@
   void write_bootstrapmethod_attribute();
   void write_nest_host_attribute();
   void write_nest_members_attribute();
+  void write_record_attribute();
 
   address writeable_address(size_t size);
   void write_u1(u1 x);
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp	Wed Oct 16 17:02:29 2019 -0400
@@ -292,6 +292,11 @@
   if (InstanceKlass::cast(k)->is_unsafe_anonymous()) {
     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;
 }
 
--- a/src/java.base/share/classes/java/io/ObjectInputStream.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.base/share/classes/java/io/ObjectInputStream.java	Wed Oct 16 17:02:29 2019 -0400
@@ -26,7 +26,9 @@
 package java.io;
 
 import java.io.ObjectStreamClass.WeakClassKey;
+import java.io.ObjectStreamClass.RecordReflector;
 import java.lang.System.Logger;
+import java.lang.invoke.MethodHandle;
 import java.lang.ref.ReferenceQueue;
 import java.lang.reflect.Array;
 import java.lang.reflect.Modifier;
@@ -218,6 +220,34 @@
  * Similarly, any serialPersistentFields or serialVersionUID field declarations
  * are also ignored--all enum types have a fixed serialVersionUID of 0L.
  *
+ * @apiNote
+ * Records are serialized differently than ordinary serializable or externalizable
+ * objects. The serialized form of a record object is a sequence of values derived
+ * from the record components. The stream format of a record object is the same as
+ * that of an ordinary object in the stream. During deserialization, if the local
+ * class equivalent of the specified stream class descriptor is a record class,
+ * then first the stream fields are read and reconstructed to serve as the record's
+ * component values; and second, a record object is created by invoking the
+ * record's <i>canonical</i> constructor with the component values as arguments (or the
+ * default value for component's type if a component value is absent from the
+ * stream).
+ * Like other serializable or externalizable objects, record objects can function
+ * as the target of back references appearing subsequently in the serialization
+ * stream. However, a cycle in the graph where the record object is referred to,
+ * either directly or transitively, by one of its components, is not preserved.
+ * The record components are deserialized prior to the invocation of the record
+ * constructor, hence this limitation (see
+ * <a href="{@docRoot}/../specs/serialization/serial-arch.html#cyclic-references">
+ * [Section 1.14, "Circular References"</a> for additional information).
+ * The process by which record objects are serialized cannot be customized; any
+ * class-specific writeObject, readObject, readObjectNoData, writeExternal,
+ * and readExternal methods defined by record classes are ignored during
+ * serialization and deserialization. However, a substitute object to be serialized
+ * or a designate replacement may be specified by the writeReplace and
+ * readResolve methods, respectively. Any serialPersistentFields or
+ * serialVersionUID field declarations are also ignored -- all record classes
+ * have a fixed serialVersionUID of 0L.
+ *
  * @author      Mike Warres
  * @author      Roger Riggs
  * @see java.io.DataInput
@@ -2085,7 +2115,12 @@
             handles.markException(passHandle, resolveEx);
         }
 
-        if (desc.isExternalizable()) {
+        final boolean isRecord = cl != null && cl.isRecord() ? true : false;
+        if (isRecord) {
+            assert obj == null;
+            obj = readRecord(desc);
+            handles.setObject(passHandle, obj);
+        } else if (desc.isExternalizable()) {
             readExternalData((Externalizable) obj, desc);
         } else {
             readSerialData(obj, desc);
@@ -2171,6 +2206,43 @@
          */
     }
 
+    /** Reads a record. */
+    private Object readRecord(ObjectStreamClass desc) throws IOException {
+        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
+        if (slots.length != 1) {
+            // skip any superclass stream field values
+            for (int i = 0; i < slots.length-1; i++) {
+                ObjectStreamClass slotDesc = slots[i].desc;
+                if (slots[i].hasData) {
+                    defaultReadFields(null, slotDesc);
+                }
+            }
+        }
+
+        FieldValues fieldValues = defaultReadFields(null, desc);
+
+        // lookup the canonical constructor
+        MethodHandle ctrMH = RecordReflector.canonicalCtr(desc.forClass());
+
+        // bind the stream field values
+        ctrMH = RecordReflector.bindCtrValues(ctrMH, desc, fieldValues);
+
+        try {
+            return ctrMH.invoke();
+        } catch (Exception e) {
+            InvalidObjectException ioe = new InvalidObjectException(e.getMessage());
+            ioe.initCause(e);
+            throw ioe;
+        } catch (Error e) {
+            throw e;
+        } catch (Throwable t) {
+            ObjectStreamException ose = new InvalidObjectException(
+                    "ReflectiveOperationException during deserialization");
+            ose.initCause(t);
+            throw ose;
+        }
+    }
+
     /**
      * Reads (or attempts to skip, if obj is null or is tagged with a
      * ClassNotFoundException) instance data for each serializable class of
@@ -2317,7 +2389,7 @@
         }
     }
 
-    private class FieldValues {
+    /*package-private*/ class FieldValues {
         final byte[] primValues;
         final Object[] objValues;
 
--- a/src/java.base/share/classes/java/io/ObjectOutputStream.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.base/share/classes/java/io/ObjectOutputStream.java	Wed Oct 16 17:02:29 2019 -0400
@@ -150,6 +150,26 @@
  * defaultWriteObject and writeFields initially terminate any existing
  * block-data record.
  *
+ * @apiNote
+ * Records are serialized differently than ordinary serializable or externalizable
+ * objects. The serialized form of a record object is a sequence of values derived
+ * from the record components. The stream format of a record object is the same as
+ * that of an ordinary object in the stream. During deserialization, if the local
+ * class equivalent of the specified stream class descriptor is a record class,
+ * then first the stream fields are read and reconstructed to serve as the record's
+ * component values; and second, a record object is created by invoking the
+ * record's <i>canonical</i> constructor with the component values as arguments (or the
+ * default value for component's type if a component value is absent from the
+ * stream).
+ * The process by which record objects are serialized cannot be customized; any
+ * class-specific writeObject, readObject, readObjectNoData, writeExternal,
+ * and readExternal methods defined by record classes are ignored during
+ * serialization and deserialization. However, a substitute object to be serialized
+ * or a designate replacement may be specified by the writeReplace and
+ * readResolve methods, respectively. Any serialPersistentFields or
+ * serialVersionUID field declarations are also ignored -- all record classes
+ * have a fixed serialVersionUID of`0L.
+ *
  * @author      Mike Warres
  * @author      Roger Riggs
  * @see java.io.DataOutput
@@ -1431,7 +1451,11 @@
             bout.writeByte(TC_OBJECT);
             writeClassDesc(desc, false);
             handles.assign(unshared ? null : obj);
-            if (desc.isExternalizable() && !desc.isProxy()) {
+
+            final boolean isRecord = obj.getClass().isRecord() ? true : false;
+            if (isRecord) {
+                writeRecordData(obj,desc);
+            } else if (desc.isExternalizable() && !desc.isProxy()) {
                 writeExternalData((Externalizable) obj);
             } else {
                 writeSerialData(obj, desc);
@@ -1475,6 +1499,18 @@
         curPut = oldPut;
     }
 
+    /** Writes the record component values for the given record object. */
+    private void writeRecordData(Object obj, ObjectStreamClass desc)
+        throws IOException
+    {
+        assert obj.getClass().isRecord();
+        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
+        if (slots.length != 1)
+            throw new InternalError("expected slot length: " + slots.length);
+
+        defaultWriteFields(obj, desc);  // TODO: use record accessors
+    }
+
     /**
      * Writes instance data for each serializable class of given object, from
      * superclass to subclass.
--- a/src/java.base/share/classes/java/io/ObjectStreamClass.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.base/share/classes/java/io/ObjectStreamClass.java	Wed Oct 16 17:02:29 2019 -0400
@@ -25,6 +25,9 @@
 
 package java.io;
 
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
@@ -32,6 +35,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.RecordComponent;
 import java.lang.reflect.UndeclaredThrowableException;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
@@ -44,6 +48,8 @@
 import java.security.PermissionCollection;
 import java.security.Permissions;
 import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -123,6 +129,8 @@
     private boolean isProxy;
     /** true if represents enum type */
     private boolean isEnum;
+    /** true if represents record type */
+    private boolean isRecord;
     /** true if represented class implements Serializable */
     private boolean serializable;
     /** true if represented class implements Externalizable */
@@ -475,6 +483,7 @@
         name = cl.getName();
         isProxy = Proxy.isProxyClass(cl);
         isEnum = Enum.class.isAssignableFrom(cl);
+        isRecord = cl.isRecord();
         serializable = Serializable.class.isAssignableFrom(cl);
         externalizable = Externalizable.class.isAssignableFrom(cl);
 
@@ -495,7 +504,11 @@
                         return null;
                     }
 
+                    if (isRecord) {
+                        suid = 0L;
+                    } else {
                     suid = getDeclaredSUID(cl);
+                    }
                     try {
                         fields = getSerialFields(cl);
                         computeFieldOffsets();
@@ -505,7 +518,9 @@
                         fields = NO_FIELDS;
                     }
 
-                    if (externalizable) {
+                    if (isRecord) {
+                        cons = null;  // ctr will be found later
+                    } else if (externalizable) {
                         cons = getExternalizableConstructor(cl);
                     } else {
                         cons = getSerializableConstructor(cl);
@@ -542,16 +557,18 @@
         if (deserializeEx == null) {
             if (isEnum) {
                 deserializeEx = new ExceptionInfo(name, "enum type");
-            } else if (cons == null) {
+            } else if (cons == null && !isRecord) {
                 deserializeEx = new ExceptionInfo(name, "no valid constructor");
             }
         }
+        if (!isRecord) {
         for (int i = 0; i < fields.length; i++) {
             if (fields[i].getField() == null) {
                 defaultSerializeEx = new ExceptionInfo(
                     name, "unmatched serializable field(s) declared");
             }
         }
+        }
         initialized = true;
     }
 
@@ -682,7 +699,7 @@
             }
 
             if (model.serializable == osc.serializable &&
-                    !cl.isArray() &&
+                    !cl.isArray() && !cl.isRecord() &&
                     suid != osc.getSerialVersionUID()) {
                 throw new InvalidClassException(osc.name,
                         "local class incompatible: " +
@@ -714,6 +731,9 @@
         }
 
         this.cl = cl;
+        if (cl != null) {
+            this.isRecord = cl.isRecord();
+        }
         this.resolveEx = resolveEx;
         this.superDesc = superDesc;
         name = model.name;
@@ -739,12 +759,14 @@
                 deserializeEx = localDesc.deserializeEx;
             }
             domains = localDesc.domains;
+            assert cl.isRecord() ? localDesc.cons == null : true;
             cons = localDesc.cons;
         }
 
         fieldRefl = getReflector(fields, localDesc);
         // reassign to matched fields so as to reflect local unshared settings
         fields = fieldRefl.getFields();
+
         initialized = true;
     }
 
@@ -1641,12 +1663,16 @@
     private static ObjectStreamField[] getSerialFields(Class<?> cl)
         throws InvalidClassException
     {
+        if (!Serializable.class.isAssignableFrom(cl))
+            return NO_FIELDS;
+
         ObjectStreamField[] fields;
-        if (Serializable.class.isAssignableFrom(cl) &&
-            !Externalizable.class.isAssignableFrom(cl) &&
+        if (cl.isRecord()) {
+            fields = getDefaultSerialFields(cl);
+            Arrays.sort(fields);
+        } else if (!Externalizable.class.isAssignableFrom(cl) &&
             !Proxy.isProxyClass(cl) &&
-            !cl.isInterface())
-        {
+                   !cl.isInterface()) {
             if ((fields = getDeclaredSerialFields(cl)) == null) {
                 fields = getDefaultSerialFields(cl);
             }
@@ -2438,4 +2464,133 @@
             }
         }
     }
+
+    /** A reflector implementation for record classes. */
+    static final class RecordReflector {
+
+        // TODO: add cache to avoid subsequent reflective calls for the same record class
+
+        /** Returns the canonical constructor for the given record class. */
+        static MethodHandle canonicalCtr(Class<?> cls) {
+            assert cls.isRecord() : "Expected record, got: " + cls;
+            PrivilegedAction<MethodHandle> pa = () -> {
+                Class<?>[] paramTypes = Arrays.stream(cls.getRecordComponents())
+                                               .map(RecordComponent::getType)
+                                               .toArray(Class<?>[]::new);
+                try {
+                    Constructor<?> ctr = cls.getConstructor(paramTypes);
+                    ctr.setAccessible(true);
+                    return MethodHandles.lookup().unreflectConstructor(ctr);
+                } catch (IllegalAccessException | NoSuchMethodException e) {
+                    throw new InternalError("should not reach here",  e);
+                }
+            };
+            return AccessController.doPrivileged(pa);
+        }
+
+        /** Binds the given stream field values to the given method handle. */
+        static MethodHandle bindCtrValues(MethodHandle ctrMH,
+                                          ObjectStreamClass desc,
+                                          ObjectInputStream.FieldValues fieldValues) {
+            RecordComponent[] recordComponents;
+            try {
+                Class<?> cls = desc.forClass();
+                PrivilegedExceptionAction<RecordComponent[]> pa = cls::getRecordComponents;
+                recordComponents = AccessController.doPrivileged(pa);
+            } catch (PrivilegedActionException e) {
+                throw new InternalError(e.getCause());
+            }
+
+            Object[] args = new Object[recordComponents.length];
+            for (int i = 0; i < recordComponents.length; i++) {
+                String name = recordComponents[i].getName();
+                Class<?> type= recordComponents[i].getType();
+                Object o = streamFieldValue(name, type, desc, fieldValues);
+                args[i] = o;
+            }
+
+            return MethodHandles.insertArguments(ctrMH, 0, args);
+        }
+
+        /** Returns the number of primitive fields for the given descriptor. */
+        private static int numberPrimValues(ObjectStreamClass desc) {
+            ObjectStreamField[] fields = desc.getFields();
+            int primValueCount = 0;
+            for (int i = 0; i < fields.length; i++) {
+                if (fields[i].isPrimitive())
+                    primValueCount++;
+                else
+                    break;  // can be no more
+            }
+            return primValueCount;
+        }
+
+        /** Returns the default value for the given type. */
+        private static Object defaultValueFor(Class<?> pType) {
+            if (pType == Integer.TYPE)
+                return 0;
+            else if (pType == Byte.TYPE)
+                return (byte)0;
+            else if (pType == Long.TYPE)
+                return 0L;
+            else if (pType == Float.TYPE)
+                return 0.0f;
+            else if (pType == Double.TYPE)
+                return 0.0d;
+            else if (pType == Short.TYPE)
+                return (short)0;
+            else if (pType == Character.TYPE)
+                return '\u0000';
+            else if (pType == Boolean.TYPE)
+                return false;
+            else
+                return null;
+        }
+
+        /**
+         * Returns the stream field value for the given name. The default value
+         * for the given type is returned if the field value is absent. */
+        private static Object streamFieldValue(String pName,
+                                               Class<?> pType,
+                                               ObjectStreamClass desc,
+                                               ObjectInputStream.FieldValues fieldValues) {
+            ObjectStreamField[] fields = desc.getFields();
+
+            for (int i = 0; i < fields.length; i++) {
+                ObjectStreamField f = fields[i];
+                String fName = f.getName();
+                if (!fName.equals(pName))
+                    continue;
+
+                Class<?> fType = f.getField().getType();
+                if (!pType.isAssignableFrom(fType))
+                    throw new InternalError(fName + " unassignable, pType:" + pType + ", fType:" + fType);
+
+                if (f.isPrimitive()) {
+                    if (pType == Integer.TYPE)
+                        return Bits.getInt(fieldValues.primValues, f.getOffset());
+                    else if (fType == Byte.TYPE)
+                        return fieldValues.primValues[f.getOffset()];
+                    else if (fType == Long.TYPE)
+                        return Bits.getLong(fieldValues.primValues, f.getOffset());
+                    else if (fType == Float.TYPE)
+                        return Bits.getFloat(fieldValues.primValues, f.getOffset());
+                    else if (fType == Double.TYPE)
+                        return Bits.getDouble(fieldValues.primValues, f.getOffset());
+                    else if (fType == Short.TYPE)
+                        return Bits.getShort(fieldValues.primValues, f.getOffset());
+                    else if (fType == Character.TYPE)
+                        return Bits.getChar(fieldValues.primValues, f.getOffset());
+                    else if (fType == Boolean.TYPE)
+                        return Bits.getBoolean(fieldValues.primValues, f.getOffset());
+                    else
+                        throw new InternalError("Unexpected type: " + fType);
+                } else { // reference
+                    return fieldValues.objValues[i - numberPrimValues(desc)];
+                }
+            }
+
+            return defaultValueFor(pType);
+        }
+    }
 }
--- a/src/java.base/share/classes/java/lang/Class.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.base/share/classes/java/lang/Class.java	Wed Oct 16 17:02:29 2019 -0400
@@ -46,6 +46,7 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
+import java.lang.reflect.RecordComponent;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.lang.constant.Constable;
@@ -2267,6 +2268,57 @@
         return copyFields(privateGetDeclaredFields(false));
     }
 
+    /**
+     * Returns an array containing {@code RecordComponent} objects reflecting all the
+     * declared record components of the record represented by this {@code Class} object.
+     * The components are returned in the same order that they are declared in the
+     * record header.
+     *
+     * @return  The array of {@code RecordComponent} objects representing all the
+     *          record components of this record. The array is empty if this class
+     *          is not a record, or if this class is a record with no components.
+     * @throws  SecurityException
+     *          If a security manager, <i>s</i>, is present and any of the
+     *          following conditions is met:
+     *
+     *          <ul>
+     *
+     *          <li> the caller's class loader is not the same as the
+     *          class loader of this class and invocation of
+     *          {@link SecurityManager#checkPermission
+     *          s.checkPermission} method with
+     *          {@code RuntimePermission("accessDeclaredMembers")}
+     *          denies access to the declared methods within this class
+     *
+     *          <li> the caller's class loader is not the same as or an
+     *          ancestor of the class loader for the current class and
+     *          invocation of {@link SecurityManager#checkPackageAccess
+     *          s.checkPackageAccess()} denies access to the package
+     *          of this class
+     *
+     *          </ul>
+     *
+     * @since 14
+     */
+    @CallerSensitive
+    public RecordComponent[] getRecordComponents() throws SecurityException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
+        }
+        if (isPrimitive() || isArray()) {
+            return new RecordComponent[0];
+        }
+        Object[] recordComponents = getRecordComponents0();
+        if (recordComponents == null || recordComponents.length == 0) {
+            return new RecordComponent[0];
+        }
+        RecordComponent[] result = new RecordComponent[recordComponents.length];
+        for (int i = 0; i < recordComponents.length; i++) {
+            result[i] = (RecordComponent)recordComponents[i];
+        }
+        return result;
+    }
 
     /**
      * Returns an array containing {@code Method} objects reflecting all the
@@ -3425,6 +3477,9 @@
     private native Method[]      getDeclaredMethods0(boolean publicOnly);
     private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
     private native Class<?>[]   getDeclaredClasses0();
+    private native String[]     getRecordComponentNames0();
+    private native Object[]     getRecordComponents0();
+    private native boolean      isRecord0();
 
     /**
      * Helper method to get the method name from arguments.
@@ -3531,6 +3586,18 @@
         this.getSuperclass() == java.lang.Enum.class;
     }
 
+    /**
+     * Returns true if and only if this class was declared as a record in the
+     * source code.
+     *
+     * @return true if and only if this class was declared as a record in the
+     *     source code
+     * @since 1.12
+     */
+    public boolean isRecord() {
+        return isRecord0();
+    }
+
     // Fetches the factory for reflective objects
     private static ReflectionFactory getReflectionFactory() {
         if (reflectionFactory == null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/Record.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,134 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package java.lang;
+
+/**
+ * This is the common base class of all Java language record classes.
+ *
+ * <p>More information about records, including descriptions of the
+ * implicitly declared methods synthesized by the compiler, can be
+ * found in section 8.10 of
+ * <cite>The Java&trade; Language Specification</cite>.
+ *
+ * <p>A <em>record class</em> is a shallowly immutable, transparent carrier for
+ * a fixed set of values, called the <em>record components</em>.  The Java&trade;
+ * language provides concise syntax for declaring record classes, whereby the
+ * record components are declared in the record header.  The list of record
+ * components declared in the record header form the <em>record descriptor</em>.
+ *
+ * <p>A record class has the following mandated members: a public <em>canonical
+ * constructor</em>, whose descriptor is the same as the record descriptor;
+ * a private final field corresponding to each component, whose name and
+ * type are the same as that of the component; a public accessor method
+ * corresponding to each component, whose name and return type are the same as
+ * that of the component.  If not explicitly declared in the body of the record,
+ * implicit implementations for these members are provided.
+ *
+ * <p>The implicit declaration of the canonical constructor initializes the
+ * component fields from the corresponding constructor arguments.  The implicit
+ * declaration of the accessor methods returns the value of the corresponding
+ * component field.  The implicit declaration of the {@link Object#equals(Object)},
+ * {@link Object#hashCode()}, and {@link Object#toString()} methods are derived
+ * from all of the component fields.
+ *
+ * <p>The primary reasons to provide an explicit declaration for the
+ * canonical constructor or accessor methods are to validate constructor
+ * arguments, perform defensive copies on mutable components, or normalize groups
+ * of components (such as reducing a rational number to lowest terms.)
+ *
+ * <p>For all record classes, the following invariant must hold: if a record R's
+ * components are {@code c1, c2, ... cn}, then if a record instance is copied
+ * as follows:
+ * <pre>
+ *     R copy = new R(r.c1(), r.c2(), ..., r.cn());
+ * </pre>
+ * then it must be the case that {@code r.equals(copy)}.
+ *
+ * @jls 8.10
+ * @since 14
+ */
+public abstract class Record {
+    /**
+     * Indicates whether some other object is "equal to" this one.  In addition
+     * to the general contract of {@link Object#equals(Object)},
+     * record classes must further participate in the invariant that when
+     * a record instance is "copied" by passing the result of the record component
+     * accessor methods to the canonical constructor, as follows:
+     * <pre>
+     *     R copy = new R(r.c1(), r.c2(), ..., r.cn());
+     * </pre>
+     * then it must be the case that {@code r.equals(copy)}.
+     *
+     * @implNote
+     * The implicitly provided implementation returns {@code true} if and
+     * only if the argument is an instance of the same record type as this object,
+     * and each component of this record is equal to the corresponding component
+     * of the argument, according to {@link java.util.Objects#equals(Object,Object)} for components
+     * whose types are reference types, and the primitive wrapper equality
+     * comparison for components whose types are primitive types.
+     *
+     * @see java.util.Objects#equals(Object,Object)
+     *
+     * @param   obj   the reference object with which to compare.
+     * @return  {@code true} if this object is the same as the obj
+     *          argument; {@code false} otherwise.
+     */
+    @Override
+    public abstract boolean equals(Object obj);
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote
+     * The implicitly provided implementation returns a hash code value derived
+     * by combining the hash code value for all the components, according to
+     * {@link Object#hashCode()} for components whose types are reference types,
+     * or the primitive wrapper hash code for components whose types are primitive
+     * types.
+     *
+     * @see     Object#hashCode()
+     *
+     * @return  a hash code value for this object.
+     */
+    @Override
+    public abstract int hashCode();
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote
+     * The implicitly provided implementation returns a string that is derived
+     * from the name of the record class and the names and string representations
+     * of all the components, according to {@link Object#toString()} for components
+     * whose types are reference types, and the primitive wrapper {@code toString}
+     * method for components whose types are primitive types.
+     *
+     * @see     Object#toString() ()
+     *
+     * @return  a string representation of the object.
+     */
+    @Override
+    public abstract String toString();
+}
--- a/src/java.base/share/classes/java/lang/annotation/ElementType.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.base/share/classes/java/lang/annotation/ElementType.java	Wed Oct 16 17:02:29 2019 -0400
@@ -114,5 +114,12 @@
      *
      * @since 9
      */
-    MODULE
+    MODULE,
+
+    /**
+     * Record component
+     *
+     * @since 14
+     */
+    RECORD_COMPONENT;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/RecordComponent.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,246 @@
+package java.lang.reflect;
+
+import jdk.internal.access.SharedSecrets;
+import sun.reflect.annotation.AnnotationParser;
+import sun.reflect.annotation.TypeAnnotation;
+import sun.reflect.annotation.TypeAnnotationParser;
+import sun.reflect.generics.factory.CoreReflectionFactory;
+import sun.reflect.generics.factory.GenericsFactory;
+import sun.reflect.generics.repository.FieldRepository;
+import sun.reflect.generics.scope.ClassScope;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A {@code RecordComponent} provides information about, and dynamic access to, a
+ * record component in a record class. Record components can only be created by the VM
+ * runtime, thus no public constructor is provided.
+ *
+ * @see AnnotatedElement
+ * @see java.lang.Class
+ *
+ * @since 14
+ */
+public final
+class RecordComponent implements AnnotatedElement {
+    // declaring class
+    private Class<?> clazz;
+    private String name;
+    private Class<?> type;
+    private Method accessor;
+    private String signature;
+    // generic info repository; lazily initialized
+    private transient FieldRepository genericInfo;
+    private byte[] annotations;
+    private byte[] typeAnnotations;
+    private RecordComponent root;
+
+    // only the JVM can create record components
+    private RecordComponent() {}
+
+    /**
+     * Returns the name of the record component represented by this {@code RecordComponent} object.
+     *
+     * @return the name of the record component represented by this {@code RecordComponent} object.
+     */
+    public String getName() {
+        return name;
+    }
+
+    private Class<?> getDeclaringClass() {
+        return clazz;
+    }
+
+    /**
+     * Returns a {@code Class} object that identifies the
+     * declared type for the record component represented by this
+     * {@code RecordComponent} object.
+     *
+     * @return a {@code Class} object identifying the declared
+     * type of the record component represented by this object
+     */
+    public Class<?> getType() {
+        return type;
+    }
+
+    /**
+     * Returns a {@code String} object that identifies the
+     * generic type.
+     *
+     * @return a {@code String} object identifying the generic declared
+     * type of the record component represented by this object
+     */
+    public String getGenericSignature() {
+        return signature;
+    }
+
+    /**
+     * Returns a {@code Type} object that represents the declared type for
+     * the record component represented by this {@code RecordComponent} object.
+     *
+     * <p>If the declared type of the record component is a parameterized type,
+     * the {@code Type} object returned must accurately reflect the
+     * actual type arguments used in the source code.
+     *
+     * <p>If the type of the underlying record component is a type variable or a
+     * parameterized type, it is created. Otherwise, it is resolved.
+     *
+     * @return a {@code Type} object that represents the declared type for
+     *     the record component represented by this {@code RecordComponent} object
+     * @throws GenericSignatureFormatError if the generic record component
+     *     signature does not conform to the format specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     * @throws TypeNotPresentException if the generic type
+     *     signature of the underlying record component refers to a non-existent
+     *     type declaration
+     * @throws MalformedParameterizedTypeException if the generic
+     *     signature of the underlying record component refers to a parameterized type
+     *     that cannot be instantiated for any reason
+     */
+    public Type getGenericType() {
+        if (getGenericSignature() != null)
+            return getGenericInfo().getGenericType();
+        else
+            return getType();
+    }
+
+    // Accessor for generic info repository
+    private FieldRepository getGenericInfo() {
+        // lazily initialize repository if necessary
+        if (genericInfo == null) {
+            // create and cache generic info repository
+            genericInfo = FieldRepository.make(getGenericSignature(),
+                    getFactory());
+        }
+        return genericInfo; //return cached repository
+    }
+
+    // Accessor for factory
+    private GenericsFactory getFactory() {
+        Class<?> c = getDeclaringClass();
+        // create scope and factory
+        return CoreReflectionFactory.make(c, ClassScope.make(c));
+    }
+
+    /**
+     * Returns an {@code AnnotatedType} object that represents the use of a type to specify
+     * the annotated type of the record component represented by this
+     * {@code RecordComponent}.
+     *
+     * @return an object representing the declared type of the record component
+     * represented by this {@code RecordComponent}
+     */
+    public AnnotatedType getAnnotatedType() {
+        if (typeAnnotations != null) {
+            // debug
+            // System.out.println("length of type annotations " + typeAnnotations.length);
+        }
+        return TypeAnnotationParser.buildAnnotatedType(typeAnnotations,
+                SharedSecrets.getJavaLangAccess().
+                        getConstantPool(getDeclaringClass()),
+                this,
+                getDeclaringClass(),
+                getGenericType(),
+                TypeAnnotation.TypeAnnotationTarget.FIELD);
+    }
+
+    /**
+     * Returns a {@code Method} object that represents the accessor for the
+     * record component represented by this {@code RecordComponent} object.
+     *
+     * @return a {@code Method} object that represents the accessor for the
+     * record component represented by this {@code RecordComponent} object.
+     */
+    public Method getAccessor() {
+        return accessor;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @Override
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        Objects.requireNonNull(annotationClass);
+        return annotationClass.cast(declaredAnnotations().get(annotationClass));
+    }
+
+    private transient volatile Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
+
+    private Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
+        Map<Class<? extends Annotation>, Annotation> declAnnos;
+        if ((declAnnos = declaredAnnotations) == null) {
+            synchronized (this) {
+                if ((declAnnos = declaredAnnotations) == null) {
+                    RecordComponent root = this.root;
+                    if (root != null) {
+                        declAnnos = root.declaredAnnotations();
+                    } else {
+                        declAnnos = AnnotationParser.parseAnnotations(
+                                annotations,
+                                SharedSecrets.getJavaLangAccess()
+                                        .getConstantPool(getDeclaringClass()),
+                                getDeclaringClass());
+                    }
+                    declaredAnnotations = declAnnos;
+                }
+            }
+        }
+        return declAnnos;
+    }
+
+    @Override
+    public Annotation[] getAnnotations() {
+        return getDeclaredAnnotations();
+    }
+
+    @Override
+    public Annotation[] getDeclaredAnnotations() { return AnnotationParser.toArray(declaredAnnotations()); }
+
+    /**
+     * Returns {@code true} if this {@code RecordComponent} was declared with
+     * variable arity; returns {@code false} otherwise.
+     *
+     * @return {@code true} if an only if this {@code RecordComponent} was declared
+     * with a variable arity.
+     */
+    public boolean isVarArgs()  {
+        RecordComponent[] recordComponents = getDeclaringClass().getRecordComponents();
+        if (recordComponents == null || recordComponents.length == 0) {
+            return false;
+        }
+        try {
+            Constructor<?> canonical = getDeclaringClass()
+                    .getConstructor(Arrays.stream(recordComponents).map(RecordComponent::getAccessor)
+                            .map(Method::getReturnType).toArray(Class<?>[]::new));
+            return canonical.isVarArgs() && this.getName().equals(recordComponents[recordComponents.length - 1].getName());
+        } catch (NoSuchMethodException nsme) {
+            throw new IncompatibleClassChangeError(
+                    String.format("a canonical constructor couldn't be found for record %s",
+                            getDeclaringClass().getCanonicalName()));
+        }
+    }
+
+    /**
+     * Returns a string describing this {@code RecordComponent}, including
+     * its generic type.  The format is the access modifiers for the
+     * record component, always {@code private} and {@code final}, in that
+     * order, followed by the generic record component type, followed by a
+     * space, followed by the fully-qualified name of the class declaring
+     * the record component, followed by a period, followed by the name of
+     * the record component.
+     *
+     * @return a string describing this {@code RecordComponent}, including
+     * its generic type
+     */
+    public String toGenericString() {
+        int mod = Modifier.PRIVATE | Modifier.FINAL;
+        Type type = getGenericType();
+        return (((mod == 0) ? "" : (Modifier.toString(mod) + " "))
+                + type.getTypeName() + " "
+                + getDeclaringClass().getTypeName() + "."
+                + getName());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2017, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package java.lang.invoke;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Bootstrap methods for state-driven implementations of core methods,
+ * including {@link Object#equals(Object)}, {@link Object#hashCode()}, and
+ * {@link Object#toString()}.  These methods may be used, for example, by
+ * Java&trade; compiler implementations to implement the bodies of {@link Object}
+ * methods for record clases.
+ */
+public class ObjectMethods {
+
+    private ObjectMethods() { }
+
+    private static final MethodType DESCRIPTOR_MT = MethodType.methodType(MethodType.class);
+    private static final MethodType NAMES_MT = MethodType.methodType(List.class);
+    private static final MethodHandle FALSE = MethodHandles.constant(boolean.class, false);
+    private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true);
+    private static final MethodHandle ZERO = MethodHandles.constant(int.class, 0);
+    private static final MethodHandle CLASS_IS_INSTANCE;
+    private static final MethodHandle OBJECT_EQUALS;
+    private static final MethodHandle OBJECTS_EQUALS;
+    private static final MethodHandle OBJECTS_HASHCODE;
+    private static final MethodHandle OBJECTS_TOSTRING;
+    private static final MethodHandle OBJECT_EQ;
+    private static final MethodHandle OBJECT_HASHCODE;
+    private static final MethodHandle OBJECT_TO_STRING;
+    private static final MethodHandle STRING_FORMAT;
+    private static final MethodHandle HASH_COMBINER;
+
+    private static final HashMap<Class<?>, MethodHandle> primitiveEquals = new HashMap<>();
+    private static final HashMap<Class<?>, MethodHandle> primitiveHashers = new HashMap<>();
+    private static final HashMap<Class<?>, MethodHandle> primitiveToString = new HashMap<>();
+
+    static {
+        try {
+            MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
+            MethodHandles.Lookup lookup = MethodHandles.Lookup.IMPL_LOOKUP;
+
+            ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+                @Override public ClassLoader run() { return ClassLoader.getPlatformClassLoader(); }
+            });
+
+            CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance",
+                                                         MethodType.methodType(boolean.class, Object.class));
+            OBJECT_EQUALS = publicLookup.findVirtual(Object.class, "equals",
+                                                     MethodType.methodType(boolean.class, Object.class));
+            OBJECT_HASHCODE = publicLookup.findVirtual(Object.class, "hashCode",
+                                                       MethodType.fromMethodDescriptorString("()I", loader));
+            OBJECT_TO_STRING = publicLookup.findVirtual(Object.class, "toString",
+                                                        MethodType.methodType(String.class));
+            STRING_FORMAT = publicLookup.findStatic(String.class, "format",
+                                                    MethodType.methodType(String.class, String.class, Object[].class));
+            OBJECTS_EQUALS = publicLookup.findStatic(Objects.class, "equals",
+                                                     MethodType.methodType(boolean.class, Object.class, Object.class));
+            OBJECTS_HASHCODE = publicLookup.findStatic(Objects.class, "hashCode",
+                                                       MethodType.methodType(int.class, Object.class));
+            OBJECTS_TOSTRING = publicLookup.findStatic(Objects.class, "toString",
+                                                       MethodType.methodType(String.class, Object.class));
+
+            OBJECT_EQ = lookup.findStatic(ObjectMethods.class, "eq",
+                                          MethodType.methodType(boolean.class, Object.class, Object.class));
+            HASH_COMBINER = lookup.findStatic(ObjectMethods.class, "hashCombiner",
+                                              MethodType.fromMethodDescriptorString("(II)I", loader));
+
+            primitiveEquals.put(byte.class, lookup.findStatic(ObjectMethods.class, "eq",
+                                                              MethodType.fromMethodDescriptorString("(BB)Z", loader)));
+            primitiveEquals.put(short.class, lookup.findStatic(ObjectMethods.class, "eq",
+                                                               MethodType.fromMethodDescriptorString("(SS)Z", loader)));
+            primitiveEquals.put(char.class, lookup.findStatic(ObjectMethods.class, "eq",
+                                                              MethodType.fromMethodDescriptorString("(CC)Z", loader)));
+            primitiveEquals.put(int.class, lookup.findStatic(ObjectMethods.class, "eq",
+                                                             MethodType.fromMethodDescriptorString("(II)Z", loader)));
+            primitiveEquals.put(long.class, lookup.findStatic(ObjectMethods.class, "eq",
+                                                              MethodType.fromMethodDescriptorString("(JJ)Z", loader)));
+            primitiveEquals.put(float.class, lookup.findStatic(ObjectMethods.class, "eq",
+                                                               MethodType.fromMethodDescriptorString("(FF)Z", loader)));
+            primitiveEquals.put(double.class, lookup.findStatic(ObjectMethods.class, "eq",
+                                                                MethodType.fromMethodDescriptorString("(DD)Z", loader)));
+            primitiveEquals.put(boolean.class, lookup.findStatic(ObjectMethods.class, "eq",
+                                                                 MethodType.fromMethodDescriptorString("(ZZ)Z", loader)));
+
+            primitiveHashers.put(byte.class, lookup.findStatic(Byte.class, "hashCode",
+                                                               MethodType.fromMethodDescriptorString("(B)I", loader)));
+            primitiveHashers.put(short.class, lookup.findStatic(Short.class, "hashCode",
+                                                                MethodType.fromMethodDescriptorString("(S)I", loader)));
+            primitiveHashers.put(char.class, lookup.findStatic(Character.class, "hashCode",
+                                                               MethodType.fromMethodDescriptorString("(C)I", loader)));
+            primitiveHashers.put(int.class, lookup.findStatic(Integer.class, "hashCode",
+                                                              MethodType.fromMethodDescriptorString("(I)I", loader)));
+            primitiveHashers.put(long.class, lookup.findStatic(Long.class, "hashCode",
+                                                               MethodType.fromMethodDescriptorString("(J)I", loader)));
+            primitiveHashers.put(float.class, lookup.findStatic(Float.class, "hashCode",
+                                                                MethodType.fromMethodDescriptorString("(F)I", loader)));
+            primitiveHashers.put(double.class, lookup.findStatic(Double.class, "hashCode",
+                                                                 MethodType.fromMethodDescriptorString("(D)I", loader)));
+            primitiveHashers.put(boolean.class, lookup.findStatic(Boolean.class, "hashCode",
+                                                                  MethodType.fromMethodDescriptorString("(Z)I", loader)));
+
+            primitiveToString.put(byte.class, lookup.findStatic(Byte.class, "toString",
+                                                                MethodType.methodType(String.class, byte.class)));
+            primitiveToString.put(short.class, lookup.findStatic(Short.class, "toString",
+                                                                 MethodType.methodType(String.class, short.class)));
+            primitiveToString.put(char.class, lookup.findStatic(Character.class, "toString",
+                                                                MethodType.methodType(String.class, char.class)));
+            primitiveToString.put(int.class, lookup.findStatic(Integer.class, "toString",
+                                                               MethodType.methodType(String.class, int.class)));
+            primitiveToString.put(long.class, lookup.findStatic(Long.class, "toString",
+                                                                MethodType.methodType(String.class, long.class)));
+            primitiveToString.put(float.class, lookup.findStatic(Float.class, "toString",
+                                                                 MethodType.methodType(String.class, float.class)));
+            primitiveToString.put(double.class, lookup.findStatic(Double.class, "toString",
+                                                                  MethodType.methodType(String.class, double.class)));
+            primitiveToString.put(boolean.class, lookup.findStatic(Boolean.class, "toString",
+                                                                   MethodType.methodType(String.class, boolean.class)));
+        }
+        catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static int hashCombiner(int x, int y) {
+        return x*31 + y;
+    }
+
+    private static boolean eq(Object a, Object b) { return a == b; }
+    private static boolean eq(byte a, byte b) { return a == b; }
+    private static boolean eq(short a, short b) { return a == b; }
+    private static boolean eq(char a, char b) { return a == b; }
+    private static boolean eq(int a, int b) { return a == b; }
+    private static boolean eq(long a, long b) { return a == b; }
+    private static boolean eq(float a, float b) { return Float.compare(a, b) == 0; }
+    private static boolean eq(double a, double b) { return Double.compare(a, b) == 0; }
+    private static boolean eq(boolean a, boolean b) { return a == b; }
+
+    /** Get the method handle for combining two values of a given type */
+    private static MethodHandle equalator(Class<?> clazz) {
+        return (clazz.isPrimitive()
+                ? primitiveEquals.get(clazz)
+                : OBJECTS_EQUALS.asType(MethodType.methodType(boolean.class, clazz, clazz)));
+    }
+
+    /** Get the hasher for a value of a given type */
+    private static MethodHandle hasher(Class<?> clazz) {
+        return (clazz.isPrimitive()
+                ? primitiveHashers.get(clazz)
+                : OBJECTS_HASHCODE.asType(MethodType.methodType(int.class, clazz)));
+    }
+
+    /** Get the stringifier for a value of a given type */
+    private static MethodHandle stringifier(Class<?> clazz) {
+        return (clazz.isPrimitive()
+                ? primitiveToString.get(clazz)
+                : OBJECTS_TOSTRING.asType(MethodType.methodType(String.class, clazz)));
+    }
+
+    /**
+     * Generates a method handle for the {@code equals} method for a given data class
+     * @param receiverClass   the data class
+     * @param getters         the list of getters
+     * @return the method handle
+     */
+    private static MethodHandle makeEquals(Class<?> receiverClass,
+                                          List<MethodHandle> getters) {
+        MethodType rr = MethodType.methodType(boolean.class, receiverClass, receiverClass);
+        MethodType ro = MethodType.methodType(boolean.class, receiverClass, Object.class);
+        MethodHandle instanceFalse = MethodHandles.dropArguments(FALSE, 0, receiverClass, Object.class); // (RO)Z
+        MethodHandle instanceTrue = MethodHandles.dropArguments(TRUE, 0, receiverClass, Object.class); // (RO)Z
+        MethodHandle isSameObject = OBJECT_EQ.asType(ro); // (RO)Z
+        MethodHandle isInstance = MethodHandles.dropArguments(CLASS_IS_INSTANCE.bindTo(receiverClass), 0, receiverClass); // (RO)Z
+        MethodHandle accumulator = MethodHandles.dropArguments(TRUE, 0, receiverClass, receiverClass); // (RR)Z
+
+        for (MethodHandle getter : getters) {
+            MethodHandle equalator = equalator(getter.type().returnType()); // (TT)Z
+            MethodHandle thisFieldEqual = MethodHandles.filterArguments(equalator, 0, getter, getter); // (RR)Z
+            accumulator = MethodHandles.guardWithTest(thisFieldEqual, accumulator, instanceFalse.asType(rr));
+        }
+
+        return MethodHandles.guardWithTest(isSameObject,
+                                           instanceTrue,
+                                           MethodHandles.guardWithTest(isInstance, accumulator.asType(ro), instanceFalse));
+    }
+
+    /**
+     * Generates a method handle for the {@code hashCode} method for a given data class
+     * @param receiverClass   the data class
+     * @param getters         the list of getters
+     * @return the method handle
+     */
+    private static MethodHandle makeHashCode(Class<?> receiverClass,
+                                            List<MethodHandle> getters) {
+        MethodHandle accumulator = MethodHandles.dropArguments(ZERO, 0, receiverClass); // (R)I
+
+        // @@@ Use loop combinator instead?
+        for (MethodHandle getter : getters) {
+            MethodHandle hasher = hasher(getter.type().returnType()); // (T)I
+            MethodHandle hashThisField = MethodHandles.filterArguments(hasher, 0, getter);    // (R)I
+            MethodHandle combineHashes = MethodHandles.filterArguments(HASH_COMBINER, 0, accumulator, hashThisField); // (RR)I
+            accumulator = MethodHandles.permuteArguments(combineHashes, accumulator.type(), 0, 0); // adapt (R)I to (RR)I
+        }
+
+        return accumulator;
+    }
+
+    /**
+     * Generates a method handle for the {@code toString} method for a given data class
+     * @param receiverClass   the data class
+     * @param getters         the list of getters
+     * @param names           the names
+     * @return the method handle
+     */
+    private static MethodHandle makeToString(Class<?> receiverClass,
+                                            List<MethodHandle> getters,
+                                            List<String> names) {
+        // This is a pretty lousy algorithm; we spread the receiver over N places,
+        // apply the N getters, apply N toString operations, and concat the result with String.format
+        // Better to use String.format directly, or delegate to StringConcatFactory
+        // Also probably want some quoting around String components
+
+        assert getters.size() == names.size();
+
+        int[] invArgs = new int[getters.size()];
+        Arrays.fill(invArgs, 0);
+        MethodHandle[] filters = new MethodHandle[getters.size()];
+        StringBuilder sb = new StringBuilder();
+        sb.append(receiverClass.getSimpleName()).append("[");
+        for (int i=0; i<getters.size(); i++) {
+            MethodHandle getter = getters.get(i); // (R)T
+            MethodHandle stringify = stringifier(getter.type().returnType()); // (T)String
+            MethodHandle stringifyThisField = MethodHandles.filterArguments(stringify, 0, getter);    // (R)String
+            filters[i] = stringifyThisField;
+            sb.append(names.get(i)).append("=%s");
+            if (i != getters.size() - 1)
+                sb.append(", ");
+        }
+        sb.append(']');
+        String formatString = sb.toString();
+        MethodHandle formatter = MethodHandles.insertArguments(STRING_FORMAT, 0, formatString)
+                                              .asCollector(String[].class, getters.size()); // (R*)String
+        if (getters.size() == 0) {
+            // Add back extra R
+            formatter = MethodHandles.dropArguments(formatter, 0, receiverClass);
+        }
+        else {
+            MethodHandle filtered = MethodHandles.filterArguments(formatter, 0, filters);
+            formatter = MethodHandles.permuteArguments(filtered, MethodType.methodType(String.class, receiverClass), invArgs);
+        }
+
+        return formatter;
+    }
+
+    /**
+     * Bootstrap method to generate the {@link Object#equals(Object)},
+     * {@link Object#hashCode()}, and {@link Object#toString()} methods, based
+     * on a description of the component names and accessor methods, for either
+     * {@code invokedynamic} call sites or dynamic constant pool entries
+     *
+     * @param lookup       the lookup
+     * @param methodName   the name of the method to generate, which must be one of
+     *                     {@code "equals"}, {@code "hashCode"}, or {@code "toString"}
+     * @param type         a {@link MethodType} corresponding the descriptor type
+     *                     for the method, which must correspond to the descriptor
+     *                     for the corresponding {@link Object} method, if linking
+     *                     an {@code invokedynamic} call site, or the
+     *                     constant {@code MethodHandle.class}, if linking a
+     *                     dynamic constant
+     * @param theClass     the class hosting the components
+     * @param names        the list of component names, joined into a string separated by ";"
+     * @param getters      method handles for the accessor methods for the components
+     * @return             a call site if invoked by indy, or a method handle
+     *                     if invoked by a condy
+     * @throws IllegalArgumentException if the bootstrap arguments are invalid
+     *                                  or inconsistent
+     * @throws Throwable if any exception is thrown during call site construction
+     */
+    public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, TypeDescriptor type,
+                                   Class<?> theClass,
+                                   String names,
+                                   MethodHandle... getters) throws Throwable {
+        MethodType methodType;
+        if (type instanceof MethodType)
+            methodType = (MethodType) type;
+        else {
+            methodType = null;
+            if (!MethodHandle.class.equals(type))
+                throw new IllegalArgumentException(type.toString());
+        }
+        List<MethodHandle> getterList = List.of(getters);
+        MethodHandle handle;
+        switch (methodName) {
+            case "equals":
+                if (methodType != null && !methodType.equals(MethodType.methodType(boolean.class, theClass, Object.class)))
+                    throw new IllegalArgumentException("Bad method type: " + methodType);
+                handle = makeEquals(theClass, getterList);
+                return methodType != null ? new ConstantCallSite(handle) : handle;
+            case "hashCode":
+                if (methodType != null && !methodType.equals(MethodType.methodType(int.class, theClass)))
+                    throw new IllegalArgumentException("Bad method type: " + methodType);
+                handle = makeHashCode(theClass, getterList);
+                return methodType != null ? new ConstantCallSite(handle) : handle;
+            case "toString":
+                if (methodType != null && !methodType.equals(MethodType.methodType(String.class, theClass)))
+                    throw new IllegalArgumentException("Bad method type: " + methodType);
+                List<String> nameList = "".equals(names) ? List.of() : List.of(names.split(";"));
+                if (nameList.size() != getterList.size())
+                    throw new IllegalArgumentException("Name list and accessor list do not match");
+                handle = makeToString(theClass, getterList, nameList);
+                return methodType != null ? new ConstantCallSite(handle) : handle;
+            default:
+                throw new IllegalArgumentException(methodName);
+        }
+    }
+}
--- a/src/java.base/share/classes/module-info.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.base/share/classes/module-info.java	Wed Oct 16 17:02:29 2019 -0400
@@ -132,6 +132,8 @@
     // additional qualified exports may be inserted at build time
     // see make/gensrc/GenModuleInfo.gmk
 
+    exports sun.invoke.util to
+        jdk.compiler;
     exports com.sun.security.ntlm to
         java.security.sasl;
     exports jdk.internal to
--- a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java	Wed Oct 16 17:02:29 2019 -0400
@@ -90,7 +90,8 @@
         METHOD_RETURN,
         METHOD_RECEIVER,
         METHOD_FORMAL_PARAMETER,
-        THROWS;
+        THROWS,
+        RECORD_COMPONENT;
     }
 
     public static final class TypeAnnotationTargetInfo {
--- a/src/java.base/share/native/libjava/Class.c	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.base/share/native/libjava/Class.c	Wed Oct 16 17:02:29 2019 -0400
@@ -38,6 +38,10 @@
 #include "check_classname.h"
 #include "java_lang_Class.h"
 
+/* defined in libverify.so/verify.dll (src file common/check_format.c) */
+extern jboolean VerifyClassname(char *utf_name, jboolean arrayAllowed);
+extern jboolean VerifyFixClassname(char *utf_name);
+
 #define OBJ "Ljava/lang/Object;"
 #define CLS "Ljava/lang/Class;"
 #define CPL "Ljdk/internal/reflect/ConstantPool;"
@@ -73,6 +77,8 @@
     {"getRawTypeAnnotations", "()" BA,      (void *)&JVM_GetClassTypeAnnotations},
     {"getNestHost0",         "()" CLS,      (void *)&JVM_GetNestHost},
     {"getNestMembers0",      "()[" CLS,     (void *)&JVM_GetNestMembers},
+    {"getRecordComponents0",  "()[" OBJ,        (void *)&JVM_GetRecordComponents},
+    {"isRecord0",                 "()Z",        (void *)&JVM_IsRecord},
     {"linkClass",            "(" CLS ")V",  (void *)&JVM_LinkClass},
 };
 
--- a/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java	Wed Oct 16 17:02:29 2019 -0400
@@ -78,8 +78,8 @@
      * The annotation may appear directly or be inherited.  Only
      * package elements, module elements, and type elements <i>included</i> in this
      * round of annotation processing, or declarations of members,
-     * constructors, parameters, or type parameters declared within
-     * those, are returned.  Included type elements are {@linkplain
+     * constructors, parameters, type parameters, or record components
+     * declared within those, are returned.  Included type elements are {@linkplain
      * #getRootElements root types} and any member types nested within
      * them.  Elements of a package are not considered included simply
      * because a {@code package-info} file for that package was
@@ -133,8 +133,8 @@
      * The annotation may appear directly or be inherited.  Only
      * package elements, module elements, and type elements <i>included</i> in this
      * round of annotation processing, or declarations of members,
-     * constructors, parameters, or type parameters declared within
-     * those, are returned.  Included type elements are {@linkplain
+     * constructors, parameters, type parameters, or record components
+     * declared within those, are returned.  Included type elements are {@linkplain
      * #getRootElements root types} and any member types nested within
      * them.  Elements in a package are not considered included simply
      * because a {@code package-info} file for that package was
--- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java	Wed Oct 16 17:02:29 2019 -0400
@@ -63,6 +63,12 @@
      *  14: TBD
      */
 
+    // TOOD: The textual specs of isIdentifier, isName, and isKeyword
+    // may or may not need to be explicitly updated for "record" and
+    // "sealed" depending on how those tokens are formally handled in
+    // the JLS. If they are treated as restricted keywords, a spec
+    // update may not be strictly needed.
+
     /**
      * The original version.
      *
--- a/src/java.compiler/share/classes/javax/lang/model/element/Element.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/element/Element.java	Wed Oct 16 17:02:29 2019 -0400
@@ -118,6 +118,7 @@
      * @see TypeElement#getSimpleName
      * @see VariableElement#getSimpleName
      * @see ModuleElement#getSimpleName
+     * @see RecordComponentElement#getSimpleName
      * @revised 9
      * @spec JPMS
      */
@@ -148,6 +149,11 @@
      * parameter}, {@linkplain ExecutableElement the executable
      * element} which declares the parameter is returned.
      *
+     * <li> If this is a {@linkplain
+     * RecordComponentElement#getEnclosingElement record component},
+     * {@linkplain TypeElement the type} which declares the
+     * record component is returned.
+     *
      * <li> If this is a {@linkplain ModuleElement#getEnclosingElement
      * module}, {@code null} is returned.
      *
@@ -166,7 +172,7 @@
      *
      * A {@linkplain TypeElement#getEnclosedElements class or
      * interface} is considered to enclose the fields, methods,
-     * constructors, and member types that it directly declares.
+     * constructors, record components, and member types that it directly declares.
      *
      * A {@linkplain PackageElement#getEnclosedElements package}
      * encloses the top-level classes and interfaces within it, but is
--- a/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java	Wed Oct 16 17:02:29 2019 -0400
@@ -46,8 +46,12 @@
     // Declared types
     /** An enum type. */
     ENUM,
-    /** A class not described by a more specific kind (like {@code ENUM}). */
+    /**
+     * A class not described by a more specific kind (like {@code
+     * ENUM} or {@code RECORD}).
+     */
     CLASS,
+
     /** An annotation type. */
     ANNOTATION_TYPE,
     /**
@@ -90,6 +94,8 @@
      */
     OTHER,
 
+    // Constants added since initial release
+
     /**
      * A resource variable.
      * @since 1.7
@@ -101,17 +107,28 @@
      * @since 9
      * @spec JPMS
      */
-     MODULE;
+     MODULE,
 
+    /**
+     * A record type.
+     * @since amber
+     */
+    RECORD,
+
+    /**
+     * A record component of a {@code record}.
+     * @since 14
+     */
+    RECORD_COMPONENT;
 
     /**
      * Returns {@code true} if this is a kind of class:
-     * either {@code CLASS} or {@code ENUM}.
+     * either {@code CLASS} or {@code ENUM} or {@code RECORD}.
      *
      * @return {@code true} if this is a kind of class
      */
     public boolean isClass() {
-        return this == CLASS || this == ENUM;
+        return this == CLASS || this == ENUM || this == RECORD;
     }
 
     /**
--- a/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java	Wed Oct 16 17:02:29 2019 -0400
@@ -164,4 +164,19 @@
     default R visitModule(ModuleElement e, P p) {
         return visitUnknown(e, p);
     }
+
+    /**
+     * Visits a record component element.
+     *
+     * @implSpec The default implementation visits a {@code
+     * RecordComponentElement} by calling {@code visitUnknown(e, p)}.
+     *
+     * @param e  the element to visit
+     * @param p  a visitor-specified parameter
+     * @return a visitor-specified result
+     * @since 14
+     */
+    default R visitRecordComponent(RecordComponentElement e, P p) {
+        return visitUnknown(e, p);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.compiler/share/classes/javax/lang/model/element/RecordComponentElement.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,66 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package javax.lang.model.element;
+
+/**
+ * Represents a record component.
+ *
+ * @since 14
+ */
+
+public interface RecordComponentElement extends Element {
+    /**
+     * Returns the enclosing element of this record component.
+     *
+     * The enclosing element of a record component is the type
+     * declaring the record component.
+     *
+     * @return the enclosing element of this record component
+     */
+    @Override
+    Element getEnclosingElement();
+
+    /**
+     * Returns the simple name of this record component.
+     *
+     * <p>The name of each record component must be distinct from the
+     * names of all other record components.
+     *
+     * @return the simple name of this record component
+     *
+     * @jls 6.2 Names and Identifiers
+     */
+    @Override
+    Name getSimpleName();
+
+    /**
+     * Returns the executable element for the accessor associated with the
+     * given record component.
+     *
+     * @return the record component accessor.
+     */
+    ExecutableElement getAccessor();
+}
--- a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java	Wed Oct 16 17:02:29 2019 -0400
@@ -32,7 +32,7 @@
 /**
  * Represents a class or interface program element.  Provides access
  * to information about the type and its members.  Note that an enum
- * type is a kind of class and an annotation type is a kind of
+ * type and a record type are kinds of classes and an annotation type is a kind of
  * interface.
  *
  * <p> While a {@code TypeElement} represents a class or interface
@@ -82,8 +82,9 @@
     TypeMirror asType();
 
     /**
-     * Returns the fields, methods, constructors, and member types
-     * that are directly declared in this class or interface.
+     * Returns the fields, methods, constructors, record components,
+     * and member types that are directly declared in this class or
+     * interface.
      *
      * This includes any {@linkplain Elements.Origin#MANDATED
      * mandated} elements such as the (implicit) default constructor
@@ -178,6 +179,38 @@
     List<? extends TypeParameterElement> getTypeParameters();
 
     /**
+     * Returns the record components of this type element in
+     * declaration order.
+     *
+     * @implSpec The default implementations of this method returns an
+     * empty and unmodifiable list.
+     *
+     * @return the record components, or an empty list if there are
+     * none
+     *
+     * @since 14
+     */
+    default List<? extends RecordComponentElement> getRecordComponents() {
+        return List.of();
+    }
+
+    /**
+     * Returns the permitted subtypes of this type element in
+     * declaration order.
+     *
+     * @implSpec The default implementations of this method returns an
+     * empty and unmodifiable list.
+     *
+     * @return the permitted subtypes, or an empty list
+     * if there are none
+     *
+     * @since amber
+     */
+    default List<? extends TypeMirror> getPermittedSubtypes() {
+        return List.of();
+    }
+
+    /**
      * Returns the package of a top-level type and returns the
      * immediately lexically enclosing element for a {@linkplain
      * NestingKind#isNested nested} type.
--- a/src/java.compiler/share/classes/javax/lang/model/element/package-info.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/element/package-info.java	Wed Oct 16 17:02:29 2019 -0400
@@ -90,8 +90,8 @@
  * new RuntimeException();"}.  If a program refers to a missing type Xyz,
  * the returned model must contain no less information than if the
  * declaration of type Xyz were assumed to be {@code "class Xyz {}"},
- * {@code "interface Xyz {}"}, {@code "enum Xyz {}"}, or {@code
- * "@interface Xyz {}"}. If a program refers to a missing type {@code
+ * {@code "interface Xyz {}"}, {@code "enum Xyz {}"}, {@code
+ * "@interface Xyz {}"}, or {@code "record Xyz {}"}. If a program refers to a missing type {@code
  * Xyz<K1, ... ,Kn>}, the returned model must contain no less
  * information than if the declaration of Xyz were assumed to be
  * {@code "class Xyz<T1, ... ,Tn> {}"} or {@code "interface Xyz<T1,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2011, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package javax.lang.model.util;
+
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.RecordComponentElement;
+import static javax.lang.model.SourceVersion.*;
+
+
+/**
+ * A skeletal visitor of program elements with default behavior
+ * appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14}
+ * source version.
+ *
+ * <p> <b>WARNING:</b> The {@code ElementVisitor} interface
+ * implemented by this class may have methods added to it in the
+ * future to accommodate new, currently unknown, language structures
+ * added to future versions of the Java&trade; programming language.
+ * Therefore, methods whose names begin with {@code "visit"} may be
+ * added to this class in the future; to avoid incompatibilities,
+ * classes which extend this class should not declare any instance
+ * methods with names beginning with {@code "visit"}.
+ *
+ * <p>When such a new visit method is added, the default
+ * implementation in this class will be to call the {@link
+ * #visitUnknown visitUnknown} method.  A new abstract element visitor
+ * class will also be introduced to correspond to the new language
+ * level; this visitor will have different default behavior for the
+ * visit method in question.  When the new visitor is introduced, all
+ * or portions of this visitor may be deprecated.
+ *
+ * @param <R> the return type of this visitor's methods.  Use {@link
+ *            Void} for visitors that do not need to return results.
+ * @param <P> the type of the additional parameter to this visitor's
+ *            methods.  Use {@code Void} for visitors that do not need an
+ *            additional parameter.
+ *
+ * @see AbstractElementVisitor6
+ * @see AbstractElementVisitor7
+ * @see AbstractElementVisitor8
+ * @see AbstractElementVisitor9
+ * @since 14
+ */
+@SupportedSourceVersion(RELEASE_14)
+public abstract class AbstractElementVisitor14<R, P> extends AbstractElementVisitor9<R, P> {
+    /**
+     * Constructor for concrete subclasses to call.
+     */
+    protected AbstractElementVisitor14(){
+        super();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec Visits a {@code RecordComponentElement} in a manner defined by a
+     * subclass.
+     *
+     * @param t  {@inheritDoc}
+     * @param p  {@inheritDoc}
+     * @return   {@inheritDoc}
+     */
+    @Override
+    public abstract R visitRecordComponent(RecordComponentElement t, P p);
+}
--- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor6.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor6.java	Wed Oct 16 17:02:29 2019 -0400
@@ -66,6 +66,7 @@
  * @see AbstractElementVisitor7
  * @see AbstractElementVisitor8
  * @see AbstractElementVisitor9
+ * @see AbstractElementVisitor14
  * @since 1.6
  */
 @SupportedSourceVersion(RELEASE_6)
@@ -143,4 +144,22 @@
         // Use implementation from interface default method
         return ElementVisitor.super.visitModule(e, p);
     }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec Visits a {@code RecordComponentElement} by calling {@code
+     * visitUnknown}.
+     *
+     * @param e  {@inheritDoc}
+     * @param p  {@inheritDoc}
+     * @return   {@inheritDoc}
+     *
+     * @since 14
+     */
+    @Override
+    public R visitRecordComponent(RecordComponentElement e, P p) {
+        // Use implementation from interface default method
+        return ElementVisitor.super.visitRecordComponent(e, p);
+    }
 }
--- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor7.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor7.java	Wed Oct 16 17:02:29 2019 -0400
@@ -61,6 +61,7 @@
  * @see AbstractElementVisitor6
  * @see AbstractElementVisitor8
  * @see AbstractElementVisitor9
+ * @see AbstractElementVisitor14
  * @since 1.7
  */
 @SupportedSourceVersion(RELEASE_7)
--- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor8.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor8.java	Wed Oct 16 17:02:29 2019 -0400
@@ -61,6 +61,7 @@
  * @see AbstractElementVisitor6
  * @see AbstractElementVisitor7
  * @see AbstractElementVisitor9
+ * @see AbstractElementVisitor14
  * @since 1.8
  */
 @SupportedSourceVersion(RELEASE_8)
--- a/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java	Wed Oct 16 17:02:29 2019 -0400
@@ -83,7 +83,12 @@
         Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS,
                                                ElementKind.ENUM,
                                                ElementKind.INTERFACE,
+                                               ElementKind.RECORD,
                                                ElementKind.ANNOTATION_TYPE));
+
+    private static final Set<ElementKind> RECORD_COMPONENT_KIND =
+        Set.of(ElementKind.RECORD_COMPONENT);
+
     /**
      * Returns a list of fields in {@code elements}.
      * @return a list of fields in {@code elements}
@@ -105,6 +110,28 @@
     }
 
     /**
+     * Returns a list of record components in {@code elements}.
+     * @return a list of record components in {@code elements}
+     * @param elements the elements to filter
+     * @since 14
+     */
+    public static List<RecordComponentElement>
+        recordComponentsIn(Iterable<? extends Element> elements) {
+        return listFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class);
+    }
+
+    /**
+     * Returns a set of record components in {@code elements}.
+     * @return a set of record components in {@code elements}
+     * @param elements the elements to filter
+     * @since 14
+     */
+    public static Set<RecordComponentElement>
+    recordComponentsIn(Set<? extends Element> elements) {
+        return setFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class);
+    }
+
+    /**
      * Returns a list of constructors in {@code elements}.
      * @return a list of constructors in {@code elements}
      * @param elements the elements to filter
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2011, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package javax.lang.model.util;
+
+import javax.lang.model.element.*;
+import javax.annotation.processing.SupportedSourceVersion;
+import static javax.lang.model.SourceVersion.*;
+import javax.lang.model.SourceVersion;
+
+/**
+ * A visitor of program elements based on their {@linkplain
+ * ElementKind kind} with default behavior appropriate for the {@link
+ * SourceVersion#RELEASE_14 RELEASE_14} source version.
+ *
+ * For {@linkplain
+ * Element elements} <code><i>Xyz</i></code> that may have more than one
+ * kind, the <code>visit<i>Xyz</i></code> methods in this class delegate
+ * to the <code>visit<i>Xyz</i>As<i>Kind</i></code> method corresponding to the
+ * first argument's kind.  The <code>visit<i>Xyz</i>As<i>Kind</i></code> methods
+ * call {@link #defaultAction defaultAction}, passing their arguments
+ * to {@code defaultAction}'s corresponding parameters.
+ *
+ * <p> Methods in this class may be overridden subject to their
+ * general contract.  Note that annotating methods in concrete
+ * subclasses with {@link java.lang.Override @Override} will help
+ * ensure that methods are overridden as intended.
+ *
+ * <p> <b>WARNING:</b> The {@code ElementVisitor} interface
+ * implemented by this class may have methods added to it or the
+ * {@code ElementKind} {@code enum} used in this case may have
+ * constants added to it in the future to accommodate new, currently
+ * unknown, language structures added to future versions of the
+ * Java&trade; programming language.  Therefore, methods whose names
+ * begin with {@code "visit"} may be added to this class in the
+ * future; to avoid incompatibilities, classes which extend this class
+ * should not declare any instance methods with names beginning with
+ * {@code "visit"}.
+ *
+ * <p>When such a new visit method is added, the default
+ * implementation in this class will be to call the {@link
+ * #visitUnknown visitUnknown} method.  A new abstract element kind
+ * visitor class will also be introduced to correspond to the new
+ * language level; this visitor will have different default behavior
+ * for the visit method in question.  When the new visitor is
+ * introduced, all or portions of this visitor may be deprecated.
+ *
+ * @param <R> the return type of this visitor's methods.  Use {@link
+ *            Void} for visitors that do not need to return results.
+ * @param <P> the type of the additional parameter to this visitor's
+ *            methods.  Use {@code Void} for visitors that do not need an
+ *            additional parameter.
+ *
+ * @see ElementKindVisitor6
+ * @see ElementKindVisitor7
+ * @see ElementKindVisitor8
+ * @see ElementKindVisitor9
+ * @since 14
+ */
+@SupportedSourceVersion(RELEASE_14)
+public class ElementKindVisitor14<R, P> extends ElementKindVisitor9<R, P> {
+    /**
+     * Constructor for concrete subclasses; uses {@code null} for the
+     * default value.
+     */
+    protected ElementKindVisitor14() {
+        super(null);
+    }
+
+    /**
+     * Constructor for concrete subclasses; uses the argument for the
+     * default value.
+     *
+     * @param defaultValue the value to assign to {@link #DEFAULT_VALUE}
+     */
+    protected ElementKindVisitor14(R defaultValue) {
+        super(defaultValue);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec This implementation calls {@code defaultAction}.
+     *
+     * @param e the element to visit
+     * @param p a visitor-specified parameter
+     * @return  the result of {@code defaultAction}
+     */
+    @Override
+    public R visitRecordComponent(RecordComponentElement e, P p) {
+        return defaultAction(e, p);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec This implementation calls {@code defaultAction}.
+     *.
+     * @param e the element to visit
+     * @param p a visitor-specified parameter
+     * @return  the result of {@code defaultAction}
+     */
+    @Override
+    public R visitTypeAsRecord(TypeElement e, P p) {
+        return defaultAction(e, p);
+    }
+}
--- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java	Wed Oct 16 17:02:29 2019 -0400
@@ -80,6 +80,7 @@
  * @see ElementKindVisitor7
  * @see ElementKindVisitor8
  * @see ElementKindVisitor9
+ * @see ElementKindVisitor14
  * @since 1.6
  */
 @SupportedSourceVersion(RELEASE_6)
@@ -154,6 +155,9 @@
         case INTERFACE:
             return visitTypeAsInterface(e, p);
 
+        case RECORD:
+            return visitTypeAsRecord(e, p);
+
         default:
             throw new AssertionError("Bad kind " + k + " for TypeElement" + e);
         }
@@ -212,6 +216,21 @@
     }
 
     /**
+     * Visits a {@code RECORD} type element.
+     *
+     * @implSpec This implementation calls {@code visitUnknown}.
+     *.
+     * @param e the element to visit
+     * @param p a visitor-specified parameter
+     * @return  the result of {@code visitUnknown}
+     *
+     * @since amber
+     */
+    public R visitTypeAsRecord(TypeElement e, P p) {
+        return visitUnknown(e, p);
+    }
+
+    /**
      * Visits a variable element
      *
      * @implSpec This implementation dispatches to the visit method for
--- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor7.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor7.java	Wed Oct 16 17:02:29 2019 -0400
@@ -74,6 +74,7 @@
  * @see ElementKindVisitor6
  * @see ElementKindVisitor8
  * @see ElementKindVisitor9
+ * @see ElementKindVisitor14
  * @since 1.7
  */
 @SupportedSourceVersion(RELEASE_7)
--- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor8.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor8.java	Wed Oct 16 17:02:29 2019 -0400
@@ -74,6 +74,7 @@
  * @see ElementKindVisitor6
  * @see ElementKindVisitor7
  * @see ElementKindVisitor9
+ * @see ElementKindVisitor14
  * @since 1.8
  */
 @SupportedSourceVersion(RELEASE_8)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2011, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package javax.lang.model.util;
+
+import javax.lang.model.element.*;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import static javax.lang.model.SourceVersion.*;
+
+/**
+ * A scanning visitor of program elements with default behavior
+ * appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14}
+ * source version.
+ *
+ * The <code>visit<i>Xyz</i></code> methods in this
+ * class scan their component elements by calling {@code scan} on
+ * their {@linkplain Element#getEnclosedElements enclosed elements},
+ * {@linkplain ExecutableElement#getParameters parameters}, etc., as
+ * indicated in the individual method specifications.  A subclass can
+ * control the order elements are visited by overriding the
+ * <code>visit<i>Xyz</i></code> methods.  Note that clients of a scanner
+ * may get the desired behavior be invoking {@code v.scan(e, p)} rather
+ * than {@code v.visit(e, p)} on the root objects of interest.
+ *
+ * <p>When a subclass overrides a <code>visit<i>Xyz</i></code> method, the
+ * new method can cause the enclosed elements to be scanned in the
+ * default way by calling <code>super.visit<i>Xyz</i></code>.  In this
+ * fashion, the concrete visitor can control the ordering of traversal
+ * over the component elements with respect to the additional
+ * processing; for example, consistently calling
+ * <code>super.visit<i>Xyz</i></code> at the start of the overridden
+ * methods will yield a preorder traversal, etc.  If the component
+ * elements should be traversed in some other order, instead of
+ * calling <code>super.visit<i>Xyz</i></code>, an overriding visit method
+ * should call {@code scan} with the elements in the desired order.
+ *
+ * <p> Methods in this class may be overridden subject to their
+ * general contract.  Note that annotating methods in concrete
+ * subclasses with {@link java.lang.Override @Override} will help
+ * ensure that methods are overridden as intended.
+ *
+ * <p> <b>WARNING:</b> The {@code ElementVisitor} interface
+ * implemented by this class may have methods added to it in the
+ * future to accommodate new, currently unknown, language structures
+ * added to future versions of the Java&trade; programming language.
+ * Therefore, methods whose names begin with {@code "visit"} may be
+ * added to this class in the future; to avoid incompatibilities,
+ * classes which extend this class should not declare any instance
+ * methods with names beginning with {@code "visit"}.
+ *
+ * <p>When such a new visit method is added, the default
+ * implementation in this class will be to call the {@link
+ * #visitUnknown visitUnknown} method.  A new element scanner visitor
+ * class will also be introduced to correspond to the new language
+ * level; this visitor will have different default behavior for the
+ * visit method in question.  When the new visitor is introduced, all
+ * or portions of this visitor may be deprecated.
+ *
+ * @param <R> the return type of this visitor's methods.  Use {@link
+ *            Void} for visitors that do not need to return results.
+ * @param <P> the type of the additional parameter to this visitor's
+ *            methods.  Use {@code Void} for visitors that do not need an
+ *            additional parameter.
+ *
+ * @see ElementScanner6
+ * @see ElementScanner7
+ * @see ElementScanner8
+ * @see ElementScanner9
+ * @since 14
+ */
+@SupportedSourceVersion(RELEASE_14)
+public class ElementScanner14<R, P> extends ElementScanner9<R, P> {
+    /**
+     * Constructor for concrete subclasses; uses {@code null} for the
+     * default value.
+     */
+    protected ElementScanner14(){
+        super(null);
+    }
+
+    /**
+     * Constructor for concrete subclasses; uses the argument for the
+     * default value.
+     *
+     * @param defaultValue the default value
+     */
+    protected ElementScanner14(R defaultValue){
+        super(defaultValue);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec This implementation scans the enclosed elements.
+     *
+     * @param e the element to visit
+     * @param p a visitor-specified parameter
+     * @return  the result of the scan
+     */
+    @Override
+    public R visitRecordComponent(RecordComponentElement e, P p) {
+        return scan(e.getEnclosedElements(), p);
+    }
+}
--- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java	Wed Oct 16 17:02:29 2019 -0400
@@ -91,6 +91,7 @@
  * @see ElementScanner7
  * @see ElementScanner8
  * @see ElementScanner9
+ * @see ElementScanner14
  * @since 1.6
  */
 @SupportedSourceVersion(RELEASE_6)
--- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java	Wed Oct 16 17:02:29 2019 -0400
@@ -87,6 +87,7 @@
  * @see ElementScanner6
  * @see ElementScanner8
  * @see ElementScanner9
+ * @see ElementScanner14
  * @since 1.7
  */
 @SupportedSourceVersion(RELEASE_7)
--- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java	Wed Oct 16 17:02:29 2019 -0400
@@ -87,6 +87,7 @@
  * @see ElementScanner6
  * @see ElementScanner7
  * @see ElementScanner9
+ * @see ElementScanner14
  * @since 1.8
  */
 @SupportedSourceVersion(RELEASE_8)
--- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java	Wed Oct 16 17:02:29 2019 -0400
@@ -89,6 +89,7 @@
  * @see ElementScanner6
  * @see ElementScanner7
  * @see ElementScanner8
+ * @see ElementScanner14
  * @since 9
  * @spec JPMS
  */
--- a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java	Wed Oct 16 17:02:29 2019 -0400
@@ -31,6 +31,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.LinkedHashSet;
+import java.util.Objects;
 
 import javax.lang.model.AnnotatedConstruct;
 import javax.lang.model.element.*;
@@ -629,4 +630,38 @@
      * @since 1.8
      */
     boolean isFunctionalInterface(TypeElement type);
+
+    /**
+     * TODO: needed? @see RecordComponentElement#getAccessor()
+     *
+     * Returns the executable element for the getter associated with the given variable element.
+     *
+     * @implSpec The default implementation of this method returns
+     * {@code null}.
+     *
+     * @param variableElement the field for which the getter is to be found.
+     * @return the field's getter; otherwise {@code null} if there is no getter.
+     * @since amber
+     */
+    default ExecutableElement getterFor(VariableElement variableElement) {
+        return null;
+    }
+
+    /**
+     * Returns the record component for the given accessor. Returns null if the
+     * given method is not a record component accessor.
+     *
+     * @param accessor the method for which the record component should be found.
+     * @return the record component, or null if the given method is not an record component accessor
+     */
+    default RecordComponentElement recordComponentFor(ExecutableElement accessor) {
+        if (accessor.getEnclosingElement().getKind() == ElementKind.RECORD) {
+            for (RecordComponentElement rec : ElementFilter.recordComponentsIn(accessor.getEnclosingElement().getEnclosedElements())) {
+                if (Objects.equals(rec.getAccessor(), accessor)) {
+                    return rec;
+                }
+            }
+        }
+        return null;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2011, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package javax.lang.model.util;
+
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.RecordComponentElement;
+import static javax.lang.model.SourceVersion.*;
+
+/**
+ * A simple visitor of program elements with default behavior
+ * appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14}
+ * source version.
+ *
+ * Visit methods corresponding to {@code RELEASE_14} and earlier
+ * language constructs call {@link #defaultAction defaultAction},
+ * passing their arguments to {@code defaultAction}'s corresponding
+ * parameters.
+ *
+ * <p> Methods in this class may be overridden subject to their
+ * general contract.  Note that annotating methods in concrete
+ * subclasses with {@link java.lang.Override @Override} will help
+ * ensure that methods are overridden as intended.
+ *
+ * <p> <b>WARNING:</b> The {@code ElementVisitor} interface
+ * implemented by this class may have methods added to it in the
+ * future to accommodate new, currently unknown, language structures
+ * added to future versions of the Java&trade; programming language.
+ * Therefore, methods whose names begin with {@code "visit"} may be
+ * added to this class in the future; to avoid incompatibilities,
+ * classes which extend this class should not declare any instance
+ * methods with names beginning with {@code "visit"}.
+ *
+ * <p>When such a new visit method is added, the default
+ * implementation in this class will be to call the {@link
+ * #visitUnknown visitUnknown} method.  A new simple element visitor
+ * class will also be introduced to correspond to the new language
+ * level; this visitor will have different default behavior for the
+ * visit method in question.  When the new visitor is introduced, all
+ * or portions of this visitor may be deprecated.
+ *
+ * @param <R> the return type of this visitor's methods.  Use {@code Void}
+ *             for visitors that do not need to return results.
+ * @param <P> the type of the additional parameter to this visitor's methods.  Use {@code Void}
+ *              for visitors that do not need an additional parameter.
+ *
+ * @see SimpleElementVisitor6
+ * @see SimpleElementVisitor7
+ * @see SimpleElementVisitor8
+ * @see SimpleElementVisitor9
+ * @since 14
+ */
+@SupportedSourceVersion(RELEASE_14)
+public class SimpleElementVisitor14<R, P> extends SimpleElementVisitor9<R, P> {
+    /**
+     * Constructor for concrete subclasses; uses {@code null} for the
+     * default value.
+     */
+    protected SimpleElementVisitor14(){
+        super(null);
+    }
+
+    /**
+     * Constructor for concrete subclasses; uses the argument for the
+     * default value.
+     *
+     * @param defaultValue the value to assign to {@link #DEFAULT_VALUE}
+     */
+    protected SimpleElementVisitor14(R defaultValue){
+        super(defaultValue);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec Visits a {@code RecordComponentElement} by calling {@code
+     * defaultAction}.
+     *
+     * @param e the element to visit
+     * @param p a visitor-specified parameter
+     * @return  {@inheritDoc}
+     */
+    @Override
+    public R visitRecordComponent(RecordComponentElement e, P p) {
+        return defaultAction(e, p);
+    }
+}
--- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java	Wed Oct 16 17:02:29 2019 -0400
@@ -77,6 +77,7 @@
  * @see SimpleElementVisitor7
  * @see SimpleElementVisitor8
  * @see SimpleElementVisitor9
+ * @see SimpleElementVisitor14
  * @since 1.6
  */
 @SupportedSourceVersion(RELEASE_6)
--- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor7.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor7.java	Wed Oct 16 17:02:29 2019 -0400
@@ -70,6 +70,7 @@
  * @see SimpleElementVisitor6
  * @see SimpleElementVisitor8
  * @see SimpleElementVisitor9
+ * @see SimpleElementVisitor14
  * @since 1.7
  */
 @SupportedSourceVersion(RELEASE_7)
--- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor8.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor8.java	Wed Oct 16 17:02:29 2019 -0400
@@ -69,6 +69,7 @@
  * @see SimpleElementVisitor6
  * @see SimpleElementVisitor7
  * @see SimpleElementVisitor9
+ * @see SimpleElementVisitor14
  * @since 1.8
  */
 @SupportedSourceVersion(RELEASE_8)
--- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor9.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor9.java	Wed Oct 16 17:02:29 2019 -0400
@@ -70,6 +70,7 @@
  * @see SimpleElementVisitor6
  * @see SimpleElementVisitor7
  * @see SimpleElementVisitor8
+ * @see SimpleElementVisitor14
  * @since 9
  * @spec JPMS
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/AccessorTree.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.source.doctree;
+
+import java.util.List;
+
+/**
+ *
+ * A tree node for an @getter or @setter block tag.
+ *
+ * <p>
+ * &#064;getter description <br>
+ * &#064;setter description <br>
+ *
+ * @since 1.10
+ */
+public interface AccessorTree extends BlockTagTree {
+    /**
+     * Returns the description of the {@code @getter} or {@code @setter} tag.
+     * @return the description associated with this tag
+     */
+    List<? extends DocTree> getDescription();
+}
--- a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTree.java	Wed Oct 16 17:02:29 2019 -0400
@@ -35,6 +35,19 @@
      * Enumerates all kinds of trees.
      */
     enum Kind {
+
+        /**
+         * Used for instances of {@link AccessorTree}
+         * representing an embedded getter JavaDoc.
+         */
+        GETTER("getter"),
+
+        /**
+         * Used for instances of {@link AccessorTree}
+         * representing an embedded getter JavaDoc.
+         */
+        SETTER("setter"),
+
         /**
          * Used for instances of {@link AttributeTree}
          * representing an HTML attribute.
--- a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java	Wed Oct 16 17:02:29 2019 -0400
@@ -57,6 +57,14 @@
 public interface DocTreeVisitor<R,P> {
 
     /**
+     * Visits an AaccessorTree node.
+     * @param node the node being visited
+     * @param p a parameter value
+     * @return a result value
+     */
+    R visitAccessor(AccessorTree node, P p);
+
+    /**
      * Visits an AttributeTree node.
      * @param node the node being visited
      * @param p a parameter value
--- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeFactory.java	Wed Oct 16 17:02:29 2019 -0400
@@ -31,6 +31,7 @@
 import javax.tools.Diagnostic;
 import javax.tools.JavaFileObject;
 
+import com.sun.source.doctree.AccessorTree;
 import com.sun.source.doctree.AttributeTree;
 import com.sun.source.doctree.AttributeTree.ValueKind;
 import com.sun.source.doctree.AuthorTree;
@@ -39,6 +40,7 @@
 import com.sun.source.doctree.DocCommentTree;
 import com.sun.source.doctree.DocRootTree;
 import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.DocTree.Kind;
 import com.sun.source.doctree.DocTypeTree;
 import com.sun.source.doctree.EndElementTree;
 import com.sun.source.doctree.EntityTree;
@@ -235,6 +237,13 @@
     LiteralTree newLiteralTree(TextTree text);
 
     /**
+     * Create a new {@code AccessorTree} object, to represent a {@code @getter} tag.
+     * @param description the content of the tag
+     * @return a {@code AccessorTree} object
+     */
+    AccessorTree newAccessorTree(Kind kind, List<? extends DocTree> description);
+
+    /**
      * Create a new {@code ParamTree} object, to represent a {@code @param } tag.
      * @param isTypeParameter true if this is a type parameter, and false otherwise
      * @param name the parameter being described
--- a/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/DocTreeScanner.java	Wed Oct 16 17:02:29 2019 -0400
@@ -489,6 +489,18 @@
     }
 
     /**
+     * {@inheritDoc} This implementation returns {@code null}.
+     *
+     * @param node  {@inheritDoc}
+     * @param p  {@inheritDoc}
+     * @return the result of scanning
+     */
+    @Override
+    public R visitAccessor(AccessorTree node, P p) {
+        return scan(node.getDescription(), p);
+    }
+
+    /**
      * {@inheritDoc} This implementation scans the children in left to right order.
      *
      * @param node  {@inheritDoc}
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java	Wed Oct 16 17:02:29 2019 -0400
@@ -298,6 +298,18 @@
      * @return  the result of {@code defaultAction}
      */
     @Override
+    public R visitAccessor(AccessorTree node, P p) {
+        return defaultAction(node, p);
+    }
+
+    /**
+     * {@inheritDoc} This implementation calls {@code defaultAction}.
+     *
+     * @param node {@inheritDoc}
+     * @param p {@inheritDoc}
+     * @return  the result of {@code defaultAction}
+     */
+    @Override
     public R visitParam(ParamTree node, P p) {
         return defaultAction(node, p);
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTrees.java	Wed Oct 16 17:02:29 2019 -0400
@@ -420,10 +420,10 @@
 
     @Override @DefinedBy(Api.COMPILER_TREE)
     public Element getElement(DocTreePath path) {
-        DocTree forTree = path.getLeaf();
-        if (forTree instanceof DCReference)
-            return attributeDocReference(path.getTreePath(), ((DCReference) forTree));
-        if (forTree instanceof DCIdentifier) {
+        DocTree tree = path.getLeaf();
+        if (tree instanceof DCReference)
+            return attributeDocReference(path.getTreePath(), ((DCReference) tree));
+        if (tree instanceof DCIdentifier) {
             if (path.getParentPath().getLeaf() instanceof DCParam) {
                 return attributeParamIdentifier(path.getTreePath(), (DCParam) path.getParentPath().getLeaf());
             }
@@ -536,7 +536,7 @@
         }
     }
 
-    private Symbol attributeParamIdentifier(TreePath path, DCParam ptag) {
+    private Symbol attributeParamIdentifier(TreePath path, DCParam paramTag) {
         Symbol javadocSymbol = getElement(path);
         if (javadocSymbol == null)
             return null;
@@ -544,16 +544,18 @@
         List<? extends Symbol> params = List.nil();
         if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) {
             MethodSymbol ee = (MethodSymbol) javadocSymbol;
-            params = ptag.isTypeParameter()
+            params = paramTag.isTypeParameter()
                     ? ee.getTypeParameters()
                     : ee.getParameters();
         } else if (kind.isClass() || kind.isInterface()) {
             ClassSymbol te = (ClassSymbol) javadocSymbol;
-            params = te.getTypeParameters();
+            params = paramTag.isTypeParameter()
+                    ? te.getTypeParameters()
+                    : te.getRecordComponents();
         }
 
         for (Symbol param : params) {
-            if (param.getSimpleName() == ptag.getName().getName()) {
+            if (param.getSimpleName() == paramTag.getName().getName()) {
                 return param;
             }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Accessors.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.tools.javac.code;
+
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+
+import java.util.function.Function;
+
+public class Accessors {
+
+    public enum Kind {
+        GET(names -> names.get) {
+            @Override
+            public Type accessorType(Symtab syms, Type type) {
+                return new MethodType(List.nil(), type, List.nil(), syms.methodClass);
+            }
+        },
+        SET(names -> names.set) {
+            @Override
+            public Type accessorType(Symtab syms, Type type) {
+                return new MethodType(List.of(type), syms.voidType, List.nil(), syms.methodClass);
+            }
+        };
+
+        private final Function<Names, Name> nameFunc;
+
+        Kind(Function<Names, Name> nameFunc) {
+            this.nameFunc = nameFunc;
+        }
+
+        public Name name(Names names) {
+            return nameFunc.apply(names);
+        }
+
+        public abstract Type accessorType(Symtab syms, Type type);
+    }
+
+    public static Kind fromName(Name name) {
+        for (Kind k : Kind.values()) {
+            if (k.name(name.table.names).equals(name)) {
+                return k;
+            }
+        }
+        return null;
+    }
+}
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Wed Oct 16 17:02:29 2019 -0400
@@ -324,12 +324,31 @@
      */
     public static final long NAME_FILLED = 1L<<58; //ParamSymbols only
 
+    /**
+     * Flag to indicate that a class is a record. The flag is also used to mark fields that are
+     * part of the state vector of a record.
+     */
+    public static final long RECORD = 1L<<61;
+
+    /**
+     * Flag to mark a record constructor as a compact one
+     */
+    public static final long COMPACT_RECORD_CONSTRUCTOR = 1L<<51;
+
+    /**
+     * Flag that marks if a the implementation of a record component, a field,
+     * was originally declared as a varargs
+     */
+    public static final long ORIGINALLY_VARARGS = 1L<<49;
+
     /** Modifier masks.
      */
     public static final int
         AccessFlags           = PUBLIC | PROTECTED | PRIVATE,
         LocalClassFlags       = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
+        LocalRecordFlags                 = LocalClassFlags | STATIC,
         MemberClassFlags      = LocalClassFlags | INTERFACE | AccessFlags,
+        MemberRecordClassFlags           = MemberClassFlags | STATIC,
         ClassFlags            = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
         InterfaceVarFlags     = FINAL | STATIC | PUBLIC,
         VarFlags              = AccessFlags | FINAL | STATIC |
@@ -337,10 +356,17 @@
         ConstructorFlags      = AccessFlags,
         InterfaceMethodFlags  = ABSTRACT | PUBLIC,
         MethodFlags           = AccessFlags | ABSTRACT | STATIC | NATIVE |
+                                           SYNCHRONIZED | FINAL | STRICTFP,
+        RecordMethodFlags                = AccessFlags | ABSTRACT | STATIC |
                                 SYNCHRONIZED | FINAL | STRICTFP;
     public static final long
-        ExtendedStandardFlags       = (long)StandardFlags | DEFAULT,
-        ModifierFlags               = ((long)StandardFlags & ~INTERFACE) | DEFAULT,
+        ExtendedStandardFlags            = (long)StandardFlags | DEFAULT,
+        ExtendedLocalClassFlags          = (long)LocalClassFlags,
+        ExtendedLocalRecordFlags         = (long)LocalRecordFlags,
+        ExtendedMemberClassFlags         = (long)MemberClassFlags,
+        ExtendedMemberRecordClassFlags   = (long)MemberRecordClassFlags,
+        ExtendedClassFlags               = (long)ClassFlags,
+        ModifierFlags                    = ((long)StandardFlags & ~INTERFACE) | DEFAULT,
         InterfaceMethodMask         = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | DEFAULT,
         AnnotationTypeElementMask   = ABSTRACT | PUBLIC,
         LocalVarFlags               = FINAL | PARAMETER,
@@ -441,7 +467,8 @@
         HAS_RESOURCE(Flags.HAS_RESOURCE),
         POTENTIALLY_AMBIGUOUS(Flags.POTENTIALLY_AMBIGUOUS),
         ANONCONSTR_BASED(Flags.ANONCONSTR_BASED),
-        NAME_FILLED(Flags.NAME_FILLED);
+        NAME_FILLED(Flags.NAME_FILLED),
+        RECORD(Flags.RECORD);
 
         Flag(long flag) {
             this.value = flag;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java	Wed Oct 16 17:02:29 2019 -0400
@@ -277,6 +277,7 @@
 
         case ANNOTATION_TYPE:
         case CLASS:
+        case RECORD:
             return KindName.CLASS;
 
         case INTERFACE:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java	Wed Oct 16 17:02:29 2019 -0400
@@ -168,7 +168,8 @@
         if (feature == Feature.SWITCH_EXPRESSION ||
             feature == Feature.SWITCH_MULTIPLE_CASE_LABELS ||
             feature == Feature.SWITCH_RULE ||
-            feature == Feature.TEXT_BLOCKS)
+            feature == Feature.TEXT_BLOCKS ||
+            feature == Feature.RECORDS)
             return true;
         //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
         //When real preview features will be added, this method can be implemented to return 'true'
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Wed Oct 16 17:02:29 2019 -0400
@@ -199,7 +199,8 @@
         SWITCH_MULTIPLE_CASE_LABELS(JDK14, Fragments.FeatureMultipleCaseLabels, DiagKind.PLURAL),
         SWITCH_RULE(JDK14, Fragments.FeatureSwitchRules, DiagKind.PLURAL),
         SWITCH_EXPRESSION(JDK14, Fragments.FeatureSwitchExpressions, DiagKind.PLURAL),
-        TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL);
+        TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL),
+        RECORDS(JDK14);
 
         enum DiagKind {
             NORMAL,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Wed Oct 16 17:02:29 2019 -0400
@@ -42,12 +42,14 @@
 import javax.lang.model.element.ModuleElement;
 import javax.lang.model.element.NestingKind;
 import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.RecordComponentElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.TypeParameterElement;
 import javax.lang.model.element.VariableElement;
 import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
 
+import com.sun.tools.javac.code.Accessors;
 import com.sun.tools.javac.code.Kinds.Kind;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.code.Type.*;
@@ -61,6 +63,7 @@
 import com.sun.tools.javac.tree.JCTree.Tag;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.Name;
 
 import static com.sun.tools.javac.code.Flags.*;
@@ -370,6 +373,10 @@
         return (flags_field & DEPRECATED) != 0;
     }
 
+    public boolean isRecord() {
+        return (flags_field & RECORD) != 0;
+    }
+
     public boolean hasDeprecatedAnnotation() {
         return (flags_field & DEPRECATED_ANNOTATION) != 0;
     }
@@ -402,15 +409,27 @@
         return (flags() & INTERFACE) != 0;
     }
 
+    public boolean isAbstract() {
+        return (flags() & ABSTRACT) != 0;
+    }
+
     public boolean isPrivate() {
         return (flags_field & Flags.AccessFlags) == PRIVATE;
     }
 
+    public boolean isPublic() {
+        return (flags_field & Flags.AccessFlags) == PUBLIC;
+    }
+
     public boolean isEnum() {
         return (flags() & ENUM) != 0;
     }
 
-    /** Is this symbol declared (directly or indirectly) local
+    public boolean isFinal() {
+        return (flags_field & FINAL) != 0;
+    }
+ 
+   /** Is this symbol declared (directly or indirectly) local
      *  to a method or variable initializer?
      *  Also includes fields of inner classes which are in
      *  turn local to a method or variable initializer.
@@ -824,7 +843,7 @@
         }
 
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
-        public java.util.List<Symbol> getEnclosedElements() {
+        public List<Symbol> getEnclosedElements() {
             List<Symbol> list = List.nil();
             if (kind == TYP && type.hasTag(TYPEVAR)) {
                 return list;
@@ -1260,6 +1279,8 @@
         /** the annotation metadata attached to this class */
         private AnnotationTypeMetadata annotationTypeMetadata;
 
+        private List<RecordComponent> recordComponents = List.nil();
+
         public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
             super(TYP, flags, name, type, owner);
             this.members_field = null;
@@ -1328,6 +1349,18 @@
             return fullname;
         }
 
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public List<Symbol> getEnclosedElements() {
+            List<Symbol> result = super.getEnclosedElements();
+            if (!recordComponents.isEmpty()) {
+                List<RecordComponent> reversed = recordComponents.reverse();
+                for (RecordComponent rc : reversed) {
+                    result = result.prepend(rc);
+                }
+            }
+            return result;
+        }
+
         public Name flatName() {
             return flatname;
         }
@@ -1429,6 +1462,8 @@
                 return ElementKind.INTERFACE;
             else if ((flags & ENUM) != 0)
                 return ElementKind.ENUM;
+            else if ((flags & RECORD) != 0)
+                return ElementKind.RECORD;
             else
                 return ElementKind.CLASS;
         }
@@ -1440,6 +1475,24 @@
             return Flags.asModifierSet(flags & ~DEFAULT);
         }
 
+        public RecordComponent getRecordComponent(VarSymbol field, boolean addIfMissing) {
+            for (RecordComponent rc : recordComponents) {
+                if (rc.name == field.name) {
+                    return rc;
+                }
+            }
+            RecordComponent rc = null;
+            if (addIfMissing) {
+                recordComponents = recordComponents.append(rc = new RecordComponent(PUBLIC, field.name, field.type, field.owner));
+            }
+            return rc;
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public List<? extends RecordComponent> getRecordComponents() {
+            return recordComponents;
+        }
+
         @DefinedBy(Api.LANGUAGE_MODEL)
         public NestingKind getNestingKind() {
             apiComplete();
@@ -1453,7 +1506,6 @@
                 return NestingKind.MEMBER;
         }
 
-
         @Override
         protected <A extends Annotation> Attribute.Compound getAttribute(final Class<A> annoType) {
 
@@ -1469,9 +1521,6 @@
                                      : superType.getAttribute(annoType);
         }
 
-
-
-
         @DefinedBy(Api.LANGUAGE_MODEL)
         public <R, P> R accept(ElementVisitor<R, P> v, P p) {
             return v.visitType(this, p);
@@ -1552,6 +1601,8 @@
          */
         public int adr = -1;
 
+        public List<Pair<Accessors.Kind, MethodSymbol>> accessors = List.nil();
+
         /** Construct a variable symbol, given its flags, name, type and owner.
          */
         public VarSymbol(long flags, Name name, Type type, Symbol owner) {
@@ -1596,6 +1647,14 @@
             return new VarSymbol(flags_field, name, types.memberType(site, this), owner);
         }
 
+        @Override
+        public Type erasure(Types types) {
+            if (erasure_field == null) {
+                erasure_field = types.erasure(type);
+            }
+            return erasure_field;
+        }
+
         @DefinedBy(Api.LANGUAGE_MODEL)
         public ElementKind getKind() {
             long flags = flags();
@@ -1677,6 +1736,36 @@
         }
     }
 
+    public static class RecordComponent extends VarSymbol implements RecordComponentElement {
+
+        /**
+         * Construct a record component, given its flags, name, type and owner.
+         */
+        public RecordComponent(long flags, Name name, Type type, Symbol owner) {
+            super(flags, name, type, owner);
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public ElementKind getKind() {
+            return ElementKind.RECORD_COMPONENT;
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public ExecutableElement getAccessor() {
+            for (Pair<Accessors.Kind, MethodSymbol> accessor : accessors) {
+                if (accessor.fst == Accessors.Kind.GET) {
+                    return accessor.snd;
+                }
+            }
+            throw new AssertionError("record component without accessor");
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
+        public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+            return v.visitRecordComponent(this, p);
+        }
+    }
+
     public static class ParamSymbol extends VarSymbol {
         public ParamSymbol(long flags, Name name, Type type, Symbol owner) {
             super(flags, name, type, owner);
@@ -1780,6 +1869,10 @@
                     ClassFile.CONSTANT_InterfaceMethodref : ClassFile.CONSTANT_Methodref;
         }
 
+        public boolean isDynamic() {
+            return false;
+        }
+
         public boolean isHandle() {
             return false;
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/SymbolMetadata.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/SymbolMetadata.java	Wed Oct 16 17:02:29 2019 -0400
@@ -255,4 +255,36 @@
     private boolean isStarted() {
         return attributes != DECL_NOT_STARTED;
     }
+
+    private List<Attribute.Compound> removeFromCompoundList(List<Attribute.Compound> l, Attribute.Compound compound) {
+        ListBuffer<Attribute.Compound> lb = new ListBuffer<>();
+        for (Attribute.Compound c : l) {
+            if (c != compound) {
+                lb.add(c);
+            }
+        }
+        return lb.toList();
+    }
+
+    private List<Attribute.TypeCompound> removeFromTypeCompoundList(List<Attribute.TypeCompound> l, Attribute.TypeCompound compound) {
+        ListBuffer<Attribute.TypeCompound> lb = new ListBuffer<>();
+        for (Attribute.TypeCompound c : l) {
+            if (c != compound) {
+                lb.add(c);
+            }
+        }
+        return lb.toList();
+    }
+
+    public void remove(Attribute.Compound compound) {
+        if (attributes.contains(compound)) {
+            attributes = removeFromCompoundList(attributes, compound);
+        } else if (type_attributes.contains(compound)) {
+            type_attributes = removeFromTypeCompoundList(type_attributes, (TypeCompound)compound);
+        } else if (init_type_attributes.contains(compound)) {
+            init_type_attributes = removeFromTypeCompoundList(init_type_attributes, (TypeCompound)compound);
+        } else if (clinit_type_attributes.contains(compound)) {
+            clinit_type_attributes = removeFromTypeCompoundList(clinit_type_attributes, (TypeCompound)compound);
+        }
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Wed Oct 16 17:02:29 2019 -0400
@@ -161,6 +161,7 @@
     /** Predefined types.
      */
     public final Type objectType;
+    public final Type objectMethodsType;
     public final Type objectsType;
     public final Type classType;
     public final Type classLoaderType;
@@ -214,6 +215,11 @@
     public final Type documentedType;
     public final Type elementTypeType;
     public final Type functionalInterfaceType;
+    public final Type typeDescriptorType;
+    public final Type recordType;
+    public final Type objectStreamFieldType;
+    public final Type objectOutputStreamType;
+    public final Type objectInputStreamType;
 
     /** The symbol representing the length field of an array.
      */
@@ -508,6 +514,7 @@
 
         // Enter predefined classes. All are assumed to be in the java.base module.
         objectType = enterClass("java.lang.Object");
+        objectMethodsType = enterClass("java.lang.invoke.ObjectMethods");
         objectsType = enterClass("java.util.Objects");
         classType = enterClass("java.lang.Class");
         stringType = enterClass("java.lang.String");
@@ -570,6 +577,11 @@
         lambdaMetafactory = enterClass("java.lang.invoke.LambdaMetafactory");
         stringConcatFactory = enterClass("java.lang.invoke.StringConcatFactory");
         functionalInterfaceType = enterClass("java.lang.FunctionalInterface");
+        typeDescriptorType = enterClass("java.lang.invoke.TypeDescriptor");
+        recordType = enterClass("java.lang.Record");
+        objectStreamFieldType = enterClass("java.io.ObjectStreamField");
+        objectOutputStreamType = enterClass("java.io.ObjectOutputStream");
+        objectInputStreamType = enterClass("java.io.ObjectInputStream");
 
         synthesizeEmptyInterfaceIfMissing(autoCloseableType);
         synthesizeEmptyInterfaceIfMissing(cloneableType);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Wed Oct 16 17:02:29 2019 -0400
@@ -200,7 +200,7 @@
         if (e.value.name == names.TYPE) {
             if (s.kind == TYP)
                 return AnnotationType.DECLARATION;
-        } else if (e.value.name == names.FIELD) {
+        } else if (e.value.name == names.FIELD || e.value.name == names.RECORD_COMPONENT) {
             if (s.kind == VAR &&
                     s.owner.kind != MTH)
                 return AnnotationType.DECLARATION;
@@ -1266,7 +1266,7 @@
                 // No type annotations can occur here.
             } else {
                 // There is nothing else in a variable declaration that needs separation.
-                Assert.error("Unhandled variable kind");
+                Assert.error("Unhandled variable kind: " + tree.sym.getKind());
             }
 
             scan(tree.mods);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Wed Oct 16 17:02:29 2019 -0400
@@ -1479,6 +1479,19 @@
 
     // </editor-fold>
 
+    public List<VarSymbol> recordVars(Type t) {
+        List<VarSymbol> vars = List.nil();
+        while (!t.hasTag(NONE)) {
+            if (t.hasTag(CLASS)) {
+                for (Symbol s : t.tsym.members().getSymbols(s -> s.kind == VAR && (s.flags() & RECORD) != 0)) {
+                    vars = vars.prepend((VarSymbol)s);
+                }
+            }
+            t = supertype(t);
+        }
+        return vars;
+    }
+
     // <editor-fold defaultstate="collapsed" desc="Contains Type">
     public boolean containedBy(Type t, Type s) {
         switch (t.getTag()) {
@@ -5174,7 +5187,7 @@
             append('>');
         }
 
-        private void assembleSig(List<Type> types) {
+        public void assembleSig(List<Type> types) {
             for (List<Type> ts = types; ts.nonEmpty(); ts = ts.tail) {
                 assembleSig(ts.head);
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Oct 16 17:02:29 2019 -0400
@@ -276,7 +276,7 @@
         validate(() -> { //validate annotations
             JavaFileObject prev = log.useSource(localEnv.toplevel.sourcefile);
             try {
-                chk.validateAnnotations(annotations, s);
+                chk.validateAnnotations(annotations, TreeInfo.declarationFor(s, localEnv.tree), s);
             } finally {
                 log.useSource(prev);
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Oct 16 17:02:29 2019 -0400
@@ -1087,12 +1087,11 @@
                 if (tree.name == names.init && owner.type != syms.objectType) {
                     JCBlock body = tree.body;
                     if (body.stats.isEmpty() ||
-                            !TreeInfo.isSelfCall(body.stats.head)) {
-                        body.stats = body.stats.
-                                prepend(typeEnter.SuperCall(make.at(body.pos),
-                                        List.nil(),
-                                        List.nil(),
-                                        false));
+                            TreeInfo.getConstructorInvocationName(body.stats, names,
+                                    (env.enclClass.sym.flags() & RECORD) != 0) == names.empty) {
+                        JCStatement supCall = make.at(body.pos).Exec(make.Apply(List.nil(),
+                                make.Ident(names._super), make.Idents(List.nil())));
+                        body.stats = body.stats.prepend(supCall);
                     } else if ((env.enclClass.sym.flags() & ENUM) != 0 &&
                             (tree.mods.flags & GENERATEDCONSTR) == 0 &&
                             TreeInfo.isSuperCall(body.stats.head)) {
@@ -1997,6 +1996,11 @@
             log.error(tree.pos(), Errors.RetOutsideMeth);
         } else if (env.info.yieldResult != null) {
             log.error(tree.pos(), Errors.ReturnOutsideSwitchExpression);
+        } else if (!env.info.isLambda &&
+                !env.info.isNewClass &&
+                env.enclMethod != null &&
+                TreeInfo.isCanonicalConstructor(env.enclMethod)) {
+            log.error(tree, Errors.CanonicalCantHaveReturnStatement);
         } else {
             // Attribute return expression, if it exists, and check that
             // it conforms to result type of enclosing method.
@@ -2659,8 +2663,10 @@
         try {
             if (needsRecovery && isSerializable(pt())) {
                 localEnv.info.isSerializable = true;
-                localEnv.info.isLambda = true;
+                localEnv.info.isSerializableLambda = true;
+                localEnv.info.isSerializableLambda = true;
             }
+            localEnv.info.isLambda = true;
             List<Type> explicitParamTypes = null;
             if (that.paramKind == JCLambda.ParameterKind.EXPLICIT) {
                 //attribute lambda parameters
@@ -3707,7 +3713,7 @@
         }
 
         if (env.info.isSerializable) {
-            chk.checkAccessFromSerializableElement(tree, env.info.isLambda);
+            chk.checkAccessFromSerializableElement(tree, env.info.isSerializableLambda);
         }
 
         result = checkId(tree, env1.enclClass.sym.type, sym, env, resultInfo);
@@ -3849,7 +3855,7 @@
         }
 
         if (env.info.isSerializable) {
-            chk.checkAccessFromSerializableElement(tree, env.info.isLambda);
+            chk.checkAccessFromSerializableElement(tree, env.info.isSerializableLambda);
         }
 
         env.info.selectSuper = selectSuperPrev;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java	Wed Oct 16 17:02:29 2019 -0400
@@ -62,6 +62,10 @@
      */
     boolean isSerializable = false;
 
+    /** Is this a serializable lambda?
+     */
+    boolean isSerializableLambda = false;
+
     /** Is this a lambda environment?
      */
     boolean isLambda = false;
@@ -133,12 +137,13 @@
         info.yieldResult = yieldResult;
         info.defaultSuperCallSite = defaultSuperCallSite;
         info.isSerializable = isSerializable;
-        info.isLambda = isLambda;
+        info.isSerializableLambda = isSerializableLambda;
         info.attributionMode = attributionMode;
         info.isAnonymousDiamond = isAnonymousDiamond;
         info.isNewClass = isNewClass;
         info.preferredTreeForDiagnostics = preferredTreeForDiagnostics;
         info.visitingServiceImplementation = visitingServiceImplementation;
+        info.isLambda = isLambda;
         return info;
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Oct 16 17:02:29 2019 -0400
@@ -27,7 +27,9 @@
 
 import java.util.*;
 import java.util.function.Supplier;
-
+import java.util.stream.Collectors;
+
+import javax.lang.model.element.ElementKind;
 import javax.tools.JavaFileManager;
 
 import com.sun.tools.javac.code.*;
@@ -116,7 +118,7 @@
 
         names = Names.instance(context);
         dfltTargetMeta = new Name[] { names.PACKAGE, names.TYPE,
-            names.FIELD, names.METHOD, names.CONSTRUCTOR,
+            names.FIELD, names.RECORD_COMPONENT, names.METHOD, names.CONSTRUCTOR,
             names.ANNOTATION_TYPE, names.LOCAL_VARIABLE, names.PARAMETER};
         log = Log.instance(context);
         rs = Resolve.instance(context);
@@ -1159,6 +1161,8 @@
                 } else {
                     mask = implicit = InterfaceMethodFlags;
                 }
+            } else if ((sym.owner.flags_field & RECORD) != 0) {
+                mask = RecordMethodFlags;
             } else {
                 mask = MethodFlags;
             }
@@ -1169,12 +1173,16 @@
             break;
         case TYP:
             if (sym.isLocal()) {
-                mask = LocalClassFlags;
+                mask = (flags & RECORD) != 0 ? LocalRecordFlags : ExtendedLocalClassFlags;
                 if ((sym.owner.flags_field & STATIC) == 0 &&
-                    (flags & ENUM) != 0)
+                    (flags & ENUM) != 0) {
                     log.error(pos, Errors.EnumsMustBeStatic);
+                }
+                if ((flags & RECORD) != 0 && (flags & STATIC) == 0) {
+                    log.error(pos, Errors.NestedRecordsMustBeStatic);
+                }
             } else if (sym.owner.kind == TYP) {
-                mask = MemberClassFlags;
+                mask = (flags & RECORD) != 0 ? ExtendedMemberRecordClassFlags : ExtendedMemberClassFlags;
                 if (sym.owner.owner.kind == PCK ||
                     (sym.owner.flags_field & STATIC) != 0)
                     mask |= STATIC;
@@ -1183,7 +1191,7 @@
                 // Nested interfaces and enums are always STATIC (Spec ???)
                 if ((flags & (INTERFACE | ENUM)) != 0 ) implicit = STATIC;
             } else {
-                mask = ClassFlags;
+                mask = ExtendedClassFlags;
             }
             // Interfaces are always ABSTRACT
             if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
@@ -1193,6 +1201,10 @@
                 mask &= ~(ABSTRACT | FINAL);
                 implicit |= implicitEnumFinalFlag(tree);
             }
+            if ((flags & RECORD) != 0) {
+                // records can't be declared abstract
+                mask &= ~ABSTRACT;
+            }
             // Imply STRICTFP if owner has STRICTFP set.
             implicit |= sym.owner.flags_field & STRICTFP;
             break;
@@ -2813,9 +2825,9 @@
 
     /** Check the annotations of a symbol.
      */
-    public void validateAnnotations(List<JCAnnotation> annotations, Symbol s) {
+    public void validateAnnotations(List<JCAnnotation> annotations, JCTree declarationTree, Symbol s) {
         for (JCAnnotation a : annotations)
-            validateAnnotation(a, s);
+            validateAnnotation(a, declarationTree, s);
     }
 
     /** Check the type annotations.
@@ -2827,11 +2839,70 @@
 
     /** Check an annotation of a symbol.
      */
-    private void validateAnnotation(JCAnnotation a, Symbol s) {
+    private void validateAnnotation(JCAnnotation a, JCTree declarationTree, Symbol s) {
         validateAnnotationTree(a);
-
-        if (a.type.tsym.isAnnotationType() && !annotationApplicable(a, s))
+        boolean isRecordMember = s.isRecord() || s.enclClass() != null && s.enclClass().isRecord();
+
+        boolean isRecordField = isRecordMember &&
+                (s.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.MANDATED | Flags.RECORD)) != 0 &&
+                declarationTree.hasTag(VARDEF) &&
+                s.owner.kind == TYP;
+
+        if (isRecordField) {
+            // we are seeing a record field, which had the original annotations, now is the moment,
+            // before stripping some of them just below, to check if the original annotations
+            // applied to records at all, first version only cares about declaration annotations
+            // we will add type annotations later on
+            Name[] targets = getTargetNames(a);
+            boolean appliesToRecords = false;
+            for (Name target : targets) {
+                appliesToRecords =
+                                target == names.FIELD ||
+                                target == names.PARAMETER ||
+                                target == names.METHOD ||
+                                target == names.TYPE_USE ||
+                                target == names.RECORD_COMPONENT;
+                if (appliesToRecords) {
+                    break;
+                }
+            }
+            if (!appliesToRecords) {
             log.error(a.pos(), Errors.AnnotationTypeNotApplicable);
+            } else {
+                ClassSymbol recordClass = (ClassSymbol) s.owner;
+                RecordComponent rc = recordClass.getRecordComponent((VarSymbol)s, false);
+                rc.appendAttributes(s.getRawAttributes().stream().filter(anno ->
+                    Arrays.stream(getTargetNames(anno.type.tsym)).anyMatch(name -> name == names.RECORD_COMPONENT)
+                ).collect(List.collector()));
+                rc.appendUniqueTypeAttributes(s.getRawTypeAttributes());
+                // to get all the type annotations applied to the type
+                rc.type = s.type;
+            }
+        }
+
+        //System.out.println("at Check.validateAnnotation: flags: " + Flags.toString(s.flags_field) + ", declaration tree " + declarationTree);
+
+        if (a.type.tsym.isAnnotationType() && !annotationApplicable(a, s)) {
+            // debug
+            //System.out.println("at Check.validateAnnotation: flags: " + Flags.toString(s.flags_field) + ", declaration tree " + declarationTree);
+            if (isRecordMember && (s.flags_field & Flags.MANDATED) != 0) {
+                JCModifiers modifiers = TreeInfo.getModifiers(declarationTree);
+                // lets first remove the annotation from the modifier
+                if (modifiers != null) {
+                    ListBuffer<JCAnnotation> newAnnotations = new ListBuffer<>();
+                    for (JCAnnotation anno : modifiers.annotations) {
+                        if (anno != a) {
+                            newAnnotations.add(anno);
+                        }
+                    }
+                    modifiers.annotations = newAnnotations.toList();
+                }
+                // now lets remove it from the symbol
+                s.getMetadata().remove(a.attribute);
+            } else {
+                log.error(a.pos(), Errors.AnnotationTypeNotApplicable);
+            }
+        }
 
         if (a.annotationType.type.tsym == syms.functionalInterfaceType.tsym) {
             if (s.kind != TYP) {
@@ -2990,6 +3061,7 @@
             targets.add(names.ANNOTATION_TYPE);
             targets.add(names.CONSTRUCTOR);
             targets.add(names.FIELD);
+            targets.add(names.RECORD_COMPONENT);
             targets.add(names.LOCAL_VARIABLE);
             targets.add(names.METHOD);
             targets.add(names.PACKAGE);
@@ -3081,24 +3153,36 @@
         }
 
     /** Is the annotation applicable to the symbol? */
-    boolean annotationApplicable(JCAnnotation a, Symbol s) {
-        Attribute.Array arr = getAttributeTargetAttribute(a.annotationType.type.tsym);
+    Name[] getTargetNames(JCAnnotation a) {
+        return getTargetNames(a.annotationType.type.tsym);
+    }
+
+    public Name[] getTargetNames(TypeSymbol annoSym) {
+        Attribute.Array arr = getAttributeTargetAttribute(annoSym);
         Name[] targets;
-
         if (arr == null) {
-            targets = defaultTargetMetaInfo(a, s);
+            targets = defaultTargetMetaInfo();
         } else {
             // TODO: can we optimize this?
             targets = new Name[arr.values.length];
             for (int i=0; i<arr.values.length; ++i) {
                 Attribute app = arr.values[i];
                 if (!(app instanceof Attribute.Enum)) {
-                    return true; // recovery
+                    return new Name[0];
                 }
                 Attribute.Enum e = (Attribute.Enum) app;
                 targets[i] = e.value.name;
             }
         }
+        return targets;
+    }
+
+    boolean annotationApplicable(JCAnnotation a, Symbol s) {
+        Name[] targets = getTargetNames(a);
+        if (targets.length == 0) {
+            // recovery
+            return true;
+        }
         for (Name target : targets) {
             if (target == names.TYPE) {
                 if (s.kind == TYP)
@@ -3106,12 +3190,16 @@
             } else if (target == names.FIELD) {
                 if (s.kind == VAR && s.owner.kind != MTH)
                     return true;
+            } else if (target == names.RECORD_COMPONENT) {
+                if (s.getKind() == ElementKind.RECORD_COMPONENT) {
+                    return true;
+                }
             } else if (target == names.METHOD) {
                 if (s.kind == MTH && !s.isConstructor())
                     return true;
             } else if (target == names.PARAMETER) {
-                if (s.kind == VAR && s.owner.kind == MTH &&
-                      (s.flags() & PARAMETER) != 0) {
+                if (s.kind == VAR &&
+                    (s.owner.kind == MTH && (s.flags() & PARAMETER) != 0)) {
                     return true;
                 }
             } else if (target == names.CONSTRUCTOR) {
@@ -3158,8 +3246,8 @@
         return (Attribute.Array) atValue;
     }
 
-    private final Name[] dfltTargetMeta;
-    private Name[] defaultTargetMetaInfo(JCAnnotation a, Symbol s) {
+    public final Name[] dfltTargetMeta;
+    private Name[] defaultTargetMetaInfo() {
         return dfltTargetMeta;
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java	Wed Oct 16 17:02:29 2019 -0400
@@ -400,6 +400,9 @@
             PackageSymbol packge = (PackageSymbol)owner;
             for (Symbol q = packge; q != null && q.kind == PCK; q = q.owner)
                 q.flags_field |= EXISTS;
+            if ((tree.mods.flags & Flags.RECORD) != 0) {
+                tree.mods.flags &= ~Flags.STATIC;
+            }
             c = syms.enterClass(env.toplevel.modle, tree.name, packge);
             packge.members().enterIfAbsent(c);
             if ((tree.mods.flags & PUBLIC) != 0 && !classNameMatchesFileName(c, env)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Oct 16 17:02:29 2019 -0400
@@ -30,6 +30,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
 import com.sun.tools.javac.code.*;
@@ -525,6 +526,7 @@
             try {
                 alive = Liveness.ALIVE;
                 scanStat(tree.body);
+                tree.completesNormally = alive != Liveness.DEAD;
 
                 if (alive == Liveness.ALIVE && !tree.sym.type.getReturnType().hasTag(VOID))
                     log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt);
@@ -1757,17 +1759,21 @@
 
         /** Check that trackable variable is initialized.
          */
-        void checkInit(DiagnosticPosition pos, VarSymbol sym) {
-            checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
+        boolean checkInit(DiagnosticPosition pos, VarSymbol sym, boolean compactConstructor) {
+            return checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym), compactConstructor);
         }
 
-        void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
+        boolean checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey, boolean compactConstructor) {
             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
                 trackable(sym) &&
                 !inits.isMember(sym.adr)) {
+                if (sym.owner.kind != TYP || !compactConstructor || !uninits.isMember(sym.adr)) {
                 log.error(pos, errkey);
+                }
                 inits.incl(sym.adr);
+                return false;
             }
+            return true;
         }
 
         /** Utility method to reset several Bits instances.
@@ -1985,6 +1991,7 @@
                     // leave caught unchanged.
                     scan(tree.body);
 
+                    boolean isCompactConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0;
                     if (isInitialConstructor) {
                         boolean isSynthesized = (tree.sym.flags() &
                                                  GENERATEDCONSTR) != 0;
@@ -1994,11 +2001,17 @@
                             if (var.owner == classDef.sym) {
                                 // choose the diagnostic position based on whether
                                 // the ctor is default(synthesized) or not
-                                if (isSynthesized) {
+                                if (isSynthesized && !isCompactConstructor) {
                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
-                                        var, Errors.VarNotInitializedInDefaultConstructor(var));
+                                        var, Errors.VarNotInitializedInDefaultConstructor(var), isCompactConstructor);
                                 } else {
-                                    checkInit(TreeInfo.diagEndPos(tree.body), var);
+                                    boolean wasInitialized = checkInit(TreeInfo.diagEndPos(tree.body), var, isCompactConstructor && tree.completesNormally);
+                                    if (!wasInitialized && var.owner.kind == TYP && isCompactConstructor && uninits.isMember(var.adr) && tree.completesNormally) {
+                                        /*  this way we indicate Lower that it should generate an initialization for this field
+                                         *  in the compact constructor
+                                         */
+                                        var.flags_field |= COMPACT_RECORD_CONSTRUCTOR;
+                                    }
                                 }
                             }
                         }
@@ -2015,7 +2028,7 @@
                             Assert.check(exit instanceof AssignPendingExit);
                             inits.assign(((AssignPendingExit) exit).exit_inits);
                             for (int i = firstadr; i < nextadr; i++) {
-                                checkInit(exit.tree.pos(), vardecls[i].sym);
+                                checkInit(exit.tree.pos(), vardecls[i].sym, isCompactConstructor);
                             }
                         }
                     }
@@ -2557,7 +2570,7 @@
             super.visitSelect(tree);
             if (TreeInfo.isThisQualifier(tree.selected) &&
                 tree.sym.kind == VAR) {
-                checkInit(tree.pos(), (VarSymbol)tree.sym);
+                checkInit(tree.pos(), (VarSymbol)tree.sym, false);
             }
         }
 
@@ -2618,7 +2631,7 @@
 
         public void visitIdent(JCIdent tree) {
             if (tree.sym.kind == VAR) {
-                checkInit(tree.pos(), (VarSymbol)tree.sym);
+                checkInit(tree.pos(), (VarSymbol)tree.sym, false);
                 referenced(tree.sym);
             }
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Oct 16 17:02:29 2019 -0400
@@ -28,13 +28,16 @@
 import java.util.*;
 import java.util.Map.Entry;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Kinds.KindSelector;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.comp.Resolve.MethodResolutionContext;
 import com.sun.tools.javac.jvm.*;
+import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
 import com.sun.tools.javac.main.Option.PkgInfo;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.tree.*;
@@ -802,6 +805,21 @@
         return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, List.nil());
     }
 
+    private Symbol findMethodOrFailSilently(
+            DiagnosticPosition pos,
+            Env<AttrContext> env,
+            Type site,
+            Name name,
+            List<Type> argtypes,
+            List<Type> typeargtypes) {
+        MethodResolutionContext resolveContext = rs.new MethodResolutionContext();
+        resolveContext.internalResolution = true;
+        resolveContext.silentFail = true;
+        Symbol sym = rs.resolveQualifiedMethod(resolveContext, pos, env, site.tsym,
+                site, name, argtypes, typeargtypes);
+        return sym;
+    }
+
     /** Anon inner classes are used as access constructor tags.
      * accessConstructorTag will use an existing anon class if one is available,
      * and synthethise a class (with makeEmptyClass) if one is not available.
@@ -2188,6 +2206,10 @@
             (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
             visitEnumDef(tree);
 
+        if ((tree.mods.flags & RECORD) != 0) {
+            visitRecordDef(tree);
+        }
+
         // If this is a nested class, define a this$n field for
         // it and add to proxies.
         JCVariableDecl otdef = null;
@@ -2257,6 +2279,54 @@
         result = make_at(tree.pos()).Block(SYNTHETIC, List.nil());
     }
 
+    List<JCTree> accessors(JCClassDecl tree) {
+        ListBuffer<JCTree> buffer = new ListBuffer<>();
+        tree.defs.stream()
+                .filter(t -> t.hasTag(VARDEF))
+                .map(t -> (JCVariableDecl)t)
+                .filter(vd -> vd.sym.accessors.nonEmpty())
+                .forEach(vd -> {
+                    for (Pair<Accessors.Kind, MethodSymbol> accessor : vd.sym.accessors) {
+                        MethodSymbol accessorSym = accessor.snd;
+                        if ((accessorSym.flags() & Flags.MANDATED) != 0) {
+                            make_at(tree.pos());
+                            switch (accessor.fst) {
+                                case GET:
+                                    buffer.add(make.MethodDef(accessorSym, make.Block(0,
+                                            List.of(make.Return(make.Ident(vd.sym))))));
+                                    break;
+                                case SET:
+                                    buffer.add(make.MethodDef(accessorSym, make.Block(0,
+                                            List.of(make.Exec(
+                                                    make.Assign(make.Ident(vd.sym), make.Ident(accessorSym.params.head))
+                                                            .setType(vd.sym.type))))));
+                                    break;
+                                default:
+                                    Assert.error("Cannot get here!");
+                            }
+                        }
+                    }
+                });
+        return buffer.toList();
+    }
+
+    /* this method looks for explicit accessors to add them to the corresponding field
+     */
+    void findUserDefinedAccessors(JCClassDecl tree) {
+        tree.defs.stream()
+                .filter(t -> t.hasTag(VARDEF))
+                .map(t -> (JCVariableDecl)t)
+                .filter(vd -> (vd.sym.accessors.isEmpty() && !vd.sym.isStatic()))
+                .forEach(vd -> {
+                    MethodSymbol msym = lookupMethod(tree.pos(),
+                            vd.name,
+                            tree.sym.type,
+                            List.nil());
+                    Assert.check(msym != null, "there has to be a user defined accessor");
+                    vd.sym.accessors = List.of(new Pair<>(Accessors.Kind.GET, msym));
+                });
+    }
+
     /** Translate an enum class. */
     private void visitEnumDef(JCClassDecl tree) {
         make_at(tree.pos());
@@ -2412,6 +2482,169 @@
             prepend(makeLit(syms.stringType, var.name.toString()));
     }
 
+    /** Translate a record. */
+    private void visitRecordDef(JCClassDecl tree) {
+        make_at(tree.pos());
+        List<VarSymbol> vars = types.recordVars(tree.type);
+        MethodHandleSymbol[] getterMethHandles = new MethodHandleSymbol[vars.size()];
+        // for the extractor we use the user provided getter, for the rest we access the field directly
+        MethodHandleSymbol[] getterMethHandlesForExtractor = new MethodHandleSymbol[vars.size()];
+        int index = 0;
+        for (VarSymbol var : vars) {
+            if (var.owner != tree.sym) {
+                var = new VarSymbol(var.flags_field, var.name, var.type, tree.sym);
+            }
+            getterMethHandles[index] = var.asMethodHandle(true);
+            if (!var.accessors.isEmpty()) {
+                getterMethHandlesForExtractor[index] = getterMethHandles[index];
+            } else {
+                MethodSymbol msym = lookupMethod(tree, var.name, tree.sym.type, List.nil());
+                getterMethHandlesForExtractor[index] = msym.asHandle();
+            }
+            index++;
+        }
+
+        tree.defs = tree.defs.appendList(accessors(tree));
+        tree.defs = tree.defs.appendList(List.of(
+                generateRecordMethod(tree, names.toString, vars, getterMethHandles),
+                generateRecordMethod(tree, names.hashCode, vars, getterMethHandles),
+                generateRecordMethod(tree, names.equals, vars, getterMethHandles)
+        ));
+        findUserDefinedAccessors(tree);
+    }
+
+    JCTree generateRecordMethod(JCClassDecl tree, Name name, List<VarSymbol> vars, MethodHandleSymbol[] getterMethHandles) {
+        make_at(tree.pos());
+        boolean isEquals = name == names.equals;
+        MethodSymbol msym = lookupMethod(tree.pos(),
+                name,
+                tree.sym.type,
+                isEquals ? List.of(syms.objectType) : List.nil());
+        if ((msym.flags() & RECORD) != 0) {
+            Name bootstrapName = names.bootstrap;
+            LoadableConstant[] staticArgsValues = new LoadableConstant[2 + getterMethHandles.length];
+            staticArgsValues[0] = (ClassType)tree.sym.type;
+            String concatNames = vars.stream()
+                    .map(v -> v.name)
+                    .collect(Collectors.joining(";", "", ""));
+            staticArgsValues[1] = LoadableConstant.String(concatNames);
+            int index = 2;
+            for (MethodHandleSymbol mho : getterMethHandles) {
+                staticArgsValues[index] = mho;
+                index++;
+            }
+
+            List<Type> staticArgTypes = List.of(syms.classType,
+                    syms.stringType,
+                    new ArrayType(syms.methodHandleType, syms.arrayClass));
+
+            JCFieldAccess qualifier = makeIndyQualifier(syms.objectMethodsType, tree, msym,
+                    List.of(syms.methodHandleLookupType,
+                            syms.stringType,
+                            syms.typeDescriptorType).appendList(staticArgTypes),
+                    staticArgsValues, bootstrapName, name, false);
+
+            VarSymbol _this = new VarSymbol(SYNTHETIC, names._this, tree.sym.type, tree.sym);
+
+            JCMethodInvocation proxyCall;
+            if (!isEquals) {
+                proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this)));
+            } else {
+                VarSymbol o = msym.params.head;
+                o.adr = 0;
+                proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this), make.Ident(o)));
+            }
+            proxyCall.type = qualifier.type;
+            return make.MethodDef(msym, make.Block(0, List.of(make.Return(proxyCall))));
+        } else {
+            return make.Block(SYNTHETIC, List.nil());
+        }
+    }
+
+    private String argsTypeSig(List<Type> typeList) {
+        LowerSignatureGenerator sg = new LowerSignatureGenerator();
+        sg.assembleSig(typeList);
+        return sg.toString();
+    }
+
+    /**
+     * Signature Generation
+     */
+    private class LowerSignatureGenerator extends Types.SignatureGenerator {
+
+        /**
+         * An output buffer for type signatures.
+         */
+        StringBuilder sb = new StringBuilder();
+
+        LowerSignatureGenerator() {
+            super(types);
+        }
+
+        @Override
+        protected void append(char ch) {
+            sb.append(ch);
+        }
+
+        @Override
+        protected void append(byte[] ba) {
+            sb.append(new String(ba));
+        }
+
+        @Override
+        protected void append(Name name) {
+            sb.append(name.toString());
+        }
+
+        @Override
+        public String toString() {
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Creates an indy qualifier, helpful to be part of an indy invocation
+     * @param site                the site
+     * @param tree                a class declaration tree
+     * @param msym                the method symbol
+     * @param staticArgTypes      the static argument types
+     * @param staticArgValues     the static argument values
+     * @param bootstrapName       the bootstrap name to look for
+     * @param argName             normally bootstraps receives a method name as second argument, if you want that name
+     *                            to be different to that of the bootstrap name pass a different name here
+     * @param isStatic            is it static or not
+     * @return                    a field access tree
+     */
+    JCFieldAccess makeIndyQualifier(
+            Type site,
+            JCClassDecl tree,
+            MethodSymbol msym,
+            List<Type> staticArgTypes,
+            LoadableConstant[] staticArgValues,
+            Name bootstrapName,
+            Name argName,
+            boolean isStatic) {
+        Symbol bsm = rs.resolveInternalMethod(tree.pos(), attrEnv, site,
+                bootstrapName, staticArgTypes, List.nil());
+
+        MethodType indyType = msym.type.asMethodType();
+        indyType = new MethodType(
+                isStatic ? List.nil() : indyType.argtypes.prepend(tree.sym.type),
+                indyType.restype,
+                indyType.thrown,
+                syms.methodClass
+        );
+        DynamicMethodSymbol dynSym = new DynamicMethodSymbol(argName,
+                syms.noSymbol,
+                ((MethodSymbol)bsm).asHandle(),
+                indyType,
+                staticArgValues);
+        JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), argName);
+        qualifier.sym = dynSym;
+        qualifier.type = msym.type.asMethodType().restype;
+        return qualifier;
+    }
+
     public void visitMethodDef(JCMethodDecl tree) {
         if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
             // Add "String $enum$name, int $enum$ordinal" to the beginning of the
@@ -2539,6 +2772,27 @@
                 lambdaTranslationMap = prevLambdaTranslationMap;
             }
         }
+        if (tree.name == names.init && (tree.sym.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
+            // lets find out if there is any field waiting to be initialized
+            ListBuffer<VarSymbol> fields = new ListBuffer<>();
+            for (Symbol sym : currentClass.getEnclosedElements()) {
+                if (sym.kind == Kinds.Kind.VAR && ((sym.flags() & RECORD) != 0))
+                    fields.append((VarSymbol) sym);
+            }
+            for (VarSymbol field: fields) {
+                if ((field.flags_field & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
+                    VarSymbol param = tree.params.stream().filter(p -> p.name == field.name).findFirst().get().sym;
+                    make.at(tree.pos);
+                    tree.body.stats = tree.body.stats.append(
+                            make.Exec(
+                                    make.Assign(
+                                            make.Select(make.This(field.owner.erasure(types)), field),
+                                            make.Ident(param)).setType(field.erasure(types))));
+                    // we don't need the flag at the field anymore
+                    field.flags_field &= ~Flags.COMPACT_RECORD_CONSTRUCTOR;
+                }
+            }
+        }
         result = tree;
     }
     //where
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Wed Oct 16 17:02:29 2019 -0400
@@ -296,7 +296,8 @@
                 v.setLazyConstValue(initEnv(tree, initEnv), attr, tree);
             }
         }
-        if (chk.checkUnique(tree.pos(), v, enclScope)) {
+        if ((v.flags_field & (HYPOTHETICAL | RECORD)) != (HYPOTHETICAL | RECORD) &&
+                chk.checkUnique(tree.pos(), v, enclScope)) {
             chk.checkTransparentVar(tree.pos(), v, enclScope);
             enclScope.enter(v);
         } else if (v.owner.kind == MTH) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Oct 16 17:02:29 2019 -0400
@@ -2664,7 +2664,7 @@
                                   List<Type> typeargtypes) {
         return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes);
     }
-    private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext,
+    public Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext,
                                   DiagnosticPosition pos, Env<AttrContext> env,
                                   Symbol location, Type site, Name name, List<Type> argtypes,
                                   List<Type> typeargtypes) {
@@ -2678,7 +2678,7 @@
             @Override
             Symbol access(Env<AttrContext> env, DiagnosticPosition pos, Symbol location, Symbol sym) {
                 if (sym.kind.isResolutionError()) {
-                    sym = super.access(env, pos, location, sym);
+                    sym = resolveContext.silentFail ? sym : super.access(env, pos, location, sym);
                 } else {
                     MethodSymbol msym = (MethodSymbol)sym;
                     if ((msym.flags() & SIGNATURE_POLYMORPHIC) != 0) {
@@ -4793,7 +4793,7 @@
      * can be nested - this means that when each overload resolution routine should
      * work within the resolution context it created.
      */
-    class MethodResolutionContext {
+    public class MethodResolutionContext {
 
         private List<Candidate> candidates = List.nil();
 
@@ -4801,7 +4801,9 @@
 
         MethodCheck methodCheck = resolveMethodCheck;
 
-        private boolean internalResolution = false;
+        public boolean internalResolution = false;
+        // in case of failure, don't report the error
+        public boolean silentFail = false;
         private DeferredAttr.AttrMode attrMode = DeferredAttr.AttrMode.SPECULATIVE;
 
         void addInapplicableCandidate(Symbol sym, JCDiagnostic details) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Wed Oct 16 17:02:29 2019 -0400
@@ -25,9 +25,11 @@
 
 package com.sun.tools.javac.comp;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
 
 import javax.tools.JavaFileObject;
 
@@ -55,6 +57,9 @@
 import static com.sun.tools.javac.code.TypeTag.CLASS;
 import static com.sun.tools.javac.code.TypeTag.ERROR;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
+
+import static com.sun.tools.javac.code.TypeTag.*;
+import static com.sun.tools.javac.code.TypeTag.BOT;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
 import com.sun.tools.javac.util.Dependencies.CompletionCause;
@@ -678,6 +683,9 @@
             if (tree.extending != null) {
                 extending = clearTypeParams(tree.extending);
                 supertype = attr.attribBase(extending, baseEnv, true, false, true);
+                if (supertype == syms.recordType) {
+                    log.error(tree, Errors.InvalidSupertypeRecord);
+                }
             } else {
                 extending = null;
                 supertype = ((tree.mods.flags & Flags.ENUM) != 0)
@@ -685,7 +693,7 @@
                                   true, false, false)
                 : (sym.fullname == names.java_lang_Object)
                 ? Type.noType
-                : syms.objectType;
+                : sym.isRecord() ? syms.recordType : syms.objectType;
             }
             ct.supertype_field = modelMissingTypes(baseEnv, supertype, extending, false);
 
@@ -801,7 +809,7 @@
     private final class HeaderPhase extends AbstractHeaderPhase {
 
         public HeaderPhase() {
-            super(CompletionCause.HEADER_PHASE, new MembersPhase());
+            super(CompletionCause.HEADER_PHASE, new RecordPhase());
         }
 
         @Override
@@ -851,12 +859,10 @@
         }
     }
 
-    /** Enter member fields and methods of a class
-     */
-    private final class MembersPhase extends Phase {
+    private abstract class AbstractMembersPhase extends Phase {
 
-        public MembersPhase() {
-            super(CompletionCause.MEMBERS_PHASE, null);
+        public AbstractMembersPhase(CompletionCause completionCause, Phase next) {
+            super(completionCause, next);
         }
 
         private boolean completing;
@@ -880,50 +886,86 @@
                 completing = prevCompleting;
             }
         }
+    }
+
+    private final class RecordPhase extends AbstractMembersPhase {
+
+        public RecordPhase() {
+            super(CompletionCause.RECORD_PHASE, new MembersPhase());
+        }
+
+        @Override
+        protected void runPhase(Env<AttrContext> env) {
+            JCClassDecl tree = env.enclClass;
+            ClassSymbol sym = tree.sym;
+            if ((sym.flags_field & RECORD) != 0) {
+                List<JCVariableDecl> fields = TreeInfo.recordFields(tree);
+                memberEnter.memberEnter(fields, env);
+                for (JCVariableDecl field : fields) {
+                    sym.getRecordComponent(field.sym, true);
+                }
+            }
+        }
+    }
+
+    /** Enter member fields and methods of a class
+     */
+    private final class MembersPhase extends AbstractMembersPhase {
+
+        public MembersPhase() {
+            super(CompletionCause.MEMBERS_PHASE, null);
+        }
 
         @Override
         protected void runPhase(Env<AttrContext> env) {
             JCClassDecl tree = env.enclClass;
             ClassSymbol sym = tree.sym;
             ClassType ct = (ClassType)sym.type;
+            boolean defaultConstructorGenerated = false;
 
             // Add default constructor if needed.
             if ((sym.flags() & INTERFACE) == 0 &&
                 !TreeInfo.hasConstructors(tree.defs)) {
-                List<Type> argtypes = List.nil();
-                List<Type> typarams = List.nil();
-                List<Type> thrown = List.nil();
-                long ctorFlags = 0;
-                boolean based = false;
-                boolean addConstructor = true;
-                JCNewClass nc = null;
+                DefaultConstructorHelper helper = new BasicConstructorHelper(sym);
                 if (sym.name.isEmpty()) {
-                    nc = (JCNewClass)env.next.tree;
+                    JCNewClass nc = (JCNewClass)env.next.tree;
                     if (nc.constructor != null) {
-                        addConstructor = nc.constructor.kind != ERR;
-                        Type superConstrType = types.memberType(sym.type,
-                                                                nc.constructor);
-                        argtypes = superConstrType.getParameterTypes();
-                        typarams = superConstrType.getTypeArguments();
-                        ctorFlags = nc.constructor.flags() & VARARGS;
-                        if (nc.encl != null) {
-                            argtypes = argtypes.prepend(nc.encl.type);
-                            based = true;
+                        if (nc.constructor.kind != ERR) {
+                            helper = new AnonClassConstructorHelper(sym, (MethodSymbol)nc.constructor, nc.encl);
+                        } else {
+                            helper = null;
                         }
-                        thrown = superConstrType.getThrownTypes();
+                    }
+                } else if ((sym.flags() & RECORD) != 0) {
+                    helper = new RecordConstructorHelper(sym, TreeInfo.recordFields(tree));
+                }
+                if (helper != null) {
+                    JCTree constrDef = defaultConstructor(make.at(tree.pos), helper);
+                    tree.defs = tree.defs.prepend(constrDef);
+                    defaultConstructorGenerated = true;
+                }
+            } else {
+                if ((sym.flags() & RECORD) != 0) {
+                    // there are constructors but they could be incomplete
+                    for (JCTree def : tree.defs) {
+                        if (TreeInfo.isConstructor(def)) {
+                            Name constructorInvocationName =
+                                    TreeInfo.getConstructorInvocationName(((JCMethodDecl)def).body.stats, names, true);
+                            if (constructorInvocationName == names.empty ||
+                                    constructorInvocationName == names._super) {
+                                JCMethodDecl methDecl = (JCMethodDecl)def;
+                                if ((methDecl.mods.flags & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0) {
+                                    if (constructorInvocationName == names.empty) {
+                                        JCStatement supCall = make.at(methDecl.body.pos).Exec(make.Apply(List.nil(),
+                                                make.Ident(names._super), List.nil()));
+                                        methDecl.body.stats = methDecl.body.stats.prepend(supCall);
+            }
+                                }
+                            }
+                        }
                     }
                 }
-                if (addConstructor) {
-                    MethodSymbol basedConstructor = nc != null ?
-                            (MethodSymbol)nc.constructor : null;
-                    JCTree constrDef = DefaultConstructor(make.at(tree.pos), sym,
-                                                        basedConstructor,
-                                                        typarams, argtypes, thrown,
-                                                        ctorFlags, based);
-                    tree.defs = tree.defs.prepend(constrDef);
-                }
             }
-
             // enter symbols for 'this' into current scope.
             VarSymbol thisSym =
                 new VarSymbol(FINAL | HASINIT, names._this, sym.type, sym);
@@ -945,7 +987,7 @@
                 }
             }
 
-            finishClass(tree, env);
+            finishClass(tree, env, defaultConstructorGenerated);
 
             if (allowTypeAnnos) {
                 typeAnnotations.organizeTypeAnnotationsSignatures(env, (JCClassDecl)env.tree);
@@ -955,13 +997,26 @@
 
         /** Enter members for a class.
          */
-        void finishClass(JCClassDecl tree, Env<AttrContext> env) {
+        void finishClass(JCClassDecl tree, Env<AttrContext> env, boolean defaultConstructorGenerated) {
             if ((tree.mods.flags & Flags.ENUM) != 0 &&
                 !tree.sym.type.hasTag(ERROR) &&
                 (types.supertype(tree.sym.type).tsym.flags() & Flags.ENUM) == 0) {
                 addEnumMembers(tree, env);
             }
-            memberEnter.memberEnter(tree.defs, env);
+            boolean isRecord = (tree.sym.flags_field & RECORD) != 0;
+            List<JCTree> defsToEnter = isRecord ?
+                    tree.defs.diff(List.convert(JCTree.class, TreeInfo.recordFields(tree))) : tree.defs;
+            memberEnter.memberEnter(defsToEnter, env);
+            if (isRecord) {
+                checkForSerializationMembers(tree, env);
+            }
+            List<JCTree> defsBeforeAddingNewMembers = tree.defs;
+            if (isRecord) {
+                addRecordMembersIfNeeded(tree, env, defaultConstructorGenerated);
+                addAccessorsIfNeeded(tree, env);
+            }
+            // now we need to enter any additional mandated member that could have been added in the previous step
+            memberEnter.memberEnter(tree.defs.diff(List.convert(JCTree.class, defsBeforeAddingNewMembers)), env);
 
             if (tree.sym.isAnnotationType()) {
                 Assert.check(tree.sym.isCompleted());
@@ -969,6 +1024,65 @@
             }
         }
 
+        /** Add the accessors for fields to the symbol table.
+         */
+        private void addAccessorsIfNeeded(JCClassDecl tree, Env<AttrContext> env) {
+            tree.defs.stream()
+                    .filter(t -> t.hasTag(VARDEF))
+                    .map(t -> (JCVariableDecl)t)
+                    .filter(vd -> vd.accessors != null && vd.accessors.nonEmpty())
+                    .forEach(vd -> addAccessors(vd, env));
+        }
+
+        private void addAccessors(JCVariableDecl tree, Env<AttrContext> env) {
+            for (Pair<Accessors.Kind, Name> accessor : tree.accessors) {
+                Type accessorType = accessor.fst.accessorType(syms, tree.sym.type);
+                MethodSymbol implSym = lookupMethod(env.enclClass.sym, accessor.snd, accessorType.getParameterTypes());
+                if (implSym == null || (implSym.flags_field & MANDATED) != 0) {
+                    JCMethodDecl getter = make.at(tree.pos).MethodDef(make.Modifiers(Flags.PUBLIC | Flags.MANDATED, tree.mods.annotations),
+                              accessor.snd,
+                              make.Type(accessorType.getReturnType()),
+                              List.nil(),
+                              accessorType.getParameterTypes().stream()
+                                      .map(ptype -> make.Param(tree.name, tree.sym.type, env.enclClass.sym))
+                                      .collect(List.collector()),
+                              List.nil(), // thrown
+                              null,
+                              null);
+                    memberEnter.memberEnter(getter, env);
+                    RecordComponent rec = ((ClassSymbol) tree.sym.owner).getRecordComponent(tree.sym, false);
+                    rec.accessors = rec.accessors.prepend(new Pair<>(accessor.fst, getter.sym));
+                    tree.sym.accessors = tree.sym.accessors.prepend(new Pair<>(accessor.fst, getter.sym));
+                } else if (implSym != null) {
+                    if ((implSym.flags() & Flags.PUBLIC) == 0) {
+                        log.error(TreeInfo.declarationFor(implSym, env.enclClass), Errors.MethodMustBePublic(implSym.name));
+                    }
+                    if (!types.isSameType(implSym.type.getReturnType(), tree.sym.type)) {
+                        log.error(TreeInfo.declarationFor(implSym, env.enclClass), Errors.AccessorReturnTypeDoesntMatch(tree.sym.type, implSym.type.getReturnType()));
+                    }
+                    if (implSym.type.asMethodType().thrown.stream().anyMatch(exc -> !isUnchecked(exc))) {
+                        log.error(TreeInfo.declarationFor(implSym, env.enclClass), Errors.MethodCantThrowCheckedException);
+                    }
+                }
+            }
+        }
+
+        /** Is exc an exception symbol that need not be declared?
+         */
+        boolean isUnchecked(ClassSymbol exc) {
+            return exc.kind == ERR ||
+                   exc.isSubClass(syms.errorType.tsym, types) ||
+                   exc.isSubClass(syms.runtimeExceptionType.tsym, types);
+        }
+
+        /** Is exc an exception type that need not be declared?
+         */
+        boolean isUnchecked(Type exc) {
+            return (exc.hasTag(TYPEVAR)) ? isUnchecked(types.supertype(exc)) :
+                   (exc.hasTag(CLASS)) ? isUnchecked((ClassSymbol)exc.tsym) :
+                   exc.hasTag(BOT);
+        }
+
         /** Add the implicit members for an enum type
          *  to the symbol table.
          */
@@ -1003,136 +1117,359 @@
             memberEnter.memberEnter(valueOf, env);
         }
 
+        private void checkForSerializationMembers(JCClassDecl tree, Env<AttrContext> env) {
+            // non-static void writeObject(java.io.ObjectOutputStream) {}
+            MethodSymbol ms = lookupMethod(tree.sym, names.writeObject, List.of(syms.objectOutputStreamType));
+            if (ms != null) {
+                errorOnSerializationMember(tree, names.writeObject, ms, syms.voidType, false);
+            }
+            // non-static void readObjectNoData() {}
+            ms = lookupMethod(tree.sym, names.readObjectNoData, List.nil());
+            if (ms != null) {
+                errorOnSerializationMember(tree, names.readObjectNoData, ms, syms.voidType, false);
+            }
+            // non-static void readObject(java.io.ObjectInputStream stream) {}
+            ms = lookupMethod(tree.sym, names.readObject, List.of(syms.objectInputStreamType));
+            if (ms != null) {
+                errorOnSerializationMember(tree, names.readObject, ms, syms.voidType, false);
+            }
+            Type objectStreamFieldArr = new ArrayType(syms.objectStreamFieldType, syms.arrayClass);
+            Symbol fieldSym = lookupField(tree.sym, names.serialPersistentFields, objectStreamFieldArr);
+            if (fieldSym != null) {
+                errorOnSerializationMember(tree, names.serialPersistentFields, fieldSym, objectStreamFieldArr, true);
+            }
+        }
+
+        private void errorOnSerializationMember(JCClassDecl tree,
+                                                Name name, Symbol sym, Type expectedType, boolean shouldBeStatic) {
+            Type typeOrReturnType = sym.kind == MTH ? sym.type.asMethodType().getReturnType() : sym.type;
+            if (sym.isStatic() == shouldBeStatic && (typeOrReturnType == expectedType || types.isSameType(typeOrReturnType, expectedType))) {
+                for (JCTree def : tree.defs) {
+                    Symbol sym2 = TreeInfo.symbolFor(def);
+                    if (sym2 == sym) {
+                        log.error(def, Errors.IllegalRecordMember(name));
+                        return;
+                    }
+                }
+                log.error(tree, Errors.IllegalRecordMember(name));
+            }
+        }
+
+        /** Add the implicit members for a record
+         *  to the symbol table.
+         */
+        private void addRecordMembersIfNeeded(JCClassDecl tree, Env<AttrContext> env, boolean defaultConstructorGenerated) {
+            if (!defaultConstructorGenerated) {
+                // let's check if there is a constructor with exactly the same arguments as the record components
+                List<Type> recordComponentTypes = TreeInfo.recordFields(tree).map(vd -> vd.sym.type);
+                List<Type> erasedTypes = types.erasure(recordComponentTypes);
+                JCMethodDecl canonicalDecl = null;
+                for (JCTree def : tree.defs) {
+                    if (TreeInfo.isConstructor(def)) {
+                        JCMethodDecl mdecl = (JCMethodDecl)def;
+                        if (types.isSameTypes(mdecl.sym.type.getParameterTypes(), erasedTypes)) {
+                            canonicalDecl = mdecl;
+                            break;
+                        }
+                    }
+                }
+                if (canonicalDecl != null && !types.isSameTypes(erasedTypes, recordComponentTypes)) {
+                    // error we found a constructor with the same erasure as the canonical constructor
+                    log.error(canonicalDecl, Errors.ConstructorWithSameErasureAsCanonical);
+                }
+                MethodSymbol canonicalInit = canonicalDecl == null ?
+                        null :
+                        canonicalDecl.sym;
+                if (canonicalInit == null) {
+                    RecordConstructorHelper helper = new RecordConstructorHelper(tree.sym, TreeInfo.recordFields(tree));
+                    JCTree constrDef = defaultConstructor(make.at(tree.pos), helper);
+                    tree.defs = tree.defs.prepend(constrDef);
+                    defaultConstructorGenerated = true;
+                } else {
+                    /* there is an explicit constructor that match the canonical constructor by type
+                       let's check that the match is also by name
+                    */
+                    List<Name> recordComponentNames = TreeInfo.recordFields(tree).map(vd -> vd.sym.name);
+                    List<Name> initParamNames = canonicalInit.params.map(p -> p.name);
+                    if (!initParamNames.equals(recordComponentNames)) {
+                        log.error(canonicalDecl, Errors.CanonicalWithNameMismatch);
+                    }
+                    if (!canonicalInit.isPublic()) {
+                        log.error(canonicalDecl, Errors.CanonicalConstructorMustBePublic);
+                    }
+                    if (canonicalInit.type.asMethodType().thrown.stream().anyMatch(exc -> !isUnchecked(exc))) {
+                        log.error(canonicalDecl, Errors.MethodCantThrowCheckedException);
+                    }
+                    // let's use the RECORD flag to mark it as the canonical constructor
+                    canonicalInit.flags_field |= Flags.RECORD;
+                }
+            }
+
+            if (lookupMethod(tree.sym, names.toString, List.nil()) == null) {
+                // public String toString() { return ???; }
+                JCMethodDecl toString = make.
+                    MethodDef(make.Modifiers(Flags.PUBLIC | Flags.RECORD | Flags.MANDATED),
+                              names.toString,
+                              make.Type(syms.stringType),
+                              List.nil(),
+                              List.nil(),
+                              List.nil(), // thrown
+                              null,
+                              null);
+                memberEnter.memberEnter(toString, env);
+            }
+
+            if (lookupMethod(tree.sym, names.hashCode, List.nil()) == null) {
+                // public int hashCode() { return ???; }
+                JCMethodDecl hashCode = make.
+                    MethodDef(make.Modifiers(Flags.PUBLIC | Flags.RECORD | Flags.FINAL | Flags.MANDATED),
+                              names.hashCode,
+                              make.Type(syms.intType),
+                              List.nil(),
+                              List.nil(),
+                              List.nil(), // thrown
+                              null,
+                              null);
+                memberEnter.memberEnter(hashCode, env);
+            }
+
+            if (lookupMethod(tree.sym, names.equals, List.of(syms.objectType)) == null) {
+                // public boolean equals(Object o) { return ???; }
+                JCMethodDecl equals = make.
+                    MethodDef(make.Modifiers(Flags.PUBLIC | Flags.RECORD | Flags.FINAL | Flags.MANDATED),
+                              names.equals,
+                              make.Type(syms.booleanType),
+                              List.nil(),
+                              List.of(make.VarDef(make.Modifiers(Flags.PARAMETER),
+                                                names.fromString("o"),
+                                                make.Type(syms.objectType), null)),
+                              List.nil(), // thrown
+                              null,
+                              null);
+                memberEnter.memberEnter(equals, env);
+            }
+
+            // lets remove a temporary flag used to mark if the record component was initially declared as a varargs
+            List<JCVariableDecl> recordFields = TreeInfo.recordFields(tree);
+            for (JCVariableDecl field: recordFields) {
+                field.mods.flags &= ~Flags.ORIGINALLY_VARARGS;
+                field.sym.flags_field &= ~Flags.ORIGINALLY_VARARGS;
+            }
+        }
+
+    }
+
+    private MethodSymbol lookupMethod(TypeSymbol tsym, Name name, List<Type> argtypes) {
+        for (Symbol s : tsym.members().getSymbolsByName(name, s -> s.kind == MTH)) {
+            if (types.isSameTypes(s.type.getParameterTypes(), argtypes)) {
+                return (MethodSymbol) s;
+            }
+        }
+        return null;
+    }
+
+    private Symbol lookupField(TypeSymbol tsym, Name name, Type type) {
+        for (Symbol s : tsym.members().getSymbolsByName(name, s -> s.kind == VAR)) {
+            if (types.isSameType(s.type, type)) {
+                return s;
+            }
+        }
+        return null;
     }
 
 /* ***************************************************************************
  * tree building
  ****************************************************************************/
 
-    /** Generate default constructor for given class. For classes different
-     *  from java.lang.Object, this is:
-     *
-     *    c(argtype_0 x_0, ..., argtype_n x_n) throws thrown {
-     *      super(x_0, ..., x_n)
-     *    }
-     *
-     *  or, if based == true:
-     *
-     *    c(argtype_0 x_0, ..., argtype_n x_n) throws thrown {
-     *      x_0.super(x_1, ..., x_n)
-     *    }
-     *
-     *  @param make     The tree factory.
-     *  @param c        The class owning the default constructor.
-     *  @param argtypes The parameter types of the constructor.
-     *  @param thrown   The thrown exceptions of the constructor.
-     *  @param based    Is first parameter a this$n?
-     */
-    JCTree DefaultConstructor(TreeMaker make,
-                            ClassSymbol c,
-                            MethodSymbol baseInit,
-                            List<Type> typarams,
-                            List<Type> argtypes,
-                            List<Type> thrown,
-                            long flags,
-                            boolean based) {
-        JCTree result;
-        if ((c.flags() & ENUM) != 0 &&
-            (types.supertype(c.type).tsym == syms.enumSym)) {
+    interface DefaultConstructorHelper {
+       Type constructorType();
+       MethodSymbol constructorSymbol();
+       Type enclosingType();
+       TypeSymbol owner();
+       List<Name> superArgs();
+       default JCMethodDecl finalAdjustment(JCMethodDecl md) { return md; }
+    }
+
+    class BasicConstructorHelper implements DefaultConstructorHelper {
+
+        TypeSymbol owner;
+        Type constructorType;
+        MethodSymbol constructorSymbol;
+
+        BasicConstructorHelper(TypeSymbol owner) {
+            this.owner = owner;
+        }
+
+        @Override
+        public Type constructorType() {
+            if (constructorType == null) {
+                constructorType = new MethodType(List.nil(), syms.voidType, List.nil(), syms.methodClass);
+            }
+            return constructorType;
+        }
+
+        @Override
+        public MethodSymbol constructorSymbol() {
+            if (constructorSymbol == null) {
+                long flags;
+                if ((owner().flags() & ENUM) != 0 &&
+                    (types.supertype(owner().type).tsym == syms.enumSym)) {
             // constructors of true enums are private
-            flags = (flags & ~AccessFlags) | PRIVATE | GENERATEDCONSTR;
-        } else
-            flags |= (c.flags() & AccessFlags) | GENERATEDCONSTR;
-        if (c.name.isEmpty()) {
-            flags |= ANONCONSTR;
+                    flags = PRIVATE | GENERATEDCONSTR;
+                } else if (owner().isRecord()) {
+                    // record constructors are public
+                    flags = PUBLIC | GENERATEDCONSTR;
+                } else {
+                    flags = (owner().flags() & AccessFlags) | GENERATEDCONSTR;
         }
-        if (based) {
-            flags |= ANONCONSTR_BASED;
+                constructorSymbol = new MethodSymbol(flags, names.init,
+                    constructorType(), owner());
+        }
+            return constructorSymbol;
         }
-        Type mType = new MethodType(argtypes, null, thrown, c);
-        Type initType = typarams.nonEmpty() ?
-            new ForAll(typarams, mType) :
-            mType;
-        MethodSymbol init = new MethodSymbol(flags, names.init,
-                initType, c);
-        init.params = createDefaultConstructorParams(make, baseInit, init,
-                argtypes, based);
-        List<JCVariableDecl> params = make.Params(argtypes, init);
-        List<JCStatement> stats = List.nil();
-        if (c.type != syms.objectType) {
-            stats = stats.prepend(SuperCall(make, typarams, params, based));
+
+        @Override
+        public Type enclosingType() {
+            return Type.noType;
+    }
+
+        @Override
+        public TypeSymbol owner() {
+            return owner;
         }
-        result = make.MethodDef(init, make.Block(0, stats));
-        return result;
+
+        @Override
+        public List<Name> superArgs() {
+            return List.nil();
+            }
+        }
+
+    class AnonClassConstructorHelper extends BasicConstructorHelper {
+
+        MethodSymbol constr;
+        Type encl;
+        boolean based = false;
+
+        AnonClassConstructorHelper(TypeSymbol owner, MethodSymbol constr, JCExpression encl) {
+            super(owner);
+            this.constr = constr;
+            this.encl = encl != null ? encl.type : Type.noType;
     }
 
-    private List<VarSymbol> createDefaultConstructorParams(
-            TreeMaker make,
-            MethodSymbol baseInit,
-            MethodSymbol init,
-            List<Type> argtypes,
-            boolean based) {
-        List<VarSymbol> initParams = null;
-        List<Type> argTypesList = argtypes;
-        if (based) {
-            /*  In this case argtypes will have an extra type, compared to baseInit,
-             *  corresponding to the type of the enclosing instance i.e.:
-             *
-             *  Inner i = outer.new Inner(1){}
-             *
-             *  in the above example argtypes will be (Outer, int) and baseInit
-             *  will have parameter's types (int). So in this case we have to add
-             *  first the extra type in argtypes and then get the names of the
-             *  parameters from baseInit.
-             */
-            initParams = List.nil();
-            VarSymbol param = new VarSymbol(PARAMETER, make.paramName(0), argtypes.head, init);
-            initParams = initParams.append(param);
-            argTypesList = argTypesList.tail;
+        @Override
+        public Type constructorType() {
+            if (constructorType == null) {
+                Type ctype = types.memberType(owner.type, constr);
+                if (!enclosingType().hasTag(NONE)) {
+                    ctype = types.createMethodTypeWithParameters(ctype, ctype.getParameterTypes().prepend(enclosingType()));
+                    based = true;
+                }
+                constructorType = ctype;
+            }
+            return constructorType;
         }
-        if (baseInit != null && baseInit.params != null &&
-            baseInit.params.nonEmpty() && argTypesList.nonEmpty()) {
-            initParams = (initParams == null) ? List.nil() : initParams;
-            List<VarSymbol> baseInitParams = baseInit.params;
-            while (baseInitParams.nonEmpty() && argTypesList.nonEmpty()) {
-                VarSymbol param = new VarSymbol(baseInitParams.head.flags() | PARAMETER,
-                        baseInitParams.head.name, argTypesList.head, init);
-                initParams = initParams.append(param);
-                baseInitParams = baseInitParams.tail;
-                argTypesList = argTypesList.tail;
+
+        @Override
+        public MethodSymbol constructorSymbol() {
+            MethodSymbol csym = super.constructorSymbol();
+            csym.flags_field |= ANONCONSTR | (constr.flags() & VARARGS);
+            csym.flags_field |= based ? ANONCONSTR_BASED : 0;
+            ListBuffer<VarSymbol> params = new ListBuffer<>();
+            List<Type> argtypes = constructorType().getParameterTypes();
+            if (!enclosingType().hasTag(NONE)) {
+                argtypes = argtypes.tail;
+                params = params.prepend(new VarSymbol(PARAMETER, make.paramName(0), enclosingType(), csym));
+            }
+            if (constr.params != null) {
+                for (VarSymbol p : constr.params) {
+                    params.add(new VarSymbol(PARAMETER | p.flags(), p.name, argtypes.head, csym));
+                    argtypes = argtypes.tail;
+                }
             }
+            csym.params = params.toList();
+            return csym;
         }
-        return initParams;
+
+        @Override
+        public Type enclosingType() {
+            return encl;
+        }
+
+        @Override
+        public List<Name> superArgs() {
+            List<JCVariableDecl> params = make.Params(constructorType().getParameterTypes(), constructorSymbol());
+            if (!enclosingType().hasTag(NONE)) {
+            params = params.tail;
+            }
+            return params.map(vd -> vd.name);
+        }
     }
 
-    /** Generate call to superclass constructor. This is:
-     *
-     *    super(id_0, ..., id_n)
-     *
-     * or, if based == true
-     *
-     *    id_0.super(id_1,...,id_n)
-     *
-     *  where id_0, ..., id_n are the names of the given parameters.
-     *
-     *  @param make    The tree factory
-     *  @param params  The parameters that need to be passed to super
-     *  @param typarams  The type parameters that need to be passed to super
-     *  @param based   Is first parameter a this$n?
-     */
-    JCExpressionStatement SuperCall(TreeMaker make,
-                   List<Type> typarams,
-                   List<JCVariableDecl> params,
-                   boolean based) {
-        JCExpression meth;
-        if (based) {
-            meth = make.Select(make.Ident(params.head), names._super);
-            params = params.tail;
+    class RecordConstructorHelper extends BasicConstructorHelper {
+
+        List<VarSymbol> recordFieldSymbols;
+        List<JCVariableDecl> recordFieldDecls;
+
+        RecordConstructorHelper(TypeSymbol owner, List<JCVariableDecl> recordFieldDecls) {
+            super(owner);
+            this.recordFieldDecls = recordFieldDecls;
+            this.recordFieldSymbols = recordFieldDecls.map(vd -> vd.sym);
+        }
+
+        @Override
+        public Type constructorType() {
+            if (constructorType == null) {
+                List<Type> argtypes = recordFieldSymbols.map(v -> v.type);
+                constructorType = new MethodType(argtypes, syms.voidType, List.nil(), syms.methodClass);
+            }
+            return constructorType;
+        }
+
+        @Override
+        public MethodSymbol constructorSymbol() {
+            MethodSymbol csym = super.constructorSymbol();
+            // if we have to generate a default constructor for records we will treat it as the compact one
+            // to trigger field initialization later on
+            csym.flags_field |= Flags.COMPACT_RECORD_CONSTRUCTOR;
+            ListBuffer<VarSymbol> params = new ListBuffer<>();
+            for (VarSymbol p : recordFieldSymbols) {
+                params.add(new VarSymbol(MANDATED | PARAMETER | RECORD | ((p.flags_field & Flags.ORIGINALLY_VARARGS) != 0 ? Flags.VARARGS : 0), p.name, p.type, csym));
+            }
+            csym.params = params.toList();
+            csym.flags_field |= RECORD | PUBLIC;
+            return csym;
+        }
+
+        @Override
+        public JCMethodDecl finalAdjustment(JCMethodDecl md) {
+            List<JCVariableDecl> tmpRecordFieldDecls = recordFieldDecls;
+            for (JCVariableDecl arg : md.params) {
+                arg.mods.annotations = tmpRecordFieldDecls.head.mods.annotations;
+                arg.vartype = tmpRecordFieldDecls.head.vartype;
+                tmpRecordFieldDecls = tmpRecordFieldDecls.tail;
+            }
+            return md;
+        }
+    }
+
+    JCTree defaultConstructor(TreeMaker make, DefaultConstructorHelper helper) {
+        Type initType = helper.constructorType();
+        MethodSymbol initSym = helper.constructorSymbol();
+        ListBuffer<JCStatement> stats = new ListBuffer<>();
+        if (helper.owner().type != syms.objectType) {
+            JCExpression meth;
+            if (!helper.enclosingType().hasTag(NONE)) {
+                meth = make.Select(make.Ident(initSym.params.head), names._super);
         } else {
             meth = make.Ident(names._super);
         }
-        List<JCExpression> typeargs = typarams.nonEmpty() ? make.Types(typarams) : null;
-        return make.Exec(make.Apply(typeargs, meth, make.Idents(params)));
+            List<JCExpression> typeargs = initType.getTypeArguments().nonEmpty() ?
+                    make.Types(initType.getTypeArguments()) : null;
+            JCStatement superCall = make.Exec(make.Apply(typeargs, meth, helper.superArgs().map(make::Ident)));
+            stats.add(superCall);
+        }
+        JCMethodDecl result = make.MethodDef(initSym, make.Block(0, stats.toList()));
+        return helper.finalAdjustment(result);
     }
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Wed Oct 16 17:02:29 2019 -0400
@@ -105,6 +105,10 @@
      */
     boolean allowModules;
 
+    /** Switch: allow records
+     */
+    boolean allowRecords;
+
    /** Lint option: warn about classfile issues
      */
     boolean lintClassfile;
@@ -264,6 +268,7 @@
         Source source = Source.instance(context);
         preview = Preview.instance(context);
         allowModules     = Feature.MODULES.allowedInSource(source);
+        allowRecords = Feature.RECORDS.allowedInSource(source);
 
         saveParameterNames = options.isSet(PARAMETERS);
 
@@ -1184,6 +1189,19 @@
                     }
                 }
             },
+
+            new AttributeReader(names.Record, V57, CLASS_ATTRIBUTE) {
+                @Override
+                protected boolean accepts(AttributeKind kind) {
+                    return super.accepts(kind) && allowRecords;
+                }
+                protected void read(Symbol sym, int attrLen) {
+                    if (sym.kind == TYP) {
+                        sym.flags_field |= RECORD;
+                    }
+                    bp = bp + attrLen;
+                }
+            }
         };
 
         for (AttributeReader r: readers)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Wed Oct 16 17:02:29 2019 -0400
@@ -49,6 +49,7 @@
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.List;
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
@@ -345,8 +346,11 @@
     /** Write member (field or method) attributes;
      *  return number of attributes written.
      */
-    int writeMemberAttrs(Symbol sym) {
-        int acount = writeFlagAttrs(sym.flags());
+    int writeMemberAttrs(Symbol sym, boolean isRecordComponent) {
+        int acount = 0;
+        if (!isRecordComponent) {
+            acount = writeFlagAttrs(sym.flags());
+        }
         long flags = sym.flags();
         if ((flags & (SYNTHETIC | BRIDGE)) != SYNTHETIC &&
             (flags & ANONCONSTR) == 0 &&
@@ -403,9 +407,9 @@
             return 0;
     }
 
-
     private void writeParamAnnotations(List<VarSymbol> params,
                                        RetentionPolicy retention) {
+        databuf.appendByte(params.length());
         for (VarSymbol s : params) {
             ListBuffer<Attribute.Compound> buf = new ListBuffer<>();
             for (Attribute.Compound a : s.getRawAttributes())
@@ -427,11 +431,11 @@
     /** Write method parameter annotations;
      *  return number of attributes written.
      */
-    int writeParameterAttrs(MethodSymbol m) {
+    int writeParameterAttrs(List<VarSymbol> vars) {
         boolean hasVisible = false;
         boolean hasInvisible = false;
-        if (m.params != null) {
-            for (VarSymbol s : m.params) {
+        if (vars != null) {
+            for (VarSymbol s : vars) {
                 for (Attribute.Compound a : s.getRawAttributes()) {
                     switch (types.getRetention(a)) {
                     case SOURCE: break;
@@ -446,13 +450,13 @@
         int attrCount = 0;
         if (hasVisible) {
             int attrIndex = writeAttr(names.RuntimeVisibleParameterAnnotations);
-            writeParamAnnotations(m, RetentionPolicy.RUNTIME);
+            writeParamAnnotations(vars, RetentionPolicy.RUNTIME);
             endAttr(attrIndex);
             attrCount++;
         }
         if (hasInvisible) {
             int attrIndex = writeAttr(names.RuntimeInvisibleParameterAnnotations);
-            writeParamAnnotations(m, RetentionPolicy.CLASS);
+            writeParamAnnotations(vars, RetentionPolicy.CLASS);
             endAttr(attrIndex);
             attrCount++;
         }
@@ -831,6 +835,23 @@
         endAttr(alenIdx);
     }
 
+    int writeRecordAttribute(ClassSymbol csym) {
+        int alenIdx = writeAttr(names.Record);
+        Scope s = csym.members();
+        databuf.appendChar(csym.getRecordComponents().size());
+        for (VarSymbol v: csym.getRecordComponents()) {
+            //databuf.appendChar(poolWriter.putMember(v.accessors.head.snd));
+            databuf.appendChar(poolWriter.putName(v.name));
+            databuf.appendChar(poolWriter.putDescriptor(v));
+            int acountIdx = beginAttrs();
+            int acount = 0;
+            acount += writeMemberAttrs(v, true);
+            endAttrs(acountIdx, acount);
+        }
+        endAttr(alenIdx);
+        return 1;
+    }
+
     /**
      * Write NestMembers attribute (if needed)
      */
@@ -920,7 +941,7 @@
             endAttr(alenIdx);
             acount++;
         }
-        acount += writeMemberAttrs(v);
+        acount += writeMemberAttrs(v, false);
         endAttrs(acountIdx, acount);
     }
 
@@ -960,13 +981,13 @@
             endAttr(alenIdx);
             acount++;
         }
-        if (options.isSet(PARAMETERS) && target.hasMethodParameters()) {
+        if (target.hasMethodParameters() && (options.isSet(PARAMETERS) || m.isConstructor() && m.isRecord())) {
             if (!m.isLambdaMethod()) // Per JDK-8138729, do not emit parameters table for lambda bodies.
                 acount += writeMethodParametersAttr(m);
         }
-        acount += writeMemberAttrs(m);
+        acount += writeMemberAttrs(m, false);
         if (!m.isLambdaMethod())
-            acount += writeParameterAttrs(m);
+            acount += writeParameterAttrs(m.params);
         endAttrs(acountIdx, acount);
     }
 
@@ -1600,6 +1621,10 @@
             }
         }
 
+        if (c.isRecord()) {
+            acount += writeRecordAttribute(c);
+        }
+
         if (!poolWriter.bootstrapMethods.isEmpty()) {
             writeBootstrapMethods();
             acount++;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Oct 16 17:02:29 2019 -0400
@@ -31,6 +31,7 @@
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Attribute.Compound;
 import com.sun.tools.javac.code.Attribute.TypeCompound;
 import com.sun.tools.javac.code.Symbol.VarSymbol;
 import com.sun.tools.javac.comp.*;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolConstant.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolConstant.java	Wed Oct 16 17:02:29 2019 -0400
@@ -35,6 +35,8 @@
 import java.util.Objects;
 import java.util.stream.Stream;
 
+import com.sun.tools.javac.code.Symbol;
+
 /**
  * This interface models all javac entities that can be used to represent constant pool entries.
  * A pool constant entity must (i) be associated with a constant pool entry tag and have a function
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Wed Oct 16 17:02:29 2019 -0400
@@ -45,6 +45,7 @@
 import com.sun.source.util.JavacTask;
 import com.sun.tools.javac.api.JavacTaskImpl;
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Accessors.Kind;
 import com.sun.tools.javac.code.Attribute.Compound;
 import com.sun.tools.javac.code.Directive.ExportsDirective;
 import com.sun.tools.javac.code.Directive.ExportsFlag;
@@ -462,6 +463,8 @@
         Symbol sym = cast(Symbol.class, e);
         if ((sym.flags() & Flags.GENERATEDCONSTR) != 0)
             return Origin.MANDATED;
+        if ((sym.flags() & Flags.MANDATED) != 0)
+            return Origin.MANDATED;
         //TypeElement.getEnclosedElements does not return synthetic elements,
         //and most synthetic elements are not read from the classfile anyway:
         return Origin.EXPLICIT;
@@ -800,4 +803,18 @@
     public void newRound() {
         resultCache.clear();
     }
+
+    @Override
+    public ExecutableElement getterFor(VariableElement variableElement) {
+        return accessorFor(Kind.GET, variableElement);
+    }
+
+    private ExecutableElement accessorFor(Accessors.Kind kind, VariableElement variableElement) {
+        for (Pair<Accessors.Kind, MethodSymbol> accessor : ((VarSymbol)variableElement).accessors) {
+            if (accessor.fst == kind) {
+                return accessor.snd;
+            }
+        }
+        return null;
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java	Wed Oct 16 17:02:29 2019 -0400
@@ -30,6 +30,7 @@
 import java.util.Map;
 
 import com.sun.source.doctree.AttributeTree.ValueKind;
+import com.sun.source.doctree.DocTree;
 import com.sun.tools.javac.parser.DocCommentParser.TagParser.Kind;
 import com.sun.tools.javac.parser.Tokens.Comment;
 import com.sun.tools.javac.parser.Tokens.TokenKind;
@@ -1322,6 +1323,12 @@
                 }
             },
 
+            // {@getter text}
+            new AccessorParser(DCTree.Kind.GETTER),
+
+            // {@getter text}
+            new AccessorParser(DCTree.Kind.SETTER),
+
             // @param parameter-name description
             new TagParser(Kind.BLOCK, DCTree.Kind.PARAM) {
                 public DCTree parse(int pos) throws ParseException {
@@ -1527,4 +1534,14 @@
 
     }
 
+    class AccessorParser extends TagParser {
+        AccessorParser(DocTree.Kind kind) {
+            super(Kind.BLOCK, kind, true);
+        }
+
+        public DCTree parse(int pos) throws ParseException {
+            List<DCTree> desc = blockContent();
+            return m.at(pos).newAccessorTree(treeKind, desc);
+        }
+    }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Oct 16 17:02:29 2019 -0400
@@ -101,11 +101,13 @@
     private Preview preview;
 
     /** The name table. */
-    private Names names;
+    protected Names names;
 
     /** End position mappings container */
     protected final AbstractEndPosTable endPosTable;
 
+    private final boolean debug;
+
     // Because of javac's limited lookahead, some contexts are ambiguous in
     // the presence of type annotations even though they are not ambiguous
     // in the absence of type annotations.  Consider this code:
@@ -184,6 +186,12 @@
         endPosTable = newEndPosTable(keepEndPositions);
         this.allowYieldStatement = (!preview.isPreview(Feature.SWITCH_EXPRESSION) || preview.isEnabled()) &&
                 Feature.SWITCH_EXPRESSION.allowedInSource(source);
+        this.allowRecords = true; // to speed up testing for now
+                /*
+                (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) &&
+                Feature.RECORDS.allowedInSource(source);
+                */
+        debug = fac.options.isSet("debug");
     }
 
     protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
@@ -217,6 +225,10 @@
      */
     boolean allowYieldStatement;
 
+    /** Switch: are records allowed in this source level?
+     */
+    boolean allowRecords;
+
     /** The type of the method receiver, as specified by a first "this" parameter.
      */
     JCVariableDecl receiverParam;
@@ -1785,7 +1797,7 @@
 
     JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) {
         List<JCVariableDecl> params = explicitParams ?
-                formalParameters(true) :
+                formalParameters(true, false) :
                 implicitParameters(hasParens);
         if (explicitParams) {
             LambdaClassifier lambdaClassifier = new LambdaClassifier();
@@ -2400,7 +2412,7 @@
         JCClassDecl body = null;
         if (token.kind == LBRACE) {
             int pos = token.pos;
-            List<JCTree> defs = classOrInterfaceBody(names.empty, false);
+            List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
             JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
             body = toP(F.at(pos).AnonymousClassDef(mods, defs));
         }
@@ -2535,6 +2547,7 @@
     @SuppressWarnings("fallthrough")
     List<JCStatement> blockStatement() {
         //todo: skip to anchor on error(?)
+        Comment dc;
         int pos = token.pos;
         switch (token.kind) {
         case RBRACE: case CASE: case DEFAULT: case EOF:
@@ -2546,30 +2559,30 @@
             return List.of(parseSimpleStatement());
         case MONKEYS_AT:
         case FINAL: {
-            Comment dc = token.comment(CommentStyle.JAVADOC);
+            dc = token.comment(CommentStyle.JAVADOC);
             JCModifiers mods = modifiersOpt();
             if (token.kind == INTERFACE ||
                 token.kind == CLASS ||
                 token.kind == ENUM) {
-                return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
+                return List.of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
             } else {
                 JCExpression t = parseType(true);
                 return localVariableDeclarations(mods, t);
             }
         }
         case ABSTRACT: case STRICTFP: {
-            Comment dc = token.comment(CommentStyle.JAVADOC);
+            dc = token.comment(CommentStyle.JAVADOC);
             JCModifiers mods = modifiersOpt();
-            return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
+            return List.of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
         }
         case INTERFACE:
         case CLASS:
-            Comment dc = token.comment(CommentStyle.JAVADOC);
-            return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+            dc = token.comment(CommentStyle.JAVADOC);
+            return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
         case ENUM:
             log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.LocalEnum);
             dc = token.comment(CommentStyle.JAVADOC);
-            return List.of(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
+            return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), dc));
         case IDENTIFIER:
             if (token.name() == names.yield && allowYieldStatement) {
                 Token next = S.token(1);
@@ -2616,7 +2629,14 @@
 
                 //else intentional fall-through
             }
-        default:
+        }
+        if (isRecordToken() &&
+            (peekToken(TokenKind.IDENTIFIER, TokenKind.LPAREN) ||
+             peekToken(TokenKind.IDENTIFIER, TokenKind.LT))) {
+            JCModifiers mods = modifiersOpt();
+            dc = token.comment(CommentStyle.JAVADOC);
+            return List.of(recordDeclaration(mods, dc));
+        } else {
             Token prevToken = token;
             JCExpression t = term(EXPR | TYPE);
             if (token.kind == COLON && t.hasTag(IDENT)) {
@@ -3303,16 +3323,27 @@
                 log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK13));
             }
         }
+        if (name == names.record) {
+            if (allowRecords) {
+                return true;
+            } else if (shouldWarn) {
+                log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14));
+            }
+        }
         return false;
     }
 
+    boolean isRestrictedRecordTypeName(Name name) {
+        return allowRecords && name == names.record;
+    }
+
     /** VariableDeclaratorId = Ident BracketsOpt
      */
     JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
-        return variableDeclaratorId(mods, type, false);
+        return variableDeclaratorId(mods, type, false, false);
     }
     //where
-    JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean lambdaParameter) {
+    JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean lambdaParameter, boolean recordComponent) {
         int pos = token.pos;
         Name name;
         if (lambdaParameter && token.kind == UNDERSCORE) {
@@ -3358,7 +3389,15 @@
             log.error(token.pos, Errors.VarargsAndOldArraySyntax);
         }
         type = bracketsOpt(type);
-        return toP(F.at(pos).VarDef(mods, name, type, null));
+        List<Pair<Accessors.Kind, Name>> accessors = null;
+        if (recordComponent) {
+            if (forbiddenRecordComponentNames.contains(name.toString())) {
+                log.error(pos, Errors.IllegalRecordComponentName(name));
+            }
+            accessors = List.of(new Pair<>(Accessors.Kind.GET, name));
+        }
+
+        return toP(F.at(pos).VarDef(mods, name, type, null, accessors));
     }
 
     /** Resources = Resource { ";" Resources }
@@ -3627,7 +3666,7 @@
             nextToken();
             return toP(F.at(pos).Skip());
         } else {
-            return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
+            return classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment);
         }
     }
 
@@ -3636,9 +3675,11 @@
      *  @param mods     Any modifiers starting the class or interface declaration
      *  @param dc       The documentation comment for the class, or null.
      */
-    protected JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
+    protected JCStatement classOrRecordOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
         if (token.kind == CLASS) {
             return classDeclaration(mods, dc);
+        } if (isRecordToken()) {
+            return recordDeclaration(mods, dc);
         } else if (token.kind == INTERFACE) {
             return interfaceDeclaration(mods, dc);
         } else if (token.kind == ENUM) {
@@ -3656,8 +3697,12 @@
             if (parseModuleInfo) {
                 erroneousTree = syntaxError(pos, errs, Errors.ExpectedModuleOrOpen);
             } else {
+                if (allowRecords) {
+                    erroneousTree = syntaxError(pos, errs, Errors.Expected4(CLASS, INTERFACE, ENUM, RECORD));
+                } else {
                 erroneousTree = syntaxError(pos, errs, Errors.Expected3(CLASS, INTERFACE, ENUM));
             }
+            }
             return toP(F.Exec(erroneousTree));
         }
     }
@@ -3684,22 +3729,129 @@
             nextToken();
             implementing = typeList();
         }
-        List<JCTree> defs = classOrInterfaceBody(name, false);
+        List<JCTree> defs = classInterfaceOrRecordBody(name, false, false);
         JCClassDecl result = toP(F.at(pos).ClassDef(
             mods, name, typarams, extending, implementing, defs));
         attach(result, dc);
         return result;
     }
 
+    protected JCClassDecl recordDeclaration(JCModifiers mods, Comment dc) {
+        int pos = token.pos;
+        if ((mods.flags & Flags.ABSTRACT) != 0) {
+            log.error(mods.pos, Errors.RecordCantBeAbstract);
+        }
+        nextToken();
+        mods.flags |= Flags.RECORD | Flags.STATIC | Flags.FINAL;
+        Name name = typeName();
+
+        List<JCTypeParameter> typarams = typeParametersOpt();
+
+        List<JCVariableDecl> headerFields = formalParameters(false, true);
+
+        List<JCExpression> implementing = List.nil();
+        if (token.kind == IMPLEMENTS) {
+            nextToken();
+            implementing = typeList();
+        }
+        List<JCTree> defs = List.nil();
+        defs = classInterfaceOrRecordBody(name, false, true);
+        java.util.List<JCVariableDecl> fields = new ArrayList<>();
+        Set<Name> seenNames = new HashSet<>();
+        for (JCVariableDecl field : headerFields) {
+            if (seenNames.add(field.name)) {
+                fields.add(field);
+            } else {
+                log.error(field.pos(), Errors.RecordCantDeclareDuplicateFields);
+            }
+        }
+        for (JCTree def : defs) {
+            if (def.hasTag(METHODDEF)) {
+                JCMethodDecl methDef = (JCMethodDecl) def;
+                if (methDef.name == names.init && methDef.params.isEmpty()) {
+                    if ((methDef.mods.flags & Flags.PUBLIC) == 0) {
+                        log.error(methDef, Errors.MethodMustBePublic(names.init));
+                    }
+                    ListBuffer<JCVariableDecl> tmpParams = new ListBuffer<>();
+                    for (JCVariableDecl param : fields) {
+                        tmpParams.add(F.at(param).VarDef(F.Modifiers(Flags.PARAMETER | param.mods.flags & Flags.VARARGS), param.name, param.vartype, null));
+                    }
+                    methDef.params = tmpParams.toList();
+                }
+            }
+        }
+        for (int i = fields.size() - 1; i >= 0; i--) {
+            JCVariableDecl field = fields.get(i);
+            if ((field.mods.flags & Flags.VARARGS) != 0) {
+                if ((field.mods.flags & Flags.VARARGS) != 0) {
+                    field.mods.flags = field.mods.flags & ~Flags.VARARGS | Flags.ORIGINALLY_VARARGS;
+                    field = F.at(field).VarDef(field.mods, field.name, field.vartype, null, field.accessors);
+                }
+            }
+            defs = defs.prepend(field);
+        }
+        JCClassDecl result = toP(F.at(pos).ClassDef(mods, name, typarams, null, implementing, defs));
+        attach(result, dc);
+        return result;
+    }
+
     Name typeName() {
         int pos = token.pos;
         Name name = ident();
         if (isRestrictedTypeName(name, pos, true)) {
             reportSyntaxError(pos, Errors.RestrictedTypeNotAllowed(name, name == names.var ? Source.JDK10 : Source.JDK13));
         }
+
+        if (isRestrictedRecordTypeName(name)) {
+            reportSyntaxError(pos, Errors.RecordNotAllowed(name));
+        }
         return name;
     }
 
+    List<JCVariableDecl> headerFields() {
+        ListBuffer<JCVariableDecl> fields = new ListBuffer<>();
+        if (token.kind == LPAREN) {
+            nextToken();
+            // check for empty record
+            if (token.kind == RPAREN) {
+                nextToken();
+                return List.nil();
+            }
+            fields.add(headerField());
+            while (token.kind == COMMA) {
+                nextToken();
+                fields.add(headerField());
+            }
+            accept(RPAREN);
+        } else {
+            accept(LPAREN);
+        }
+        return fields.toList();
+    }
+
+    static final Set<String> forbiddenRecordComponentNames = Set.of(
+            "clone", "finalize", "getClass", "hashCode",
+            "notify", "notifyAll", "readObjectNoData",
+            "readResolve", "serialPersistentFields",
+            "serialVersionUID", "toString", "wait",
+            "writeReplace");
+
+    JCVariableDecl headerField() {
+        JCModifiers mods = modifiersOpt();
+        if (mods.flags != 0) {
+            log.error(mods.pos, Errors.RecordCantDeclareFieldModifiers);
+        }
+        mods.flags |= Flags.RECORD | Flags.FINAL | Flags.PRIVATE | Flags.MANDATED;
+        JCExpression type = parseType();
+        int pos = token.pos;
+        Name id = ident();
+        if (forbiddenRecordComponentNames.contains(id.toString())) {
+            log.error(pos, Errors.IllegalRecordComponentName(id));
+        }
+        List<Pair<Accessors.Kind, Name>> accessors = List.of(new Pair<>(Accessors.Kind.GET, id));
+        return toP(F.at(pos).VarDef(mods, id, type, null, accessors));
+    }
+
     /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
      *                         [EXTENDS TypeList] InterfaceBody
      *  @param mods    The modifiers starting the interface declaration
@@ -3718,7 +3870,7 @@
             nextToken();
             extending = typeList();
         }
-        List<JCTree> defs = classOrInterfaceBody(name, true);
+        List<JCTree> defs = classInterfaceOrRecordBody(name, true, false);
         JCClassDecl result = toP(F.at(pos).ClassDef(
             mods, name, typarams, null, extending, defs));
         attach(result, dc);
@@ -3809,8 +3961,8 @@
                     hasStructuralErrors = true;
                 }
                 wasError = false;
-                defs.appendList(classOrInterfaceBodyDeclaration(enumName,
-                                                                false));
+                defs.appendList(classOrInterfaceOrRecordBodyDeclaration(enumName,
+                                                                false, false));
                 if (token.pos <= endPosTable.errorEndPos) {
                     // error recovery
                    skip(false, true, true, false);
@@ -3863,7 +4015,7 @@
         JCClassDecl body = null;
         if (token.kind == LBRACE) {
             JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM);
-            List<JCTree> defs = classOrInterfaceBody(names.empty, false);
+            List<JCTree> defs = classInterfaceOrRecordBody(names.empty, false, false);
             body = toP(F.at(identPos).AnonymousClassDef(mods1, defs));
         }
         if (args.isEmpty() && body == null)
@@ -3893,7 +4045,7 @@
     /** ClassBody     = "{" {ClassBodyDeclaration} "}"
      *  InterfaceBody = "{" {InterfaceBodyDeclaration} "}"
      */
-    List<JCTree> classOrInterfaceBody(Name className, boolean isInterface) {
+    List<JCTree> classInterfaceOrRecordBody(Name className, boolean isInterface, boolean isRecord) {
         accept(LBRACE);
         if (token.pos <= endPosTable.errorEndPos) {
             // error recovery
@@ -3903,7 +4055,7 @@
         }
         ListBuffer<JCTree> defs = new ListBuffer<>();
         while (token.kind != RBRACE && token.kind != EOF) {
-            defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface));
+            defs.appendList(classOrInterfaceOrRecordBodyDeclaration(className, isInterface, isRecord));
             if (token.pos <= endPosTable.errorEndPos) {
                // error recovery
                skip(false, true, true, false);
@@ -3942,7 +4094,7 @@
      *      )
      *
      */
-    protected List<JCTree> classOrInterfaceBodyDeclaration(Name className, boolean isInterface) {
+    protected List<JCTree> classOrInterfaceOrRecordBodyDeclaration(Name className, boolean isInterface, boolean isRecord) {
         if (token.kind == SEMI) {
             nextToken();
             return List.nil();
@@ -3950,10 +4102,14 @@
             Comment dc = token.comment(CommentStyle.JAVADOC);
             int pos = token.pos;
             JCModifiers mods = modifiersOpt();
+            if (debug) {
+                System.out.println("read flags " + Flags.toString(mods.flags));
+            }
             if (token.kind == CLASS ||
+                isRecordToken() ||
                 token.kind == INTERFACE ||
                 token.kind == ENUM) {
-                return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
+                return List.of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
             } else if (token.kind == LBRACE &&
                        (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 &&
                        mods.annotations.isEmpty()) {
@@ -3990,22 +4146,27 @@
                     // method returns types are un-annotated types
                     type = unannotatedType(false);
                 }
-                if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
+                if ((token.kind == LPAREN && !isInterface ||
+                        isRecord && token.kind == LBRACE) && type.hasTag(IDENT)) {
                     if (isInterface || tk.name() != className)
                         log.error(DiagnosticFlag.SYNTAX, pos, Errors.InvalidMethDeclRetTypeReq);
                     else if (annosAfterParams.nonEmpty())
                         illegal(annosAfterParams.head.pos);
+                    if (isRecord && token.kind == LBRACE) {
+                        mods.flags |= Flags.COMPACT_RECORD_CONSTRUCTOR;
+                    }
                     return List.of(methodDeclaratorRest(
                         pos, mods, null, names.init, typarams,
-                        isInterface, true, dc));
+                        isInterface, true, isRecord, dc));
                 } else {
                     pos = token.pos;
                     Name name = ident();
                     if (token.kind == LPAREN) {
                         return List.of(methodDeclaratorRest(
                             pos, mods, type, name, typarams,
-                            isInterface, isVoid, dc));
+                            isInterface, isVoid, false, dc));
                     } else if (!isVoid && typarams.isEmpty()) {
+                        if (!isRecord || (isRecord && (mods.flags & Flags.STATIC) != 0)) {
                         List<JCTree> defs =
                             variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
                                                     new ListBuffer<JCTree>(), false).toList();
@@ -4013,6 +4174,10 @@
                         storeEnd(defs.last(), S.prevToken().endPos);
                         return defs;
                     } else {
+                            nextToken();
+                            return List.of(syntaxError(pos, null, Errors.RecordFieldsMustBeInHeader));
+                        }
+                    } else {
                         pos = token.pos;
                         List<JCTree> err;
                         if (isVoid || typarams.nonEmpty()) {
@@ -4031,6 +4196,10 @@
         }
     }
 
+    boolean isRecordToken() {
+        return allowRecords && token.kind == IDENTIFIER && token.name() == names.record;
+    }
+
     /** MethodDeclaratorRest =
      *      FormalParameters BracketsOpt [THROWS TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
      *  VoidMethodDeclaratorRest =
@@ -4044,6 +4213,7 @@
                               Name name,
                               List<JCTypeParameter> typarams,
                               boolean isInterface, boolean isVoid,
+                              boolean isRecord,
                               Comment dc) {
         if (isInterface) {
             if ((mods.flags & Flags.STATIC) != 0) {
@@ -4057,13 +4227,16 @@
         try {
             this.receiverParam = null;
             // Parsing formalParameters sets the receiverParam, if present
-            List<JCVariableDecl> params = formalParameters();
+            List<JCVariableDecl> params = List.nil();
+            List<JCExpression> thrown = List.nil();
+            if (!isRecord || name != names.init || token.kind == LPAREN) {
+                params = formalParameters();
             if (!isVoid) type = bracketsOpt(type);
-            List<JCExpression> thrown = List.nil();
             if (token.kind == THROWS) {
                 nextToken();
                 thrown = qualidentList(true);
             }
+            }
             JCBlock body = null;
             JCExpression defaultValue;
             if (token.kind == LBRACE) {
@@ -4174,15 +4347,15 @@
      *  FormalParameterListNovarargs = [ FormalParameterListNovarargs , ] FormalParameter
      */
     List<JCVariableDecl> formalParameters() {
-        return formalParameters(false);
+        return formalParameters(false, false);
     }
-    List<JCVariableDecl> formalParameters(boolean lambdaParameters) {
+    List<JCVariableDecl> formalParameters(boolean lambdaParameters, boolean recordComponents) {
         ListBuffer<JCVariableDecl> params = new ListBuffer<>();
         JCVariableDecl lastParam;
         accept(LPAREN);
         if (token.kind != RPAREN) {
-            this.allowThisIdent = !lambdaParameters;
-            lastParam = formalParameter(lambdaParameters);
+            this.allowThisIdent = !lambdaParameters && !recordComponents;
+            lastParam = formalParameter(lambdaParameters, recordComponents);
             if (lastParam.nameexpr != null) {
                 this.receiverParam = lastParam;
             } else {
@@ -4194,7 +4367,7 @@
                     log.error(DiagnosticFlag.SYNTAX, lastParam, Errors.VarargsMustBeLast);
                 }
                 nextToken();
-                params.append(lastParam = formalParameter(lambdaParameters));
+                params.append(lastParam = formalParameter(lambdaParameters, recordComponents));
             }
         }
         if (token.kind == RPAREN) {
@@ -4306,10 +4479,17 @@
      *  LastFormalParameter = { FINAL | '@' Annotation } Type '...' Ident | FormalParameter
      */
     protected JCVariableDecl formalParameter() {
-        return formalParameter(false);
+        return formalParameter(false, false);
     }
-    protected JCVariableDecl formalParameter(boolean lambdaParameter) {
-        JCModifiers mods = optFinal(Flags.PARAMETER);
+
+    protected JCVariableDecl formalParameter(boolean lambdaParameter, boolean recordComponent) {
+        JCModifiers mods = !recordComponent ? optFinal(Flags.PARAMETER) : modifiersOpt();
+        if (recordComponent && mods.flags != 0) {
+            log.error(mods.pos, Errors.RecordCantDeclareFieldModifiers);
+        }
+        if (recordComponent) {
+            mods.flags |= Flags.RECORD | Flags.FINAL | Flags.PRIVATE | Flags.MANDATED;
+        }
         // need to distinguish between vararg annos and array annos
         // look at typeAnnotationsPushedBack comment
         this.permitTypeAnnotationsPushBack = true;
@@ -4330,12 +4510,12 @@
             }
             typeAnnotationsPushedBack = List.nil();
         }
-        return variableDeclaratorId(mods, type, lambdaParameter);
+        return variableDeclaratorId(mods, type, lambdaParameter, recordComponent);
     }
 
     protected JCVariableDecl implicitParameter() {
         JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
-        return variableDeclaratorId(mods, null, true);
+        return variableDeclaratorId(mods, null, true, false);
     }
 
 /* ---------- auxiliary methods -------------- */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Wed Oct 16 17:02:29 2019 -0400
@@ -84,7 +84,7 @@
         key = new TokenKind[maxKey+1];
         for (int i = 0; i <= maxKey; i++) key[i] = TokenKind.IDENTIFIER;
         for (TokenKind t : TokenKind.values()) {
-            if (t.name != null)
+            if (t.name != null && !t.reserved())
             key[tokenName[t.ordinal()].getIndex()] = t;
         }
     }
@@ -226,6 +226,7 @@
         GTGTEQ(">>="),
         GTGTGTEQ(">>>="),
         MONKEYS_AT("@"),
+        RECORD("record", Tag.RESERVED),
         CUSTOM;
 
         public final String name;
@@ -276,6 +277,10 @@
             }
         }
 
+        public boolean reserved() {
+            return tag == Tag.RESERVED;
+        }
+
         public String getKind() {
             return "Token";
         }
@@ -315,7 +320,8 @@
             DEFAULT,
             NAMED,
             STRING,
-            NUMERIC
+            NUMERIC,
+            RESERVED;
         }
 
         /** The token kind */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Wed Oct 16 17:02:29 2019 -0400
@@ -974,7 +974,7 @@
      * Leave class public for external testing purposes.
      */
     public static class ComputeAnnotationSet extends
-        ElementScanner9<Set<TypeElement>, Set<TypeElement>> {
+        ElementScanner14<Set<TypeElement>, Set<TypeElement>> {
         final Elements elements;
 
         public ComputeAnnotationSet(Elements elements) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacRoundEnvironment.java	Wed Oct 16 17:02:29 2019 -0400
@@ -109,9 +109,9 @@
     /**
      * Returns the elements annotated with the given annotation type.
      * Only type elements <i>included</i> in this round of annotation
-     * processing, or declarations of members, parameters, or type
-     * parameters declared within those, are returned.  Included type
-     * elements are {@linkplain #getRootElements specified
+     * processing, or declarations of members, parameters, type
+     * parameters, or record components declared within those, are returned.
+     * Included type elements are {@linkplain #getRootElements specified
      * types} and any types nested within them.
      *
      * @param a  annotation type being requested
@@ -123,7 +123,7 @@
         throwIfNotAnnotation(a);
 
         Set<Element> result = Collections.emptySet();
-        ElementScanner9<Set<Element>, TypeElement> scanner =
+        ElementScanner14<Set<Element>, TypeElement> scanner =
             new AnnotationSetScanner(result);
 
         for (Element element : rootElements)
@@ -144,7 +144,7 @@
         }
 
         Set<Element> result = Collections.emptySet();
-        ElementScanner9<Set<Element>, Set<TypeElement>> scanner =
+        ElementScanner14<Set<Element>, Set<TypeElement>> scanner =
             new AnnotationSetMultiScanner(result);
 
         for (Element element : rootElements)
@@ -224,7 +224,7 @@
     }
 
     private static abstract class ElementScanningIncludingTypeParameters<R, P>
-        extends ElementScanner9<R, P> {
+        extends ElementScanner14<R, P> {
 
         protected ElementScanningIncludingTypeParameters(R defaultValue) {
             super(defaultValue);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java	Wed Oct 16 17:02:29 2019 -0400
@@ -39,6 +39,8 @@
 import java.io.Writer;
 import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 
 import com.sun.tools.javac.util.DefinedBy;
 import com.sun.tools.javac.util.DefinedBy.Api;
@@ -89,7 +91,7 @@
      * Used for the -Xprint option and called by Elements.printElements
      */
     public static class PrintingElementVisitor
-        extends SimpleElementVisitor9<PrintingElementVisitor, Boolean> {
+        extends SimpleElementVisitor14<PrintingElementVisitor, Boolean> {
         int indentation; // Indentation level;
         final PrintWriter writer;
         final Elements elementUtils;
@@ -111,6 +113,13 @@
         }
 
         @Override @DefinedBy(Api.LANGUAGE_MODEL)
+	public PrintingElementVisitor visitRecordComponent(RecordComponentElement e, Boolean p) {
+	    // Do nothing; printing of component information done by
+	    // printing the record type itself
+            return this;
+        }
+
+        @Override @DefinedBy(Api.LANGUAGE_MODEL)
         public PrintingElementVisitor visitExecutable(ExecutableElement e, Boolean p) {
             ElementKind kind = e.getKind();
 
@@ -123,7 +132,7 @@
                     enclosing != null &&
                     NestingKind.ANONYMOUS ==
                     // Use an anonymous class to determine anonymity!
-                    (new SimpleElementVisitor9<NestingKind, Void>() {
+                    (new SimpleElementVisitor14<NestingKind, Void>() {
                         @Override @DefinedBy(Api.LANGUAGE_MODEL)
                         public NestingKind visitType(TypeElement e, Void p) {
                             return e.getNestingKind();
@@ -216,6 +225,16 @@
 
                 printFormalTypeParameters(e, false);
 
+                if (kind == RECORD) {
+                    // Print out record components
+                    writer.print("(");
+                    writer.print(e.getRecordComponents()
+                                 .stream()
+                                 .map(recordDes -> recordDes.asType().toString() + " " + recordDes.getSimpleName())
+                                 .collect(Collectors.joining(", ")));
+                    writer.print(")");
+                }
+
                 // Print superclass information if informative
                 if (kind == CLASS) {
                     TypeMirror supertype = e.getSuperclass();
@@ -255,7 +274,13 @@
                 for(Element element : enclosedElements)
                     this.visit(element);
             } else {
-                for(Element element : e.getEnclosedElements())
+                for(Element element :
+                        (kind != RECORD ?
+                         e.getEnclosedElements() :
+                         e.getEnclosedElements()
+                         .stream()
+                         .filter(elt -> elementUtils.getOrigin(elt) == Elements.Origin.EXPLICIT )
+                         .collect(Collectors.toList()) ) )
                     this.visit(element);
             }
 
@@ -448,6 +473,10 @@
                 modifiers.remove(Modifier.ABSTRACT);
                 break;
 
+            case RECORD:
+                modifiers.remove(Modifier.FINAL);
+                break;
+
             case METHOD:
             case FIELD:
                 Element enclosingElement = e.getEnclosingElement();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Oct 16 17:02:29 2019 -0400
@@ -2159,6 +2159,10 @@
 compiler.err.expected3=\
     {0}, {1}, or {2} expected
 
+# 0: token, 1: token, 2: token, 3: token
+compiler.err.expected4=\
+    {0}, {1}, {2}, or {3} expected
+
 compiler.err.premature.eof=\
     reached end of file while parsing
 
@@ -3400,6 +3404,92 @@
 compiler.err.switch.mixing.case.types=\
     different case kinds used in the switch
 
+###
+# errors related to records
+
+compiler.err.record.cant.be.abstract=\
+    records cannot be abstract
+
+compiler.err.record.cant.declare.duplicate.fields=\
+    records cannot declare fields with the same name
+
+compiler.err.record.cant.declare.field.modifiers=\
+    records cannot declare field modifiers
+
+compiler.err.record.can.only.declare.methods.as.members=\
+    records can only declare methods as members
+
+# 0: fragment
+compiler.err.cant.extend.record=\
+    Illegal ''extends'' clause for record\n\
+    {0}
+
+compiler.misc.bad.record.super=\
+    A record must extend class AbstractRecord or an ''abstract'' record
+
+# 0: type, 1: name, 2: type, 3: name
+compiler.misc.super.field.mismatch=\
+    Superclass field declaration mismatch\n\
+    expected: {0} {1}\n\
+    found: {2} {3}
+
+compiler.misc.bad.super.fields=\
+    A record cannot have both an explicit constructor, and an implicit superclass header.
+
+compiler.err.record.fields.must.be.in.header=\
+    instance fields in a record must be declared in the header
+
+compiler.err.local.record=\
+    records must not be local
+
+compiler.err.nested.records.must.be.static=\
+    nested records must always be static
+
+# 0: name
+compiler.err.duplicate.argument.to.super=\
+    duplicate argument {0}, arguments passed to the super of a record must be unique
+
+# 0: name
+compiler.err.record.not.allowed=\
+    ''{0}'' not allowed here\n\
+    as of release 14, ''{0}'' is a restricted type name and cannot be used for type declarations
+
+# 0: name
+compiler.err.method.must.be.public=\
+    method: {0}(), must be public
+
+compiler.err.canonical.constructor.must.be.public=\
+    canonical constructor must be public
+
+compiler.err.canonical.with.name.mismatch=\
+    constructor with same signature as canonical does not match by parameter names
+
+compiler.err.constructor.with.same.erasure.as.canonical=\
+    constructor with same erasure as canonical constructor
+
+# 0: type, 1: type
+compiler.err.accessor.return.type.doesnt.match=\
+    type returned by the accessor is not the same as the type of the corresponding record component\n\
+    required: {0}\n\
+    found:    {1}\n\
+
+# 0: name
+compiler.err.illegal.record.component.name=\
+    Illegal record component name: {0}
+
+# 0: name
+compiler.err.illegal.record.member=\
+    Illegal record member: {0}
+
+compiler.err.invalid.supertype.record=\
+    no class can explicitly extend java.lang.Record
+
+compiler.err.method.cant.throw.checked.exception=\
+    method cannot throw checked exception
+
+compiler.err.canonical.cant.have.return.statement=\
+    canonical constructor can not have return statements
+
 ############################################
 # messages previouly at javac.properties
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DCTree.java	Wed Oct 16 17:02:29 2019 -0400
@@ -575,6 +575,32 @@
         }
     }
 
+    public static class DCAccessor extends DCInlineTag implements AccessorTree {
+        public final Kind kind;
+        public final List<? extends DocTree> description;
+
+        DCAccessor(Kind kind, List<? extends DocTree> description) {
+            Assert.check(kind == Kind.GETTER || kind == Kind.SETTER);
+            this.kind = kind;
+            this.description = description;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public Kind getKind() {
+            return kind;
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public <R, D> R accept(DocTreeVisitor<R, D> v, D d) {
+            return v.visitAccessor(this, d);
+        }
+
+        @Override @DefinedBy(Api.COMPILER_TREE)
+        public List<? extends DocTree> getDescription() {
+            return description;
+        }
+    }
+
     public static class DCParam extends DCBlockTag implements ParamTree {
         public final boolean isTypeParameter;
         public final DCIdentifier name;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocPretty.java	Wed Oct 16 17:02:29 2019 -0400
@@ -129,6 +129,19 @@
         }
     }
 
+    @Override
+    public Void visitAccessor(AccessorTree node, Void aVoid) {
+        try {
+            print("{");
+            printTagName(node);
+            print(node.getDescription());
+            print("}");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+        return null;
+    }
+
     @Override @DefinedBy(Api.COMPILER_TREE)
     public Void visitAttribute(AttributeTree node, Void p) {
         try {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java	Wed Oct 16 17:02:29 2019 -0400
@@ -55,6 +55,7 @@
 import com.sun.tools.javac.parser.ReferenceParser;
 import com.sun.tools.javac.parser.Tokens.Comment;
 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
+import com.sun.tools.javac.tree.DCTree.DCAccessor;
 import com.sun.tools.javac.tree.DCTree.DCAttribute;
 import com.sun.tools.javac.tree.DCTree.DCAuthor;
 import com.sun.tools.javac.tree.DCTree.DCComment;
@@ -361,6 +362,13 @@
     }
 
     @Override @DefinedBy(Api.COMPILER_TREE)
+    public DCAccessor newAccessorTree(Kind kind, List<? extends DocTree> desc) {
+        DCAccessor tree = new DCAccessor(kind, desc);
+        tree.pos = pos;
+        return tree;
+    }
+
+    @Override @DefinedBy(Api.COMPILER_TREE)
     public DCParam newParamTree(boolean isTypeParameter, IdentifierTree name, List<? extends DocTree> description) {
         DCParam tree = new DCParam(isTypeParameter, (DCIdentifier) name, cast(description));
         tree.pos = pos;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Oct 16 17:02:29 2019 -0400
@@ -848,6 +848,9 @@
         public JCExpression defaultValue;
         /** method symbol */
         public MethodSymbol sym;
+        /** does this method completes normally */
+        public boolean completesNormally;
+
         protected JCMethodDecl(JCModifiers mods,
                             Name name,
                             JCExpression restype,
@@ -932,23 +935,27 @@
         public VarSymbol sym;
         /** explicit start pos */
         public int startPos = Position.NOPOS;
+        /** accessors */
+        public List<Pair<Accessors.Kind, Name>> accessors;
 
         protected JCVariableDecl(JCModifiers mods,
                          Name name,
                          JCExpression vartype,
                          JCExpression init,
-                         VarSymbol sym) {
+                         VarSymbol sym,
+                         List<Pair<Accessors.Kind, Name>> accessors) {
             this.mods = mods;
             this.name = name;
             this.vartype = vartype;
             this.init = init;
             this.sym = sym;
+            this.accessors = accessors;
         }
 
         protected JCVariableDecl(JCModifiers mods,
                          JCExpression nameexpr,
                          JCExpression vartype) {
-            this(mods, null, vartype, null, null);
+            this(mods, null, vartype, null, null, null);
             this.nameexpr = nameexpr;
             if (nameexpr.hasTag(Tag.IDENT)) {
                 this.name = ((JCIdent)nameexpr).name;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Oct 16 17:02:29 2019 -0400
@@ -82,6 +82,10 @@
         }
     }
 
+    public static boolean isCanonicalConstructor(JCTree tree) {
+        return isConstructor(tree) && ((JCMethodDecl)tree).sym.isRecord();
+    }
+
     public static boolean isReceiverParam(JCTree tree) {
         if (tree.hasTag(VARDEF)) {
             return ((JCVariableDecl)tree).nameexpr != null;
@@ -98,6 +102,25 @@
         return false;
     }
 
+    /** Is there a constructor invocation in the given list of trees?
+     */
+    public static Name getConstructorInvocationName(List<? extends JCTree> trees, Names names, boolean isRecord) {
+        for (JCTree tree : trees) {
+            if (tree.hasTag(EXEC)) {
+                JCExpressionStatement stat = (JCExpressionStatement)tree;
+                if (stat.expr.hasTag(APPLY)) {
+                    JCMethodInvocation apply = (JCMethodInvocation)stat.expr;
+                    Name methName = TreeInfo.name(apply.meth);
+                    if (methName == names._this ||
+                        methName == names._super) {
+                        return methName;
+                    }
+                }
+            }
+        }
+        return names.empty;
+    }
+
     public static boolean isMultiCatch(JCCatch catchClause) {
         return catchClause.param.vartype.hasTag(TYPEUNION);
     }
@@ -190,6 +213,23 @@
         }
     }
 
+    public static List<JCVariableDecl> recordFields(JCClassDecl tree) {
+        return tree.defs.stream()
+                .filter(t -> t.hasTag(VARDEF))
+                .map(t -> (JCVariableDecl)t)
+                .filter(vd -> (vd.getModifiers().flags & (Flags.RECORD)) == RECORD)
+                .collect(List.collector());
+    }
+
+    public static List<Type> recordFieldTypes(JCClassDecl tree) {
+        return tree.defs.stream()
+                .filter(t -> t.hasTag(VARDEF))
+                .map(t -> (JCVariableDecl)t)
+                .filter(vd -> (vd.getModifiers().flags & (Flags.RECORD)) == RECORD)
+                .map(vd -> vd.type)
+                .collect(List.collector());
+    }
+
     /** Is this a constructor whose first (non-synthetic) statement is not
      *  of the form this(...)?
      */
@@ -886,6 +926,24 @@
         }
     }
 
+    /** If this tree has a modifiers field, return it otherwise return null
+     */
+    public static JCModifiers getModifiers(JCTree tree) {
+        tree = skipParens(tree);
+        switch (tree.getTag()) {
+            case VARDEF:
+                return ((JCVariableDecl) tree).mods;
+            case METHODDEF:
+                return ((JCMethodDecl) tree).mods;
+            case CLASSDEF:
+                return ((JCClassDecl) tree).mods;
+            case MODULEDEF:
+                return ((JCModuleDecl) tree).mods;
+        default:
+            return null;
+        }
+    }
+
     /** Return true if this is a nonstatic selection. */
     public static boolean nonstaticSelect(JCTree tree) {
         tree = skipParens(tree);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Wed Oct 16 17:02:29 2019 -0400
@@ -211,7 +211,11 @@
     }
 
     public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init) {
-        JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null);
+        return VarDef(mods, name, vartype, init, null);
+    }
+
+    public JCVariableDecl VarDef(JCModifiers mods, Name name, JCExpression vartype, JCExpression init, List<Pair<Accessors.Kind, Name>> accessors) {
+        JCVariableDecl tree = new JCVariableDecl(mods, name, vartype, init, null, accessors);
         tree.pos = pos;
         return tree;
     }
@@ -840,7 +844,7 @@
                 v.name,
                 Type(v.type),
                 init,
-                v).setPos(pos).setType(v.type);
+                v, null).setPos(pos).setType(v.type);
     }
 
     /** Create annotation trees from annotations.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Dependencies.java	Wed Oct 16 17:02:29 2019 -0400
@@ -91,6 +91,7 @@
         HIERARCHY_PHASE,
         IMPORTS_PHASE,
         MEMBER_ENTER,
+        RECORD_PHASE,
         MEMBERS_PHASE,
         OTHER;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Wed Oct 16 17:02:29 2019 -0400
@@ -70,6 +70,8 @@
     public final Name uses;
     public final Name open;
     public final Name with;
+    public final Name get;
+    public final Name set;
     public final Name yield;
 
     // field and method names
@@ -83,6 +85,7 @@
     public final Name deserializeLambda;
     public final Name desiredAssertionStatus;
     public final Name equals;
+    public final Name oldEquals;
     public final Name error;
     public final Name finalize;
     public final Name forRemoval;
@@ -100,6 +103,8 @@
     public final Name value;
     public final Name valueOf;
     public final Name values;
+    public final Name readResolve;
+    public final Name readObject;
 
     // class names
     public final Name java_io_Serializable;
@@ -141,6 +146,7 @@
     public final Name ModuleResolution;
     public final Name NestHost;
     public final Name NestMembers;
+    public final Name Record;
     public final Name RuntimeInvisibleAnnotations;
     public final Name RuntimeInvisibleParameterAnnotations;
     public final Name RuntimeInvisibleTypeAnnotations;
@@ -168,6 +174,7 @@
     public final Name TYPE;
     public final Name TYPE_PARAMETER;
     public final Name TYPE_USE;
+    public final Name RECORD_COMPONENT;
 
     // members of java.lang.annotation.RetentionPolicy
     public final Name CLASS;
@@ -191,6 +198,21 @@
     public final Name makeConcat;
     public final Name makeConcatWithConstants;
 
+    // record related
+    // members of java.lang.invoke.ObjectMethods
+    public final Name bootstrap;
+
+    public final Name record;
+    public final Name where;
+    public final Name non;
+    public final Name ofLazyProjection;
+
+    // serialization members, used by records too
+    public final Name serialPersistentFields;
+    public final Name writeObject;
+    public final Name writeReplace;
+    public final Name readObjectNoData;
+
     public final Name.Table table;
 
     public Names(Context context) {
@@ -220,6 +242,8 @@
         uses = fromString("uses");
         open = fromString("open");
         with = fromString("with");
+        get = fromString("get");
+        set = fromString("set");
         yield = fromString("yield");
 
         // field and method names
@@ -233,6 +257,7 @@
         deserializeLambda = fromString("$deserializeLambda$");
         desiredAssertionStatus = fromString("desiredAssertionStatus");
         equals = fromString("equals");
+        oldEquals = fromString("oldEquals");
         error = fromString("<error>");
         finalize = fromString("finalize");
         forRemoval = fromString("forRemoval");
@@ -250,6 +275,8 @@
         value = fromString("value");
         valueOf = fromString("valueOf");
         values = fromString("values");
+        readResolve = fromString("readResolve");
+        readObject = fromString("readObject");
         dollarThis = fromString("$this");
 
         // class names
@@ -292,6 +319,7 @@
         ModuleResolution = fromString("ModuleResolution");
         NestHost = fromString("NestHost");
         NestMembers = fromString("NestMembers");
+        Record = fromString("Record");
         RuntimeInvisibleAnnotations = fromString("RuntimeInvisibleAnnotations");
         RuntimeInvisibleParameterAnnotations = fromString("RuntimeInvisibleParameterAnnotations");
         RuntimeInvisibleTypeAnnotations = fromString("RuntimeInvisibleTypeAnnotations");
@@ -319,6 +347,7 @@
         TYPE = fromString("TYPE");
         TYPE_PARAMETER = fromString("TYPE_PARAMETER");
         TYPE_USE = fromString("TYPE_USE");
+        RECORD_COMPONENT = fromString("RECORD_COMPONENT");
 
         // members of java.lang.annotation.RetentionPolicy
         CLASS = fromString("CLASS");
@@ -340,6 +369,17 @@
         // string concat
         makeConcat = fromString("makeConcat");
         makeConcatWithConstants = fromString("makeConcatWithConstants");
+
+        bootstrap = fromString("bootstrap");
+        record = fromString("record");
+        where = fromString("where");
+        non = fromString("non");
+        ofLazyProjection = fromString("ofLazyProjection");
+
+        serialPersistentFields = fromString("serialPersistentFields");
+        writeObject = fromString("writeObject");
+        writeReplace = fromString("writeReplace");
+        readObjectNoData = fromString("readObjectNoData");
     }
 
     protected Name.Table createTable(Options options) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PubapiVisitor.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.compiler/share/classes/com/sun/tools/sjavac/comp/PubapiVisitor.java	Wed Oct 16 17:02:29 2019 -0400
@@ -36,7 +36,7 @@
 import javax.lang.model.element.TypeParameterElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementScanner9;
+import javax.lang.model.util.ElementScanner14;
 
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.util.DefinedBy;
@@ -56,7 +56,7 @@
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
-public class PubapiVisitor extends ElementScanner9<Void, Void> {
+public class PubapiVisitor extends ElementScanner14<Void, Void> {
 
     private PubApi collectedApi = new PubApi();
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java	Wed Oct 16 17:02:29 2019 -0400
@@ -38,7 +38,7 @@
 import javax.lang.model.element.ModuleElement;
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.SimpleElementVisitor9;
+import javax.lang.model.util.SimpleElementVisitor14;
 
 import com.sun.source.doctree.DocTree;
 import jdk.javadoc.internal.doclets.formats.html.markup.Entity;
@@ -180,7 +180,7 @@
 
     protected void addDescription(Content dl, Element element) {
         SearchIndexItem si = new SearchIndexItem();
-        new SimpleElementVisitor9<Void, Void>() {
+        new SimpleElementVisitor14<Void, Void>() {
 
             @Override
             public Void visitModule(ModuleElement e, Void p) {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Wed Oct 16 17:02:29 2019 -0400
@@ -33,6 +33,7 @@
 
 import javax.lang.model.element.AnnotationMirror;
 import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
 import javax.lang.model.element.ModuleElement;
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
@@ -294,9 +295,9 @@
      * Get the class hierarchy tree for the given class.
      *
      * @param type the class to print the hierarchy for
-     * @return a content tree for class inheritence
+     * @return a content tree for class inheritance
      */
-    private Content getClassInheritenceTree(TypeMirror type) {
+    private Content getClassInheritanceTree(TypeMirror type) {
         TypeMirror sup;
         HtmlTree classTree = null;
         do {
@@ -347,19 +348,20 @@
         if (!utils.isClass(typeElement)) {
             return;
         }
-        classContentTree.add(getClassInheritenceTree(typeElement.asType()));
+        classContentTree.add(getClassInheritanceTree(typeElement.asType()));
     }
 
     /**
      * {@inheritDoc}
      */
     @Override
-    public void addTypeParamInfo(Content classInfoTree) {
-        if (!utils.getTypeParamTrees(typeElement).isEmpty()) {
-            Content typeParam = (new ParamTaglet()).getTagletOutput(typeElement,
+    public void addParamInfo(Content classInfoTree) {
+        if (utils.hasBlockTag(typeElement, DocTree.Kind.PARAM)) {
+            Content paramInfo = (new ParamTaglet()).getTagletOutput(typeElement,
                     getTagletWriterInstance(false));
-            Content dl = HtmlTree.DL(typeParam);
-            classInfoTree.add(dl);
+            if (!paramInfo.isEmpty()) {
+                classInfoTree.add(HtmlTree.DL(paramInfo));
+            }
         }
     }
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java	Wed Oct 16 17:02:29 2019 -0400
@@ -155,6 +155,7 @@
     public final Content propertyLabel;
     public final Content propertyDetailsLabel;
     public final Content propertySummaryLabel;
+    public final Content record;
     public final Content seeLabel;
     public final Content serializedForm;
     public final Content servicesLabel;
@@ -282,6 +283,7 @@
         propertyLabel = getContent("doclet.Property");
         propertyDetailsLabel = getContent("doclet.Property_Detail");
         propertySummaryLabel = getContent("doclet.Property_Summary");
+        record = getContent("doclet.Record");
         seeLabel = getContent("doclet.See");
         serializedForm = getContent("doclet.Serialized_Form");
         servicesLabel = getContent("doclet.Services");
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java	Wed Oct 16 17:02:29 2019 -0400
@@ -236,22 +236,21 @@
      * {@inheritDoc}
      */
     @Override // defined by AbstractDoclet
-    protected void generateClassFiles(SortedSet<TypeElement> arr, ClassTree classtree)
+    protected void generateClassFiles(SortedSet<TypeElement> typeElems, ClassTree classTree)
             throws DocletException {
-        List<TypeElement> list = new ArrayList<>(arr);
-        for (TypeElement klass : list) {
-            if (utils.hasHiddenTag(klass) ||
-                    !(configuration.isGeneratedDoc(klass) && utils.isIncluded(klass))) {
+        for (TypeElement te : typeElems) {
+            if (utils.hasHiddenTag(te) ||
+                    !(configuration.isGeneratedDoc(te) && utils.isIncluded(te))) {
                 continue;
             }
-            if (utils.isAnnotationType(klass)) {
+            if (utils.isAnnotationType(te)) {
                 AbstractBuilder annotationTypeBuilder =
                     configuration.getBuilderFactory()
-                        .getAnnotationTypeBuilder(klass);
+                        .getAnnotationTypeBuilder(te);
                 annotationTypeBuilder.build();
             } else {
                 AbstractBuilder classBuilder =
-                    configuration.getBuilderFactory().getClassBuilder(klass, classtree);
+                    configuration.getBuilderFactory().getClassBuilder(te, classTree);
                 classBuilder.build();
             }
         }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Wed Oct 16 17:02:29 2019 -0400
@@ -51,7 +51,7 @@
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.SimpleAnnotationValueVisitor9;
-import javax.lang.model.util.SimpleElementVisitor9;
+import javax.lang.model.util.SimpleElementVisitor14;
 import javax.lang.model.util.SimpleTypeVisitor9;
 
 import com.sun.source.doctree.AttributeTree;
@@ -1512,7 +1512,8 @@
                 @Override
                 public Boolean visitLink(LinkTree node, Content c) {
                     // we need to pass the DocTreeImpl here, so ignore node
-                    result.add(seeTagToContent(element, tag));
+                    Content content = seeTagToContent(element, tag);
+                    result.add(content);
                     return false;
                 }
 
@@ -1666,7 +1667,7 @@
             return text;
         }
 
-        DocPath redirectPathFromRoot = new SimpleElementVisitor9<DocPath, Void>() {
+        DocPath redirectPathFromRoot = new SimpleElementVisitor14<DocPath, Void>() {
             @Override
             public DocPath visitType(TypeElement e, Void p) {
                 return docPaths.forPackage(utils.containingPackage(e));
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Wed Oct 16 17:02:29 2019 -0400
@@ -214,6 +214,15 @@
      * {@inheritDoc}
      */
     @Override
+    public void addRecordSummary(SortedSet<TypeElement> records, Content summaryContentTree) {
+        TableHeader tableHeader= new TableHeader(contents.record, contents.descriptionLabel);
+        addClassesSummary(records, resources.recordSummary, tableHeader, summaryContentTree);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public void addExceptionSummary(SortedSet<TypeElement> exceptions, Content summaryContentTree) {
         TableHeader tableHeader= new TableHeader(contents.exception, contents.descriptionLabel);
         addClassesSummary(exceptions, resources.exceptionSummary, tableHeader, summaryContentTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java	Wed Oct 16 17:02:29 2019 -0400
@@ -28,13 +28,20 @@
 import java.util.List;
 
 import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.SimpleElementVisitor9;
+import javax.lang.model.util.SimpleElementVisitor14;
 
 import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.DocTree.Kind;
 import com.sun.source.doctree.IndexTree;
+import com.sun.source.doctree.ParamTree;
 import com.sun.source.doctree.SystemPropertyTree;
 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
@@ -193,12 +200,15 @@
     public Content paramTagOutput(Element element, DocTree paramTag, String paramName) {
         ContentBuilder body = new ContentBuilder();
         CommentHelper ch = utils.getCommentHelper(element);
-        body.add(HtmlTree.CODE(new RawHtml(paramName)));
+        // define id attributes for state components so that generated descriptions may refer to them
+        boolean defineID = (element.getKind() == ElementKind.RECORD)
+                && (paramTag instanceof ParamTree) && !((ParamTree) paramTag).isTypeParameter();
+        Content nameTree = new StringContent(paramName);
+        body.add(HtmlTree.CODE(defineID ? HtmlTree.A_ID("param-" + paramName, nameTree) : nameTree));
         body.add(" - ");
         List<? extends DocTree> description = ch.getDescription(configuration, paramTag);
         body.add(htmlWriter.commentTagsToContent(paramTag, element, description, false, inSummary));
-        HtmlTree result = HtmlTree.DD(body);
-        return result;
+        return HtmlTree.DD(body);
     }
 
     /**
@@ -272,6 +282,26 @@
 
     }
 
+    public Content accessorTagOutput(Element holder, List<? extends DocTree> tags) {
+        if (!tags.isEmpty()) {
+            //Todo: check that there's only one tag
+            DocTree.Kind kind = tags.get(0).getKind();
+            ExecutableElement accessor = utils.findAccessorFor((VariableElement)holder, kind);
+            //add reference to getter/setter
+            Content body = htmlWriter.getDocLink(LinkInfoImpl.Kind.SEE_TAG, (TypeElement)holder.getEnclosingElement(),
+                    accessor, accessor.getSimpleName() + utils.makeSignature(accessor, true), false, false);
+            ContentBuilder result = new ContentBuilder();
+            String key = kind == Kind.GETTER ?
+                    "doclet.getter" : "doclet.setter";
+            result.add(HtmlTree.DT(HtmlTree.SPAN(HtmlStyle.seeLabel,
+                    new StringContent(resources.getText(key)))));
+            result.add(HtmlTree.DD(body));
+            return result;
+        } else {
+            return new ContentBuilder();
+        }
+    }
+
     private void appendSeparatorIfNotEmpty(ContentBuilder body) {
         if (!body.isEmpty()) {
             body.add(", ");
@@ -427,7 +457,7 @@
                 si.setDescription(desc);
                 si.setUrl(htmlWriter.path.getPath() + "#" + anchorName);
                 DocPaths docPaths = configuration.docPaths;
-                new SimpleElementVisitor9<Void, Void>() {
+                new SimpleElementVisitor14<Void, Void>() {
                     @Override
                     public Void visitVariable(VariableElement e, Void p) {
                         TypeElement te = utils.getEnclosingTypeElement(e);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/BaseConfiguration.java	Wed Oct 16 17:02:29 2019 -0400
@@ -26,13 +26,14 @@
 package jdk.javadoc.internal.doclets.toolkit;
 
 import java.io.*;
+import java.lang.ref.*;
 import java.util.*;
 
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ModuleElement;
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
-import javax.lang.model.util.SimpleElementVisitor9;
+import javax.lang.model.util.SimpleElementVisitor14;
 import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
 
@@ -1235,7 +1236,7 @@
                     : docEnv.getSpecifiedElements();
 
             for (Element e : inset) {
-                new SimpleElementVisitor9<Void, Void>() {
+                new SimpleElementVisitor14<Void, Void>() {
                     @Override
                     @DefinedBy(Api.LANGUAGE_MODEL)
                     public Void visitModule(ModuleElement e, Void p) {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ClassWriter.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ClassWriter.java	Wed Oct 16 17:02:29 2019 -0400
@@ -73,11 +73,11 @@
     public Content getClassInfoTreeHeader();
 
     /**
-     * Add the type parameter information.
+     * Add the type parameter and state component information.
      *
      * @param classInfoTree content tree to which the documentation will be added
      */
-    public void addTypeParamInfo(Content classInfoTree);
+    public void addParamInfo(Content classInfoTree);
 
     /**
      * Add all super interfaces if this is an interface.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java	Wed Oct 16 17:02:29 2019 -0400
@@ -38,20 +38,26 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Name;
 import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.RecordComponentElement;
+import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.util.Elements;
 import javax.tools.FileObject;
 import javax.tools.JavaFileObject;
 import javax.tools.SimpleJavaFileObject;
 
+import com.sun.source.doctree.AttributeTree;
 import com.sun.source.doctree.DocCommentTree;
 import com.sun.source.doctree.DocTree;
 import com.sun.source.doctree.IdentifierTree;
+import com.sun.source.doctree.ParamTree;
 import com.sun.source.doctree.ReferenceTree;
 import com.sun.source.doctree.TextTree;
 import com.sun.source.util.DocTreeFactory;
@@ -65,6 +71,7 @@
 public class CommentUtils {
 
     final BaseConfiguration configuration;
+    final Utils utils;
     final Resources resources;
     final DocTreeFactory treeFactory;
     final HashMap<Element, DocCommentDuo> dcTreesMap = new HashMap<>();
@@ -73,6 +80,7 @@
 
     protected CommentUtils(BaseConfiguration configuration) {
         this.configuration = configuration;
+        utils = configuration.utils;
         resources = configuration.getResources();
         trees = configuration.docEnv.getDocTrees();
         treeFactory = trees.getDocTreeFactory();
@@ -107,17 +115,17 @@
         return treeFactory.newSeeTree(list);
     }
 
-    public DocTree makeTextTree(String content) {
-        TextTree text = treeFactory.newTextTree(content);
-        return (DocTree) text;
+    public TextTree makeTextTree(String content) {
+        return treeFactory.newTextTree(content);
     }
 
-    public void setEnumValuesTree(Element e) {
-        Utils utils = configuration.utils;
-        String klassName = utils.getSimpleName(utils.getEnclosingTypeElement(e));
+    public TextTree makeTextTreeForResource(String key) {
+        return treeFactory.newTextTree(resources.getText(key));
+    }
 
+    public void setEnumValuesTree(ExecutableElement ee) {
         List<DocTree> fullBody = new ArrayList<>();
-        fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_values_doc.fullbody", klassName)));
+        fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_values_doc.fullbody")));
 
         List<DocTree> descriptions = new ArrayList<>();
         descriptions.add(treeFactory.newTextTree(resources.getText("doclet.enum_values_doc.return")));
@@ -125,11 +133,10 @@
         List<DocTree> tags = new ArrayList<>();
         tags.add(treeFactory.newReturnTree(descriptions));
         DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
-        dcTreesMap.put(e, new DocCommentDuo(null, docTree));
+        dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
     }
 
-    public void setEnumValueOfTree(Element e) {
-
+    public void setEnumValueOfTree(ExecutableElement ee) {
         List<DocTree> fullBody = new ArrayList<>();
         fullBody.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.fullbody")));
 
@@ -137,7 +144,6 @@
 
         List<DocTree> paramDescs = new ArrayList<>();
         paramDescs.add(treeFactory.newTextTree(resources.getText("doclet.enum_valueof_doc.param_name")));
-        ExecutableElement ee = (ExecutableElement) e;
         java.util.List<? extends VariableElement> parameters = ee.getParameters();
         VariableElement param = parameters.get(0);
         IdentifierTree id = treeFactory.newIdentifierTree(elementUtils.getName(param.getSimpleName().toString()));
@@ -161,7 +167,230 @@
 
         DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
 
-        dcTreesMap.put(e, new DocCommentDuo(null, docTree));
+        dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
+    }
+
+    /**
+     * Generates the description for the canonical constructor for a record.
+     * @param ee the constructor
+     */
+    public void setRecordConstructorTree(ExecutableElement ee) {
+        TypeElement te = utils.getEnclosingTypeElement(ee);
+
+        List<DocTree> fullBody =
+                makeDescriptionWithName("doclet.record_constructor_doc.fullbody", te.getSimpleName());
+
+        List<DocTree> tags = new ArrayList<>();
+        java.util.List<? extends VariableElement> parameters = ee.getParameters();
+        for (VariableElement param : ee.getParameters()) {
+            Name name = param.getSimpleName();
+            IdentifierTree id = treeFactory.newIdentifierTree(name);
+            tags.add(treeFactory.newParamTree(false, id,
+                    makeDescriptionWithComponent("doclet.record_constructor_doc.param_name", te, name)));
+        }
+
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, tags);
+        dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
+    }
+
+    /**
+     * Generates the description for the standard {@code equals} method for a record.
+     * @param ee the {@code equals} method
+     */
+    public void setRecordEqualsTree(ExecutableElement ee) {
+        List<DocTree> fullBody = new ArrayList<>();
+        add(fullBody, "doclet.record_equals_doc.fullbody.head");
+        fullBody.add(treeFactory.newTextTree(" "));
+
+        List<? extends RecordComponentElement> comps = ((TypeElement) ee.getEnclosingElement()).getRecordComponents();
+        boolean hasPrimitiveComponents =
+                comps.stream().anyMatch(e -> e.asType().getKind().isPrimitive());
+        boolean hasReferenceComponents =
+                comps.stream().anyMatch(e -> !e.asType().getKind().isPrimitive());
+        if (hasPrimitiveComponents && hasReferenceComponents) {
+            add(fullBody, "doclet.record_equals_doc.fullbody.tail.both");
+        } else if (hasPrimitiveComponents) {
+            add(fullBody, "doclet.record_equals_doc.fullbody.tail.primitive");
+        } else if (hasReferenceComponents) {
+            add(fullBody, "doclet.record_equals_doc.fullbody.tail.reference");
+        }
+        Name paramName = ee.getParameters().get(0).getSimpleName();
+        IdentifierTree id = treeFactory.newIdentifierTree(paramName);
+        List<DocTree> paramDesc =
+                makeDescriptionWithName("doclet.record_equals_doc.param_name", paramName);
+        DocTree paramTree = treeFactory.newParamTree(false, id, paramDesc);
+
+        DocTree returnTree = treeFactory.newReturnTree(
+                makeDescriptionWithName("doclet.record_equals_doc.return", paramName));
+
+        TreePath treePath = utils.getTreePath(ee.getEnclosingElement());
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(paramTree, returnTree));
+        dcTreesMap.put(ee, new DocCommentDuo(treePath, docTree));
+    }
+
+    private void add(List<DocTree> contents, String resourceKey) {
+        // Special case to allow '{@link ...}' to appear in the string.
+        // A less general case would be to detect literal use of Object.equals
+        // A more general case would be to allow access to DocCommentParser somehow
+        String body = resources.getText(resourceKey);
+        Pattern p = Pattern.compile("\\{@link (\\S*)(.*)}");
+        Matcher m = p.matcher(body);
+        int start = 0;
+        while (m.find(start)) {
+            if (m.start() > start) {
+                contents.add(treeFactory.newTextTree(body.substring(start, m.start())));
+            }
+            ReferenceTree refTree = treeFactory.newReferenceTree(m.group(1));
+            List<DocTree> descr = List.of(treeFactory.newTextTree(m.group(2).trim())) ;
+            contents.add(treeFactory.newLinkTree(refTree, descr));
+            start = m.end();
+        }
+        if (start < body.length()) {
+            contents.add(treeFactory.newTextTree(body.substring(start)));
+        }
+    }
+
+    /**
+     * Generates the description for the standard {@code hashCode} method for a record.
+     * @param ee the {@code hashCode} method
+     */
+    public void setRecordHashCodeTree(ExecutableElement ee) {
+        List<DocTree> fullBody = List.of(makeTextTreeForResource("doclet.record_hashCode_doc.fullbody"));
+
+        DocTree returnTree = treeFactory.newReturnTree(
+                List.of(makeTextTreeForResource("doclet.record_hashCode_doc.return")));
+
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(returnTree));
+        dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
+    }
+
+    /**
+     * Generates the description for the standard {@code toString} method for a record.
+     * @param ee the {@code toString} method
+     */
+    public void setRecordToStringTree(ExecutableElement ee) {
+        List<DocTree> fullBody = List.of(
+                treeFactory.newTextTree(resources.getText("doclet.record_toString_doc.fullbody")));
+
+        DocTree returnTree = treeFactory.newReturnTree(List.of(
+                treeFactory.newTextTree(resources.getText("doclet.record_toString_doc.return"))));
+
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(returnTree));
+        dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
+    }
+
+    /**
+     * Generates the description for the accessor method for a state component of a record.
+     * @param ee the accessor method
+     */
+    public void setRecordAccessorTree(ExecutableElement ee) {
+        TypeElement te = utils.getEnclosingTypeElement(ee);
+
+        List<DocTree> fullBody =
+                makeDescriptionWithComponent("doclet.record_accessor_doc.fullbody", te, ee.getSimpleName());
+
+        DocTree returnTree = treeFactory.newReturnTree(
+                    makeDescriptionWithComponent("doclet.record_accessor_doc.return", te, ee.getSimpleName()));
+
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(returnTree));
+        dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
+    }
+
+    /**
+     * Generates the description for the field for a state component of a record.
+     * @param ve the field
+     */
+    public void setRecordFieldTree(VariableElement ve) {
+        TypeElement te = utils.getEnclosingTypeElement(ve);
+
+        List<DocTree> fullBody =
+            makeDescriptionWithComponent("doclet.record_field_doc.fullbody", te, ve.getSimpleName());
+
+        DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of());
+        dcTreesMap.put(ve, new DocCommentDuo(null, docTree));
+    }
+
+    /**
+     * Creates a description that contains a reference to a state component of a record.
+     * The description is looked up as a resource, and should contain {@code {0}} where the
+     * reference to the component is to be inserted. The reference will be a link if the
+     * doc comment for the record has a {@code @param} tag for the component.
+     * @param key the resource key for the description
+     * @param elem the record element
+     * @param component the name of the component
+     * @return the description
+     */
+    private List<DocTree> makeDescriptionWithComponent(String key, TypeElement elem, Name component) {
+        List<DocTree> result = new ArrayList<>();
+        String text = resources.getText(key);
+        int index = text.indexOf("{0}");
+        result.add(treeFactory.newTextTree(text.substring(0, index)));
+        Name A = elementUtils.getName("a");
+        Name CODE = elementUtils.getName("code");
+        Name HREF = elementUtils.getName("href");
+        List<DocTree> code = List.of(
+                treeFactory.newStartElementTree(CODE, List.of(), false),
+                treeFactory.newTextTree(component.toString()),
+                treeFactory.newEndElementTree(CODE));
+        if (hasParamForComponent(elem, component)) {
+            DocTree href = treeFactory.newAttributeTree(HREF,
+                    AttributeTree.ValueKind.DOUBLE,
+                    List.of(treeFactory.newTextTree("#param-" + component)));
+            result.add(treeFactory.newStartElementTree(A, List.of(href), false));
+            result.addAll(code);
+            result.add(treeFactory.newEndElementTree(A));
+        } else {
+            result.addAll(code);
+        }
+        result.add(treeFactory.newTextTree(text.substring(index + 3)));
+        return result;
+    }
+
+    /**
+     * Returns whether or not the doc comment for a record contains an {@code @param}}
+     * for a state component of the record.
+     * @param elem the record element
+     * @param component the name of the component
+     * @return whether or not there is a {@code @param}} for the component
+     */
+    private boolean hasParamForComponent(TypeElement elem, Name component) {
+        DocCommentTree elemComment = utils.getDocCommentTree(elem);
+        if (elemComment == null) {
+            return false;
+        }
+
+        for (DocTree t : elemComment.getBlockTags()) {
+            if (t instanceof ParamTree && ((ParamTree) t).getName().getName() == component) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Creates a description that contains the simple name of a program element
+     * The description is looked up as a resource, and should contain {@code {0}} where the
+     * name is to be inserted. T
+     * @param key the resource key for the description
+     * @param name the name
+     * @return the description
+     */
+    private List<DocTree> makeDescriptionWithName(String key, Name name) {
+        String text = resources.getText(key);
+        int index = text.indexOf("{0}");
+        if (index == -1) {
+            return List.of(treeFactory.newTextTree(text));
+        } else {
+            Name CODE = elementUtils.getName("code");
+            return List.of(
+                    treeFactory.newTextTree(text.substring(0, index)),
+                    treeFactory.newStartElementTree(CODE, List.of(), false),
+                    treeFactory.newTextTree(name.toString()),
+                    treeFactory.newEndElementTree(CODE),
+                    treeFactory.newTextTree(text.substring(index + 3))
+            );
+        }
     }
 
     /*
@@ -215,7 +444,7 @@
     }
 
     public void setDocCommentTree(Element element, List<? extends DocTree> fullBody,
-                                  List<? extends DocTree> blockTags, Utils utils) {
+                                  List<? extends DocTree> blockTags) {
         DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, blockTags);
         dcTreesMap.put(element, new DocCommentDuo(null, docTree));
         // A method having null comment (no comment) that might need to be replaced
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java	Wed Oct 16 17:02:29 2019 -0400
@@ -95,6 +95,15 @@
             Content summaryContentTree);
 
     /**
+     * Adds the table of records to the documentation tree.
+     *
+     * @param records the records to document.
+     * @param summaryContentTree the content tree to which the summaries will be added
+     */
+    public abstract void addRecordSummary(SortedSet<TypeElement> records,
+                                        Content summaryContentTree);
+
+    /**
      * Adds the table of exceptions to the documentation tree.
      *
      * @param exceptions the exceptions to document.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Resources.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Resources.java	Wed Oct 16 17:02:29 2019 -0400
@@ -49,6 +49,7 @@
     public final String exceptionSummary;
     public final String interfaceSummary;
     public final String packageSummary;
+    public final String recordSummary;
 
     protected ResourceBundle commonBundle;
     protected ResourceBundle docletBundle;
@@ -76,6 +77,7 @@
         this.exceptionSummary = getText("doclet.Exception_Summary");
         this.interfaceSummary = getText("doclet.Interface_Summary");
         this.packageSummary = getText("doclet.Package_Summary");
+        this.recordSummary = getText("doclet.Record_Summary");
     }
 
     /**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java	Wed Oct 16 17:02:29 2019 -0400
@@ -25,11 +25,26 @@
 
 package jdk.javadoc.internal.doclets.toolkit.builders;
 
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.Elements;
 
+import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.Tree;
 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
 import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
+import jdk.javadoc.internal.doclets.toolkit.CommentUtils;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.DocFilesHandler;
 import jdk.javadoc.internal.doclets.toolkit.DocletException;
@@ -70,6 +85,11 @@
     private final boolean isEnum;
 
     /**
+     * Keep track of whether or not this typeElement is an record.
+     */
+    private final boolean isRecord;
+
+    /**
      * The content tree for the class documentation.
      */
     private Content contentTree;
@@ -91,13 +111,21 @@
         if (utils.isInterface(typeElement)) {
             isInterface = true;
             isEnum = false;
+            isRecord = false;
         } else if (utils.isEnum(typeElement)) {
             isInterface = false;
             isEnum = true;
-            utils.setEnumDocumentation(typeElement);
+            isRecord = false;
+            setEnumDocumentation(typeElement);
+        } else if (utils.isRecord(typeElement)) {
+            isInterface = false;
+            isEnum = false;
+            isRecord = true;
+            setRecordDocumentation(typeElement);
         } else {
             isInterface = false;
             isEnum = false;
+            isRecord = false;
         }
     }
 
@@ -133,6 +161,8 @@
             key = "doclet.Interface";
         } else if (isEnum) {
             key = "doclet.Enum";
+        } else if (isRecord) {
+            key = "doclet.Record";
         } else {
             key = "doclet.Class";
         }
@@ -168,7 +198,7 @@
      */
     protected void buildClassInfo(Content classContentTree) throws DocletException {
         Content classInfoTree = new ContentBuilder();
-        buildTypeParamInfo(classInfoTree);
+        buildParamInfo(classInfoTree);
         buildSuperInterfacesInfo(classInfoTree);
         buildImplementedInterfacesInfo(classInfoTree);
         buildSubClassInfo(classInfoTree);
@@ -185,12 +215,12 @@
     }
 
     /**
-     * Build the type parameters of this class.
+     * Build the type parameters and state components of this class.
      *
      * @param classInfoTree the content tree to which the documentation will be added
      */
-    protected void buildTypeParamInfo(Content classInfoTree) {
-        writer.addTypeParamInfo(classInfoTree);
+    protected void buildParamInfo(Content classInfoTree) {
+        writer.addParamInfo(classInfoTree);
     }
 
     /**
@@ -392,4 +422,95 @@
     protected void buildMethodDetails(Content memberDetailsTree) throws DocletException {
         builderFactory.getMethodBuilder(writer).build(memberDetailsTree);
     }
+
+    /**
+     * The documentation for values() and valueOf() in Enums are set by the
+     * doclet only iff the user or overridden methods are missing.
+     * @param elem the enum element
+     */
+    private void setEnumDocumentation(TypeElement elem) {
+        CommentUtils cmtUtils = configuration.cmtUtils;
+        for (ExecutableElement ee : utils.getMethods(elem)) {
+            if (!utils.getFullBody(ee).isEmpty()) // ignore if already set
+                continue;
+            Name name = ee.getSimpleName();
+            if (name.contentEquals("values") && ee.getParameters().isEmpty()) {
+                utils.removeCommentHelper(ee); // purge previous entry
+                cmtUtils.setEnumValuesTree(ee);
+            } else if (name.contentEquals("valueOf") && ee.getParameters().size() == 1) {
+                // TODO: check parameter type
+                utils.removeCommentHelper(ee); // purge previous entry
+                cmtUtils.setEnumValueOfTree(ee);
+            }
+        }
+    }
+
+    /**
+     * Sets the documentation as needed for the mandated parts of a record type.
+     * This includes the canonical constructor, methods like {@code equals},
+     * {@code hashCode}, {@code toString}, the accessor methods, and the underlying
+     * field.
+     * @param elem the record element
+     */
+
+    private void setRecordDocumentation(TypeElement elem) {
+        CommentUtils cmtUtils = configuration.cmtUtils;
+        Set<Name> componentNames = elem.getRecordComponents().stream()
+                .map(Element::getSimpleName)
+                .collect(Collectors.toSet());
+
+        for (ExecutableElement ee : utils.getConstructors(elem)) {
+            if (utils.isCanonicalRecordConstructor(ee)) {
+                if (utils.getFullBody(ee).isEmpty()) {
+                    utils.removeCommentHelper(ee); // purge previous entry
+                    cmtUtils.setRecordConstructorTree(ee);
+                }
+                // only one canonical constructor; no longer need to keep looking
+                break;
+            }
+        }
+
+        for (VariableElement ve : utils.getFields(elem)) {
+            // The fields for the record component cannot be declared by the
+            // user and so cannot have any pre-existing comment.
+            Name name = ve.getSimpleName();
+            if (componentNames.contains(name)) {
+                utils.removeCommentHelper(ve); // purge previous entry
+                cmtUtils.setRecordFieldTree(ve);
+            }
+        }
+
+        TypeMirror objectType = utils.elementUtils.getTypeElement("java.lang.Object").asType();
+
+        for (ExecutableElement ee : utils.getMethods(elem)) {
+            if (!utils.getFullBody(ee).isEmpty()) {
+                continue;
+            }
+
+            Name name = ee.getSimpleName();
+            List<? extends VariableElement> params = ee.getParameters();
+            if (name.contentEquals("equals")) {
+                if (params.size() == 1 && utils.typeUtils.isSameType(params.get(0).asType(), objectType)) {
+                    utils.removeCommentHelper(ee); // purge previous entry
+                    cmtUtils.setRecordEqualsTree(ee);
+                }
+            } else if (name.contentEquals("hashCode")) {
+                if (params.isEmpty()) {
+                    utils.removeCommentHelper(ee); // purge previous entry
+                    cmtUtils.setRecordHashCodeTree(ee);
+                }
+            } else if (name.contentEquals("toString")) {
+                if (params.isEmpty()) {
+                    utils.removeCommentHelper(ee); // purge previous entry
+                    cmtUtils.setRecordToStringTree(ee);
+                }
+            } else if (componentNames.contains(name)) {
+                if (params.isEmpty()) {
+                    utils.removeCommentHelper(ee); // purge previous entry
+                    cmtUtils.setRecordAccessorTree(ee);
+                }
+            }
+        }
+
+    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java	Wed Oct 16 17:02:29 2019 -0400
@@ -411,7 +411,7 @@
                 blockTags.add(cmtutils.makeSeeTree(sb.toString(), setter));
             }
         }
-        cmtutils.setDocCommentTree(member, fullBody, blockTags, utils);
+        cmtutils.setDocCommentTree(member, fullBody, blockTags);
     }
 
     /**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java	Wed Oct 16 17:02:29 2019 -0400
@@ -159,6 +159,7 @@
         buildInterfaceSummary(summaryContentTree);
         buildClassSummary(summaryContentTree);
         buildEnumSummary(summaryContentTree);
+        buildRecordSummary(summaryContentTree);
         buildExceptionSummary(summaryContentTree);
         buildErrorSummary(summaryContentTree);
         buildAnnotationTypeSummary(summaryContentTree);
@@ -215,6 +216,22 @@
     }
 
     /**
+     * Build the summary for the records in this package.
+     *
+     * @param summaryContentTree the summary tree to which the record summary will
+     *                           be added
+     */
+    protected void buildRecordSummary(Content summaryContentTree) {
+        SortedSet<TypeElement> rlist = utils.isSpecified(packageElement)
+                ? utils.getTypeElementsAsSortedSet(utils.getRecords(packageElement))
+                : configuration.typeElementCatalog.records(packageElement);
+        SortedSet<TypeElement> records = utils.filterOutPrivateClasses(rlist, configuration.javafx);
+        if (!records.isEmpty()) {
+            packageWriter.addRecordSummary(records, summaryContentTree);
+        }
+    }
+
+    /**
      * Build the summary for the exceptions in this package.
      *
      * @param summaryContentTree the summary tree to which the exception summary will
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java	Wed Oct 16 17:02:29 2019 -0400
@@ -600,10 +600,10 @@
     }
 
     /**
-     * Return true if any of the given typeElements have a @serialinclude tag.
+     * Return true if any of the given typeElements have a {@code @serial include} tag.
      *
      * @param classes the typeElements to check.
-     * @return true if any of the given typeElements have a @serialinclude tag.
+     * @return true if any of the given typeElements have a {@code @serial include} tag.
      */
     private boolean serialClassFoundToDocument(SortedSet<TypeElement> classes) {
         for (TypeElement aClass : classes) {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Wed Oct 16 17:02:29 2019 -0400
@@ -93,14 +93,19 @@
 doclet.Default=Default:
 doclet.Parameters=Parameters:
 doclet.TypeParameters=Type Parameters:
+doclet.RecordComponents=Record Components:
 doclet.Parameters_warn=@param argument "{0}" is not a parameter name.
 doclet.Parameters_dup_warn=Parameter "{0}" is documented more than once.
-doclet.Type_Parameters_warn=@param argument "{0}" is not a type parameter name.
-doclet.Type_Parameters_dup_warn=Type parameter "{0}" is documented more than once.
+doclet.TypeParameters_warn=@param argument "{0}" is not the name of a type parameter.
+doclet.TypeParameters_dup_warn=Type parameter "{0}" is documented more than once.
+doclet.RecordComponents_warn=@param argument "{0}" is not the name of a record component.
+doclet.RecordComponents_dup_warn=Record component "{0}" is documented more than once.
 doclet.Returns=Returns:
 doclet.Return_tag_on_void_method=@return tag cannot be used in method with void return type.
 doclet.See_Also=See Also:
 doclet.See=See:
+doclet.getter=Getter:
+doclet.setter=Setter:
 doclet.SerialData=Serial Data:
 doclet.Services=Services
 doclet.Since=Since:
@@ -137,6 +142,7 @@
 doclet.Enum_Constant_Summary=Enum Constant Summary
 doclet.Constructor_Summary=Constructor Summary
 doclet.Method_Summary=Method Summary
+doclet.Record_Summary=Record Summary
 doclet.Interfaces=Interfaces
 doclet.Enums=Enums
 doclet.AnnotationTypes=Annotation Types
@@ -160,6 +166,7 @@
 doclet.interfaces=interfaces
 doclet.class=class
 doclet.classes=classes
+doclet.Record=Record
 doclet.Error=Error
 doclet.error=error
 doclet.errors=errors
@@ -268,3 +275,58 @@
 
 doclet.enum_valueof_doc.throws_npe=\
  if the argument is null
+
+
+#Documentation for records
+doclet.record_constructor_doc.fullbody=\
+ Creates an instance of a {0} record.
+
+doclet.record_constructor_doc.param_name=\
+ the value for the {0} record component
+
+doclet.record_equals_doc.fullbody.head=\
+ Indicates whether some other object is "equal to" this one. \
+ The objects are equal if the other object is of the same class \
+ and if all the record components are equal.
+
+doclet.record_equals_doc.fullbody.tail.both=\
+ Reference components are compared with \
+ {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}; \
+ primitive components are compared with '=='.
+
+doclet.record_equals_doc.fullbody.tail.primitive=\
+ All components in this record are compared with '=='.
+
+doclet.record_equals_doc.fullbody.tail.reference=\
+ All components in this record are compared with \
+ {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}.
+
+doclet.record_equals_doc.param_name=\
+ the object with which to compare
+
+doclet.record_equals_doc.return=\
+ <code>true</code> if this object is the same as the {0} argument; <code>false</code> otherwise.
+
+doclet.record_hashCode_doc.fullbody=\
+ Returns a hash code value for this object. \
+ The value is derived from the hash code of each of the record components.
+
+doclet.record_hashCode_doc.return=\
+ a hash code value for this object
+
+doclet.record_toString_doc.fullbody=\
+ Returns a string representation of this record. \
+ The representation contains the name of the type, followed by \
+ the name and value of each of the record components.
+
+doclet.record_toString_doc.return=\
+ a string representation of this object
+
+doclet.record_accessor_doc.fullbody=\
+ Returns the value of the {0} record component.
+
+doclet.record_accessor_doc.return=\
+ the value of the {0} record component
+
+doclet.record_field_doc.fullbody=\
+ The field for the {0} record component.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/AccessorTaglet.java	Wed Oct 16 17:02:29 2019 -0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package jdk.javadoc.internal.doclets.toolkit.taglets;
+
+import java.util.EnumSet;
+
+import com.sun.source.doctree.DocTree;
+import jdk.javadoc.internal.doclets.toolkit.Content;
+import jdk.javadoc.internal.doclets.toolkit.util.Utils;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.VariableElement;
+import java.util.List;
+
+/**
+ * A taglet that represents the @param tag.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ *
+ * @author Jamie Ho
+ */
+public class AccessorTaglet extends BaseTaglet {
+
+    DocTree.Kind kind;
+
+    /**
+     * Construct a ParamTaglet.
+     */
+    public AccessorTaglet(DocTree.Kind kind) {
+        super(kind.tagName, false, EnumSet.of(Site.FIELD));
+        this.kind = kind;
+    }
+
+   /**
+     * Given an array of <code>ParamTag</code>s,return its string representation.
+     * @param holder the member that holds the param tags.
+     * @param writer the TagletWriter that will write this tag.
+     * @return the TagletOutput representation of these <code>ParamTag</code>s.
+     */
+    public Content getTagletOutput(Element holder, TagletWriter writer) {
+        Utils utils = writer.configuration().utils;
+        return writer.accessorTagOutput(holder, utils.getBlockTags(holder, kind));
+    }
+}
+
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java	Wed Oct 16 17:00:39 2019 -0400
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java	Wed Oct 16 17:02:29 2019 -0400
@@ -29,6 +29,7 @@
 
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Name;
 import javax.lang.model.element.TypeElement;
 
 import com.sun.source.doctree.DocTree;
@@ -53,6 +54,14 @@
  * @author Jamie Ho
  */
 public class ParamTaglet extends BaseTaglet implements InheritableTaglet {
+    private enum ParamKind {
+        /** Parameter of an executable element. */
+        PARAMETER,
+        /** State components of a record. */
+        RECORD_COMPONENT,
+        /** Type parameters of an executable element or type element. */
+        TYPE_PARAMETER
+    }
 
     /**
      * Construct a ParamTaglet.
@@ -101,7 +110,7 @@
                 String pname = input.isTypeVariableParamTag
                         ? utils.getTypeName(e.asType(), false)
                         : utils.getSimpleName(e);
-                if (pname.equals(target)) {
+                if (pname.contentEquals(target)) {
                     input.tagId = String.valueOf(i);
                     break;
                 }
@@ -132,15 +141,18 @@
         Utils utils = writer.configuration().utils;
         if (utils.isExecutableElement(holder)) {
             ExecutableElement member = (ExecutableElement) holder;
-            Content output = getTagletOutput(false, member, writer,
+            Content output = getTagletOutput(ParamKind.TYPE_PARAMETER, member, writer,
                 member.getTypeParameters(), utils.getTypeParamTrees(member));
-            output.add(getTagletOutput(true, member, writer,
+            output.add(getTagletOutput(ParamKind.PARAMETER, member, writer,
                 member.getParameters(), utils.getParamTrees(member)));
             return output;
         } else {
             TypeElement typeElement = (TypeElement) holder;
-            return getTagletOutput(false, typeElement, writer,
+            Content output = getTagletOutput(ParamKind.TYPE_PARAMETER, typeElement, writer,
                 typeElement.getTypeParameters(), utils.getTypeParamTrees(typeElement));
+            output.add(getTagletOutput(ParamKind.RECORD_COMPONENT, typeElement, writer,
+                    typeElement.getRecordComponents(), utils.getParamTrees(typeElement)));
+            return output;
         }
     }
 
@@ -150,25 +162,25 @@
      *
      * @param holder            the element that holds the param tags.
      * @param writer            the TagletWriter that will write this tag.
-     * @param formalParameters  The array of parmeters (from type or executable
+     * @param formalParameters  The array of parameters (from type or executable
      *                          member) to check.
      *
      * @return the content representation of these {@code @param DocTree}s.
      */
-    private Content getTagletOutput(boolean isParameters, Element holder,
+    private Content getTagletOutput(ParamKind kind, Element holder,
             TagletWriter writer, List<? extends Element> formalParameters, List<? extends DocTree> paramTags) {
         Content result = writer.getOutputInstance();
         Set<String> alreadyDocumented = new HashSet<>();
         if (!paramTags.isEmpty()) {
             result.add(
-                processParamTags(holder, isParameters, paramTags,
+                processParamTags(holder, kind, paramTags,
                 getRankMap(writer.configuration().utils, formalParameters), writer, alreadyDocumented)
             );
         }
         if (alreadyDocumented.size() != formalParameters.size()) {
             //Some parameters are missing corresponding @param tags.
             //Try to inherit them.
-            result.add(getInheritedTagletOutput(isParameters, holder,
+            result.add(getInheritedTagletOutput(kind, holder,
                 writer, formalParameters, alreadyDocumented));
         }
         return result;
@@ -178,7 +190,7 @@
      * Loop through each individual parameter, despite not having a
      * corresponding param tag, try to inherit it.
      */
-    private Content getInheritedTagletOutput(boolean isParameters, Element holder,
+    private Content getInheritedTagletOutput(ParamKind kind, Element holder,
             TagletWriter writer, List<? extends Element> formalParameters,
             Set<String> alreadyDocumented) {
         Utils utils = writer.configuration().utils;
@@ -191,16 +203,16 @@
                 // This parameter does not have any @param documentation.
                 // Try to inherit it.
                 Input input = new DocFinder.Input(writer.configuration().utils, holder, this,
-                        Integer.toString(i), !isParameters);
+                        Integer.toString(i), kind == ParamKind.TYPE_PARAMETER);
                 DocFinder.Output inheritedDoc = DocFinder.search(writer.configuration(), input);
                 if (inheritedDoc.inlineTags != null && !inheritedDoc.inlineTags.isEmpty()) {
                     Element e = formalParameters.get(i);
-                    String lname = isParameters
+                    String lname = kind != ParamKind.TYPE_PARAMETER
                             ? utils.getSimpleName(e)
                             : utils.getTypeName(e.asType(), false);
                     CommentHelper ch = utils.getCommentHelper(holder);
                     ch.setOverrideElement(inheritedDoc.holder);
-                    Content content = processParamTag(holder, isParameters, writer,
+                    Content content = processParamTag(holder, kind, writer,
                             inheritedDoc.holderTag,
                             lname,
                             alreadyDocumented.isEmpty());
@@ -230,7 +242,7 @@
                 when parameter documentation is inherited.
      * @return the Content representation of this {@code @param DocTree}.
      */
-    private Content processParamTags(Element e, boolean isParams,
+    private Content processParamTags(Element e, ParamKind kind,
             List<? extends DocTree> paramTags, Map<String, String> rankMap, TagletWriter writer,
             Set<String> alreadyDocumented) {
         Messages messages = writer.configuration().getMessages();
@@ -238,26 +250,33 @@
         if (!paramTags.isEmpty()) {
             CommentHelper ch = writer.configuration().utils.getCommentHelper(e);
             for (DocTree dt : paramTags) {
-                String paramName = isParams
-                        ? ch.getParameterName(dt)
-                        : "<" + ch.getParameterName(dt) + ">";
-                if (!rankMap.containsKey(ch.getParameterName(dt))) {
-                    messages.warning(ch.getDocTreePath(dt),
-                            isParams
-                                    ? "doclet.Parameters_warn"
-                                    : "doclet.Type_Parameters_warn",
-                            paramName);
+                String name = ch.getParameterName(dt);
+                String paramName = kind != ParamKind.TYPE_PARAMETER
+                        ? name.toString()
+                        : "<" + name + ">";
+                if (!rankMap.containsKey(name)) {
+                    String key;
+                    switch (kind) {
+                        case PARAMETER:       key = "doclet.Parameters_warn" ; break;
+                        case TYPE_PARAMETER:  key = "doclet.TypeParameters_warn" ; break;
+                        case RECORD_COMPONENT: key = "doclet.RecordComponents_warn" ; break;
+                        default: throw new IllegalArgumentException(kind.toString());
+                }
+                    messages.warning(ch.getDocTreePath(dt), key, paramName);
                 }
-                String rank = rankMap.get(ch.getParameterName(dt));
+                String rank = rankMap.get(name);