8336267: Method and Constructor signature parsing can be shared on the root object

Reviewed-by: mchung
This commit is contained in:
Chen Liang 2024-11-04 13:24:29 +00:00
parent 1f7d524fd3
commit 8d6cfba37f
3 changed files with 57 additions and 72 deletions
src/java.base/share/classes/java/lang/reflect

@ -72,8 +72,6 @@ public final class Constructor<T> extends Executable {
private final int modifiers;
// Generics and annotations support
private final transient String signature;
// generic info repository; lazily initialized
private transient volatile ConstructorRepository genericInfo;
private final byte[] annotations;
private final byte[] parameterAnnotations;
@ -88,26 +86,27 @@ public final class Constructor<T> extends Executable {
@Override
ConstructorRepository getGenericInfo() {
var genericInfo = this.genericInfo;
// lazily initialize repository if necessary
if (genericInfo == null) {
// create and cache generic info repository
genericInfo =
ConstructorRepository.make(getSignature(),
getFactory());
var root = this.root;
if (root != null) {
genericInfo = root.getGenericInfo();
} else {
genericInfo = ConstructorRepository.make(getSignature(), getFactory());
}
this.genericInfo = genericInfo;
}
return genericInfo; //return cached repository
return genericInfo;
}
@Stable
private ConstructorAccessor constructorAccessor;
// For sharing of ConstructorAccessors. This branching structure
// is currently only two levels deep (i.e., one root Constructor
// and potentially many Constructor objects pointing to it.)
//
// If this branching structure would ever contain cycles, deadlocks can
// occur in annotation code.
private Constructor<T> root;
/**
* Constructors are mutable due to {@link AccessibleObject#setAccessible(boolean)}.
* Thus, we return a new copy of a root each time a constructor is returned.
* Some lazily initialized immutable states can be stored on root and shared to the copies.
*/
private Constructor<T> root;
private transient volatile ConstructorRepository genericInfo;
private @Stable ConstructorAccessor constructorAccessor;
// End shared states
@Override
Constructor<T> getRoot() {
@ -143,13 +142,6 @@ public final class Constructor<T> extends Executable {
* "root" field points to this Constructor.
*/
Constructor<T> copy() {
// This routine enables sharing of ConstructorAccessor objects
// among Constructor objects which refer to the same underlying
// method in the VM. (All of this contortion is only necessary
// because of the "accessibility" bit in AccessibleObject,
// which implicitly requires that new java.lang.reflect
// objects be fabricated for each reflective call on Class
// objects.)
if (this.root != null)
throw new IllegalArgumentException("Can not copy a non-root Constructor");
@ -162,6 +154,7 @@ public final class Constructor<T> extends Executable {
res.root = this;
// Might as well eagerly propagate this if already present
res.constructorAccessor = constructorAccessor;
res.genericInfo = genericInfo;
return res;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2024, 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
@ -76,22 +76,18 @@ class Field extends AccessibleObject implements Member {
private final boolean trustedFinal;
// Generics and annotations support
private final transient String signature;
// generic info repository; lazily initialized
private transient volatile FieldRepository genericInfo;
private final byte[] annotations;
// Cached field accessor created without override
@Stable
private FieldAccessor fieldAccessor;
// Cached field accessor created with override
@Stable
private FieldAccessor overrideFieldAccessor;
// For sharing of FieldAccessors. This branching structure is
// currently only two levels deep (i.e., one root Field and
// potentially many Field objects pointing to it.)
//
// If this branching structure would ever contain cycles, deadlocks can
// occur in annotation code.
private Field root;
/**
* Fields are mutable due to {@link AccessibleObject#setAccessible(boolean)}.
* Thus, we return a new copy of a root each time a field is returned.
* Some lazily initialized immutable states can be stored on root and shared to the copies.
*/
private Field root;
private transient volatile FieldRepository genericInfo;
private @Stable FieldAccessor fieldAccessor; // access control enabled
private @Stable FieldAccessor overrideFieldAccessor; // access control suppressed
// End shared states
// Generics infrastructure
@ -107,17 +103,18 @@ class Field extends AccessibleObject implements Member {
// Accessor for generic info repository
private FieldRepository getGenericInfo() {
var genericInfo = this.genericInfo;
// lazily initialize repository if necessary
if (genericInfo == null) {
// create and cache generic info repository
genericInfo = FieldRepository.make(getGenericSignature(),
getFactory());
var root = this.root;
if (root != null) {
genericInfo = root.getGenericInfo();
} else {
genericInfo = FieldRepository.make(getGenericSignature(), getFactory());
}
this.genericInfo = genericInfo;
}
return genericInfo; //return cached repository
return genericInfo;
}
/**
* Package-private constructor
*/
@ -162,6 +159,7 @@ class Field extends AccessibleObject implements Member {
// Might as well eagerly propagate this if already present
res.fieldAccessor = fieldAccessor;
res.overrideFieldAccessor = overrideFieldAccessor;
res.genericInfo = genericInfo;
return res;
}

@ -81,22 +81,20 @@ public final class Method extends Executable {
private final int modifiers;
// Generics and annotations support
private final transient String signature;
// generic info repository; lazily initialized
private transient volatile MethodRepository genericInfo;
private final byte[] annotations;
private final byte[] parameterAnnotations;
private final byte[] annotationDefault;
@Stable
private MethodAccessor methodAccessor;
// For sharing of MethodAccessors. This branching structure is
// currently only two levels deep (i.e., one root Method and
// potentially many Method objects pointing to it.)
//
// If this branching structure would ever contain cycles, deadlocks can
// occur in annotation code.
private Method root;
// Hash code of this object
private int hash;
/**
* Methods are mutable due to {@link AccessibleObject#setAccessible(boolean)}.
* Thus, we return a new copy of a root each time a method is returned.
* Some lazily initialized immutable states can be stored on root and shared to the copies.
*/
private Method root;
private transient volatile MethodRepository genericInfo;
private @Stable MethodAccessor methodAccessor;
// End shared states
private int hash; // not shared right now, eligible if expensive
// Generics infrastructure
private String getGenericSignature() {return signature;}
@ -111,14 +109,16 @@ public final class Method extends Executable {
@Override
MethodRepository getGenericInfo() {
var genericInfo = this.genericInfo;
// lazily initialize repository if necessary
if (genericInfo == null) {
// create and cache generic info repository
genericInfo = MethodRepository.make(getGenericSignature(),
getFactory());
var root = this.root;
if (root != null) {
genericInfo = root.getGenericInfo();
} else {
genericInfo = MethodRepository.make(getGenericSignature(), getFactory());
}
this.genericInfo = genericInfo;
}
return genericInfo; //return cached repository
return genericInfo;
}
/**
@ -154,13 +154,6 @@ public final class Method extends Executable {
* "root" field points to this Method.
*/
Method copy() {
// This routine enables sharing of MethodAccessor objects
// among Method objects which refer to the same underlying
// method in the VM. (All of this contortion is only necessary
// because of the "accessibility" bit in AccessibleObject,
// which implicitly requires that new java.lang.reflect
// objects be fabricated for each reflective call on Class
// objects.)
if (this.root != null)
throw new IllegalArgumentException("Can not copy a non-root Method");
@ -168,8 +161,9 @@ public final class Method extends Executable {
exceptionTypes, modifiers, slot, signature,
annotations, parameterAnnotations, annotationDefault);
res.root = this;
// Might as well eagerly propagate this if already present
// Propagate shared states
res.methodAccessor = methodAccessor;
res.genericInfo = genericInfo;
return res;
}