Skip to content

Commit 2e9537b

Browse files
committed
Save native pointers to PyMethodDef
1 parent 1e69b2f commit 2e9537b

File tree

7 files changed

+99
-85
lines changed

7 files changed

+99
-85
lines changed

graalpython/com.oracle.graal.python.cext/src/descrobject.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ PyObject* PyDictProxy_New(PyObject *mapping) {
6262
return (PyObject*) UPCALL_CEXT_O(_jls_PyDictProxy_New, native_to_java(mapping));
6363
}
6464

65-
typedef PyObject* (*PyDescr_NewClassMethod_fun_t)(void* name,
65+
typedef PyObject* (*PyDescr_NewClassMethod_fun_t)(PyMethodDef* methodDef,
66+
void* name,
6667
const char* doc,
6768
int flags,
6869
int wrapper,
@@ -71,7 +72,8 @@ typedef PyObject* (*PyDescr_NewClassMethod_fun_t)(void* name,
7172
UPCALL_TYPED_ID(PyDescr_NewClassMethod, PyDescr_NewClassMethod_fun_t);
7273
PyObject* PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) {
7374
int flags = method->ml_flags;
74-
return _jls_PyDescr_NewClassMethod(polyglot_from_string(method->ml_name, SRC_CS),
75+
return _jls_PyDescr_NewClassMethod(method,
76+
polyglot_from_string(method->ml_name, SRC_CS),
7577
method->ml_doc,
7678
flags,
7779
get_method_flags_wrapper(flags),

graalpython/com.oracle.graal.python.cext/src/methodobject.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);
4444

4545
PyTypeObject PyCFunction_Type = PY_TRUFFLE_TYPE_WITH_VECTORCALL("builtin_function_or_method", &PyType_Type, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | _Py_TPFLAGS_HAVE_VECTORCALL, sizeof(PyCFunctionObject), offsetof(PyCFunctionObject, vectorcall));
4646

47-
typedef PyObject* (*PyCFunction_NewEx_fun_t)(void* name,
47+
typedef PyObject* (*PyCFunction_NewEx_fun_t)(PyMethodDef* methodDef,
48+
void* name,
4849
void* methObj,
4950
int flags,
5051
int wrapper,
@@ -53,7 +54,8 @@ typedef PyObject* (*PyCFunction_NewEx_fun_t)(void* name,
5354
const char* doc);
5455
UPCALL_TYPED_ID(PyCFunction_NewEx, PyCFunction_NewEx_fun_t);
5556
PyObject* PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) {
56-
return _jls_PyCFunction_NewEx(polyglot_from_string(ml->ml_name, SRC_CS),
57+
return _jls_PyCFunction_NewEx(ml,
58+
polyglot_from_string(ml->ml_name, SRC_CS),
5759
function_pointer_to_java(ml->ml_meth),
5860
ml->ml_flags,
5961
get_method_flags_wrapper(ml->ml_flags),

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

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,24 +57,21 @@ PyModuleDef_Init(struct PyModuleDef* def)
5757
return (PyObject*)def;
5858
}
5959

60-
// cls dict name cfunc flags sig doc
61-
typedef int (*AddFunction_fun_t)(PyObject *, PyObject *, void *, void *, int , int, char *);
62-
UPCALL_TYPED_ID(AddFunction, AddFunction_fun_t);
60+
// method_def module name cfunc flags sig doc
61+
typedef int (*AddFunctionToModule_fun_t)(PyMethodDef *, PyObject *, const char *, void *, int , int, char *);
62+
UPCALL_TYPED_ID(AddFunctionToModule, AddFunctionToModule_fun_t);
6363
int PyModule_AddFunctions(PyObject* mod, PyMethodDef* methods) {
6464
if (!methods) {
6565
return -1;
6666
}
67-
int idx = 0;
68-
PyMethodDef def = methods[idx];
69-
while (def.ml_name != NULL) {
70-
_jls_AddFunction(native_to_java(mod),
71-
NULL,
72-
polyglot_from_string(def.ml_name, SRC_CS),
73-
function_pointer_to_java(def.ml_meth),
74-
def.ml_flags,
75-
get_method_flags_wrapper(def.ml_flags),
76-
(def.ml_doc ? def.ml_doc : ""));
77-
def = methods[++idx];
67+
for (PyMethodDef* def = methods; def->ml_name != NULL; def++) {
68+
_jls_AddFunctionToModule(def,
69+
native_to_java(mod),
70+
polyglot_from_string(def->ml_name, SRC_CS),
71+
function_pointer_to_java(def->ml_meth),
72+
def->ml_flags,
73+
get_method_flags_wrapper(def->ml_flags),
74+
def->ml_doc);
7875
}
7976
return 0;
8077
}

graalpython/com.oracle.graal.python.cext/src/typeobject.c

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -392,18 +392,18 @@ int add_getset(PyTypeObject* cls, PyObject* type_dict, char* name, getter getter
392392
closure);
393393
}
394394

395-
// cls dict name cfunc flags sig doc
396-
typedef int (*AddFunction_fun_t)(PyTypeObject *, PyObject *, void *, void *, int , int, char *);
397-
UPCALL_TYPED_ID(AddFunction, AddFunction_fun_t);
398-
static void add_method_or_slot(PyTypeObject* cls, PyObject* type_dict, char* name, void* result_conversion, void* meth, int flags, int signature, char* doc) {
399-
void *resolved_meth = function_pointer_to_java(meth);
400-
_jls_AddFunction(cls,
395+
// method_def cls dict name cfunc flags sig doc
396+
typedef int (*AddFunctionToType_fun_t)(PyMethodDef *, PyTypeObject *, PyObject *, const char *, void *, int , int, char *);
397+
UPCALL_TYPED_ID(AddFunctionToType, AddFunctionToType_fun_t);
398+
static void add_method(PyTypeObject* cls, PyObject* type_dict, PyMethodDef* def) {
399+
_jls_AddFunctionToType(def,
400+
cls,
401401
native_to_java(type_dict),
402-
polyglot_from_string(name, SRC_CS),
403-
native_pointer_to_java(result_conversion != NULL ? pytruffle_decorate_function(resolved_meth, result_conversion) : resolved_meth),
404-
flags,
405-
(signature != 0 ? signature : get_method_flags_wrapper(flags)),
406-
doc);
402+
polyglot_from_string(def->ml_name, SRC_CS),
403+
function_pointer_to_java(def->ml_meth),
404+
def->ml_flags,
405+
get_method_flags_wrapper(def->ml_flags),
406+
def->ml_doc);
407407
}
408408

409409
typedef int (*add_slot_fun_t)(PyTypeObject *, PyObject *, void *, void *, int , int, char *);
@@ -440,11 +440,6 @@ int PyType_Ready(PyTypeObject* cls) {
440440
} while(0)
441441

442442
#define ADD_IF_MISSING(attr, def) if (!(attr)) { attr = def; }
443-
#define ADD_METHOD(m) ADD_METHOD_OR_SLOT(m.ml_name, NULL, m.ml_meth, m.ml_flags, NULL, m.ml_doc)
444-
#define ADD_METHOD_OR_SLOT(__name__, __res_conv__, __meth__, __flags__, __signature__, __doc__) \
445-
if (__meth__) { \
446-
add_method_or_slot(cls, dict, (__name__), (__res_conv__), (__meth__), (__flags__), (__signature__), (__doc__)); \
447-
}
448443
#define ADD_SLOT_CONV(__name__, __meth__, __flags__, __signature__) add_slot(cls, dict, (__name__), (__meth__), (__flags__), (__signature__), NULL)
449444

450445
Py_ssize_t n;
@@ -520,13 +515,9 @@ int PyType_Ready(PyTypeObject* cls) {
520515
cls->tp_dict = dict;
521516
}
522517

523-
PyMethodDef* methods = cls->tp_methods;
524-
if (methods) {
525-
int idx = 0;
526-
PyMethodDef def = methods[idx];
527-
while (def.ml_name != NULL) {
528-
ADD_METHOD(def);
529-
def = methods[++idx];
518+
if (cls->tp_methods) {
519+
for (PyMethodDef* def = cls->tp_methods; def->ml_name != NULL; def++) {
520+
add_method(cls, dict, def);
530521
}
531522
}
532523

@@ -760,9 +751,7 @@ int PyType_Ready(PyTypeObject* cls) {
760751
return 0;
761752

762753
#undef ADD_IF_MISSING
763-
#undef ADD_METHOD
764754
#undef ADD_SLOT
765-
#undef ADD_METHOD_OR_SLOT
766755
}
767756

768757
MUST_INLINE static int valid_identifier(PyObject *s) {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextBuiltins.java

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,6 @@
259259
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
260260
import com.oracle.truffle.api.RootCallTarget;
261261
import com.oracle.truffle.api.TruffleLogger;
262-
import com.oracle.truffle.api.dsl.Bind;
263262
import com.oracle.truffle.api.dsl.Cached;
264263
import com.oracle.truffle.api.dsl.Cached.Exclusive;
265264
import com.oracle.truffle.api.dsl.Cached.Shared;
@@ -298,6 +297,13 @@ public final class PythonCextBuiltins extends PythonBuiltins {
298297

299298
public static final String NATIVE_NULL = "native_null";
300299

300+
/*
301+
* Native pointer to the PyMethodDef struct for functions created in C. We need to keep it
302+
* because the C program may expect to get its pointer back when accessing m_ml member of
303+
* methods.
304+
*/
305+
public static final HiddenKey METHOD_DEF_PTR = new HiddenKey("method_def_ptr");
306+
301307
private PythonObject errorHandler;
302308

303309
@Override
@@ -2252,11 +2258,11 @@ static Object doGeneric(Object object) {
22522258
@ImportStatic(CExtContext.class)
22532259
abstract static class NewClassMethodNode extends Node {
22542260

2255-
abstract Object execute(String name, Object methObj, Object flags, Object wrapper, Object type, Object doc,
2261+
abstract Object execute(Object methodDefPtr, String name, Object methObj, Object flags, Object wrapper, Object type, Object doc,
22562262
PythonObjectFactory factory);
22572263

22582264
@Specialization(guards = "isClassOrStaticMethod(flags)")
2259-
static Object classOrStatic(String name, Object methObj, int flags, int wrapper, Object type,
2265+
static Object classOrStatic(Object methodDefPtr, String name, Object methObj, int flags, int wrapper, Object type,
22602266
Object doc, PythonObjectFactory factory,
22612267
@CachedLibrary(limit = "1") DynamicObjectLibrary dylib,
22622268
@Shared("cf") @Cached CreateFunctionNode createFunctionNode,
@@ -2270,66 +2276,76 @@ static Object classOrStatic(String name, Object methObj, int flags, int wrapper,
22702276
}
22712277
dylib.put(function, __NAME__, name);
22722278
dylib.put(function, __DOC__, cstrPtr.execute(doc));
2279+
dylib.put(function, METHOD_DEF_PTR, methodDefPtr);
22732280
return function;
22742281
}
22752282

22762283
@Specialization(guards = "!isClassOrStaticMethod(flags)")
2277-
static Object doNativeCallable(String name, Object methObj, int flags, int wrapper, Object type,
2284+
static Object doNativeCallable(Object methodDefPtr, String name, Object methObj, int flags, int wrapper, Object type,
22782285
Object doc, PythonObjectFactory factory,
22792286
@Cached PyObjectSetAttrNode setattr,
2287+
@Cached WriteAttributeToObjectNode write,
22802288
@Shared("cf") @Cached CreateFunctionNode createFunctionNode,
22812289
@Shared("cstr") @Cached CharPtrToJavaObjectNode cstrPtr) {
22822290
Object func = createFunctionNode.execute(name, methObj, wrapper, type, flags, factory);
22832291
setattr.execute(func, __NAME__, name);
22842292
setattr.execute(func, __DOC__, cstrPtr.execute(doc));
2293+
write.execute(func, METHOD_DEF_PTR, methodDefPtr);
22852294
return func;
22862295
}
22872296
}
22882297

22892298
// directly called without landing function
2290-
@Builtin(name = "AddFunction", minNumOfPositionalArgs = 6, parameterNames = {"primary", "tpDict", "name", "cfunc", "flags", "wrapper", "doc"})
2299+
@Builtin(name = "AddFunctionToType", parameterNames = {"method_def_ptr", "primary", "tpDict", "name", "cfunc", "flags", "wrapper", "doc"})
22912300
@ArgumentClinic(name = "name", conversion = ClinicConversion.String)
22922301
@ArgumentClinic(name = "flags", conversion = ClinicConversion.Int)
22932302
@ArgumentClinic(name = "wrapper", conversion = ClinicConversion.Int)
22942303
@GenerateNodeFactory
2295-
abstract static class AddFunctionNode extends PythonClinicBuiltinNode {
2304+
abstract static class AddFunctionToTypeNode extends PythonClinicBuiltinNode {
22962305
@Override
22972306
protected ArgumentClinicProvider getArgumentClinic() {
2298-
return PythonCextBuiltinsClinicProviders.AddFunctionNodeClinicProviderGen.INSTANCE;
2307+
return PythonCextBuiltinsClinicProviders.AddFunctionToTypeNodeClinicProviderGen.INSTANCE;
22992308
}
23002309

2301-
@Specialization(guards = "isPythonModule(owner)")
2302-
Object moduleFunction(VirtualFrame frame, @SuppressWarnings("unused") Object primary,
2303-
@SuppressWarnings("unused") Object tpDict,
2304-
String name, Object cfunc, int flags, int wrapper, Object doc,
2305-
@SuppressWarnings("unused") @Cached AsPythonObjectNode asPythonObjectNode,
2306-
@Bind("getOwner(asPythonObjectNode, primary)") Object owner,
2307-
@Cached ObjectBuiltins.SetattrNode setattrNode,
2308-
@CachedLibrary(limit = "1") DynamicObjectLibrary dylib,
2309-
@Cached CFunctionNewExMethodNode cFunctionNewExMethodNode) {
2310-
PythonModule mod = (PythonModule) owner;
2311-
Object modName = dylib.getOrDefault(mod.getStorage(), __NAME__, null);
2312-
assert modName != null : "module name is missing!";
2313-
Object func = cFunctionNewExMethodNode.execute(name, cfunc, flags, wrapper, mod, modName, doc, factory());
2314-
setattrNode.execute(frame, mod, name, func);
2315-
return 0;
2316-
}
2317-
2318-
@Specialization(guards = "!isPythonModule(owner)")
2319-
Object classMethod(VirtualFrame frame, @SuppressWarnings("unused") Object primary,
2310+
@Specialization
2311+
Object classMethod(VirtualFrame frame, Object methodDefPtr, Object primary,
23202312
Object tpDict, String name, Object cfunc, int flags, int wrapper, Object doc,
23212313
@Cached AsPythonObjectNode asPythonObjectNode,
2322-
@Bind("getOwner(asPythonObjectNode, primary)") Object owner,
23232314
@Cached NewClassMethodNode newClassMethodNode,
23242315
@Cached DictBuiltins.SetItemNode setItemNode) {
2325-
Object func = newClassMethodNode.execute(name, cfunc, flags, wrapper, owner, doc, factory());
2316+
Object type = asPythonObjectNode.execute(primary);
2317+
Object func = newClassMethodNode.execute(methodDefPtr, name, cfunc, flags, wrapper, type, doc, factory());
23262318
Object dict = asPythonObjectNode.execute(tpDict);
23272319
setItemNode.execute(frame, dict, name, func);
23282320
return 0;
23292321
}
2322+
}
2323+
2324+
// directly called without landing function
2325+
@Builtin(name = "AddFunctionToModule", parameterNames = {"method_def_ptr", "primary", "name", "cfunc", "flags", "wrapper", "doc"})
2326+
@ArgumentClinic(name = "name", conversion = ClinicConversion.String)
2327+
@ArgumentClinic(name = "flags", conversion = ClinicConversion.Int)
2328+
@ArgumentClinic(name = "wrapper", conversion = ClinicConversion.Int)
2329+
@GenerateNodeFactory
2330+
abstract static class AddFunctionToModuleNode extends PythonClinicBuiltinNode {
2331+
@Override
2332+
protected ArgumentClinicProvider getArgumentClinic() {
2333+
return PythonCextBuiltinsClinicProviders.AddFunctionToModuleNodeClinicProviderGen.INSTANCE;
2334+
}
23302335

2331-
static Object getOwner(AsPythonObjectNode asPythonObjectNode, Object primary) {
2332-
return asPythonObjectNode.execute(primary);
2336+
@Specialization
2337+
Object moduleFunction(VirtualFrame frame, Object methodDefPtr, Object primary,
2338+
String name, Object cfunc, int flags, int wrapper, Object doc,
2339+
@Cached AsPythonObjectNode asPythonObjectNode,
2340+
@Cached ObjectBuiltins.SetattrNode setattrNode,
2341+
@CachedLibrary(limit = "1") DynamicObjectLibrary dylib,
2342+
@Cached CFunctionNewExMethodNode cFunctionNewExMethodNode) {
2343+
PythonModule mod = (PythonModule) asPythonObjectNode.execute(primary);
2344+
Object modName = dylib.getOrDefault(mod.getStorage(), __NAME__, null);
2345+
assert modName != null : "module name is missing!";
2346+
Object func = cFunctionNewExMethodNode.execute(methodDefPtr, name, cfunc, flags, wrapper, mod, modName, doc, factory());
2347+
setattrNode.execute(frame, mod, name, func);
2348+
return 0;
23332349
}
23342350
}
23352351

@@ -2400,11 +2416,11 @@ private static void addSlot(Object clsPtr, Object tpDictPtr, Object namePtr, Obj
24002416

24012417
abstract static class CFunctionNewExMethodNode extends Node {
24022418

2403-
abstract Object execute(String name, Object methObj, Object flags, Object wrapper, Object self, Object module, Object doc,
2419+
abstract Object execute(Object methodDefPtr, String name, Object methObj, Object flags, Object wrapper, Object self, Object module, Object doc,
24042420
PythonObjectFactory factory);
24052421

24062422
@Specialization
2407-
static Object doNativeCallable(String name, Object methObj, Object flags, Object wrapper, Object self, Object module, Object doc,
2423+
static Object doNativeCallable(Object methodDefPtr, String name, Object methObj, Object flags, Object wrapper, Object self, Object module, Object doc,
24082424
PythonObjectFactory factory,
24092425
@SuppressWarnings("unused") @Cached AsPythonObjectNode asPythonObjectNode,
24102426
@Cached CreateFunctionNode createFunctionNode,
@@ -2418,11 +2434,12 @@ static Object doNativeCallable(String name, Object methObj, Object flags, Object
24182434
dylib.put(func.getStorage(), __DOC__, strDoc);
24192435
PBuiltinMethod method = factory.createBuiltinMethod(self, func);
24202436
dylib.put(method.getStorage(), __MODULE__, module);
2437+
dylib.put(method.getStorage(), METHOD_DEF_PTR, methodDefPtr);
24212438
return method;
24222439
}
24232440
}
24242441

2425-
@Builtin(name = "PyCFunction_NewEx", minNumOfPositionalArgs = 7, parameterNames = {"name", "cfunc", "flags", "wrapper", "self", "module", "doc"})
2442+
@Builtin(name = "PyCFunction_NewEx", minNumOfPositionalArgs = 8, parameterNames = {"method_def_ptr", "name", "cfunc", "flags", "wrapper", "self", "module", "doc"})
24262443
@ArgumentClinic(name = "name", conversion = ArgumentClinic.ClinicConversion.String)
24272444
@GenerateNodeFactory
24282445
abstract static class PyCFunctionNewExMethod extends PythonClinicBuiltinNode {
@@ -2432,13 +2449,13 @@ protected ArgumentClinicProvider getArgumentClinic() {
24322449
}
24332450

24342451
@Specialization
2435-
Object doNativeCallable(String name, Object methObj, int flags, int wrapper, Object selfO, Object moduleO, Object doc,
2452+
Object doNativeCallable(Object methodDefPtr, String name, Object methObj, int flags, int wrapper, Object selfO, Object moduleO, Object doc,
24362453
@Cached AsPythonObjectNode asPythonObjectNode,
24372454
@Cached CFunctionNewExMethodNode cFunctionNewExMethodNode,
24382455
@Cached ToNewRefNode newRefNode) {
24392456
Object self = asPythonObjectNode.execute(selfO);
24402457
Object module = asPythonObjectNode.execute(moduleO);
2441-
Object func = cFunctionNewExMethodNode.execute(name, methObj, flags, wrapper, self, module, doc, factory());
2458+
Object func = cFunctionNewExMethodNode.execute(methodDefPtr, name, methObj, flags, wrapper, self, module, doc, factory());
24422459
return newRefNode.execute(func);
24432460
}
24442461
}

0 commit comments

Comments
 (0)