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

View File

@ -30,6 +30,7 @@ import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.FieldAccessor; import jdk.internal.reflect.FieldAccessor;
import jdk.internal.reflect.Reflection; import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
import sun.reflect.generics.repository.FieldRepository; import sun.reflect.generics.repository.FieldRepository;
import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.CoreReflectionFactory;
import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.factory.GenericsFactory;
@ -65,12 +66,15 @@ import sun.reflect.annotation.TypeAnnotationParser;
public final public final
class Field extends AccessibleObject implements Member { class Field extends AccessibleObject implements Member {
@Stable
private Class<?> clazz; private Class<?> clazz;
private int slot; private int slot;
// This is guaranteed to be interned by the VM in the 1.4 // This is guaranteed to be interned by the VM in the 1.4
// reflection implementation // reflection implementation
private String name; private String name;
@Stable
private Class<?> type; private Class<?> type;
@Stable
private int modifiers; private int modifiers;
private boolean trustedFinal; private boolean trustedFinal;
// Generics and annotations support // Generics and annotations support
@ -79,8 +83,10 @@ class Field extends AccessibleObject implements Member {
private transient FieldRepository genericInfo; private transient FieldRepository genericInfo;
private byte[] annotations; private byte[] annotations;
// Cached field accessor created without override // Cached field accessor created without override
@Stable
private FieldAccessor fieldAccessor; private FieldAccessor fieldAccessor;
// Cached field accessor created with override // Cached field accessor created with override
@Stable
private FieldAccessor overrideFieldAccessor; private FieldAccessor overrideFieldAccessor;
// For sharing of FieldAccessors. This branching structure is // For sharing of FieldAccessors. This branching structure is
// currently only two levels deep (i.e., one root Field and // currently only two levels deep (i.e., one root Field and
@ -421,8 +427,10 @@ class Field extends AccessibleObject implements Member {
if (!override) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); 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) { if (!override) {
Class<?> caller = Reflection.getCallerClass(); Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, obj); checkAccess(caller, obj);
getFieldAccessor().setDouble(obj, d);
} else {
getOverrideFieldAccessor().setDouble(obj, d);
} }
getFieldAccessor(obj).setDouble(obj, d);
} }
// check access to field // check access to field
@ -1105,53 +1147,69 @@ class Field extends AccessibleObject implements Member {
} }
// security check is done before calling this method // security check is done before calling this method
private FieldAccessor getFieldAccessor(Object obj) private FieldAccessor getFieldAccessor() {
throws IllegalAccessException FieldAccessor a = fieldAccessor;
{ return (a != null) ? a : acquireFieldAccessor();
boolean ov = override; }
FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
return (a != null) ? a : acquireFieldAccessor(ov); private FieldAccessor getOverrideFieldAccessor() {
FieldAccessor a = overrideFieldAccessor;
return (a != null) ? a : acquireOverrideFieldAccessor();
} }
// NOTE that there is no synchronization used here. It is correct // NOTE that there is no synchronization used here. It is correct
// (though not efficient) to generate more than one FieldAccessor // (though not efficient) to generate more than one FieldAccessor
// for a given Field. However, avoiding synchronization will // for a given Field. However, avoiding synchronization will
// probably make the implementation more scalable. // 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 // First check to see if one has been created yet, and take it
// if so // if so
FieldAccessor tmp = null; Field root = this.root;
if (root != null) tmp = root.getFieldAccessor(overrideFinalCheck); FieldAccessor tmp = root == null ? null : root.fieldAccessor;
if (tmp != null) { if (tmp != null) {
if (overrideFinalCheck) fieldAccessor = tmp;
overrideFieldAccessor = tmp;
else
fieldAccessor = tmp;
} else { } else {
// Otherwise fabricate one and propagate it up to the root // Otherwise fabricate one and propagate it up to the root
tmp = reflectionFactory.newFieldAccessor(this, overrideFinalCheck); tmp = reflectionFactory.newFieldAccessor(this, false);
setFieldAccessor(tmp, overrideFinalCheck); setFieldAccessor(tmp);
} }
return tmp; return tmp;
} }
// Returns FieldAccessor for this Field object, not looking up private FieldAccessor acquireOverrideFieldAccessor() {
// the chain to the root // First check to see if one has been created yet, and take it
private FieldAccessor getFieldAccessor(boolean overrideFinalCheck) { // if so
return (overrideFinalCheck)? overrideFieldAccessor : fieldAccessor; 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 // (recursively) its root
private void setFieldAccessor(FieldAccessor accessor, boolean overrideFinalCheck) { private void setFieldAccessor(FieldAccessor accessor) {
if (overrideFinalCheck) fieldAccessor = accessor;
overrideFieldAccessor = accessor;
else
fieldAccessor = accessor;
// Propagate up // Propagate up
Field root = this.root;
if (root != null) { 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[] annotations;
private byte[] parameterAnnotations; private byte[] parameterAnnotations;
private byte[] annotationDefault; private byte[] annotationDefault;
private volatile MethodAccessor methodAccessor; @Stable
private MethodAccessor methodAccessor;
// For sharing of MethodAccessors. This branching structure is // For sharing of MethodAccessors. This branching structure is
// currently only two levels deep (i.e., one root Method and // currently only two levels deep (i.e., one root Method and
// potentially many Method objects pointing to it.) // potentially many Method objects pointing to it.)
@ -665,8 +666,8 @@ public final class Method extends Executable {
private MethodAccessor acquireMethodAccessor() { private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it // First check to see if one has been created yet, and take it
// if so // if so
MethodAccessor tmp = null; Method root = this.root;
if (root != null) tmp = root.getMethodAccessor(); MethodAccessor tmp = root == null ? null : root.getMethodAccessor();
if (tmp != null) { if (tmp != null) {
methodAccessor = tmp; methodAccessor = tmp;
} else { } else {
@ -689,6 +690,7 @@ public final class Method extends Executable {
void setMethodAccessor(MethodAccessor accessor) { void setMethodAccessor(MethodAccessor accessor) {
methodAccessor = accessor; methodAccessor = accessor;
// Propagate up // Propagate up
Method root = this.root;
if (root != null) { if (root != null) {
root.setMethodAccessor(accessor); root.setMethodAccessor(accessor);
} }

View File

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

View File

@ -25,25 +25,38 @@
package jdk.internal.reflect; package jdk.internal.reflect;
import jdk.internal.vm.annotation.Stable;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
/** Delegates its invocation to another MethodAccessorImpl and can /** Delegates its invocation to another MethodAccessorImpl and can
change its delegate at run time. */ change its delegate at run time. */
class DelegatingMethodAccessorImpl extends MethodAccessorImpl { 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) { DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
setDelegate(delegate); initialDelegate = Objects.requireNonNull(delegate);
} }
@Override
public Object invoke(Object obj, Object[] args) public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException 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) { void setDelegate(MethodAccessorImpl delegate) {
this.delegate = delegate; altDelegate = Objects.requireNonNull(delegate);
} }
} }

View File

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

View File

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

View File

@ -25,8 +25,6 @@
package jdk.internal.reflect; package jdk.internal.reflect;
import sun.reflect.misc.ReflectUtil;
import java.lang.reflect.*; import java.lang.reflect.*;
import jdk.internal.misc.Unsafe; import jdk.internal.misc.Unsafe;
@ -39,12 +37,13 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl {
= U.objectFieldOffset(NativeMethodAccessorImpl.class, "generated"); = U.objectFieldOffset(NativeMethodAccessorImpl.class, "generated");
private final Method method; private final Method method;
private DelegatingMethodAccessorImpl parent; private final DelegatingMethodAccessorImpl parent;
private int numInvocations; private int numInvocations;
private volatile int generated; private volatile int generated;
NativeMethodAccessorImpl(Method method) { NativeMethodAccessorImpl(Method method) {
this.method = method; this.method = method;
this.parent = new DelegatingMethodAccessorImpl(this);
} }
public Object invoke(Object obj, Object[] args) public Object invoke(Object obj, Object[] args)
@ -77,8 +76,8 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl {
return invoke0(method, obj, args); return invoke0(method, obj, args);
} }
void setParent(DelegatingMethodAccessorImpl parent) { DelegatingMethodAccessorImpl getParent() {
this.parent = parent; return parent;
} }
private static native Object invoke0(Method m, Object obj, Object[] args); 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.JavaLangReflectAccess;
import jdk.internal.access.SharedSecrets; import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM; import jdk.internal.misc.VM;
import sun.reflect.misc.ReflectUtil;
import sun.security.action.GetPropertyAction; import sun.security.action.GetPropertyAction;
import sun.security.util.SecurityConstants; import sun.security.util.SecurityConstants;
@ -210,12 +209,8 @@ public class ReflectionFactory {
method.getExceptionTypes(), method.getExceptionTypes(),
method.getModifiers()); method.getModifiers());
} else { } else {
NativeMethodAccessorImpl acc = NativeMethodAccessorImpl acc = new NativeMethodAccessorImpl(method);
new NativeMethodAccessorImpl(method); return acc.getParent();
DelegatingMethodAccessorImpl res =
new DelegatingMethodAccessorImpl(acc);
acc.setParent(res);
return res;
} }
} }
@ -252,12 +247,8 @@ public class ReflectionFactory {
c.getExceptionTypes(), c.getExceptionTypes(),
c.getModifiers()); c.getModifiers());
} else { } else {
NativeConstructorAccessorImpl acc = NativeConstructorAccessorImpl acc = new NativeConstructorAccessorImpl(c);
new NativeConstructorAccessorImpl(c); return acc.getParent();
DelegatingConstructorAccessorImpl res =
new DelegatingConstructorAccessorImpl(acc);
acc.setParent(res);
return res;
} }
} }

