8274299: Make Method/Constructor/Field accessors @Stable

Reviewed-by: redestad, mchung
This commit is contained in:
Peter Levart 2021-10-05 14:16:20 +00:00
parent 1459180f35
commit 7ad74d82d7
13 changed files with 748 additions and 85 deletions

View file

@ -30,6 +30,7 @@ import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.ConstructorAccessor;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
import sun.reflect.annotation.TypeAnnotation;
import sun.reflect.annotation.TypeAnnotationParser;
import sun.reflect.generics.repository.ConstructorRepository;
@ -62,10 +63,12 @@ import java.util.StringJoiner;
* @since 1.1
*/
public final class Constructor<T> extends Executable {
@Stable
private Class<T> clazz;
private int slot;
private Class<?>[] parameterTypes;
private Class<?>[] exceptionTypes;
@Stable
private int modifiers;
// Generics and annotations support
private transient String signature;
@ -94,7 +97,8 @@ public final class Constructor<T> extends Executable {
return genericInfo; //return cached repository
}
private volatile ConstructorAccessor constructorAccessor;
@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.)
@ -491,7 +495,7 @@ public final class Constructor<T> extends Executable {
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
ConstructorAccessor ca = constructorAccessor; // read @Stable
if (ca == null) {
ca = acquireConstructorAccessor();
}
@ -532,8 +536,8 @@ public final class Constructor<T> extends Executable {
private ConstructorAccessor acquireConstructorAccessor() {
// First check to see if one has been created yet, and take it
// if so.
ConstructorAccessor tmp = null;
if (root != null) tmp = root.getConstructorAccessor();
Constructor<?> root = this.root;
ConstructorAccessor tmp = root == null ? null : root.getConstructorAccessor();
if (tmp != null) {
constructorAccessor = tmp;
} else {
@ -556,6 +560,7 @@ public final class Constructor<T> extends Executable {
void setConstructorAccessor(ConstructorAccessor accessor) {
constructorAccessor = accessor;
// Propagate up
Constructor<?> root = this.root;
if (root != null) {
root.setConstructorAccessor(accessor);
}

View file

@ -30,6 +30,7 @@ import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.FieldAccessor;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
import sun.reflect.generics.repository.FieldRepository;
import sun.reflect.generics.factory.CoreReflectionFactory;
import sun.reflect.generics.factory.GenericsFactory;
@ -65,12 +66,15 @@ import sun.reflect.annotation.TypeAnnotationParser;
public final
class Field extends AccessibleObject implements Member {
@Stable
private Class<?> clazz;
private int slot;
// This is guaranteed to be interned by the VM in the 1.4
// reflection implementation
private String name;
@Stable
private Class<?> type;
@Stable
private int modifiers;
private boolean trustedFinal;
// Generics and annotations support
@ -79,8 +83,10 @@ class Field extends AccessibleObject implements Member {
private transient FieldRepository genericInfo;
private 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
@ -421,8 +427,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
return getFieldAccessor().get(obj);
} else {
return getOverrideFieldAccessor().get(obj);
}
return getFieldAccessor(obj).get(obj);
}
/**
@ -455,8 +463,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
return getFieldAccessor().getBoolean(obj);
} else {
return getOverrideFieldAccessor().getBoolean(obj);
}
return getFieldAccessor(obj).getBoolean(obj);
}
/**
@ -489,8 +499,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
return getFieldAccessor().getByte(obj);
} else {
return getOverrideFieldAccessor().getByte(obj);
}
return getFieldAccessor(obj).getByte(obj);
}
/**
@ -525,8 +537,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
return getFieldAccessor().getChar(obj);
} else {
return getOverrideFieldAccessor().getChar(obj);
}
return getFieldAccessor(obj).getChar(obj);
}
/**
@ -561,8 +575,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
return getFieldAccessor().getShort(obj);
} else {
return getOverrideFieldAccessor().getShort(obj);
}
return getFieldAccessor(obj).getShort(obj);
}
/**
@ -597,8 +613,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
return getFieldAccessor().getInt(obj);
} else {
return getOverrideFieldAccessor().getInt(obj);
}
return getFieldAccessor(obj).getInt(obj);
}
/**
@ -633,8 +651,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
return getFieldAccessor().getLong(obj);
} else {
return getOverrideFieldAccessor().getLong(obj);
}
return getFieldAccessor(obj).getLong(obj);
}
/**
@ -669,8 +689,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
return getFieldAccessor().getFloat(obj);
} else {
return getOverrideFieldAccessor().getFloat(obj);
}
return getFieldAccessor(obj).getFloat(obj);
}
/**
@ -705,8 +727,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
return getFieldAccessor().getDouble(obj);
} else {
return getOverrideFieldAccessor().getDouble(obj);
}
return getFieldAccessor(obj).getDouble(obj);
}
/**
@ -795,8 +819,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
getFieldAccessor().set(obj, value);
} else {
getOverrideFieldAccessor().set(obj, value);
}
getFieldAccessor(obj).set(obj, value);
}
/**
@ -832,8 +858,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
getFieldAccessor().setBoolean(obj, z);
} else {
getOverrideFieldAccessor().setBoolean(obj, z);
}
getFieldAccessor(obj).setBoolean(obj, z);
}
/**
@ -869,8 +897,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
getFieldAccessor().setByte(obj, b);
} else {
getOverrideFieldAccessor().setByte(obj, b);
}
getFieldAccessor(obj).setByte(obj, b);
}
/**
@ -906,8 +936,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
getFieldAccessor().setChar(obj, c);
} else {
getOverrideFieldAccessor().setChar(obj, c);
}
getFieldAccessor(obj).setChar(obj, c);
}
/**
@ -943,8 +975,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
getFieldAccessor().setShort(obj, s);
} else {
getOverrideFieldAccessor().setShort(obj, s);
}
getFieldAccessor(obj).setShort(obj, s);
}
/**
@ -980,8 +1014,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
getFieldAccessor().setInt(obj, i);
} else {
getOverrideFieldAccessor().setInt(obj, i);
}
getFieldAccessor(obj).setInt(obj, i);
}
/**
@ -1017,8 +1053,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
getFieldAccessor().setLong(obj, l);
} else {
getOverrideFieldAccessor().setLong(obj, l);
}
getFieldAccessor(obj).setLong(obj, l);
}
/**
@ -1054,8 +1092,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
getFieldAccessor().setFloat(obj, f);
} else {
getOverrideFieldAccessor().setFloat(obj, f);
}
getFieldAccessor(obj).setFloat(obj, f);
}
/**
@ -1091,8 +1131,10 @@ class Field extends AccessibleObject implements Member {
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj);
getFieldAccessor().setDouble(obj, d);
} else {
getOverrideFieldAccessor().setDouble(obj, d);
}
getFieldAccessor(obj).setDouble(obj, d);
}
// check access to field
@ -1105,53 +1147,69 @@ class Field extends AccessibleObject implements Member {
}
// security check is done before calling this method
private FieldAccessor getFieldAccessor(Object obj)
throws IllegalAccessException
{
boolean ov = override;
FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
return (a != null) ? a : acquireFieldAccessor(ov);
private FieldAccessor getFieldAccessor() {
FieldAccessor a = fieldAccessor;
return (a != null) ? a : acquireFieldAccessor();
}
private FieldAccessor getOverrideFieldAccessor() {
FieldAccessor a = overrideFieldAccessor;
return (a != null) ? a : acquireOverrideFieldAccessor();
}
// NOTE that there is no synchronization used here. It is correct
// (though not efficient) to generate more than one FieldAccessor
// for a given Field. However, avoiding synchronization will
// probably make the implementation more scalable.
private FieldAccessor acquireFieldAccessor(boolean overrideFinalCheck) {
private FieldAccessor acquireFieldAccessor() {
// First check to see if one has been created yet, and take it
// if so
FieldAccessor tmp = null;
if (root != null) tmp = root.getFieldAccessor(overrideFinalCheck);
Field root = this.root;
FieldAccessor tmp = root == null ? null : root.fieldAccessor;
if (tmp != null) {
if (overrideFinalCheck)
overrideFieldAccessor = tmp;
else
fieldAccessor = tmp;
fieldAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newFieldAccessor(this, overrideFinalCheck);
setFieldAccessor(tmp, overrideFinalCheck);
tmp = reflectionFactory.newFieldAccessor(this, false);
setFieldAccessor(tmp);
}
return tmp;
}
// Returns FieldAccessor for this Field object, not looking up
// the chain to the root
private FieldAccessor getFieldAccessor(boolean overrideFinalCheck) {
return (overrideFinalCheck)? overrideFieldAccessor : fieldAccessor;
private FieldAccessor acquireOverrideFieldAccessor() {
// First check to see if one has been created yet, and take it
// if so
Field root = this.root;
FieldAccessor tmp = root == null ? null : root.overrideFieldAccessor;
if (tmp != null) {
overrideFieldAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newFieldAccessor(this, true);
setOverrideFieldAccessor(tmp);
}
return tmp;
}
// Sets the FieldAccessor for this Field object and
// Sets the fieldAccessor for this Field object and
// (recursively) its root
private void setFieldAccessor(FieldAccessor accessor, boolean overrideFinalCheck) {
if (overrideFinalCheck)
overrideFieldAccessor = accessor;
else
fieldAccessor = accessor;
private void setFieldAccessor(FieldAccessor accessor) {
fieldAccessor = accessor;
// Propagate up
Field root = this.root;
if (root != null) {
root.setFieldAccessor(accessor, overrideFinalCheck);
root.setFieldAccessor(accessor);
}
}
// Sets the overrideFieldAccessor for this Field object and
// (recursively) its root
private void setOverrideFieldAccessor(FieldAccessor accessor) {
overrideFieldAccessor = accessor;
// Propagate up
Field root = this.root;
if (root != null) {
root.setOverrideFieldAccessor(accessor);
}
}

View file

@ -85,7 +85,8 @@ public final class Method extends Executable {
private byte[] annotations;
private byte[] parameterAnnotations;
private byte[] annotationDefault;
private volatile MethodAccessor methodAccessor;
@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.)
@ -665,8 +666,8 @@ public final class Method extends Executable {
private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it
// if so
MethodAccessor tmp = null;
if (root != null) tmp = root.getMethodAccessor();
Method root = this.root;
MethodAccessor tmp = root == null ? null : root.getMethodAccessor();
if (tmp != null) {
methodAccessor = tmp;
} else {
@ -689,6 +690,7 @@ public final class Method extends Executable {
void setMethodAccessor(MethodAccessor accessor) {
methodAccessor = accessor;
// Propagate up
Method root = this.root;
if (root != null) {
root.setMethodAccessor(accessor);
}

View file

@ -25,16 +25,25 @@
package jdk.internal.reflect;
import jdk.internal.vm.annotation.Stable;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
/** Delegates its invocation to another ConstructorAccessorImpl and can
change its delegate at run time. */
class DelegatingConstructorAccessorImpl extends ConstructorAccessorImpl {
private ConstructorAccessorImpl delegate;
// initial non-null delegate
@Stable
private final ConstructorAccessorImpl initialDelegate;
// alternative delegate: starts as null;
// only single change from null -> non-null is guaranteed
@Stable
private ConstructorAccessorImpl altDelegate;
DelegatingConstructorAccessorImpl(ConstructorAccessorImpl delegate) {
setDelegate(delegate);
initialDelegate = Objects.requireNonNull(delegate);
}
public Object newInstance(Object[] args)
@ -42,10 +51,15 @@ class DelegatingConstructorAccessorImpl extends ConstructorAccessorImpl {
IllegalArgumentException,
InvocationTargetException
{
return delegate.newInstance(args);
return delegate().newInstance(args);
}
private ConstructorAccessorImpl delegate() {
var d = altDelegate;
return d != null ? d : initialDelegate;
}
void setDelegate(ConstructorAccessorImpl delegate) {
this.delegate = delegate;
altDelegate = Objects.requireNonNull(delegate);
}
}

View file

@ -25,25 +25,38 @@
package jdk.internal.reflect;
import jdk.internal.vm.annotation.Stable;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
/** Delegates its invocation to another MethodAccessorImpl and can
change its delegate at run time. */
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;
// initial non-null delegate
@Stable private final MethodAccessorImpl initialDelegate;
// alternative delegate: starts as null;
// only single change from null -> non-null is guaranteed
@Stable private MethodAccessorImpl altDelegate;
DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
setDelegate(delegate);
initialDelegate = Objects.requireNonNull(delegate);
}
@Override
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
return delegate.invoke(obj, args);
return delegate().invoke(obj, args);
}
private MethodAccessorImpl delegate() {
var d = altDelegate;
return d != null ? d : initialDelegate;
}
void setDelegate(MethodAccessorImpl delegate) {
this.delegate = delegate;
altDelegate = Objects.requireNonNull(delegate);
}
}

View file

@ -25,12 +25,23 @@
package jdk.internal.reflect;
import jdk.internal.vm.annotation.Stable;
import java.lang.reflect.Field;
/** Package-private implementation of the FieldAccessor interface
which has access to all classes and all fields, regardless of
language restrictions. See MagicAccessorImpl. */
abstract class FieldAccessorImpl extends MagicAccessorImpl
implements FieldAccessor {
@Stable
protected final Field field;
FieldAccessorImpl(Field field) {
this.field = field;
}
/** Matches specification in {@link java.lang.reflect.Field} */
public abstract Object get(Object obj)
throws IllegalArgumentException;

View file

@ -25,8 +25,6 @@
package jdk.internal.reflect;
import sun.reflect.misc.ReflectUtil;
import java.lang.reflect.*;
import jdk.internal.misc.Unsafe;
@ -39,12 +37,13 @@ class NativeConstructorAccessorImpl extends ConstructorAccessorImpl {
= U.objectFieldOffset(NativeConstructorAccessorImpl.class, "generated");
private final Constructor<?> c;
private DelegatingConstructorAccessorImpl parent;
private final DelegatingConstructorAccessorImpl parent;
private int numInvocations;
private volatile int generated;
NativeConstructorAccessorImpl(Constructor<?> c) {
this.c = c;
this.parent = new DelegatingConstructorAccessorImpl(this);
}
public Object newInstance(Object[] args)
@ -77,8 +76,8 @@ class NativeConstructorAccessorImpl extends ConstructorAccessorImpl {
return newInstance0(c, args);
}
void setParent(DelegatingConstructorAccessorImpl parent) {
this.parent = parent;
DelegatingConstructorAccessorImpl getParent() {
return parent;
}
private static native Object newInstance0(Constructor<?> c, Object[] args)

View file

@ -25,8 +25,6 @@
package jdk.internal.reflect;
import sun.reflect.misc.ReflectUtil;
import java.lang.reflect.*;
import jdk.internal.misc.Unsafe;
@ -39,12 +37,13 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl {
= U.objectFieldOffset(NativeMethodAccessorImpl.class, "generated");
private final Method method;
private DelegatingMethodAccessorImpl parent;
private final DelegatingMethodAccessorImpl parent;
private int numInvocations;
private volatile int generated;
NativeMethodAccessorImpl(Method method) {
this.method = method;
this.parent = new DelegatingMethodAccessorImpl(this);
}
public Object invoke(Object obj, Object[] args)
@ -77,8 +76,8 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl {
return invoke0(method, obj, args);
}
void setParent(DelegatingMethodAccessorImpl parent) {
this.parent = parent;
DelegatingMethodAccessorImpl getParent() {
return parent;
}
private static native Object invoke0(Method m, Object obj, Object[] args);

View file

@ -44,7 +44,6 @@ import java.util.Properties;
import jdk.internal.access.JavaLangReflectAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import sun.reflect.misc.ReflectUtil;
import sun.security.action.GetPropertyAction;
import sun.security.util.SecurityConstants;
@ -210,12 +209,8 @@ public class ReflectionFactory {
method.getExceptionTypes(),
method.getModifiers());
} else {
NativeMethodAccessorImpl acc =
new NativeMethodAccessorImpl(method);
DelegatingMethodAccessorImpl res =
new DelegatingMethodAccessorImpl(acc);
acc.setParent(res);
return res;
NativeMethodAccessorImpl acc = new NativeMethodAccessorImpl(method);
return acc.getParent();
}
}
@ -252,12 +247,8 @@ public class ReflectionFactory {
c.getExceptionTypes(),
c.getModifiers());
} else {
NativeConstructorAccessorImpl acc =
new NativeConstructorAccessorImpl(c);
DelegatingConstructorAccessorImpl res =
new DelegatingConstructorAccessorImpl(acc);
acc.setParent(res);
return res;
NativeConstructorAccessorImpl acc = new NativeConstructorAccessorImpl(c);
return acc.getParent();
}
}

View file

@ -28,6 +28,7 @@ package jdk.internal.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.Stable;
/** Base class for jdk.internal.misc.Unsafe-based FieldAccessors. The
observation is that there are only nine types of fields from the
@ -39,12 +40,12 @@ import jdk.internal.misc.Unsafe;
abstract class UnsafeFieldAccessorImpl extends FieldAccessorImpl {
static final Unsafe unsafe = Unsafe.getUnsafe();
protected final Field field;
@Stable
protected final long fieldOffset;
protected final boolean isFinal;
UnsafeFieldAccessorImpl(Field field) {
this.field = field;
super(field);
if (Modifier.isStatic(field.getModifiers()))
fieldOffset = unsafe.staticFieldOffset(field);
else

View file

@ -31,6 +31,7 @@ import java.security.AccessController;
import java.util.Set;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.Stable;
/** Base class for jdk.internal.misc.Unsafe-based FieldAccessors for static
fields. The observation is that there are only nine types of
@ -45,6 +46,7 @@ abstract class UnsafeStaticFieldAccessorImpl extends UnsafeFieldAccessorImpl {
Set.of("base"));
}
@Stable
protected final Object base; // base
UnsafeStaticFieldAccessorImpl(Field field) {