Skip to content

Commit d22ad91

Browse files
committed
Introduce C landing functions.
1 parent 49d0455 commit d22ad91

8 files changed

Lines changed: 140 additions & 37 deletions

File tree

‎graalpython/com.oracle.graal.python.cext/src/capi.c‎

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,15 +156,19 @@ static inline PyObject* PyTruffle_Explicit_Cast(PyObject* cobj, unsigned long fl
156156
}
157157

158158

159-
PyObject* to_sulong(void *o) {
160-
PyObject* cobj = truffle_invoke(PY_TRUFFLE_CEXT, "to_sulong", o);
159+
__attribute__((always_inline))
160+
static inline PyObject* _explicit_cast(PyObject* cobj) {
161161
if(polyglot_is_value(cobj)) {
162162
unsigned long flags = polyglot_as_i64(polyglot_invoke(PY_TRUFFLE_CEXT, "PyTruffle_GetTpFlags", cobj));
163163
return PyTruffle_Explicit_Cast(cobj, flags);
164164
}
165165
return cobj;
166166
}
167167

168+
PyObject* to_sulong(void *o) {
169+
return _explicit_cast(truffle_invoke(PY_TRUFFLE_CEXT, "to_sulong", o));
170+
}
171+
168172
void* get_ob_type(PyObject* obj) {
169173
return to_java_type(obj->ob_type);
170174
}
@@ -382,3 +386,47 @@ int PyTruffle_Debug(void *arg) {
382386
truffle_invoke(PY_TRUFFLE_CEXT, "PyTruffle_Debug", arg);
383387
return 0;
384388
}
389+
390+
PyObject *wrap_direct(PyCFunction fun, PyObject *module, ...) {
391+
PyObject *res = NULL;
392+
switch(polyglot_get_arg_count()) {
393+
case 0:
394+
res = fun(Py_None, Py_None);
395+
break;
396+
case 2:
397+
res = fun(module, Py_None);
398+
break;
399+
case 3:
400+
res = fun(module, _explicit_cast((PyObject*)polyglot_get_arg(2)));
401+
break;
402+
case 4:
403+
res = ((PyCFunctionWithKeywords)fun)(module, _explicit_cast((PyObject*)polyglot_get_arg(1)), _explicit_cast((PyObject*)polyglot_get_arg(3)));
404+
break;
405+
}
406+
PyTruffle_Debug(res);
407+
return res;
408+
}
409+
410+
PyObject *wrap_varargs(PyCFunction fun, PyObject *module, PyObject *varargs) {
411+
return fun(module, _explicit_cast(varargs));
412+
}
413+
414+
PyObject *wrap_keywords(PyCFunctionWithKeywords fun, PyObject *module, PyObject *varargs, PyObject *kwargs) {
415+
return fun(module, _explicit_cast(varargs), _explicit_cast(kwargs));
416+
}
417+
418+
PyObject *wrap_noargs(PyCFunction fun, PyObject *module, PyObject *pnone) {
419+
return fun(module, pnone);
420+
}
421+
422+
PyObject *wrap_fastcall(_PyCFunctionFast fun, PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) {
423+
Py_ssize_t i;
424+
for (i=0; i < nargs; i++) {
425+
args[i] = _explicit_cast(args[i]);
426+
}
427+
return fun(self, args, nargs, _explicit_cast(kwnames));
428+
}
429+
430+
PyObject *wrap_unsupported(void *fun, ...) {
431+
return NULL;
432+
}

‎graalpython/com.oracle.graal.python.cext/src/capi.h‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ void initialize_exceptions();
9494
// defined in 'pyhash.c'
9595
void initialize_hashes();
9696

97+
// prototype of C landing function
98+
PyObject *wrap_direct(PyCFunction fun, PyObject *module, ...);
99+
PyObject *wrap_varargs(PyCFunction fun, PyObject *module, PyObject *varargs);
100+
PyObject *wrap_keywords(PyCFunctionWithKeywords fun, PyObject *module, PyObject *varargs, PyObject *kwargs);
101+
PyObject *wrap_noargs(PyCFunction fun, PyObject *module, PyObject *pnone);
102+
PyObject *wrap_fastcall(_PyCFunctionFast fun, PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames);
103+
PyObject *wrap_unsupported(void *fun, ...);
104+
97105
#define write_struct_field(object, struct, fieldname, value) \
98106
truffle_write(to_java(object), \
99107
#fieldname , \
@@ -119,6 +127,21 @@ void initialize_hashes();
119127
truffle_read(PY_TRUFFLE_CEXT, "METH_FASTCALL") : \
120128
truffle_read(PY_TRUFFLE_CEXT, "METH_UNSUPPORTED")))))))
121129

