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