diff --git a/substratevm/mx.substratevm/testhello.py b/substratevm/mx.substratevm/testhello.py
index 046211164acc..3d04c62ab2c9 100644
--- a/substratevm/mx.substratevm/testhello.py
+++ b/substratevm/mx.substratevm/testhello.py
@@ -197,7 +197,7 @@ def test():
fr"#4{spaces_pattern}{address_pattern} in com\.oracle\.svm\.core\.JavaMainWrapper::runCore{no_param_types_pattern} {no_arg_values_pattern} at {package_pattern}JavaMainWrapper\.java:[0-9]+",
fr"#5{spaces_pattern}com\.oracle\.svm\.core\.JavaMainWrapper::doRun{param_types_pattern} {arg_values_pattern} at {package_pattern}JavaMainWrapper\.java:[0-9]+",
fr"#6{spaces_pattern}({address_pattern} in )?com\.oracle\.svm\.core\.JavaMainWrapper::run{param_types_pattern} {arg_values_pattern} at {package_pattern}JavaMainWrapper\.java:[0-9]+",
- fr"#7{spaces_pattern}com\.oracle\.svm\.core\.code\.IsolateEnterStub::JavaMainWrapper_run_{varname_pattern}{param_types_pattern} {arg_values_pattern}"
+ fr"#7{spaces_pattern}({address_pattern} in )?com\.oracle\.svm\.core\.code\.IsolateEnterStub::JavaMainWrapper_run_{varname_pattern}{param_types_pattern} {arg_values_pattern}"
]
if musl:
# musl has a different entry point - drop the last two frames
@@ -408,7 +408,7 @@ def test():
fr"#5{spaces_pattern}{address_pattern} in com\.oracle\.svm\.core\.JavaMainWrapper::runCore{no_param_types_pattern} {no_arg_values_pattern} at {package_pattern}JavaMainWrapper\.java:[0-9]+",
fr"#6{spaces_pattern}com\.oracle\.svm\.core\.JavaMainWrapper::doRun{param_types_pattern} {arg_values_pattern} at {package_pattern}JavaMainWrapper\.java:[0-9]+",
fr"#7{spaces_pattern}({address_pattern} in )?com\.oracle\.svm\.core\.JavaMainWrapper::run{param_types_pattern} {arg_values_pattern} at {package_pattern}JavaMainWrapper\.java:[0-9]+",
- fr"#8{spaces_pattern}com\.oracle\.svm\.core\.code\.IsolateEnterStub::JavaMainWrapper_run_{varname_pattern}{param_types_pattern} {arg_values_pattern}"
+ fr"#8{spaces_pattern}({address_pattern} in )?com\.oracle\.svm\.core\.code\.IsolateEnterStub::JavaMainWrapper_run_{varname_pattern}{param_types_pattern} {arg_values_pattern}"
]
if musl:
# musl has a different entry point - drop the last two frames
diff --git a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/UpcallStub.java b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/UpcallStub.java
index 92ac68ba0252..8d4148793aac 100644
--- a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/UpcallStub.java
+++ b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/UpcallStub.java
@@ -218,9 +218,15 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
arguments.addFirst(returnBuffer);
}
- /* Transfers to the Java-side stub; note that exceptions should be handled there. */
+ /*
+ * Transfers to the Java-side stub; note that exceptions should be handled there. We
+ * explicitly disable inline for this call to prevent that operations floating to a point
+ * where the base registers are not initialized yet.
+ */
arguments.addFirst(mh);
InvokeWithExceptionNode returnValue = kit.createJavaCallWithException(CallTargetNode.InvokeKind.Static, highLevelStub, arguments.toArray(ValueNode.EMPTY_ARRAY));
+ returnValue.setUseForInlining(false);
+
kit.exceptionPart();
kit.append(new DeadEndNode());
kit.endInvokeWithException();
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java
index ad4dfde9e0bd..0753d08e470e 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java
@@ -101,7 +101,7 @@ private ValueNode createInvoke(AnalysisMethod method, HostedGraphKit kit, Analys
if (method.getAnnotation(CEnumLookup.class) != null) {
/* Call a method that converts the primitive value to a Java enum. */
EnumInfo enumInfo = (EnumInfo) nativeLibraries.findElementInfo(returnType);
- return CInterfaceEnumTool.singleton().createInvokeLookupEnum(kit, returnType, enumInfo, arg);
+ return CInterfaceEnumTool.singleton().createInvokeLookupEnum(kit, returnType, enumInfo, arg, true);
} else if (method.getAnnotation(CEnumValue.class) != null) {
/* Call a method that converts a Java enum to a primitive value. */
ResolvedJavaType declaringType = method.getDeclaringClass();
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CCallStubMethod.java
index 2f2aaa69f322..81e71ea698d4 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CCallStubMethod.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CCallStubMethod.java
@@ -143,7 +143,7 @@ private ValueNode adaptReturnValue(AnalysisMethod method, NativeLibraries native
"Enum class %s needs a method that is annotated with @%s because it is used as the return type of a method annotated with @%s: %s.",
declaredReturnType, CEnumLookup.class.getSimpleName(), getCorrespondingAnnotationName(), getOriginal());
- return CInterfaceEnumTool.singleton().createInvokeLookupEnum(kit, declaredReturnType, enumInfo, value);
+ return CInterfaceEnumTool.singleton().createInvokeLookupEnum(kit, declaredReturnType, enumInfo, value, true);
}
private EnumInfo getEnumInfo(NativeLibraries nativeLibraries, AnalysisType type, boolean isReturnType) {
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java
index 0cd79b174e31..93f69f710e67 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java
@@ -24,6 +24,8 @@
*/
package com.oracle.svm.hosted.code;
+import static com.oracle.svm.core.Uninterruptible.Utils.isUninterruptible;
+
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Iterator;
@@ -92,6 +94,40 @@
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
+/**
+ * Builds a graph for each {@link CEntryPoint} method. Each graph looks roughly like the pseudocode
+ * below. Note that only the prologue may be inlined, while all other calls must never be inlined.
+ * This restriction is necessary because the prologue typically initializes well-known registers
+ * such as the heap base, so we need to make sure that nothing (not even Java heap constants) can
+ * float above the (potentially inlined) prologue logic.
+ *
+ * Besides that, we also need to prevent inlining to ensure that exception handling works correctly
+ * (see GR-24649).
+ *
+ * {@snippet :
+ * CEntryPointCallStub(args) {
+ * prologue();
+ * if (errorInPrologue) {
+ * return prologueBailout();
+ * }
+ *
+ * adaptedArgs = adaptArgumentValues(args);
+ * ensureClassInitialization();
+ * try {
+ * result = targetMethod(adaptedArgs);
+ * } catch (Throwable e) {
+ * result = exceptionHandler(e);
+ * result = adaptReturnValue(result);
+ * epilogue();
+ * return result;
+ * }
+ *
+ * result = adaptReturnValue(result);
+ * epilogue();
+ * return result;
+ * }
+ * }
+ */
public final class CEntryPointCallStubMethod extends EntryPointCallStubMethod {
static CEntryPointCallStubMethod create(BigBang bb, AnalysisMethod targetMethod, CEntryPointData entryPointData) {
MetaAccessProvider originalMetaAccess = GraalAccess.getOriginalProviders().getMetaAccess();
@@ -170,36 +206,47 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
ImageSingletons.lookup(CInterfaceWrapper.class).tagCEntryPointPrologue(kit, method);
}
+ /* Invoke the prologue. This call is the only one that may be inlined. */
InvokeWithExceptionNode invokePrologue = generatePrologue(kit, parameterLoadTypes, targetMethod.getParameterAnnotations(), args);
if (invokePrologue != null) {
ResolvedJavaMethod prologueMethod = invokePrologue.callTarget().targetMethod();
JavaKind prologueReturnKind = prologueMethod.getSignature().getReturnKind();
if (prologueReturnKind == JavaKind.Int) {
kit.startIf(kit.unique(new IntegerEqualsNode(invokePrologue, ConstantNode.forInt(0, kit.getGraph()))), BranchProbabilityNode.VERY_FAST_PATH_PROFILE);
+
+ /* Prologue returned zero, so continue execution normally. */
kit.thenPart();
+
+ /* Prologue returned non-zero, start the error handling. */
kit.elsePart();
Class> bailoutCustomizer = entryPointData.getPrologueBailout();
JavaKind targetMethodReturnKind = targetMethod.getSignature().getReturnKind();
+
+ /* Generate the default bailout logic if no custom bailout logic was registered. */
boolean createdReturnNode = false;
if (bailoutCustomizer == CEntryPointOptions.AutomaticPrologueBailout.class) {
if (targetMethodReturnKind == JavaKind.Int) {
+ /* Directly return the error code that was returned from the prologue. */
kit.createReturn(invokePrologue, JavaKind.Int);
createdReturnNode = true;
} else if (targetMethodReturnKind == JavaKind.Void) {
+ /* Swallow the error code from the prologue. */
kit.createReturn(null, JavaKind.Void);
createdReturnNode = true;
} else {
- VMError.shouldNotReachHere("@CEntryPointOptions on " + targetMethod + " must specify a custom prologue bailout as the method's return type is neither int nor void.");
+ throw VMError.shouldNotReachHere("@CEntryPointOptions on " + targetMethod + " must specify a custom prologue bailout as the method's return type is neither int nor void.");
}
}
+ /* Invoke the custom bailout logic if necessary. */
if (!createdReturnNode) {
AnalysisMethod[] bailoutMethods = kit.getMetaAccess().lookupJavaType(bailoutCustomizer).getDeclaredMethods(false);
UserError.guarantee(bailoutMethods.length == 1 && bailoutMethods[0].isStatic(), "Prologue bailout customization class must declare exactly one static method: %s -> %s",
targetMethod, bailoutCustomizer);
- InvokeWithExceptionNode invokeBailoutCustomizer = generatePrologueOrEpilogueInvoke(kit, bailoutMethods[0], invokePrologue);
+ InvokeWithExceptionNode invokeBailoutCustomizer = createInvokeStaticWithFatalExceptionHandler(kit, bailoutMethods[0], invokePrologue);
+ invokeBailoutCustomizer.setUseForInlining(false);
VMError.guarantee(bailoutMethods[0].getSignature().getReturnKind() == method.getSignature().getReturnKind(),
"Return type mismatch: %s is incompatible with %s", bailoutMethods[0], targetMethod);
kit.createReturn(invokeBailoutCustomizer, targetMethod.getSignature().getReturnKind());
@@ -211,13 +258,18 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
}
}
+ /* Convert primitive argument values to Java enums if needed. */
adaptArgumentValues(kit, parameterTypes, parameterEnumInfos, args);
+ /* Ensure that the target class is initialized. */
AnalysisMethod aTargetMethod = kit.getMetaAccess().getUniverse().lookup(targetMethod);
kit.emitEnsureInitializedCall(aTargetMethod.getDeclaringClass());
+ /*
+ * Invoke the target method that is annotated with @CEntryPoint. Also support non-static
+ * test methods by passing null as the receiver (they are not allowed to use the receiver).
+ */
int invokeBci = kit.bci();
- // Also support non-static test methods (they are not allowed to use the receiver)
InvokeKind invokeKind = aTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
ValueNode[] invokeArgs = args;
if (invokeKind != InvokeKind.Static) {
@@ -225,13 +277,17 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
invokeArgs[0] = kit.createObject(null);
System.arraycopy(args, 0, invokeArgs, 1, args.length);
}
+
InvokeWithExceptionNode invoke = kit.startInvokeWithException(aTargetMethod, invokeKind, kit.getFrameState(), invokeBci, invokeArgs);
+ invoke.setUseForInlining(false);
patchNodeSourcePosition(invoke);
+
+ /* Invoke the exception handler if an exception occurred in the target method. */
kit.exceptionPart();
- ExceptionObjectNode exception = kit.exceptionObject();
- generateExceptionHandler(method, kit, exception, invoke.getStackKind());
+ generateExceptionHandler(method, kit, kit.exceptionObject(), invoke.getStackKind());
kit.endInvokeWithException();
+ /* Invoke the epilogue and return the value that was returned from the target method. */
generateEpilogueAndReturn(method, kit, invoke);
return kit.finalizeGraph();
}
@@ -271,7 +327,8 @@ private StructuredGraph buildBuiltinGraph(DebugContext debug, AnalysisMethod met
ExecutionContextParameters executionContext = findExecutionContextParameters(kit, aTargetMethod.toParameterList(), aTargetMethod.getParameterAnnotations());
- final CEntryPoint.Builtin builtin = entryPointData.getBuiltin();
+ /* Find the target method for the built-in. */
+ CEntryPoint.Builtin builtin = entryPointData.getBuiltin();
AnalysisMethod builtinCallee = null;
for (AnalysisMethod candidate : kit.getMetaAccess().lookupJavaType(CEntryPointBuiltins.class).getDeclaredMethods(false)) {
CEntryPointBuiltinImplementation annotation = candidate.getAnnotation(CEntryPointBuiltinImplementation.class);
@@ -282,90 +339,91 @@ private StructuredGraph buildBuiltinGraph(DebugContext debug, AnalysisMethod met
}
VMError.guarantee(builtinCallee != null, "No candidate for @%s built-in %s", CEntryPoint.class.getSimpleName(), builtin);
+ /* Determine which Isolate/IsolateThread should be used as the context. */
AnalysisType isolateType = kit.getMetaAccess().lookupJavaType(Isolate.class);
AnalysisType threadType = kit.getMetaAccess().lookupJavaType(IsolateThread.class);
- int builtinIsolateIndex = -1;
- int builtinThreadIndex = -1;
+ int isolateIndex = -1;
+ int threadIndex = -1;
List builtinParamTypes = builtinCallee.toParameterList();
for (int i = 0; i < builtinParamTypes.size(); i++) {
AnalysisType type = builtinParamTypes.get(i);
if (isolateType.isAssignableFrom(type)) {
- VMError.guarantee(builtinIsolateIndex == -1, "@%s built-in with more than one %s parameter: %s",
+ VMError.guarantee(isolateIndex == -1, "@%s built-in with more than one %s parameter: %s",
CEntryPoint.class.getSimpleName(), Isolate.class.getSimpleName(), builtinCallee);
- builtinIsolateIndex = i;
+ isolateIndex = i;
} else if (threadType.isAssignableFrom(type)) {
- VMError.guarantee(builtinThreadIndex == -1, "@%s built-in with more than one %s parameter: %s",
+ VMError.guarantee(threadIndex == -1, "@%s built-in with more than one %s parameter: %s",
CEntryPoint.class.getSimpleName(), IsolateThread.class.getSimpleName(), builtinCallee);
- builtinThreadIndex = i;
+ threadIndex = i;
} else {
- VMError.shouldNotReachHere("@%s built-in currently may have only %s or %s parameters: %s",
+ throw VMError.shouldNotReachHere("@%s built-in currently may have only %s or %s parameters: %s",
CEntryPoint.class.getSimpleName(), Isolate.class.getSimpleName(), IsolateThread.class.getSimpleName(), builtinCallee);
}
}
ValueNode[] args = kit.getInitialArguments().toArray(ValueNode.EMPTY_ARRAY);
-
ValueNode[] builtinArgs = new ValueNode[builtinParamTypes.size()];
- if (builtinIsolateIndex != -1) {
+ if (isolateIndex != -1) {
VMError.guarantee(executionContext.designatedIsolateIndex != -1 || executionContext.isolateCount == 1,
"@%s built-in %s needs exactly one %s parameter: %s", CEntryPoint.class.getSimpleName(), entryPointData.getBuiltin(), Isolate.class.getSimpleName(), builtinCallee);
int index = (executionContext.designatedIsolateIndex != -1) ? executionContext.designatedIsolateIndex : executionContext.lastIsolateIndex;
- builtinArgs[builtinIsolateIndex] = args[index];
+ builtinArgs[isolateIndex] = args[index];
}
- if (builtinThreadIndex != -1) {
+ if (threadIndex != -1) {
VMError.guarantee(executionContext.designatedThreadIndex != -1 || executionContext.threadCount == 1,
"@%s built-in %s needs exactly one %s parameter: %s", CEntryPoint.class.getSimpleName(), entryPointData.getBuiltin(), IsolateThread.class.getSimpleName(), builtinCallee);
int index = (executionContext.designatedThreadIndex != -1) ? executionContext.designatedThreadIndex : executionContext.lastThreadIndex;
- builtinArgs[builtinThreadIndex] = args[index];
+ builtinArgs[threadIndex] = args[index];
}
- int invokeBci = kit.bci();
- InvokeWithExceptionNode invoke = kit.startInvokeWithException(builtinCallee, InvokeKind.Static, kit.getFrameState(), invokeBci, builtinArgs);
- kit.exceptionPart();
- ExceptionObjectNode exception = kit.exceptionObject();
+ /* Invoke the target method. */
+ InvokeWithExceptionNode invoke = kit.startInvokeWithException(builtinCallee, InvokeKind.Static, kit.getFrameState(), kit.bci(), builtinArgs);
- generateExceptionHandler(method, kit, exception, invoke.getStackKind());
+ /* Invoke the exception handler if an exception occurred in the target method. */
+ kit.exceptionPart();
+ generateExceptionHandler(method, kit, kit.exceptionObject(), invoke.getStackKind());
kit.endInvokeWithException();
if (ImageSingletons.contains(CInterfaceWrapper.class)) {
ImageSingletons.lookup(CInterfaceWrapper.class).tagCEntryPointEpilogue(kit, method);
}
+ /* Return the result. */
kit.createReturn(invoke, aTargetMethod.getSignature().getReturnKind());
-
return kit.finalizeGraph();
}
/**
* The signature may contain Java object types. The only Java object types that we support at
- * the moment are Java enums (annotated with @CEnum). This method replaces all Java enums with
- * suitable primitive types.
+ * the moment are Java enums (annotated with {@link CEnum}). This method replaces all Java enums
+ * with suitable primitive types.
*/
private EnumInfo[] adaptParameterTypes(NativeLibraries nativeLibraries, HostedGraphKit kit, List parameterTypes, List parameterLoadTypes) {
EnumInfo[] parameterEnumInfos = null;
for (int i = 0; i < parameterTypes.size(); i++) {
- if (!CInterfaceEnumTool.isPrimitiveOrWord(parameterTypes.get(i))) {
- EnumInfo enumInfo = getEnumInfo(nativeLibraries, targetMethod, parameterTypes.get(i), false);
- UserError.guarantee(enumInfo.hasCEnumLookupMethods(),
- "Enum class %s needs a method that is annotated with @%s because it is used as a parameter of an entry point method: %s",
- parameterTypes.get(i), CEnumLookup.class.getSimpleName(), targetMethod);
-
- if (parameterEnumInfos == null) {
- parameterEnumInfos = new EnumInfo[parameterTypes.size()];
- }
- parameterEnumInfos[i] = enumInfo;
-
- /* The argument is a @CEnum, so change the type to a primitive type. */
- AnalysisType paramType = CInterfaceEnumTool.getCEnumValueType(enumInfo, kit.getMetaAccess());
- parameterLoadTypes.set(i, paramType);
-
- final int parameterIndex = i;
- FrameState initialState = kit.getGraph().start().stateAfter();
- Iterator matchingNodes = initialState.values().filter(node -> ((ParameterNode) node).index() == parameterIndex).iterator();
- ValueNode parameterNode = matchingNodes.next();
- assert !matchingNodes.hasNext() && parameterNode.usages().filter(n -> n != initialState).isEmpty();
- parameterNode.setStamp(StampFactory.forKind(paramType.getJavaKind()));
+ if (CInterfaceEnumTool.isPrimitiveOrWord(parameterTypes.get(i))) {
+ continue;
+ }
+
+ EnumInfo enumInfo = getEnumInfo(nativeLibraries, targetMethod, parameterTypes.get(i), false);
+ UserError.guarantee(enumInfo.hasCEnumLookupMethods(), "Enum class %s needs a method that is annotated with @%s because it is used as a parameter of an entry point method: %s",
+ parameterTypes.get(i), CEnumLookup.class.getSimpleName(), targetMethod);
+
+ if (parameterEnumInfos == null) {
+ parameterEnumInfos = new EnumInfo[parameterTypes.size()];
}
+ parameterEnumInfos[i] = enumInfo;
+
+ /* The argument is a @CEnum, so change the type to a primitive type. */
+ AnalysisType paramType = CInterfaceEnumTool.getCEnumValueType(enumInfo, kit.getMetaAccess());
+ parameterLoadTypes.set(i, paramType);
+
+ final int parameterIndex = i;
+ FrameState initialState = kit.getGraph().start().stateAfter();
+ Iterator matchingNodes = initialState.values().filter(node -> ((ParameterNode) node).index() == parameterIndex).iterator();
+ ValueNode parameterNode = matchingNodes.next();
+ assert !matchingNodes.hasNext() && parameterNode.usages().filter(n -> n != initialState).isEmpty();
+ parameterNode.setStamp(StampFactory.forKind(paramType.getJavaKind()));
}
return parameterEnumInfos;
}
@@ -384,13 +442,16 @@ private static EnumInfo getEnumInfo(NativeLibraries nativeLibraries, ResolvedJav
CEnum.class.getSimpleName(), method, type);
}
+ /** Converts primitive argument values to Java enums if necessary, see {@link CEnum}. */
private static void adaptArgumentValues(HostedGraphKit kit, List parameterTypes, EnumInfo[] parameterEnumInfos, ValueNode[] args) {
- if (parameterEnumInfos != null) {
- // These methods must be called after the prologue established a safe context
- for (int i = 0; i < parameterEnumInfos.length; i++) {
- if (parameterEnumInfos[i] != null) {
- args[i] = CInterfaceEnumTool.singleton().createInvokeLookupEnum(kit, parameterTypes.get(i), parameterEnumInfos[i], args[i]);
- }
+ if (parameterEnumInfos == null) {
+ /* No conversion necessary. */
+ return;
+ }
+
+ for (int i = 0; i < parameterEnumInfos.length; i++) {
+ if (parameterEnumInfos[i] != null) {
+ args[i] = CInterfaceEnumTool.singleton().createInvokeLookupEnum(kit, parameterTypes.get(i), parameterEnumInfos[i], args[i], false);
}
}
}
@@ -398,28 +459,21 @@ private static void adaptArgumentValues(HostedGraphKit kit, List p
private InvokeWithExceptionNode generatePrologue(HostedGraphKit kit, List parameterTypes, Annotation[][] parameterAnnotations, ValueNode[] args) {
Class> prologueClass = entryPointData.getPrologue();
if (prologueClass == NoPrologue.class) {
- UserError.guarantee(Uninterruptible.Utils.isUninterruptible(targetMethod),
- "%s.%s is allowed only for methods annotated with @%s: %s",
- CEntryPointOptions.class.getSimpleName(),
- NoPrologue.class.getSimpleName(),
- Uninterruptible.class.getSimpleName(),
- targetMethod);
+ UserError.guarantee(isUninterruptible(targetMethod), "%s.%s is allowed only for methods annotated with @%s: %s",
+ CEntryPointOptions.class.getSimpleName(), NoPrologue.class.getSimpleName(), Uninterruptible.class.getSimpleName(), targetMethod);
return null;
}
+
+ /* Generate a call to a custom prologue method, if one is registered. */
if (prologueClass != CEntryPointOptions.AutomaticPrologue.class) {
AnalysisType prologue = kit.getMetaAccess().lookupJavaType(prologueClass);
AnalysisMethod[] prologueMethods = prologue.getDeclaredMethods(false);
- UserError.guarantee(prologueMethods.length == 1 && prologueMethods[0].isStatic(),
- "Prologue class must declare exactly one static method: %s -> %s",
- targetMethod,
- prologue);
- UserError.guarantee(Uninterruptible.Utils.isUninterruptible(prologueMethods[0]),
- "Prologue method must be annotated with @%s: %s", Uninterruptible.class.getSimpleName(), prologueMethods[0]);
+ UserError.guarantee(prologueMethods.length == 1 && prologueMethods[0].isStatic(), "Prologue class must declare exactly one static method: %s -> %s", targetMethod, prologue);
ValueNode[] prologueArgs = matchPrologueParameters(kit, parameterTypes, args, prologueMethods[0]);
- return generatePrologueOrEpilogueInvoke(kit, prologueMethods[0], prologueArgs);
+ return createInvokeStaticWithFatalExceptionHandler(kit, prologueMethods[0], prologueArgs);
}
- // Automatically choose prologue from signature and annotations and call
+ /* Find the IsolateThread argument that should be used as the context. */
ExecutionContextParameters executionContext = findExecutionContextParameters(kit, parameterTypes, parameterAnnotations);
int contextIndex = -1;
if (executionContext.designatedThreadIndex != -1) {
@@ -427,19 +481,24 @@ private InvokeWithExceptionNode generatePrologue(HostedGraphKit kit, List %s",
- targetMethod,
- prologueMethod);
+ UserError.guarantee(prologueType.isPrimitive() || kit.getWordTypes().isWord(prologueType), "Prologue method parameter types are restricted to primitive types and word types: %s -> %s",
+ targetMethod, prologueMethod);
while (i < types.size() && !prologueType.isAssignableFrom(types.get(i))) {
i++;
}
+
if (i >= types.size()) {
- throw UserError.abort("Unable to match signature of entry point method to that of prologue method: %s -> %s",
- targetMethod,
- prologueMethod);
+ throw UserError.abort("Unable to match signature of entry point method to that of prologue method: %s -> %s", targetMethod, prologueMethod);
}
prologueValues[p] = values[i];
i++;
@@ -541,61 +587,73 @@ private ValueNode[] matchPrologueParameters(HostedGraphKit kit, List %s", targetMethod, handler);
- UserError.guarantee(Uninterruptible.Utils.isUninterruptible(handlerMethods[0]),
- "Exception handler method must be annotated with @%s: %s", Uninterruptible.class.getSimpleName(), handlerMethods[0]);
- List handlerParameterTypes = handlerMethods[0].toParameterList();
- UserError.guarantee(handlerParameterTypes.size() == 1 &&
- handlerParameterTypes.get(0).isAssignableFrom(throwable),
- "Exception handler method must have exactly one parameter of type Throwable: %s -> %s", targetMethod, handlerMethods[0]);
- InvokeWithExceptionNode handlerInvoke = kit.startInvokeWithException(handlerMethods[0], InvokeKind.Static, kit.getFrameState(), kit.bci(), exception);
- kit.noExceptionPart();
- ValueNode returnValue = handlerInvoke;
- if (handlerInvoke.getStackKind() != returnKind) {
- JavaKind fromKind = handlerInvoke.getStackKind();
- if (fromKind == JavaKind.Float && returnKind == JavaKind.Double) {
- returnValue = kit.unique(new FloatConvertNode(FloatConvert.F2D, returnValue));
- } else if (fromKind.isUnsigned() && returnKind.isNumericInteger() && returnKind.getBitCount() > fromKind.getBitCount()) {
- returnValue = kit.unique(new ZeroExtendNode(returnValue, returnKind.getBitCount()));
- } else if (fromKind.isNumericInteger() && returnKind.isNumericInteger() && returnKind.getBitCount() > fromKind.getBitCount()) {
- returnValue = kit.unique(new SignExtendNode(returnValue, returnKind.getBitCount()));
- } else {
- throw UserError.abort("Exception handler method return type must be assignable to entry point method return type: %s -> %s",
- targetMethod, handlerMethods[0]);
- }
- }
-
- /* The exception is handled, we can continue with the normal epilogue. */
- generateEpilogueAndReturn(method, kit, returnValue);
+ return;
+ }
- kit.exceptionPart(); // fail-safe for exceptions in exception handler
- kit.append(new CEntryPointLeaveNode(LeaveAction.ExceptionAbort, kit.exceptionObject()));
- kit.append(new LoweredDeadEndNode());
- kit.endInvokeWithException();
+ /* Determine which method was registered as the exception handler. */
+ AnalysisType throwable = kit.getMetaAccess().lookupJavaType(Throwable.class);
+ AnalysisType handler = kit.getMetaAccess().lookupJavaType(entryPointData.getExceptionHandler());
+ AnalysisMethod[] handlerMethods = handler.getDeclaredMethods(false);
+ UserError.guarantee(handlerMethods.length == 1 && handlerMethods[0].isStatic(), "Exception handler class must declare exactly one static method: %s -> %s", targetMethod, handler);
+ UserError.guarantee(isUninterruptible(handlerMethods[0]), "Exception handler method must be annotated with @%s: %s", Uninterruptible.class.getSimpleName(), handlerMethods[0]);
+
+ List handlerParameterTypes = handlerMethods[0].toParameterList();
+ UserError.guarantee(handlerParameterTypes.size() == 1 && handlerParameterTypes.getFirst().isAssignableFrom(throwable),
+ "Exception handler method must have exactly one parameter of type Throwable: %s -> %s", targetMethod, handlerMethods[0]);
+
+ /* Invoke the exception handler method. */
+ InvokeWithExceptionNode handlerInvoke = kit.startInvokeWithException(handlerMethods[0], InvokeKind.Static, kit.getFrameState(), kit.bci(), exception);
+ handlerInvoke.setUseForInlining(false);
+
+ /*
+ * The exception handler method finished successfully. Invoke the epilogue and return the
+ * value that was returned from the exception handler method.
+ */
+ kit.noExceptionPart();
+ ValueNode returnValue = handlerInvoke;
+ if (handlerInvoke.getStackKind() != returnKind) {
+ JavaKind fromKind = handlerInvoke.getStackKind();
+ if (fromKind == JavaKind.Float && returnKind == JavaKind.Double) {
+ returnValue = kit.unique(new FloatConvertNode(FloatConvert.F2D, returnValue));
+ } else if (fromKind.isUnsigned() && returnKind.isNumericInteger() && returnKind.getBitCount() > fromKind.getBitCount()) {
+ returnValue = kit.unique(new ZeroExtendNode(returnValue, returnKind.getBitCount()));
+ } else if (fromKind.isNumericInteger() && returnKind.isNumericInteger() && returnKind.getBitCount() > fromKind.getBitCount()) {
+ returnValue = kit.unique(new SignExtendNode(returnValue, returnKind.getBitCount()));
+ } else {
+ throw UserError.abort("Exception handler method return type must be assignable to entry point method return type: %s -> %s",
+ targetMethod, handlerMethods[0]);
+ }
}
+ generateEpilogueAndReturn(method, kit, returnValue);
+
+ /* The exception handler method threw an exception. This is a fatal error. */
+ kit.exceptionPart();
+ kit.append(new CEntryPointLeaveNode(LeaveAction.ExceptionAbort, kit.exceptionObject()));
+ kit.append(new LoweredDeadEndNode());
+ kit.endInvokeWithException();
}
+ /** Converts a Java enum to a primitive value if necessary, see {@link CEnum}. */
private ValueNode adaptReturnValue(HostedGraphKit kit, ValueNode value) {
if (value.getStackKind().isPrimitive()) {
+ /* No conversion necessary. */
return value;
}
- /* The method returns a Java enum, so we need to convert the enum to a primitive value. */
AnalysisType returnType = targetSignature.getReturnType();
NativeLibraries nativeLibraries = NativeLibraries.singleton();
-
EnumInfo enumInfo = getEnumInfo(nativeLibraries, targetMethod, returnType, true);
- ValueNode result = CInterfaceEnumTool.singleton().startInvokeWithExceptionEnumToValue(kit, enumInfo, CInterfaceEnumTool.getCEnumValueType(enumInfo, kit.getMetaAccess()), value);
- result = kit.getGraph().unique(new ZeroExtendNode(result, kit.getWordTypes().getWordKind().getBitCount()));
+ /* Invoke the method that does the conversion from Java enum to primitive value. */
+ InvokeWithExceptionNode invoke = CInterfaceEnumTool.singleton().startInvokeWithExceptionEnumToValue(kit, enumInfo, CInterfaceEnumTool.getCEnumValueType(enumInfo, kit.getMetaAccess()), value);
+ invoke.setUseForInlining(false);
+ ValueNode result = kit.getGraph().unique(new ZeroExtendNode(invoke, kit.getWordTypes().getWordKind().getBitCount()));
+
+ /* Exceptions during the conversion are fatal. */
kit.exceptionPart();
kit.append(new CEntryPointLeaveNode(LeaveAction.ExceptionAbort, kit.exceptionObject()));
kit.append(new LoweredDeadEndNode());
@@ -606,21 +664,18 @@ private ValueNode adaptReturnValue(HostedGraphKit kit, ValueNode value) {
private void generateEpilogue(HostedGraphKit kit) {
Class> epilogueClass = entryPointData.getEpilogue();
if (epilogueClass == NoEpilogue.class) {
- UserError.guarantee(Uninterruptible.Utils.isUninterruptible(targetMethod),
- "%s.%s is allowed only for methods annotated with @%s: %s",
- CEntryPointOptions.class.getSimpleName(),
- NoEpilogue.class.getSimpleName(),
- Uninterruptible.class.getSimpleName(),
- targetMethod);
+ UserError.guarantee(isUninterruptible(targetMethod), "%s.%s is allowed only for methods annotated with @%s: %s",
+ CEntryPointOptions.class.getSimpleName(), NoEpilogue.class.getSimpleName(), Uninterruptible.class.getSimpleName(), targetMethod);
return;
}
+
AnalysisType epilogue = kit.getMetaAccess().lookupJavaType(epilogueClass);
AnalysisMethod[] epilogueMethods = epilogue.getDeclaredMethods(false);
UserError.guarantee(epilogueMethods.length == 1 && epilogueMethods[0].isStatic() && epilogueMethods[0].getSignature().getParameterCount(false) == 0,
"Epilogue class must declare exactly one static method without parameters: %s -> %s", targetMethod, epilogue);
- UserError.guarantee(Uninterruptible.Utils.isUninterruptible(epilogueMethods[0]),
- "Epilogue method must be annotated with @%s: %s", Uninterruptible.class.getSimpleName(), epilogueMethods[0]);
- generatePrologueOrEpilogueInvoke(kit, epilogueMethods[0]);
+
+ InvokeWithExceptionNode invoke = createInvokeStaticWithFatalExceptionHandler(kit, epilogueMethods[0]);
+ invoke.setUseForInlining(false);
}
public boolean isNotPublished() {
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceEnumTool.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceEnumTool.java
index 426cceb807a0..0c03a95d798e 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceEnumTool.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceEnumTool.java
@@ -139,7 +139,7 @@ public ValueNode createInvokeEnumToValue(HostedGraphKit kit, EnumInfo enumInfo,
return kit.createInvokeWithExceptionAndUnwind(callTarget, kit.getFrameState(), invokeBci);
}
- public ValueNode startInvokeWithExceptionEnumToValue(HostedGraphKit kit, EnumInfo enumInfo, AnalysisType returnType, ValueNode arg) {
+ public InvokeWithExceptionNode startInvokeWithExceptionEnumToValue(HostedGraphKit kit, EnumInfo enumInfo, AnalysisType returnType, ValueNode arg) {
int invokeBci = kit.bci();
MethodCallTargetNode callTarget = createInvokeEnumToValue(kit, CallTargetFactory.from(kit), invokeBci, enumInfo, returnType, arg);
return kit.startInvokeWithException(callTarget, kit.getFrameState(), invokeBci);
@@ -183,11 +183,14 @@ private AnalysisMethod getEnumToValueMethod(GraphBuilderTool b, AnalysisType ret
};
}
- public ValueNode createInvokeLookupEnum(HostedGraphKit kit, AnalysisType enumType, EnumInfo enumInfo, ValueNode arg) {
- // Create the invocation of the actual target method: EnumRuntimeData.convertCToJava
+ public ValueNode createInvokeLookupEnum(HostedGraphKit kit, AnalysisType enumType, EnumInfo enumInfo, ValueNode arg, boolean allowInlining) {
+ // Invoke the conversion function (from long to enum)
int invokeBci = kit.bci();
MethodCallTargetNode callTarget = createInvokeLongToEnum(kit, CallTargetFactory.from(kit), invokeBci, enumInfo, arg);
InvokeWithExceptionNode invoke = kit.createInvokeWithExceptionAndUnwind(callTarget, kit.getFrameState(), invokeBci);
+ if (!allowInlining) {
+ invoke.setUseForInlining(false);
+ }
// Create the instanceof guard to narrow the return type for the analysis
LogicNode instanceOfNode = kit.append(InstanceOfNode.createAllowNull(TypeReference.createExactTrusted(enumType), invoke, null, null));