Skip to content

Commit f9ea58d

Browse files
fangererotethal
authored andcommitted
Allow ext funcs without exceptions
1 parent 25da6db commit f9ea58d

2 files changed

Lines changed: 92 additions & 78 deletions

File tree

‎graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java‎

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,7 @@ private static final class CApiExternalFunctionSignatureDesc {
10651065

10661066
String returnType;
10671067
String[] argumentTypes;
1068+
public boolean cannotRaise;
10681069

10691070
public CApiExternalFunctionSignatureDesc(VariableElement origin, String name) {
10701071
this.origin = origin;
@@ -1246,8 +1247,9 @@ private void generateExternalFunctionInvoker(List<CApiExternalFunctionSignatureD
12461247
lines.add(" }");
12471248
lines.add("");
12481249
lines.add(" @SuppressWarnings(\"restricted\")");
1249-
lines.add(" private static MethodHandle createDowncallHandle(MethodType methodType) {");
1250+
lines.add(" private static MethodHandle createDowncallHandle(MethodType methodType, boolean critical) {");
12501251
lines.add(" FunctionDescriptor functionDescriptor = createFunctionDescriptor(methodType);");
1252+
lines.add(" Linker.Option[] options = critical ? new Linker.Option[] { Linker.Option.critical(false) } : new Linker.Option[0];");
12511253
lines.add(" MethodHandle methodHandle = Linker.nativeLinker().downcallHandle(functionDescriptor);");
12521254
lines.add(" methodHandle = MethodHandles.filterArguments(methodHandle, 0, OF_ADDRESS);");
12531255
lines.add(" return methodHandle.asType(methodType);");
@@ -1292,11 +1294,12 @@ private void generateExternalFunctionInvoker(List<CApiExternalFunctionSignatureD
12921294
int end = externalFunctionSignatureInitializer.lastIndexOf(')');
12931295
String[] initArgs = externalFunctionSignatureInitializer.substring(start + 1, end).split(",");
12941296

1297+
assert !sig.cannotRaise;
1298+
sig.cannotRaise = Boolean.valueOf(initArgs[0].strip());
12951299
assert sig.returnType == null;
1296-
sig.returnType = initArgs[0].strip();
1300+
sig.returnType = initArgs[1].strip();
12971301
assert sig.argumentTypes == null;
1298-
sig.argumentTypes = Arrays.stream(initArgs).skip(1).map(String::strip).toArray(String[]::new);
1299-
1302+
sig.argumentTypes = Arrays.stream(initArgs).skip(2).map(String::strip).toArray(String[]::new);
13001303
}
13011304

13021305
for (CApiExternalFunctionSignatureDesc sig : signatures) {
@@ -1333,40 +1336,42 @@ private void generateExternalFunctionInvoker(List<CApiExternalFunctionSignatureD
13331336
methodTypeArgs.add(toClassLiteral(argType));
13341337
}
13351338
lines.add(" private static final MethodHandle " + getNfiMethodHandleVarName(sig.name) + " = createDowncallHandle(" +
1336-
"MethodType.methodType(" + returnTypeLiteral + ", " + String.join(", ", methodTypeArgs) + "));");
1339+
"MethodType.methodType(" + returnTypeLiteral + ", " + String.join(", ", methodTypeArgs) + "), false);");
13371340
}
13381341

13391342
lines.add("");
1340-
lines.add(" public static " + returnType + " invoke" + sig.name + "(" + String.join(", ", invokeArgs) + ") {");
1341-
for (int j = 0; j < argTypes.size(); j++) {
1342-
if (argTypes.get(j).contains("PyObject")) {
1343-
lines.add(" assert EnsurePythonObjectNode.doesNotNeedPromotion(" + argName(j) + ");");
1343+
if (!sig.cannotRaise) {
1344+
lines.add(" public static " + returnType + " invoke" + sig.name + "(" + String.join(", ", invokeArgs) + ") {");
1345+
for (int j = 0; j < argTypes.size(); j++) {
1346+
if (argTypes.get(j).contains("PyObject")) {
1347+
lines.add(" assert EnsurePythonObjectNode.doesNotNeedPromotion(" + argName(j) + ");");
1348+
}
13441349
}
1345-
}
1346-
String returnStmt = isVoidReturn ? "" : "return ";
1350+
String returnStmt = isVoidReturn ? "" : "return ";
13471351

1348-
lines.add(" // If any code requested the caught exception (i.e. used 'sys.exc_info()'), we store;");
1349-
lines.add(" // it to the context since we cannot propagate it through the native frames.");
1350-
lines.add("");
1351-
lines.add(" Object state = BoundaryCallContext.enter(frame, threadState, boundaryCallData);");
1352-
lines.add(" CApiTiming.enter();");
1353-
lines.add(" try {");
1354-
lines.add(" " + returnStmt + "invoke" + sig.name + "(" +
1355-
"nfiFunction.getAddress()" +
1356-
(cArgs.isEmpty() ? "" : ", " + String.join(", ", cArgs)) + ");");
1357-
lines.add(" } catch (Throwable exception) {");
1358-
lines.add(" CompilerDirectives.transferToInterpreterAndInvalidate();");
1359-
lines.add(" GilNode.uncachedAcquire();");
1360-
lines.add(" throw CompilerDirectives.shouldNotReachHere(exception);");
1361-
lines.add(" } finally {");
1362-
lines.add(" CApiTiming.exit(timing);");
1363-
lines.add(" if (frame != null && threadState.getCaughtException() != null) {");
1364-
lines.add(" PArguments.setException(frame, threadState.getCaughtException());");
1365-
lines.add(" }");
1366-
lines.add(" BoundaryCallContext.exit(frame, threadState, state);");
1367-
lines.add(" }");
1368-
lines.add(" }");
1369-
lines.add("");
1352+
lines.add(" // If any code requested the caught exception (i.e. used 'sys.exc_info()'), we store;");
1353+
lines.add(" // it to the context since we cannot propagate it through the native frames.");
1354+
lines.add("");
1355+
lines.add(" Object state = BoundaryCallContext.enter(frame, threadState, boundaryCallData);");
1356+
lines.add(" CApiTiming.enter();");
1357+
lines.add(" try {");
1358+
lines.add(" " + returnStmt + "invoke" + sig.name + "(" +
1359+
"nfiFunction.getAddress()" +
1360+
(cArgs.isEmpty() ? "" : ", " + String.join(", ", cArgs)) + ");");
1361+
lines.add(" } catch (Throwable exception) {");
1362+
lines.add(" CompilerDirectives.transferToInterpreterAndInvalidate();");
1363+
lines.add(" GilNode.uncachedAcquire();");
1364+
lines.add(" throw CompilerDirectives.shouldNotReachHere(exception);");
1365+
lines.add(" } finally {");
1366+
lines.add(" CApiTiming.exit(timing);");
1367+
lines.add(" if (frame != null && threadState.getCaughtException() != null) {");
1368+
lines.add(" PArguments.setException(frame, threadState.getCaughtException());");
1369+
lines.add(" }");
1370+
lines.add(" BoundaryCallContext.exit(frame, threadState, state);");
1371+
lines.add(" }");
1372+
lines.add(" }");
1373+
lines.add("");
1374+
}
13701375

13711376
List<String> rawInvokeArgs = new LinkedList<>();
13721377
rawInvokeArgs.add("long function");

‎graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionSignature.java‎

Lines changed: 54 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -64,104 +64,113 @@
6464
@CApiExternalFunctionSignatures
6565
public enum ExternalFunctionSignature implements NativeCExtSymbol {
6666
// typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
67-
PYCFUNCTION(PyObjectReturn, PyObject, PyObject),
67+
PYCFUNCTION(false, PyObjectReturn, PyObject, PyObject),
6868
// typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *, PyObject *);
69-
PYCFUNCTION_WITH_KEYWORDS(PyObjectReturn, PyObject, PyObject, PyObject),
69+
PYCFUNCTION_WITH_KEYWORDS(false, PyObjectReturn, PyObject, PyObject, PyObject),
7070
// typedef PyObject *(*_PyCFunctionFast) (PyObject *, PyObject *const *, Py_ssize_t);
71-
PYCFUNCTION_FAST(PyObjectReturn, PyObject, Pointer, Py_ssize_t),
71+
PYCFUNCTION_FAST(false, PyObjectReturn, PyObject, Pointer, Py_ssize_t),
7272
// typedef PyObject *(*_PyCFunctionFastWithKeywords) (PyObject *, PyObject *const *, Py_ssize_t,
7373
// PyObject *);
74-
PYCFUNCTION_FAST_WITH_KEYWORDS(PyObjectReturn, PyObject, Pointer, Py_ssize_t, PyObject),
74+
PYCFUNCTION_FAST_WITH_KEYWORDS(false, PyObjectReturn, PyObject, Pointer, Py_ssize_t, PyObject),
7575
// typedef PyObject *(*PyCMethod)(PyObject *, PyTypeObject *, PyObject *const *, size_t,
7676
// PyObject *);
77-
PYCMETHOD(PyObjectReturn, PyObject, PyTypeObject, Pointer, Py_ssize_t, PyObject),
77+
PYCMETHOD(false, PyObjectReturn, PyObject, PyTypeObject, Pointer, Py_ssize_t, PyObject),
7878

7979
// typedef PyObject * (*unaryfunc)(PyObject *);
80-
UNARYFUNC(PyObjectReturn, PyObject),
80+
UNARYFUNC(false, PyObjectReturn, PyObject),
8181
// typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
82-
BINARYFUNC(PyObjectReturn, PyObject, PyObject),
82+
BINARYFUNC(false, PyObjectReturn, PyObject, PyObject),
8383
// typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
84-
TERNARYFUNC(PyObjectReturn, PyObject, PyObject, PyObject),
84+
TERNARYFUNC(false, PyObjectReturn, PyObject, PyObject, PyObject),
8585
// typedef int (*inquiry)(PyObject *);
86-
INQUIRY(Int, PyObject),
86+
INQUIRY(false, Int, PyObject),
8787
// typedef Py_ssize_t (*lenfunc)(PyObject *);
88-
LENFUNC(PrimitiveResult64, PyObject),
88+
LENFUNC(false, PrimitiveResult64, PyObject),
8989
// typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
90-
SSIZEARGFUNC(PyObjectReturn, PyObject, Py_ssize_t),
90+
SSIZEARGFUNC(false, PyObjectReturn, PyObject, Py_ssize_t),
9191

9292
// typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
93-
SSIZESSIZEARGFUNC(PyObjectReturn, PyObject, Py_ssize_t, Py_ssize_t),
93+
SSIZESSIZEARGFUNC(false, PyObjectReturn, PyObject, Py_ssize_t, Py_ssize_t),
9494
// typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
95-
SSIZEOBJARGPROC(Int, PyObject, Py_ssize_t, PyObject),
95+
SSIZEOBJARGPROC(false, Int, PyObject, Py_ssize_t, PyObject),
9696
// typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
97-
SSIZESSIZEOBJARGPROC(Int, PyObject, Py_ssize_t, Py_ssize_t, PyObject),
97+
SSIZESSIZEOBJARGPROC(false, Int, PyObject, Py_ssize_t, Py_ssize_t, PyObject),
9898
// typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *);
99-
OBJOBJARGPROC(Int, PyObject, PyObject, PyObject),
99+
OBJOBJARGPROC(false, Int, PyObject, PyObject, PyObject),
100100

101101
// typedef int (*objobjproc)(PyObject *, PyObject *);
102-
OBJOBJPROC(Int, PyObject, PyObject),
102+
OBJOBJPROC(false, Int, PyObject, PyObject),
103103
// typedef int (*visitproc)(PyObject *, void *);
104-
VISITPROC(Int, PyObject, Pointer),
104+
VISITPROC(false, Int, PyObject, Pointer),
105105
// typedef int (*traverseproc)(PyObject *, visitproc, void *);
106-
TRAVERSEPROC(Int, PyObject, Pointer, Pointer),
106+
TRAVERSEPROC(false, Int, PyObject, Pointer, Pointer),
107107
// PyObject *PyType_GenericAlloc(PyTypeObject *, Py_ssize_t);
108-
TYPE_GENERIC_ALLOC(PyObjectReturn, PyTypeObject, Py_ssize_t),
108+
TYPE_GENERIC_ALLOC(false, PyObjectReturn, PyTypeObject, Py_ssize_t),
109109

110110
// typedef void (*freefunc)(void *);
111-
FREEFUNC(Void, Pointer),
111+
FREEFUNC(false, Void, Pointer),
112112
// typedef void (*destructor)(PyObject *);
113-
DESTRUCTOR(Void, PyObject),
113+
DESTRUCTOR(false, Void, PyObject),
114114
// void _Py_Dealloc(PyObject *);
115-
PY_DEALLOC(Void, PyObject),
115+
PY_DEALLOC(false, Void, PyObject),
116116
// typedef PyObject *(*getattrfunc)(PyObject *, char *);
117-
GETATTRFUNC(PyObjectReturn, PyObject, CharPtrAsTruffleString),
117+
GETATTRFUNC(false, PyObjectReturn, PyObject, CharPtrAsTruffleString),
118118
// typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
119-
GETATTROFUNC(PyObjectReturn, PyObject, PyObject),
119+
GETATTROFUNC(false, PyObjectReturn, PyObject, PyObject),
120120
// typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
121-
SETATTRFUNC(Int, PyObject, CharPtrAsTruffleString, PyObject),
121+
SETATTRFUNC(false, Int, PyObject, CharPtrAsTruffleString, PyObject),
122122
// typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *);
123-
SETATTROFUNC(Int, PyObject, PyObject, PyObject),
123+
SETATTROFUNC(false, Int, PyObject, PyObject, PyObject),
124124
// typedef PyObject *(*reprfunc)(PyObject *);
125-
REPRFUNC(PyObjectReturn, PyObject),
125+
REPRFUNC(false, PyObjectReturn, PyObject),
126126
// typedef Py_hash_t (*hashfunc)(PyObject *);
127-
HASHFUNC(Py_ssize_t, PyObject),
127+
HASHFUNC(false, Py_ssize_t, PyObject),
128128
// typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
129-
RICHCMPFUNC(PyObjectReturn, PyObject, PyObject, Int),
129+
RICHCMPFUNC(false, PyObjectReturn, PyObject, PyObject, Int),
130130
// typedef PyObject *(*getiterfunc) (PyObject *);
131-
GETITERFUNC(PyObjectReturn, PyObject),
131+
GETITERFUNC(false, PyObjectReturn, PyObject),
132132
// typedef PyObject *(*iternextfunc) (PyObject *);
133-
ITERNEXTFUNC(PyObjectReturn, PyObject),
133+
ITERNEXTFUNC(false, PyObjectReturn, PyObject),
134134
// typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
135-
DESCRGETFUNC(PyObjectReturn, PyObject, PyObject, PyObject),
135+
DESCRGETFUNC(false, PyObjectReturn, PyObject, PyObject, PyObject),
136136
// typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
137-
DESCRSETFUNC(Int, PyObject, PyObject, PyObject),
137+
DESCRSETFUNC(false, Int, PyObject, PyObject, PyObject),
138138
// typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
139-
INITPROC(Int, PyObject, PyObject, PyObject),
139+
INITPROC(false, Int, PyObject, PyObject, PyObject),
140140
// typedef PyObject *(*newfunc)(PyTypeObject *, PyObject *, PyObject *);
141-
NEWFUNC(PyObjectReturn, PyTypeObject, PyObject, PyObject),
141+
NEWFUNC(false, PyObjectReturn, PyTypeObject, PyObject, PyObject),
142142

143143
// typedef PyObject *(*getter)(PyObject *, void *);
144-
GETTER(PyObjectReturn, PyObject, Pointer),
144+
GETTER(false, PyObjectReturn, PyObject, Pointer),
145145
// typedef int (*setter)(PyObject *, PyObject *, void *);
146-
SETTER(Int, PyObject, PyObject, Pointer),
146+
SETTER(false, Int, PyObject, PyObject, Pointer),
147147
// typedef PyObject *(*Py_mod_create)(PyObject *, PyModuleDef *);
148-
MODCREATE(PyObjectReturn, Pointer, Pointer),
148+
MODCREATE(false, PyObjectReturn, Pointer, Pointer),
149149
// typedef int (*Py_mod_exec)(PyObject *);
150-
MODEXEC(Int, Pointer),
150+
MODEXEC(false, Int, Pointer),
151151
// typedef PyObject *(*PyInit_mod)(void);
152-
MODINIT(Pointer),
153-
// typedef void (*initialize_graal_capi)(void *, void *, void *, void *);
154-
CAPIINIT(Void, Pointer, Pointer, Pointer, Pointer),
152+
MODINIT(false, Pointer),
153+
// typedef PThreadState** (*initialize_graal_capi)(void *, void *, void *, void *);
154+
CAPIINIT(false, Pointer, Pointer, Pointer, Pointer, Pointer),
155155
// typedef void *(*GraalPyPrivate_GetFinalizeCApiPointer)(void);
156-
GETFINALIZECAPIPOINTER(Pointer),
156+
GETFINALIZECAPIPOINTER(false, Pointer),
157157

158158
// TODO(fa): should be an implicit signature
159-
GCCOLLECT(Py_ssize_t, Int);
159+
GCCOLLECT(false, Py_ssize_t, Int),
160+
GETDICTPTRFUN(true, Pointer, PyObject);
160161

161162
public final ArgDescriptor returnValue;
162163
public final ArgDescriptor[] arguments;
163164

164-
ExternalFunctionSignature(ArgDescriptor returnValue, ArgDescriptor... arguments) {
165+
/**
166+
* If {@code true}, the function will be called without a call boundary (see
167+
* {@link com.oracle.graal.python.runtime.ExecutionContext.BoundaryCallContext}). Hence, the
168+
* native function must not raise Python exception.
169+
*/
170+
public final boolean cannotRaise;
171+
172+
ExternalFunctionSignature(boolean cannotRaise, ArgDescriptor returnValue, ArgDescriptor... arguments) {
173+
this.cannotRaise = cannotRaise;
165174
this.returnValue = returnValue;
166175
this.arguments = arguments;
167176
}

0 commit comments

Comments
 (0)