Skip to content

Commit 8e88879

Browse files
committed
[GR-53368] Update autopatch_capi to deal with more usages of m_ml and m_module access.
PullRequest: graalpython/3303
2 parents 442fc43 + 2269b02 commit 8e88879

File tree

7 files changed

+85
-6
lines changed

7 files changed

+85
-6
lines changed

graalpython/com.oracle.graal.python.cext/include/cpython/methodobject.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,10 @@ static inline PyTypeObject* PyCFunction_GET_CLASS(PyObject *func_obj) {
7171
#endif
7272

7373
/*
74-
* XXX These functions are GraalPy-only. We need them to replace field access in our patches.
75-
* Currently used by (at least) cffi patch.
74+
* XXX These functions are GraalPy-only. We need them to replace field access.
75+
* Currently inserted by our autopatch_capi.py
7676
*/
7777
PyAPI_FUNC(PyObject*) _PyCFunction_GetModule(PyObject* a);
7878
PyAPI_FUNC(PyMethodDef*) _PyCFunction_GetMethodDef(PyObject* a);
79-
79+
PyAPI_FUNC(void) _PyCFunction_SetModule(PyObject* a, PyObject* b);
80+
PyAPI_FUNC(void) _PyCFunction_SetMethodDef(PyObject* a, PyMethodDef *b);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,11 @@ PyObject* _PyCFunction_GetModule(PyObject *func) {
9494
PyMethodDef* _PyCFunction_GetMethodDef(PyObject *func) {
9595
return PyCFunctionObject_m_ml(func);
9696
}
97+
98+
void _PyCFunction_SetModule(PyObject *func, PyObject *mod) {
99+
set_PyCFunctionObject_m_module(func, mod);
100+
}
101+
102+
void _PyCFunction_SetMethodDef(PyObject *func, PyMethodDef *def) {
103+
set_PyCFunctionObject_m_ml(func, def);
104+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,7 @@ private static Path resolvePath(Path path) {
749749
private static final String[] ADDITIONAL = new String[]{"PyCMethod_GetClass", "PyDescrObject_GetName", "PyDescrObject_GetType", "PyInterpreterState_GetIDFromThreadState",
750750
"PyMethodDescrObject_GetMethod", "PyObject_GetDoc", "PyObject_SetDoc", "PySlice_Start", "PySlice_Step", "PySlice_Stop", "_PyFrame_SetLineNumber",
751751
"_PyCFunction_GetModule", "_PyCFunction_GetMethodDef", "PyCode_GetName",
752+
"_PyCFunction_SetModule", "_PyCFunction_SetMethodDef",
752753
"PyCode_GetFileName", "_PyArray_Resize", "_PyArray_Data",
753754
"_PyErr_Occurred", "_PyNamespace_New", "_Py_GetErrorHandler",
754755
};

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_functions.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,9 @@ def test_PyMethodDef(self):
537537
// CPython and other don't have this function; so define it
538538
#ifndef GRAALVM_PYTHON
539539
#define _PyCFunction_GetMethodDef(OBJ) (((PyCFunctionObject*) (OBJ))->m_ml)
540+
#define _PyCFunction_SetMethodDef(OBJ, VAL) (((PyCFunctionObject*) (OBJ))->m_ml = (VAL))
541+
#define _PyCFunction_GetModule(OBJ) (((PyCFunctionObject*) (OBJ))->m_module)
542+
#define _PyCFunction_SetModule(OBJ, VAL) (((PyCFunctionObject*) (OBJ))->m_module = (VAL))
540543
#define PyMethodDescrObject_GetMethod(OBJ) (((PyMethodDescrObject *) (OBJ))->d_method)
541544
#endif
542545
@@ -680,6 +683,32 @@ def test_PyMethodDef(self):
680683
return PyUnicode_FromString(def->ml_doc);
681684
}
682685
686+
static PyObject *set_def(PyObject *self, PyObject *arg) {
687+
if (!PyCFunction_Check(arg)) {
688+
PyErr_SetString(PyExc_TypeError, "<callable> is not a PyCFunction (i.e. builtin_method_or_function)");
689+
return NULL;
690+
}
691+
PyMethodDef *def = _PyCFunction_GetMethodDef(arg);
692+
_PyCFunction_SetMethodDef(arg, def);
693+
return PyUnicode_FromString(_PyCFunction_GetMethodDef(arg)->ml_doc);
694+
}
695+
696+
static PyObject *get_set_module(PyObject *self, PyObject *arg) {
697+
if (!PyCFunction_Check(arg)) {
698+
PyErr_SetString(PyExc_TypeError, "<callable> is not a PyCFunction (i.e. builtin_method_or_function)");
699+
return NULL;
700+
}
701+
PyObject *module = _PyCFunction_GetModule(arg);
702+
Py_XINCREF(self);
703+
_PyCFunction_SetModule(arg, self);
704+
if (_PyCFunction_GetModule(arg) != self) {
705+
PyErr_SetString(PyExc_TypeError, "module of function is not self");
706+
return NULL;
707+
}
708+
Py_XINCREF(self);
709+
return self;
710+
}
711+
683712
static PyObject *new_meth(PyObject *self, PyObject *args) {
684713
PyObject *callable_type = NULL, *callable_self, *callable;
685714
if (!PyArg_ParseTuple(args, "OO:new_meth",
@@ -711,7 +740,9 @@ def = PyMethodDescrObject_GetMethod(callable);
711740
{"call_meth", (PyCFunction)call_meth, METH_VARARGS, ""},
712741
{"call_meth_descr", (PyCFunction)call_meth_descr, METH_VARARGS, ""},
713742
{"get_doc", (PyCFunction)get_doc, METH_O, ""},
714-
{"new_meth", (PyCFunction)new_meth, METH_VARARGS, ""}
743+
{"new_meth", (PyCFunction)new_meth, METH_VARARGS, ""},
744+
{"set_def", (PyCFunction)set_def, METH_O, ""},
745+
{"get_set_module", (PyCFunction)get_set_module, METH_O, ""}
715746
''',
716747
post_ready_code='''
717748
PyModule_AddIntMacro(m, METH_NOARGS);
@@ -738,6 +769,8 @@ def = PyMethodDescrObject_GetMethod(callable);
738769
assert tester.get_flags(tester.native_meth_keywords) == m.METH_VARARGS | m.METH_KEYWORDS
739770
assert tester.get_doc(tester.native_meth_keywords) == "doc keywords"
740771
assert tester.call_meth(tester.native_meth_keywords, (1, 2), {"hello": "world"}) == ((1, 2), {"hello": "world"})
772+
assert tester.set_def(tester.native_meth_keywords) == "doc keywords"
773+
assert tester.get_set_module(tester.get_set_module) == tester
741774

742775
# built-in functions
743776

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@
145145
import com.oracle.graal.python.builtins.objects.type.PythonManagedClass;
146146
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
147147
import com.oracle.graal.python.lib.PyObjectLookupAttr;
148+
import com.oracle.graal.python.lib.PyObjectSetAttr;
148149
import com.oracle.graal.python.nodes.HiddenAttr;
149150
import com.oracle.graal.python.nodes.PGuards;
150151
import com.oracle.graal.python.nodes.SpecialAttributeNames;
@@ -313,6 +314,26 @@ static Object get(PythonBuiltinObject object,
313314
}
314315
}
315316

317+
@CApiBuiltin(ret = PyMethodDef, args = {PyCFunctionObject, PyMethodDef}, call = Ignored)
318+
abstract static class Py_set_PyCFunctionObject_m_ml extends CApiBinaryBuiltinNode {
319+
@Specialization
320+
static Object get(PythonBuiltinObject object, Object methodDefPtr,
321+
@Bind("this") Node inliningTarget,
322+
@Cached HiddenAttr.WriteNode writeNode) {
323+
PBuiltinFunction resolved;
324+
if (object instanceof PBuiltinMethod builtinMethod) {
325+
resolved = builtinMethod.getBuiltinFunction();
326+
} else if (object instanceof PBuiltinFunction builtinFunction) {
327+
resolved = builtinFunction;
328+
} else {
329+
CompilerDirectives.transferToInterpreterAndInvalidate();
330+
throw CompilerDirectives.shouldNotReachHere("writing PyMethodDef for an incompatible function/method type: " + object.getClass().getSimpleName());
331+
}
332+
writeNode.execute(inliningTarget, resolved, METHOD_DEF_PTR, methodDefPtr);
333+
return PNone.NO_VALUE;
334+
}
335+
}
336+
316337
@CApiBuiltin(ret = PyObjectBorrowed, args = {PyCFunctionObject}, call = Ignored)
317338
abstract static class Py_get_PyCFunctionObject_m_module extends CApiUnaryBuiltinNode {
318339
@Specialization
@@ -324,6 +345,17 @@ Object get(Object object,
324345
}
325346
}
326347

348+
@CApiBuiltin(ret = Void, args = {PyCFunctionObject, PyObjectBorrowed}, call = Ignored)
349+
abstract static class Py_set_PyCFunctionObject_m_module extends CApiBinaryBuiltinNode {
350+
@Specialization
351+
Object set(Object object, Object value,
352+
@Bind("this") Node inliningTarget,
353+
@Cached PyObjectSetAttr setattr) {
354+
setattr.execute(null, inliningTarget, object, T___MODULE__, value);
355+
return PNone.NO_VALUE;
356+
}
357+
}
358+
327359
@CApiBuiltin(ret = PyObjectBorrowed, args = {PyCFunctionObject}, call = Ignored)
328360
abstract static class Py_get_PyCFunctionObject_m_self extends CApiUnaryBuiltinNode {
329361
@Specialization

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,8 @@ public final class CApiFunction {
541541
@CApiBuiltin(name = "_PyBytes_Resize", ret = Int, args = {PyObjectPtr, Py_ssize_t}, call = CImpl)
542542
@CApiBuiltin(name = "_PyCFunction_GetMethodDef", ret = PyMethodDef, args = {PyObject}, call = CImpl)
543543
@CApiBuiltin(name = "_PyCFunction_GetModule", ret = PyObject, args = {PyObject}, call = CImpl)
544+
@CApiBuiltin(name = "_PyCFunction_SetMethodDef", ret = Void, args = {PyObject, PyMethodDef}, call = CImpl)
545+
@CApiBuiltin(name = "_PyCFunction_SetModule", ret = Void, args = {PyObject, PyObject}, call = CImpl)
544546
@CApiBuiltin(name = "_PyDict_ContainsId", ret = Int, args = {PyObject, _PY_IDENTIFIER_PTR}, call = CImpl)
545547
@CApiBuiltin(name = "_PyDict_GetItemIdWithError", ret = PyObject, args = {PyObject, _PY_IDENTIFIER_PTR}, call = CImpl)
546548
@CApiBuiltin(name = "_PyDict_GetItemStringWithError", ret = PyObject, args = {PyObject, ConstCharPtrAsTruffleString}, call = CImpl)

graalpython/lib-graalpython/modules/autopatch_capi.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,10 @@ def consume_whitespace_forward(idx):
157157
r'\W(ob_item)\W': (replace_field_access, 'PySequence_Fast_ITEMS((PyObject*)%receiver)'),
158158
r'^\s*()(std::)?free\((const_cast<char \*>)?\(?\w+->m_ml->ml_doc\)?\);': (simple_replace, '//'),
159159
r'\W(m_ml\s*->\s*ml_doc)\W': (replace_field_access, 'PyObject_GetDoc((PyObject*)(%receiver))', 'PyObject_SetDoc((PyObject*)(%receiver), %value)'),
160-
r'\W(m_ml)\W': (replace_field_access, '_PyCFunction_GetMethodDef((PyObject*)(%receiver))'),
161-
r'\W(m_module)\W': (replace_field_access, '_PyCFunction_GetModule((PyObject*)(%receiver))'),
160+
# Py_CLEAR/Py_VISIT on a function's module is skipped for us, Java GC takes care of it
161+
r'(Py_(?:CLEAR|VISIT)\((?:(?:\(?\([a-zA-Z0-9_]|[a-zA-Z0-9_])(?:[a-zA-Z0-9_]|\)|\*\)|->)*)->m_module\);)': (simple_replace, ''),
162+
r'\W(m_ml)\W': (replace_field_access, '_PyCFunction_GetMethodDef((PyObject*)(%receiver))', '_PyCFunction_SetMethodDef((PyObject*)(%receiver), %value)'),
163+
r'\W(m_module)\W': (replace_field_access, '_PyCFunction_GetModule((PyObject*)(%receiver))', '_PyCFunction_SetModule((PyObject*)(%receiver), %value)'),
162164
r'(&PyTuple_GET_ITEM\(([\(\w](?:\w|->|\.|\(|\))*), 0\))': (simple_replace, r'PySequence_Fast_ITEMS(\2)'),
163165
# already defined by GraalPy:
164166
r'^\s*()#\s*define\s+Py_SET_TYPE\W': (simple_replace, '//'),

0 commit comments

Comments
 (0)