130+
#define get_method_flags_cwrapper(flags) \
131+
(void*)((((flags) < 0) ? \
132+
wrap_direct : \
133+
(((flags) & METH_KEYWORDS) ? \
134+
wrap_keywords : \
135+
(((flags) & METH_VARARGS) ? \
136+
wrap_varargs : \
137+
(((flags) & METH_NOARGS) ? \
138+
wrap_noargs : \
139+
(((flags) & METH_O) ? \
140+
wrap_direct : \
141+
(((flags) & METH_FASTCALL) ? \
142+
wrap_fastcall : \
143+
wrap_unsupported)))))))
144+
122145

123146
#define PY_TRUFFLE_TYPE(__TYPE_NAME__, __SUPER_TYPE__, __FLAGS__) {\
124147
PyVarObject_HEAD_INIT((__SUPER_TYPE__), 0)\

‎graalpython/com.oracle.graal.python.cext/src/moduleobject.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ int PyModule_AddFunctions(PyObject* mod, PyMethodDef* methods) {
5454
mod_w,
5555
truffle_read_string((const char*)(def.ml_name)),
5656
truffle_address_to_function(def.ml_meth),
57+
truffle_address_to_function(get_method_flags_cwrapper(def.ml_flags)),
5758
get_method_flags_wrapper(def.ml_flags),
5859
truffle_read_string((const char*)(def.ml_doc ? def.ml_doc : "")));
5960
def = methods[++idx];

