1 /* Test Vectorcall in the limited API */
2
3 // Need limited C API version 3.12 for PyObject_Vectorcall()
4 #include "pyconfig.h" // Py_GIL_DISABLED
5 #if !defined(Py_GIL_DISABLED) && !defined(Py_LIMITED_API)
6 # define Py_LIMITED_API 0x030c0000
7 #endif
8
9 #include "parts.h"
10 #include "clinic/vectorcall_limited.c.h"
11
12 /*[clinic input]
13 module _testlimitedcapi
14 [clinic start generated code]*/
15 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=2700057f9c1135ba]*/
16
17 static PyObject *
LimitedVectorCallClass_tpcall(PyObject * self,PyObject * args,PyObject * kwargs)18 LimitedVectorCallClass_tpcall(PyObject *self, PyObject *args, PyObject *kwargs) {
19 return PyUnicode_FromString("tp_call called");
20 }
21
22 static PyObject *
LimitedVectorCallClass_vectorcall(PyObject * callable,PyObject * const * args,size_t nargsf,PyObject * kwnames)23 LimitedVectorCallClass_vectorcall(PyObject *callable,
24 PyObject *const *args,
25 size_t nargsf,
26 PyObject *kwnames) {
27 return PyUnicode_FromString("vectorcall called");
28 }
29
30 static PyObject *
LimitedVectorCallClass_new(PyTypeObject * tp,PyTypeObject * a,PyTypeObject * kw)31 LimitedVectorCallClass_new(PyTypeObject *tp, PyTypeObject *a, PyTypeObject *kw)
32 {
33 PyObject *self = ((allocfunc)PyType_GetSlot(tp, Py_tp_alloc))(tp, 0);
34 if (!self) {
35 return NULL;
36 }
37 *(vectorcallfunc*)((char*)self + sizeof(PyObject)) = (
38 LimitedVectorCallClass_vectorcall);
39 return self;
40 }
41
42 /*[clinic input]
43 _testlimitedcapi.call_vectorcall
44
45 callable: object
46 /
47 [clinic start generated code]*/
48
49 static PyObject *
_testlimitedcapi_call_vectorcall(PyObject * module,PyObject * callable)50 _testlimitedcapi_call_vectorcall(PyObject *module, PyObject *callable)
51 /*[clinic end generated code: output=9cbb7832263a8eef input=0743636c12dccb28]*/
52 {
53 PyObject *args[3] = { NULL, NULL, NULL };
54 PyObject *kwname = NULL, *kwnames = NULL, *result = NULL;
55
56 args[1] = PyUnicode_FromString("foo");
57 if (!args[1]) {
58 goto leave;
59 }
60
61 args[2] = PyUnicode_FromString("bar");
62 if (!args[2]) {
63 goto leave;
64 }
65
66 kwname = PyUnicode_InternFromString("baz");
67 if (!kwname) {
68 goto leave;
69 }
70
71 kwnames = PyTuple_New(1);
72 if (!kwnames) {
73 goto leave;
74 }
75
76 if (PyTuple_SetItem(kwnames, 0, kwname)) {
77 goto leave;
78 }
79
80 result = PyObject_Vectorcall(
81 callable,
82 args + 1,
83 1 | PY_VECTORCALL_ARGUMENTS_OFFSET,
84 kwnames
85 );
86
87 leave:
88 Py_XDECREF(args[1]);
89 Py_XDECREF(args[2]);
90 Py_XDECREF(kwnames);
91
92 return result;
93 }
94
95 /*[clinic input]
96 _testlimitedcapi.call_vectorcall_method
97
98 callable: object
99 /
100 [clinic start generated code]*/
101
102 static PyObject *
_testlimitedcapi_call_vectorcall_method(PyObject * module,PyObject * callable)103 _testlimitedcapi_call_vectorcall_method(PyObject *module, PyObject *callable)
104 /*[clinic end generated code: output=4558323a46cc09eb input=a736f7dbf15f1be5]*/
105 {
106 PyObject *args[3] = { NULL, NULL, NULL };
107 PyObject *name = NULL, *kwname = NULL,
108 *kwnames = NULL, *result = NULL;
109
110 name = PyUnicode_FromString("f");
111 if (!name) {
112 goto leave;
113 }
114
115 args[0] = callable;
116 args[1] = PyUnicode_FromString("foo");
117 if (!args[1]) {
118 goto leave;
119 }
120
121 args[2] = PyUnicode_FromString("bar");
122 if (!args[2]) {
123 goto leave;
124 }
125
126 kwname = PyUnicode_InternFromString("baz");
127 if (!kwname) {
128 goto leave;
129 }
130
131 kwnames = PyTuple_New(1);
132 if (!kwnames) {
133 goto leave;
134 }
135
136 if (PyTuple_SetItem(kwnames, 0, kwname)) {
137 goto leave;
138 }
139
140
141 result = PyObject_VectorcallMethod(
142 name,
143 args,
144 2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
145 kwnames
146 );
147
148 leave:
149 Py_XDECREF(name);
150 Py_XDECREF(args[1]);
151 Py_XDECREF(args[2]);
152 Py_XDECREF(kwnames);
153
154 return result;
155 }
156
157 static PyMemberDef LimitedVectorCallClass_members[] = {
158 {"__vectorcalloffset__", Py_T_PYSSIZET, sizeof(PyObject), Py_READONLY},
159 {NULL}
160 };
161
162 static PyType_Slot LimitedVectorallClass_slots[] = {
163 {Py_tp_new, LimitedVectorCallClass_new},
164 {Py_tp_call, LimitedVectorCallClass_tpcall},
165 {Py_tp_members, LimitedVectorCallClass_members},
166 {0},
167 };
168
169 static PyType_Spec LimitedVectorCallClass_spec = {
170 .name = "_testlimitedcapi.LimitedVectorCallClass",
171 .basicsize = (int)(sizeof(PyObject) + sizeof(vectorcallfunc)),
172 .flags = Py_TPFLAGS_DEFAULT
173 | Py_TPFLAGS_HAVE_VECTORCALL
174 | Py_TPFLAGS_BASETYPE,
175 .slots = LimitedVectorallClass_slots,
176 };
177
178 static PyMethodDef TestMethods[] = {
179 _TESTLIMITEDCAPI_CALL_VECTORCALL_METHODDEF
180 _TESTLIMITEDCAPI_CALL_VECTORCALL_METHOD_METHODDEF
181 {NULL},
182 };
183
184 int
_PyTestLimitedCAPI_Init_VectorcallLimited(PyObject * m)185 _PyTestLimitedCAPI_Init_VectorcallLimited(PyObject *m)
186 {
187 if (PyModule_AddFunctions(m, TestMethods) < 0) {
188 return -1;
189 }
190
191 PyObject *LimitedVectorCallClass = PyType_FromModuleAndSpec(
192 m, &LimitedVectorCallClass_spec, NULL);
193 if (!LimitedVectorCallClass) {
194 return -1;
195 }
196 if (PyModule_AddType(m, (PyTypeObject *)LimitedVectorCallClass) < 0) {
197 return -1;
198 }
199 Py_DECREF(LimitedVectorCallClass);
200 return 0;
201 }
202