Skip to content

Commit 8eeb36f

Browse files
Hui ShiAlan Bateman
authored andcommitted
8255883: Avoid duplicated GeneratedMethodAccessor when reflect method invoked from different threads
Reviewed-by: shade, alanb
1 parent ac39489 commit 8eeb36f

File tree

2 files changed

+46
-18
lines changed

2 files changed

+46
-18
lines changed

src/java.base/share/classes/jdk/internal/reflect/NativeConstructorAccessorImpl.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,20 @@
2828
import sun.reflect.misc.ReflectUtil;
2929

3030
import java.lang.reflect.*;
31+
import jdk.internal.misc.Unsafe;
3132

3233
/** Used only for the first few invocations of a Constructor;
3334
afterward, switches to bytecode-based implementation */
3435

3536
class NativeConstructorAccessorImpl extends ConstructorAccessorImpl {
37+
private static final Unsafe U = Unsafe.getUnsafe();
38+
private static final long GENERATED_OFFSET
39+
= U.objectFieldOffset(NativeConstructorAccessorImpl.class, "generated");
40+
3641
private final Constructor<?> c;
3742
private DelegatingConstructorAccessorImpl parent;
3843
private int numInvocations;
44+
private volatile int generated;
3945

4046
NativeConstructorAccessorImpl(Constructor<?> c) {
4147
this.c = c;
@@ -51,14 +57,22 @@ public Object newInstance(Object[] args)
5157
// be found from the generated bytecode.
5258
if (++numInvocations > ReflectionFactory.inflationThreshold()
5359
&& !c.getDeclaringClass().isHidden()
54-
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
55-
ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
56-
new MethodAccessorGenerator().
57-
generateConstructor(c.getDeclaringClass(),
58-
c.getParameterTypes(),
59-
c.getExceptionTypes(),
60-
c.getModifiers());
61-
parent.setDelegate(acc);
60+
&& !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())
61+
&& generated == 0
62+
&& U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) {
63+
try {
64+
ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
65+
new MethodAccessorGenerator().
66+
generateConstructor(c.getDeclaringClass(),
67+
c.getParameterTypes(),
68+
c.getExceptionTypes(),
69+
c.getModifiers());
70+
parent.setDelegate(acc);
71+
} catch (Throwable t) {
72+
// Throwable happens in generateConstructor, restore generated to 0
73+
generated = 0;
74+
throw t;
75+
}
6276
}
6377

6478
return newInstance0(c, args);

src/java.base/share/classes/jdk/internal/reflect/NativeMethodAccessorImpl.java

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,20 @@
2828
import sun.reflect.misc.ReflectUtil;
2929

3030
import java.lang.reflect.*;
31+
import jdk.internal.misc.Unsafe;
3132

3233
/** Used only for the first few invocations of a Method; afterward,
3334
switches to bytecode-based implementation */
3435

3536
class NativeMethodAccessorImpl extends MethodAccessorImpl {
37+
private static final Unsafe U = Unsafe.getUnsafe();
38+
private static final long GENERATED_OFFSET
39+
= U.objectFieldOffset(NativeMethodAccessorImpl.class, "generated");
40+
3641
private final Method method;
3742
private DelegatingMethodAccessorImpl parent;
3843
private int numInvocations;
44+
private volatile int generated;
3945

4046
NativeMethodAccessorImpl(Method method) {
4147
this.method = method;
@@ -49,16 +55,24 @@ public Object invoke(Object obj, Object[] args)
4955
// found from the generated bytecode.
5056
if (++numInvocations > ReflectionFactory.inflationThreshold()
5157
&& !method.getDeclaringClass().isHidden()
52-
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
53-
MethodAccessorImpl acc = (MethodAccessorImpl)
54-
new MethodAccessorGenerator().
55-
generateMethod(method.getDeclaringClass(),
56-
method.getName(),
57-
method.getParameterTypes(),
58-
method.getReturnType(),
59-
method.getExceptionTypes(),
60-
method.getModifiers());
61-
parent.setDelegate(acc);
58+
&& !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())
59+
&& generated == 0
60+
&& U.compareAndSetInt(this, GENERATED_OFFSET, 0, 1)) {
61+
try {
62+
MethodAccessorImpl acc = (MethodAccessorImpl)
63+
new MethodAccessorGenerator().
64+
generateMethod(method.getDeclaringClass(),
65+
method.getName(),
66+
method.getParameterTypes(),
67+
method.getReturnType(),
68+
method.getExceptionTypes(),
69+
method.getModifiers());
70+
parent.setDelegate(acc);
71+
} catch (Throwable t) {
72+
// Throwable happens in generateMethod, restore generated to 0
73+
generated = 0;
74+
throw t;
75+
}
6276
}
6377

6478
return invoke0(method, obj, args);

0 commit comments

Comments
 (0)