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

View file

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

View file

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