View File

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

View File

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

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2014, 2020, 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.
*/
package org.openjdk.bench.java.lang.reflect;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.infra.Blackhole;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* Benchmark measuring cold-start of reflective method invocation.
*/
@BenchmarkMode(Mode.SingleShotTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Benchmark)
@Fork(value = 30, warmups = 10)
public class ReflectionColdstartBenchmark {
static class Nested {
static Object m00(Object p) {return p;}
static Object m01(Object p) {return p;}
static Object m02(Object p) {return p;}
static Object m03(Object p) {return p;}
static Object m04(Object p) {return p;}
static Object m05(Object p) {return p;}
static Object m06(Object p) {return p;}
static Object m07(Object p) {return p;}
static Object m08(Object p) {return p;}
static Object m09(Object p) {return p;}
static Object m0A(Object p) {return p;}
static Object m0B(Object p) {return p;}
static Object m0C(Object p) {return p;}
static Object m0D(Object p) {return p;}
static Object m0E(Object p) {return p;}
static Object m0F(Object p) {return p;}
static Object m10(Object p) {return p;}
static Object m11(Object p) {return p;}
static Object m12(Object p) {return p;}
static Object m13(Object p) {return p;}
static Object m14(Object p) {return p;}
static Object m15(Object p) {return p;}
static Object m16(Object p) {return p;}
static Object m17(Object p) {return p;}
static Object m18(Object p) {return p;}
static Object m19(Object p) {return p;}
static Object m1A(Object p) {return p;}
static Object m1B(Object p) {return p;}
static Object m1C(Object p) {return p;}
static Object m1D(Object p) {return p;}
static Object m1E(Object p) {return p;}
static Object m1F(Object p) {return p;}
}
private Method[] methods;
private Object arg;
@Setup(Level.Trial)
public void setup() {
methods = Nested.class.getDeclaredMethods();
arg = new Object();
}
@Benchmark
public void invokeMethods(Blackhole bh) throws ReflectiveOperationException {
for (Method m : methods) {
bh.consume(m.invoke(null, arg));
}
}
}