‎graalpython/com.oracle.graal.python.cext/src/object.c‎

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,17 +175,18 @@ int PyType_Ready(PyTypeObject* cls) {
175175
#define ADD_IF_MISSING(attr, def) if (!(attr)) { attr = def; }
176176
#define ADD_METHOD(m) ADD_METHOD_OR_SLOT(m.ml_name, m.ml_meth, m.ml_flags, m.ml_doc)
177177
#define ADD_SLOT(name, meth, flags) ADD_METHOD_OR_SLOT(name, meth, flags, name)
178-
#define ADD_METHOD_OR_SLOT(name, meth, flags, doc) \
179-
if (meth) { \
180-
truffle_invoke(PY_TRUFFLE_CEXT, \
181-
"AddFunction", \
182-
javacls, \
183-
truffle_read_string(name), \
184-
truffle_address_to_function(meth), \
185-
get_method_flags_wrapper(flags), \
186-
truffle_read_string(doc), \
187-
(flags) > 0 && ((flags) & METH_CLASS) != 0, \
188-
(flags) > 0 && ((flags) & METH_STATIC) != 0); \
178+
#define ADD_METHOD_OR_SLOT(name, meth, flags, doc) \
179+
if (meth) { \
180+
truffle_invoke(PY_TRUFFLE_CEXT, \
181+
"AddFunction", \
182+
javacls, \
183+
truffle_read_string(name), \
184+
truffle_address_to_function(meth), \
185+
truffle_address_to_function(get_method_flags_cwrapper(flags)), \
186+
get_method_flags_wrapper(flags), \
187+
truffle_read_string(doc), \
188+
(flags) > 0 && ((flags) & METH_CLASS) != 0, \
189+
(flags) > 0 && ((flags) & METH_STATIC) != 0); \
189190
}
190191

191192
// https://docs.python.org/3/c-api/typeobj.html#Py_TPFLAGS_READY

‎graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TruffleCextBuiltins.java‎

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,7 @@
5454
import com.oracle.graal.python.builtins.Builtin;
5555
import com.oracle.graal.python.builtins.CoreFunctions;
5656
import com.oracle.graal.python.builtins.PythonBuiltins;
57-
import com.oracle.graal.python.builtins.modules.TruffleCextBuiltinsFactory.AsPythonObjectNodeFactory;
5857
import com.oracle.graal.python.builtins.modules.TruffleCextBuiltinsFactory.PNativeToPTypeNodeGen;
59-
import com.oracle.graal.python.builtins.modules.TruffleCextBuiltinsFactory.ToSulongNodeFactory;
6058
import com.oracle.graal.python.builtins.objects.PNone;
6159
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
6260
import com.oracle.graal.python.builtins.objects.bytes.BytesBuiltins;
@@ -82,6 +80,7 @@
8280
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
8381
import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
8482
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
83+
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
8584
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
8685
import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
8786
import com.oracle.graal.python.nodes.object.GetClassNode;
@@ -347,23 +346,35 @@ int doLOvf(PTuple tuple, long position, Object element) {
347346
}
348347
}
349348

350-
@Builtin(name = "CreateFunction", fixedNumOfArguments = 2)
349+
@Builtin(name = "CreateFunction", minNumOfArguments = 2, maxNumOfArguments = 3)
351350
@GenerateNodeFactory
352-
abstract static class AddFunctionNode extends PythonBuiltinNode {
353-
@Specialization
351+
abstract static class CreateFunctionNode extends PythonTernaryBuiltinNode {
352+
@Specialization(guards = "isNoValue(cwrapper)")
353+
@TruffleBoundary
354+
Object runWithoutCWrapper(String name, TruffleObject callable, @SuppressWarnings("unused") PNone cwrapper) {
355+
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(new ExternalFunctionNode(getRootNode().getLanguage(PythonLanguage.class), name, null, callable));
356+
return factory().createBuiltinFunction(name, createArity(name), callTarget);
357+
}
358+
359+
@Specialization(guards = "!isNoValue(cwrapper)")
354360
@TruffleBoundary
355-
Object run(String name, TruffleObject callable) {
356-
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(new ExternalFunctionNode(getRootNode().getLanguage(PythonLanguage.class), name, callable));
361+
Object run(String name, TruffleObject callable, TruffleObject cwrapper) {
362+
RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(new ExternalFunctionNode(getRootNode().getLanguage(PythonLanguage.class), name, cwrapper, callable));
357363
return factory().createBuiltinFunction(name, createArity(name), callTarget);
358364
}
359365

360366
private static Arity createArity(String name) {
361367
return new Arity(name, 0, 0, true, true, new ArrayList<>(), new ArrayList<>());
362368
}
363369

364-
@Specialization
365-
Object run(PString name, TruffleObject callable) {
366-
return run(name.getValue(), callable);
370+
@Specialization(guards = "!isNoValue(cwrapper)")
371+
Object runWithoutCWrapper(PString name, TruffleObject callable, PNone cwrapper) {
372+
return runWithoutCWrapper(name.getValue(), callable, cwrapper);
373+
}
374+
375+
@Specialization(guards = "!isNoValue(cwrapper)")
376+
Object run(PString name, TruffleObject callable, TruffleObject cwrapper) {
377+
return run(name.getValue(), callable, cwrapper);
367378
}
368379
}
369380

@@ -512,22 +523,28 @@ PythonClass run(TruffleObject typestruct, PythonClass metaClass, PTuple baseClas
512523
}
513524

514525
static class ExternalFunctionNode extends RootNode {
526+
private final TruffleObject cwrapper;
515527
private final TruffleObject callable;
516528
private final String name;
517529
@CompilationFinal PythonContext ctxt;
518-
@Child private Node executeNode = Message.createExecute(0).createNode();
519-
@Child ToSulongNode toSulongNode = ToSulongNodeFactory.create(null);
520-
@Child AsPythonObjectNode asPythonObjectNode = AsPythonObjectNodeFactory.create(null);
530+
@Child private Node executeNode;
531+
@Child CExtNodes.ToSulongNode toSulongNode = CExtNodes.ToSulongNode.create();
532+
@Child CExtNodes.AsPythonObjectNode asPythonObjectNode = CExtNodes.AsPythonObjectNode.create();
521533
@Child private Node isNullNode = Message.IS_NULL.createNode();
522534
@Child private PNativeToPTypeNode fromForeign = PNativeToPTypeNode.create();
523535

524536
@Child private PythonObjectFactory factory = PythonObjectFactory.create();
525537

526-
public ExternalFunctionNode(PythonLanguage lang, String name, TruffleObject callable) {
538+
public ExternalFunctionNode(PythonLanguage lang, String name, TruffleObject cwrapper, TruffleObject callable) {
527539
super(lang);
528540
this.name = name;
541+
this.cwrapper = cwrapper;
529542
this.callable = callable;
530-
this.executeNode = Message.createExecute(2).createNode();
543+
if (cwrapper != null) {
544+
this.executeNode = Message.createExecute(3).createNode();
545+
} else {
546+
this.executeNode = Message.createExecute(2).createNode();
547+
}
531548
}
532549

533550
public TruffleObject getCallable() {
@@ -537,12 +554,25 @@ public TruffleObject getCallable() {
537554
@Override
538555
public Object execute(VirtualFrame frame) {
539556
Object[] frameArgs = frame.getArguments();
540-
Object[] arguments = new Object[frameArgs.length - PArguments.USER_ARGUMENTS_OFFSET];
541-
for (int i = 0; i < arguments.length; i++) {
542-
arguments[i] = toSulongNode.execute(frameArgs[i + PArguments.USER_ARGUMENTS_OFFSET]);
543-
}
544557
try {
545-
return fromNative(asPythonObjectNode.execute(checkFunctionResult(ForeignAccess.sendExecute(executeNode, callable, arguments))));
558+
TruffleObject fun;
559+
Object[] arguments;
560+
561+
if (cwrapper != null) {
562+
fun = cwrapper;
563+
arguments = new Object[1 + frameArgs.length - PArguments.USER_ARGUMENTS_OFFSET];
564+
arguments[0] = callable;
565+
for (int i = 1; i < arguments.length; i++) {
566+
arguments[i] = toSulongNode.execute(frameArgs[i + PArguments.USER_ARGUMENTS_OFFSET - 1]);
567+
}
568+
} else {
569+
fun = callable;
570+
arguments = new Object[frameArgs.length - PArguments.USER_ARGUMENTS_OFFSET];
571+
for (int i = 0; i < arguments.length; i++) {
572+
arguments[i] = toSulongNode.execute(frameArgs[i + PArguments.USER_ARGUMENTS_OFFSET]);
573+
}
574+
}
575+
return fromNative(asPythonObjectNode.execute(checkFunctionResult(ForeignAccess.sendExecute(executeNode, fun, arguments))));
546576
} catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e) {
547577
CompilerDirectives.transferToInterpreter();
548578
throw new RuntimeException(e.toString());

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ static class ToJavaNode extends PBaseNode {
185185
Object execute(Object value) {
186186
if (nativeToJavaFunction == null) {
187187
CompilerDirectives.transferToInterpreterAndInvalidate();
188-
nativeToJavaFunction = (TruffleObject) getContext().getEnv().importSymbol(NativeCAPISymbols.FUNCTION_NATIVE_TO_JAVA);
188+
nativeToJavaFunction = (TruffleObject) getContext().getEnv().importSymbol(NativeCAPISymbols.FUN_NATIVE_TO_JAVA);
189189
}
190190
return toJavaNode.execute(callNativeNode.execute(nativeToJavaFunction, new Object[]{value}));
191191
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
public abstract class NativeCAPISymbols {
4242

43-
public static final String FUNCTION_NATIVE_TO_JAVA = "native_to_java";
43+
public static final String FUN_NATIVE_TO_JAVA = "native_to_java";
4444
public static final String FUN_PY_TRUFFLE_STRING_TO_CSTR = "PyTruffle_StringToCstr";
4545
public static final String FUN_PY_OBJECT_HANDLE_FOR_JAVA_OBJECT = "PyObjectHandle_ForJavaObject";
4646
public static final String FUN_PY_OBJECT_HANDLE_FOR_JAVA_TYPE = "PyObjectHandle_ForJavaType";

‎graalpython/lib-graalpython/python_cext.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,8 @@ def __call__(*args, **kwargs):
622622
return self.__func__(None, *args, **kwargs)
623623

624624

625-
def AddFunction(primary, name, cfunc, wrapper, doc, isclass=False, isstatic=False):
626-
func = wrapper(CreateFunction(name, cfunc))
625+
def AddFunction(primary, name, cfunc, cwrapper, wrapper, doc, isclass=False, isstatic=False):
626+
func = wrapper(CreateFunction(name, cfunc, cwrapper))
627627
if isclass:
628628
func = classmethod(func)
629629
elif isstatic:

0 commit comments

Comments
 (0)