Skip to content

Commit 4cc6174

Browse files
author
Christian Wimmer
committed
[GR-33636] Fix and improve Graal IR for reflection.
PullRequest: graal/9751
2 parents 119684d + 251273f commit 4cc6174

File tree

17 files changed

+598
-372
lines changed

17 files changed

+598
-372
lines changed

substratevm/src/com.oracle.svm.core.jdk11/src/com/oracle/svm/core/jdk11/reflect/SubstrateReflectionAccessorFactoryJDK11.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939

4040
final class SubstrateReflectionAccessorFactoryJDK11 implements SubstrateReflectionAccessorFactory {
4141
@Override
42-
public SubstrateMethodAccessor createMethodAccessor(Executable member, CFunctionPointer invokeFunctionPointer, CFunctionPointer invokeSpecialFunctionPointer) {
43-
return new SubstrateMethodAccessorJDK11(member, invokeFunctionPointer, invokeSpecialFunctionPointer);
42+
public SubstrateMethodAccessor createMethodAccessor(Executable member, CFunctionPointer invokeFunctionPointer) {
43+
return new SubstrateMethodAccessorJDK11(member, invokeFunctionPointer);
4444
}
4545

4646
@Override
@@ -58,8 +58,8 @@ public void afterRegistration(AfterRegistrationAccess access) {
5858
}
5959

6060
final class SubstrateMethodAccessorJDK11 extends SubstrateMethodAccessor implements jdk.internal.reflect.MethodAccessor {
61-
SubstrateMethodAccessorJDK11(Executable member, CFunctionPointer invokeFunctionPointer, CFunctionPointer invokeSpecialFunctionPointer) {
62-
super(member, invokeFunctionPointer, invokeSpecialFunctionPointer);
61+
SubstrateMethodAccessorJDK11(Executable member, CFunctionPointer invokeFunctionPointer) {
62+
super(member, invokeFunctionPointer);
6363
}
6464
}
6565

substratevm/src/com.oracle.svm.core.jdk8/src/com/oracle/svm/core/jdk8/reflect/SubstrateReflectionAccessorFactoryJDK8.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939

4040
final class SubstrateReflectionAccessorFactoryJDK8 implements SubstrateReflectionAccessorFactory {
4141
@Override
42-
public SubstrateMethodAccessor createMethodAccessor(Executable member, CFunctionPointer invokeFunctionPointer, CFunctionPointer invokeSpecialFunctionPointer) {
43-
return new SubstrateMethodAccessorJDK8(member, invokeFunctionPointer, invokeSpecialFunctionPointer);
42+
public SubstrateMethodAccessor createMethodAccessor(Executable member, CFunctionPointer invokeFunctionPointer) {
43+
return new SubstrateMethodAccessorJDK8(member, invokeFunctionPointer);
4444
}
4545

4646
@Override
@@ -58,8 +58,8 @@ public void afterRegistration(AfterRegistrationAccess access) {
5858
}
5959

6060
final class SubstrateMethodAccessorJDK8 extends SubstrateMethodAccessor implements sun.reflect.MethodAccessor {
61-
SubstrateMethodAccessorJDK8(Executable member, CFunctionPointer invokeFunctionPointer, CFunctionPointer invokeSpecialFunctionPointer) {
62-
super(member, invokeFunctionPointer, invokeSpecialFunctionPointer);
61+
SubstrateMethodAccessorJDK8(Executable member, CFunctionPointer invokeFunctionPointer) {
62+
super(member, invokeFunctionPointer);
6363
}
6464
}
6565

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/replacements/SubstrateGraphKit.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.graalvm.compiler.nodes.calc.FloatingNode;
5656
import org.graalvm.compiler.nodes.calc.NarrowNode;
5757
import org.graalvm.compiler.nodes.extended.BoxNode;
58+
import org.graalvm.compiler.nodes.extended.GuardingNode;
5859
import org.graalvm.compiler.nodes.extended.StateSplitProxyNode;
5960
import org.graalvm.compiler.nodes.extended.UnboxNode;
6061
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
@@ -84,7 +85,6 @@
8485
import jdk.vm.ci.meta.Constant;
8586
import jdk.vm.ci.meta.JavaKind;
8687
import jdk.vm.ci.meta.JavaType;
87-
import jdk.vm.ci.meta.MetaAccessProvider;
8888
import jdk.vm.ci.meta.ResolvedJavaField;
8989
import jdk.vm.ci.meta.ResolvedJavaMethod;
9090
import jdk.vm.ci.meta.ResolvedJavaType;
@@ -148,8 +148,8 @@ public LoadFieldNode createLoadField(ValueNode object, ResolvedJavaField field)
148148
return append(LoadFieldNode.create(null, object, field));
149149
}
150150

151-
public ValueNode createLoadIndexed(ValueNode array, int index, JavaKind kind) {
152-
ValueNode loadIndexed = LoadIndexedNode.create(null, array, ConstantNode.forInt(index, getGraph()), null, kind, getMetaAccess(), getConstantReflection());
151+
public ValueNode createLoadIndexed(ValueNode array, int index, JavaKind kind, GuardingNode boundsCheck) {
152+
ValueNode loadIndexed = LoadIndexedNode.create(null, array, ConstantNode.forInt(index, getGraph()), boundsCheck, kind, getMetaAccess(), getConstantReflection());
153153
if (loadIndexed instanceof FixedNode) {
154154
return append((FixedNode) loadIndexed);
155155
}
@@ -160,8 +160,8 @@ public ValueNode createStoreIndexed(ValueNode array, int index, JavaKind kind, V
160160
return append(new StoreIndexedNode(array, ConstantNode.forInt(index, getGraph()), null, null, kind, value));
161161
}
162162

163-
public ValueNode createUnboxing(ValueNode boxed, JavaKind targetKind, MetaAccessProvider metaAccess) {
164-
return append(new UnboxNode(boxed, targetKind, metaAccess));
163+
public ValueNode createUnboxing(ValueNode boxed, JavaKind targetKind) {
164+
return append(new UnboxNode(boxed, targetKind, getMetaAccess()));
165165
}
166166

167167
public ValueNode createInvokeWithExceptionAndUnwind(Class<?> declaringClass, String name, InvokeKind invokeKind, ValueNode... args) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/invoke/MethodHandleUtils.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
import com.oracle.svm.core.SubstrateOptions;
3333
import com.oracle.svm.core.annotate.AlwaysInline;
3434

35-
import jdk.vm.ci.meta.MetaAccessProvider;
36-
import jdk.vm.ci.meta.ResolvedJavaMethod;
3735
// Checkstyle: stop
3836
import sun.invoke.util.Wrapper;
3937
// Checkstyle: resume
@@ -133,18 +131,6 @@ public static short shortUnbox(Object retVal, Class<?> returnType) {
133131
}
134132
}
135133

136-
public static ResolvedJavaMethod getThrowUnsupportedOperationException(MetaAccessProvider metaAccess) {
137-
try {
138-
return metaAccess.lookupJavaMethod(MethodHandleUtils.class.getMethod("throwUnsupportedOperationException"));
139-
} catch (NoSuchMethodException e) {
140-
throw shouldNotReachHere();
141-
}
142-
}
143-
144-
public static void throwUnsupportedOperationException() {
145-
throw new UnsupportedOperationException("MethodHandle.invoke() and MethodHandle.invokeExact() cannot be invoked through reflection");
146-
}
147-
148134
public static class MethodHandlesSupported implements BooleanSupplier {
149135
@Override
150136
public boolean getAsBoolean() {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/ReflectionAccessorHolder.java

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@
2424
*/
2525
package com.oracle.svm.core.reflect;
2626

27+
// Checkstyle: allow reflection
28+
29+
import java.lang.reflect.InvocationTargetException;
30+
31+
import com.oracle.svm.core.annotate.NeverInline;
2732
import com.oracle.svm.core.jdk.InternalVMMethod;
33+
import com.oracle.svm.core.reflect.SubstrateConstructorAccessor.ConstructorNewInstanceFunctionPointer;
34+
import com.oracle.svm.core.reflect.SubstrateMethodAccessor.MethodInvokeFunctionPointer;
2835
import com.oracle.svm.core.util.VMError;
2936

3037
/**
@@ -37,28 +44,76 @@
3744
public final class ReflectionAccessorHolder {
3845

3946
/**
40-
* Signature prototype for invoking a method via a {@link SubstrateMethodAccessor}.
47+
* Signature prototype for invoking a method via a {@link SubstrateMethodAccessor}. Must match
48+
* the signature of {@link MethodInvokeFunctionPointer#invoke}
4149
*/
42-
private static Object invokePrototype(Object obj, Object[] args) {
50+
static Object invokePrototype(boolean invokeSpecial, Object obj, Object[] args) {
4351
throw VMError.shouldNotReachHere("Only used as a prototype for generated methods");
4452
}
4553

4654
/**
4755
* Signature prototype for allocating a new instance via a {@link SubstrateConstructorAccessor}.
56+
* Must match * the signature of {@link ConstructorNewInstanceFunctionPointer#invoke}
4857
*/
49-
private static Object newInstancePrototype(Object[] args) {
58+
static Object newInstancePrototype(Object[] args) {
5059
throw VMError.shouldNotReachHere("Only used as a prototype for generated methods");
5160
}
5261

5362
/*
54-
* Methods for throwing exceptions when a method or constructor is used in an illegal way.
63+
* Methods for throwing exceptions when a method or constructor is used in an illegal way. These
64+
* methods are invoked via function pointers, so must have the same signature as the prototypes
65+
* above.
5566
*/
5667

57-
private static Object invokeSpecialError(Object obj, Object[] args) {
58-
throw new IllegalArgumentException("Static or abstract method cannot be invoked using invokeSpecial");
68+
private static void methodHandleInvokeError(boolean invokeSpecial, Object obj, Object[] args) throws InvocationTargetException {
69+
/* The nested exceptions are required by the specification. */
70+
throw new InvocationTargetException(new UnsupportedOperationException("MethodHandle.invoke() and MethodHandle.invokeExact() cannot be invoked through reflection"));
5971
}
6072

6173
private static Object newInstanceError(Object[] args) throws InstantiationException {
6274
throw new InstantiationException("Only non-abstract instance classes can be instantiated using reflection");
6375
}
76+
77+
/*
78+
* Methods for throwing exceptions from within the generated Graal IR. The signature depends on
79+
* the call site, i.e., it does not need to be the prototype signature.
80+
*/
81+
82+
@NeverInline("Exception slow path")
83+
private static InvocationTargetException throwInvocationTargetException(Throwable target) throws InvocationTargetException {
84+
throw new InvocationTargetException(target);
85+
}
86+
87+
@NeverInline("Exception slow path")
88+
private static void throwIllegalArgumentExceptionForMethod(Object member, Object obj, Object[] args) {
89+
throwIllegalArgumentException(member, false, obj, args);
90+
}
91+
92+
@NeverInline("Exception slow path")
93+
private static void throwIllegalArgumentExceptionForConstructor(Object member, Object[] args) {
94+
throwIllegalArgumentException(member, true, null, args);
95+
}
96+
97+
/**
98+
* We do not know which check in the generated metod caused the exception, so we cannot print
99+
* detailed information about that. But printing the signature of the method and all the types
100+
* of the actual arguments should make it obvious what the problem is.
101+
*/
102+
private static void throwIllegalArgumentException(Object member, boolean constructor, Object obj, Object[] args) {
103+
String sep = System.lineSeparator();
104+
StringBuilder msg = new StringBuilder();
105+
msg.append("Illegal arguments for invoking ").append(member);
106+
if (!constructor) {
107+
msg.append(sep).append(" obj: ").append(obj == null ? "null" : obj.getClass().getTypeName());
108+
}
109+
if (args == null) {
110+
msg.append(sep).append(" args: null");
111+
} else {
112+
for (int i = 0; i < args.length; i++) {
113+
Object arg = args[i];
114+
msg.append(sep).append(" args[").append(i).append("]: ").append(arg == null ? "null" : arg.getClass().getTypeName());
115+
}
116+
}
117+
throw new IllegalArgumentException(msg.toString());
118+
}
64119
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateConstructorAccessor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
public abstract class SubstrateConstructorAccessor {
3939

4040
interface ConstructorNewInstanceFunctionPointer extends CFunctionPointer {
41+
/** Must match the signature of {@link ReflectionAccessorHolder#newInstancePrototype}. */
4142
@InvokeJavaFunctionPointer
4243
Object invoke(Object[] args);
4344
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateMethodAccessor.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,41 +38,36 @@
3838
public abstract class SubstrateMethodAccessor {
3939

4040
interface MethodInvokeFunctionPointer extends CFunctionPointer {
41+
/** Must match the signature of {@link ReflectionAccessorHolder#invokePrototype}. */
4142
@InvokeJavaFunctionPointer
42-
Object invoke(Object obj, Object[] args);
43+
Object invoke(boolean invokeSpecial, Object obj, Object[] args);
4344
}
4445

4546
private final Executable member;
4647
private final CFunctionPointer invokeFunctionPointer;
47-
private final CFunctionPointer invokeSpecialFunctionPointer;
4848

49-
protected SubstrateMethodAccessor(Executable member, CFunctionPointer invokeFunctionPointer, CFunctionPointer invokeSpecialFunctionPointer) {
49+
protected SubstrateMethodAccessor(Executable member, CFunctionPointer invokeFunctionPointer) {
5050
this.member = member;
5151
this.invokeFunctionPointer = invokeFunctionPointer;
52-
this.invokeSpecialFunctionPointer = invokeSpecialFunctionPointer;
5352
}
5453

5554
public Object invoke(Object obj, Object[] args) {
5655
MethodInvokeFunctionPointer functionPointer = (MethodInvokeFunctionPointer) this.invokeFunctionPointer;
5756
if (functionPointer.isNull()) {
5857
throw invokeError();
5958
}
60-
return functionPointer.invoke(obj, args);
59+
return functionPointer.invoke(false, obj, args);
6160
}
6261

6362
private RuntimeException invokeError() {
6463
throw VMError.shouldNotReachHere("No SubstrateMethodAccessor.invokeFunctionPointer for " + member);
6564
}
6665

6766
public Object invokeSpecial(Object obj, Object[] args) {
68-
MethodInvokeFunctionPointer functionPointer = (MethodInvokeFunctionPointer) this.invokeSpecialFunctionPointer;
67+
MethodInvokeFunctionPointer functionPointer = (MethodInvokeFunctionPointer) this.invokeFunctionPointer;
6968
if (functionPointer.isNull()) {
70-
throw invokeSpecialError();
69+
throw invokeError();
7170
}
72-
return functionPointer.invoke(obj, args);
73-
}
74-
75-
private RuntimeException invokeSpecialError() {
76-
throw VMError.shouldNotReachHere("No SubstrateMethodAccessor.invokeSpecialFunctionPointer for " + member);
71+
return functionPointer.invoke(true, obj, args);
7772
}
7873
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateReflectionAccessorFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import org.graalvm.nativeimage.c.function.CFunctionPointer;
3232

3333
public interface SubstrateReflectionAccessorFactory {
34-
SubstrateMethodAccessor createMethodAccessor(Executable member, CFunctionPointer invokeFunctionPointer, CFunctionPointer invokeSpecialFunctionPointer);
34+
SubstrateMethodAccessor createMethodAccessor(Executable member, CFunctionPointer invokeFunctionPointer);
3535

3636
SubstrateConstructorAccessor createConstructorAccessor(Executable member, CFunctionPointer newInstanceFunctionPointer);
3737
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/ExceptionHelpers.java

Lines changed: 0 additions & 60 deletions
This file was deleted.

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/HostedGraphKit.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,8 @@
5757
import com.oracle.svm.core.c.BoxedRelocatedPointer;
5858
import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode;
5959
import com.oracle.svm.core.graal.code.SubstrateCompilationIdentifier;
60-
import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode;
6160
import com.oracle.svm.core.graal.replacements.SubstrateGraphKit;
6261
import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode;
63-
import com.oracle.svm.core.util.ExceptionHelpers;
6462
import com.oracle.svm.core.util.VMError;
6563
import com.oracle.svm.hosted.meta.HostedMethod;
6664

@@ -115,12 +113,6 @@ public <T extends WithExceptionNode> T appendWithUnwind(T withExceptionNode) {
115113
return appendWithUnwind(withExceptionNode, bci());
116114
}
117115

118-
public void throwInvocationTargetException(ValueNode exception) {
119-
ResolvedJavaMethod throwInvocationTargetException = findMethod(ExceptionHelpers.class, "throwInvocationTargetException", true);
120-
createJavaCallWithExceptionAndUnwind(InvokeKind.Static, throwInvocationTargetException, exception);
121-
append(new LoweredDeadEndNode());
122-
}
123-
124116
public LoadFieldNode createLoadFieldNode(ConstantNode receiver, Class<BoxedRelocatedPointer> clazz, String fieldName) {
125117
try {
126118
ResolvedJavaType type = getMetaAccess().lookupJavaType(clazz);

0 commit comments

Comments
 (0)