View File

@ -0,0 +1,439 @@
/*
* Copyright (c) 2014, 2020, 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.
*/
package org.openjdk.bench.java.lang.reflect;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* Benchmark measuring field access and method invocation using different conditions:
* <ul>
* <li>Const - Method/Field is constant-foldable</li>
* <li>Var - Method/Field is single-instance but not constant-foldable</li>
* <li>Poly - multiple Method/Field instances used at single call-site</li>
* </ul>
*/
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 10, time = 1, batchSize = 10)
@Measurement(iterations = 10, time = 1, batchSize = 10)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
@Fork(value = 1, warmups = 0)
public class ReflectionSpeedBenchmark {
static final Method staticMethodConst;
static final Method instanceMethodConst;
static final Field staticFieldConst;
static final Field instanceFieldConst;
static final Constructor<?> constructorConst;
static final Object[] constructorArgs;
static Method staticMethodVar;
static Method instanceMethodVar;
static Field staticFieldVar;
static Field instanceFieldVar;
static Constructor<?> constructorVar;
static Method[] staticMethodsPoly;
static Method[] instanceMethodsPoly;
static Field[] staticFieldsPoly;
static Field[] instanceFieldsPoly;
static Constructor<?>[] constructorsPoly;
static Object[][] constructorsArgsPoly;
static {
try {
staticMethodConst = staticMethodVar = ReflectionSpeedBenchmark.class.getDeclaredMethod("sumStatic", int.class, int.class);
instanceMethodConst = instanceMethodVar = ReflectionSpeedBenchmark.class.getDeclaredMethod("sumInstance", int.class, int.class);
staticFieldConst = staticFieldVar = ReflectionSpeedBenchmark.class.getDeclaredField("staticField");
instanceFieldConst = instanceFieldVar = ReflectionSpeedBenchmark.class.getDeclaredField("instanceField");
constructorConst = constructorVar = NestedConstruction.class.getDeclaredConstructor();
constructorArgs = new Object[0];
staticMethodsPoly = NestedStatic.class.getDeclaredMethods();
staticFieldsPoly = NestedStatic.class.getDeclaredFields();
instanceMethodsPoly = NestedInstance.class.getDeclaredMethods();
instanceFieldsPoly = NestedInstance.class.getDeclaredFields();
constructorsPoly = NestedConstruction.class.getDeclaredConstructors();
constructorsArgsPoly = new Object[constructorsPoly.length][];
for (int i = 0; i < constructorsPoly.length; i++) {
constructorsArgsPoly[i] = new Object[constructorsPoly[i].getParameterCount()];
}
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
public static class NestedStatic {
// # of fields must be 2^N
public static Object
f00, f01, f02, f03, f04, f05, f06, f07, f08, f09, f0A, f0B, f0C, f0D, f0E, f0F,
f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f1A, f1B, f1C, f1D, f1E, f1F;
// # of methods must be 2^N
public static Object m00(Object p) {return p;}
public static Object m01(Object p) {return p;}
public static Object m02(Object p) {return p;}
public static Object m03(Object p) {return p;}
public static Object m04(Object p) {return p;}
public static Object m05(Object p) {return p;}
public static Object m06(Object p) {return p;}
public static Object m07(Object p) {return p;}
public static Object m08(Object p) {return p;}
public static Object m09(Object p) {return p;}
public static Object m0A(Object p) {return p;}
public static Object m0B(Object p) {return p;}
public static Object m0C(Object p) {return p;}
public static Object m0D(Object p) {return p;}
public static Object m0E(Object p) {return p;}
public static Object m0F(Object p) {return p;}
public static Object m10(Object p) {return p;}
public static Object m11(Object p) {return p;}
public static Object m12(Object p) {return p;}
public static Object m13(Object p) {return p;}
public static Object m14(Object p) {return p;}
public static Object m15(Object p) {return p;}
public static Object m16(Object p) {return p;}
public static Object m17(Object p) {return p;}
public static Object m18(Object p) {return p;}
public static Object m19(Object p) {return p;}
public static Object m1A(Object p) {return p;}
public static Object m1B(Object p) {return p;}
public static Object m1C(Object p) {return p;}
public static Object m1D(Object p) {return p;}
public static Object m1E(Object p) {return p;}
public static Object m1F(Object p) {return p;}
}
public static class NestedInstance {
// # of fields must be 2^N
public Object
f00, f01, f02, f03, f04, f05, f06, f07, f08, f09, f0A, f0B, f0C, f0D, f0E, f0F,
f10, f11, f12, f13, f14, f15, f16, f17, f18, f19, f1A, f1B, f1C, f1D, f1E, f1F;
// # of methods must be 2^N
public Object m00(Object p) {return p;}
public Object m01(Object p) {return p;}
public Object m02(Object p) {return p;}
public Object m03(Object p) {return p;}
public Object m04(Object p) {return p;}
public Object m05(Object p) {return p;}
public Object m06(Object p) {return p;}
public Object m07(Object p) {return p;}
public Object m08(Object p) {return p;}
public Object m09(Object p) {return p;}
public Object m0A(Object p) {return p;}
public Object m0B(Object p) {return p;}
public Object m0C(Object p) {return p;}
public Object m0D(Object p) {return p;}
public Object m0E(Object p) {return p;}
public Object m0F(Object p) {return p;}
public Object m10(Object p) {return p;}
public Object m11(Object p) {return p;}
public Object m12(Object p) {return p;}
public Object m13(Object p) {return p;}
public Object m14(Object p) {return p;}
public Object m15(Object p) {return p;}
public Object m16(Object p) {return p;}
public Object m17(Object p) {return p;}
public Object m18(Object p) {return p;}
public Object m19(Object p) {return p;}
public Object m1A(Object p) {return p;}
public Object m1B(Object p) {return p;}
public Object m1C(Object p) {return p;}
public Object m1D(Object p) {return p;}
public Object m1E(Object p) {return p;}
public Object m1F(Object p) {return p;}
}
public static class NestedConstruction {
// # of constructors must be 2^N
public NestedConstruction() {}
public NestedConstruction(Void p1) {}
public NestedConstruction(Void p1, Void p2) {}
public NestedConstruction(Void p1, Void p2, Void p3) {}
public NestedConstruction(Void p1, Void p2, Void p3, Void p4) {}
public NestedConstruction(Void p1, Void p2, Void p3, Void p4, Void p5) {}
public NestedConstruction(Void p1, Void p2, Void p3, Void p4, Void p5, Void p6) {}
public NestedConstruction(Void p1, Void p2, Void p3, Void p4, Void p5, Void p6, Void p7) {}
}
private int rnd = 0;
private int a, b;
private Object o;
private NestedInstance instance;
private int nextRnd() {
return rnd += 7;
}
@Setup(Level.Iteration)
public void setup() {
a = nextRnd();
b = nextRnd();
o = new Object();
instance = new NestedInstance();
}
public static int sumStatic(int a, int b) {
return a + b;
}
public int sumInstance(int a, int b) {
return a + b;
}
public static int staticField;
public int instanceField;
// methods
@Benchmark
public int staticMethodConst() {
try {
return (Integer) staticMethodConst.invoke(null, a, b);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
}
@Benchmark
public int instanceMethodConst() {
try {
return (Integer) instanceMethodConst.invoke(this, a, b);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
}
@Benchmark
public int staticMethodVar() {
try {
return (Integer) staticMethodVar.invoke(null, a, b);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
}
@Benchmark
public int instanceMethodVar() {
try {
return (Integer) instanceMethodVar.invoke(this, a, b);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
}
@Benchmark
public Object staticMethodPoly() {
try {
return staticMethodsPoly[nextRnd() & (staticMethodsPoly.length - 1)].invoke(null, o);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
}
@Benchmark
public Object instanceMethodPoly() {
try {
return instanceMethodsPoly[nextRnd() & (instanceMethodsPoly.length - 1)].invoke(instance, o);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
}
// fields
@Benchmark
public int staticFieldConst() {
try {
return staticFieldConst.getInt(null);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}
@Benchmark
public int instanceFieldConst() {
try {
return instanceFieldConst.getInt(this);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}
@Benchmark
public int staticFieldVar() {
try {
return staticFieldVar.getInt(null);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}
@Benchmark
public int instanceFieldVar() {
try {
return instanceFieldVar.getInt(this);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}
@Benchmark
public Object staticFieldPoly() {
try {
return staticFieldsPoly[nextRnd() & (staticFieldsPoly.length - 1)].get(null);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}
@Benchmark
public Object instanceFieldPoly() {
try {
return instanceFieldsPoly[nextRnd() & (instanceFieldsPoly.length - 1)].get(instance);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}
// constructors
@Benchmark
public Object constructorConst() {
try {
return constructorConst.newInstance(constructorArgs);
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
@Benchmark
public Object constructorVar() {
try {
return constructorVar.newInstance(constructorArgs);
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
@Benchmark
public Object constructorPoly() {
try {
int i = nextRnd() & (constructorsPoly.length - 1);
return constructorsPoly[i].newInstance(constructorsArgsPoly[i]);
} catch (ReflectiveOperationException e) {
throw new AssertionError(e);
}
}
}