8257596: Clarify trusted final fields for record classes

Reviewed-by: hseigel, chegar, psandoz
This commit is contained in:
Mandy Chung 2020-12-11 22:44:48 +00:00
parent b1afed7501
commit 2001da3dd4
4 changed files with 44 additions and 29 deletions

View File

@ -739,6 +739,12 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
} }
} }
bool InstanceKlass::is_record() const {
return _record_components != NULL &&
is_final() &&
java_super() == SystemDictionary::Record_klass();
}
bool InstanceKlass::is_sealed() const { bool InstanceKlass::is_sealed() const {
return _permitted_subclasses != NULL && return _permitted_subclasses != NULL &&
_permitted_subclasses != Universe::the_empty_short_array(); _permitted_subclasses != Universe::the_empty_short_array();

View File

@ -473,7 +473,7 @@ class InstanceKlass: public Klass {
void set_record_components(Array<RecordComponent*>* record_components) { void set_record_components(Array<RecordComponent*>* record_components) {
_record_components = record_components; _record_components = record_components;
} }
bool is_record() const { return _record_components != NULL; } bool is_record() const;
// permitted subclasses // permitted subclasses
Array<u2>* permitted_subclasses() const { return _permitted_subclasses; } Array<u2>* permitted_subclasses() const { return _permitted_subclasses; }

View File

@ -1851,6 +1851,9 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
} }
JVM_END JVM_END
// A class is a record if and only if it is final and a direct subclass of
// java.lang.Record and has a Record attribute; otherwise, it is not a record.
JVM_ENTRY(jboolean, JVM_IsRecord(JNIEnv *env, jclass cls)) JVM_ENTRY(jboolean, JVM_IsRecord(JNIEnv *env, jclass cls))
{ {
JVMWrapper("JVM_IsRecord"); JVMWrapper("JVM_IsRecord");
@ -1864,6 +1867,11 @@ JVM_ENTRY(jboolean, JVM_IsRecord(JNIEnv *env, jclass cls))
} }
JVM_END JVM_END
// Returns an array containing the components of the Record attribute,
// or NULL if the attribute is not present.
//
// Note that this function returns the components of the Record attribute
// even if the class is not a record.
JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass)) JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass))
{ {
JVMWrapper("JVM_GetRecordComponents"); JVMWrapper("JVM_GetRecordComponents");
@ -1871,31 +1879,26 @@ JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass))
assert(c->is_instance_klass(), "must be"); assert(c->is_instance_klass(), "must be");
InstanceKlass* ik = InstanceKlass::cast(c); InstanceKlass* ik = InstanceKlass::cast(c);
if (ik->is_record()) { Array<RecordComponent*>* components = ik->record_components();
Array<RecordComponent*>* components = ik->record_components(); if (components != NULL) {
assert(components != NULL, "components should not be NULL"); JvmtiVMObjectAllocEventCollector oam;
{ constantPoolHandle cp(THREAD, ik->constants());
JvmtiVMObjectAllocEventCollector oam; int length = components->length();
constantPoolHandle cp(THREAD, ik->constants()); assert(length >= 0, "unexpected record_components length");
int length = components->length(); objArrayOop record_components =
assert(length >= 0, "unexpected record_components length"); oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), length, CHECK_NULL);
objArrayOop record_components = objArrayHandle components_h (THREAD, record_components);
oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), length, CHECK_NULL);
objArrayHandle components_h (THREAD, record_components);
for (int x = 0; x < length; x++) { for (int x = 0; x < length; x++) {
RecordComponent* component = components->at(x); RecordComponent* component = components->at(x);
assert(component != NULL, "unexpected NULL record component"); assert(component != NULL, "unexpected NULL record component");
oop component_oop = java_lang_reflect_RecordComponent::create(ik, component, CHECK_NULL); oop component_oop = java_lang_reflect_RecordComponent::create(ik, component, CHECK_NULL);
components_h->obj_at_put(x, component_oop); components_h->obj_at_put(x, component_oop);
}
return (jobjectArray)JNIHandles::make_local(THREAD, components_h());
} }
return (jobjectArray)JNIHandles::make_local(THREAD, components_h());
} }
// Return empty array if ofClass is not a record. return NULL;
objArrayOop result = oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), 0, CHECK_NULL);
return (jobjectArray)JNIHandles::make_local(THREAD, result);
} }
JVM_END JVM_END

View File

@ -2383,11 +2383,7 @@ public final class Class<T> implements java.io.Serializable,
if (!isRecord()) { if (!isRecord()) {
return null; return null;
} }
RecordComponent[] recordComponents = getRecordComponents0(); return getRecordComponents0();
if (recordComponents == null) {
return new RecordComponent[0];
}
return recordComponents;
} }
/** /**
@ -3577,9 +3573,17 @@ public final class Class<T> implements java.io.Serializable,
private native Field[] getDeclaredFields0(boolean publicOnly); private native Field[] getDeclaredFields0(boolean publicOnly);
private native Method[] getDeclaredMethods0(boolean publicOnly); private native Method[] getDeclaredMethods0(boolean publicOnly);
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly); private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
private native Class<?>[] getDeclaredClasses0(); private native Class<?>[] getDeclaredClasses0();
/*
* Returns an array containing the components of the Record attribute,
* or null if the attribute is not present.
*
* Note that this method returns non-null array on a class with
* the Record attribute even if this class is not a record.
*/
private native RecordComponent[] getRecordComponents0(); private native RecordComponent[] getRecordComponents0();
private native boolean isRecord0(); private native boolean isRecord0();
/** /**
* Helper method to get the method name from arguments. * Helper method to get the method name from arguments.
@ -3706,6 +3710,8 @@ public final class Class<T> implements java.io.Serializable,
* @since 16 * @since 16
*/ */
public boolean isRecord() { public boolean isRecord() {
// this superclass and final modifier check is not strictly necessary
// they are intrinsified and serve as a fast-path check
return getSuperclass() == java.lang.Record.class && return getSuperclass() == java.lang.Record.class &&
(this.getModifiers() & Modifier.FINAL) != 0 && (this.getModifiers() & Modifier.FINAL) != 0 &&
isRecord0(); isRecord0();