Skip to content
Permalink
Browse files

8225054: Compiler implementation for records

8225052: javax.lang.model support for records
8225053: Preview APIs support for records
8225055: Javadoc for records
8226314: com.sun.source support for records
8227113: Specification for java.lang.Record
8233526: JVM support for records

Implement records in the compiler and the JVM, including serialization, reflection and APIs support

Co-authored-by: Brian Goetz <brian.goetz@oracle.com>
Co-authored-by: Maurizio Cimadamore <maurizio.cimadamore@oracle.com>
Co-authored-by: Harold Seigel <harold.seigel@oracle.com>
Co-authored-by: Joe Darcy <joe.darcy@oracle.com>
Co-authored-by: Jonathan Gibbons <jonathan.gibbons@oracle.com>
Co-authored-by: Chris Hegarty <chris.hegarty@oracle.com>
Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com>
Reviewed-by: mcimadamore, briangoetz, alanb, darcy, chegar, jrose, jlahoda, coleenp, dholmes, lfoltan, mchung, sadayapalam, hannesw, sspitsyn
  • Loading branch information
8 people committed Dec 4, 2019
1 parent 0a375cf commit 827e5e32264666639d36990edd5e7d0b7e7c78a9
Showing 351 changed files with 25,011 additions and 6,448 deletions.
@@ -1,5 +1,5 @@
#
# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2014, 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
@@ -80,6 +80,7 @@ define SetupInterimModule
ADD_JAVAC_FLAGS := --module-path $(BUILDTOOLS_OUTPUTDIR)/interim_langtools_modules \
$$(INTERIM_LANGTOOLS_ADD_EXPORTS) \
--patch-module java.base=$(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim \
--add-exports java.base/jdk.internal=java.compiler.interim \
--add-exports java.base/jdk.internal=jdk.compiler.interim \
-Xlint:-module, \
))
@@ -122,6 +122,7 @@ JVM_GetNestMembers
JVM_GetPrimitiveArrayElement
JVM_GetProperties
JVM_GetProtectionDomain
JVM_GetRecordComponents
JVM_GetSimpleBinaryName
JVM_GetStackAccessControlContext
JVM_GetSystemPackage
@@ -143,6 +144,7 @@ JVM_IsArrayClass
JVM_IsConstructorIx
JVM_IsInterface
JVM_IsPrimitiveClass
JVM_IsRecord
JVM_IsSameClassPackage
JVM_IsSupportedJNIVersion
JVM_IsThreadAlive

Large diffs are not rendered by default.

@@ -42,6 +42,7 @@ class FieldInfo;
template <typename T>
class GrowableArray;
class InstanceKlass;
class RecordComponent;
class Symbol;
class TempNewSymbol;

@@ -98,6 +99,7 @@ class ClassFileParser {
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 @@ class ClassFileParser {
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,
@@ -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"
@@ -3148,6 +3149,64 @@ void java_lang_reflect_Field::set_annotations(oop field, oop value) {
field->obj_field_put(annotations_offset, value);
}

oop java_lang_reflect_RecordComponent::create(InstanceKlass* holder, RecordComponent* component, TRAPS) {
// Allocate java.lang.reflect.RecordComponent instance
HandleMark hm(THREAD);
InstanceKlass* ik = SystemDictionary::RecordComponent_klass();
assert(ik != NULL, "must be loaded");
ik->initialize(CHECK_NULL);

Handle element = ik->allocate_instance_handle(CHECK_NULL);

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_NULL);
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_NULL);
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, "%c%c%s", JVM_SIGNATURE_FUNC, JVM_SIGNATURE_ENDFUNC, type->as_C_string());
TempNewSymbol full_sig = SymbolTable::new_symbol(sig);
accessor_method = holder->find_instance_method(name, full_sig);
}

if (accessor_method != NULL) {
methodHandle method(THREAD, accessor_method);
oop m = Reflection::new_method(method, false, CHECK_NULL);
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); // sig_index is a utf8
oop component_sig = StringTable::intern(sig, CHECK_NULL);
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_NULL);
java_lang_reflect_RecordComponent::set_annotations(element(), annotation_oop);

typeArrayOop type_annotation_oop = Annotations::make_java_array(component->type_annotations(), CHECK_NULL);
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)

@@ -4311,6 +4370,13 @@ int java_lang_Short_ShortCache::_static_cache_offset;
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;



@@ -4662,6 +4728,55 @@ static int member_offset(int hardcoded_offset) {
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.
@@ -30,6 +30,8 @@
#include "oops/oop.hpp"
#include "runtime/os.hpp"

class RecordComponent;

// Interface for manipulating the basic Java classes.
//
// All dependencies on layout of actual Java classes should be kept here.
@@ -73,6 +75,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) \
@@ -1483,6 +1486,39 @@ class java_lang_LiveStackFrameInfo: AllStatic {
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 {
@@ -119,6 +119,7 @@ class GCTimer;
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 ) \
@@ -217,6 +218,9 @@ class GCTimer;
/* force inline of iterators */ \
do_klass(Iterator_klass, java_util_Iterator ) \
\
/* support for records */ \
do_klass(RecordComponent_klass, java_lang_reflect_RecordComponent ) \
\
/*end*/

class SystemDictionary : AllStatic {
@@ -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") \
@@ -161,6 +163,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") \
@@ -562,6 +565,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) \
\
@@ -518,6 +518,7 @@ JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, jboolean publicOnly);
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
@@ -538,6 +539,14 @@ JVM_GetNestHost(JNIEnv *env, jclass current);
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
@@ -137,6 +137,7 @@
LOG_TAG(parser) \
LOG_TAG(ptrqueue) \
LOG_TAG(purge) \
LOG_TAG(record) \
LOG_TAG(resolve) \
LOG_TAG(safepoint) \
LOG_TAG(sampling) \
@@ -300,7 +300,8 @@ class MetaspaceObj {
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;
@@ -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, \
@@ -823,6 +823,7 @@ intptr_t* MetaspaceShared::fix_cpp_vtable_for_dynamic_archive(MetaspaceObj::Type
case MetaspaceObj::ConstantPoolCacheType:
case MetaspaceObj::AnnotationsType:
case MetaspaceObj::MethodCountersType:
case MetaspaceObj::RecordComponentType:
// These have no vtables.
break;
case MetaspaceObj::ClassType:

0 comments on commit 827e5e3

Please sign in to comment.
You can’t perform that action at this time.