8255883: Avoid duplicated GeneratedMethodAccessor when reflect method invoked from different threads

Reviewed-by: shade, alanb
This commit is contained in:
Hui Shi 2020-11-16 11:34:47 +00:00 committed by Alan Bateman
parent ac3948930e
commit 8eeb36f14a
2 changed files with 46 additions and 18 deletions
src/java.base/share/classes/jdk/internal/reflect

@ -28,14 +28,20 @@ package jdk.internal.reflect;
import sun.reflect.misc.ReflectUtil;
import java.lang.reflect.*;
import jdk.internal.misc.Unsafe;
/** Used only for the first few invocations of a Constructor;
afterward, switches to bytecode-based implementation */
class NativeConstructorAccessorImpl extends ConstructorAccessorImpl {
private static final Unsafe U = Unsafe.getUnsafe();
private static final long GENERATED_OFFSET
= U.objectFieldOffset(NativeConstructorAccessorImpl.class, "generated");
private final Constructor<?> c;
private DelegatingConstructorAccessorImpl parent;
private int numInvocations;
private volatile int generated;
NativeConstructorAccessorImpl(Constructor<?> c) {
this.c = c;
@ -51,14 +57,22 @@ class NativeConstructorAccessorImpl extends ConstructorAccessorImpl {
// be found from the generated bytecode.
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !c.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
new MethodAccessorGenerator().
generateConstructor(c.getDeclaringClass(),
c.getParameterTypes(),
c.getExceptionTypes(),
c.getModifiers());
parent.setDelegate(acc);
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())
&& generated == 0
&& U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) {
try {
ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
new MethodAccessorGenerator().
generateConstructor(c.getDeclaringClass(),
c.getParameterTypes(),
c.getExceptionTypes(),
c.getModifiers());
parent.setDelegate(acc);
} catch (Throwable t) {
// Throwable happens in generateConstructor, restore generated to 0
generated = 0;
throw t;
}
}
return newInstance0(c, args);

@ -28,14 +28,20 @@ package jdk.internal.reflect;
import sun.reflect.misc.ReflectUtil;
import java.lang.reflect.*;
import jdk.internal.misc.Unsafe;
/** Used only for the first few invocations of a Method; afterward,
switches to bytecode-based implementation */
class NativeMethodAccessorImpl extends MethodAccessorImpl {
private static final Unsafe U = Unsafe.getUnsafe();
private static final long GENERATED_OFFSET
= U.objectFieldOffset(NativeMethodAccessorImpl.class, "generated");
private final Method method;
private DelegatingMethodAccessorImpl parent;
private int numInvocations;
private volatile int generated;
NativeMethodAccessorImpl(Method method) {
this.method = method;
@ -49,16 +55,24 @@ class NativeMethodAccessorImpl extends MethodAccessorImpl {
// found from the generated bytecode.
if (++numInvocations > ReflectionFactory.inflationThreshold()
&& !method.getDeclaringClass().isHidden()
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
MethodAccessorImpl acc = (MethodAccessorImpl)
new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
method.getParameterTypes(),
method.getReturnType(),
method.getExceptionTypes(),
method.getModifiers());
parent.setDelegate(acc);
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())
&& generated == 0
&& U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) {
try {
MethodAccessorImpl acc = (MethodAccessorImpl)
new MethodAccessorGenerator().
generateMethod(method.getDeclaringClass(),
method.getName(),
method.getParameterTypes(),
method.getReturnType(),
method.getExceptionTypes(),
method.getModifiers());
parent.setDelegate(acc);
} catch (Throwable t) {
// Throwable happens in generateMethod, restore generated to 0
generated = 0;
throw t;
}
}
return invoke0(method, obj, args);