Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(3)

Side by Side Diff: Objects/methodobject.c

Issue 29259: Add tp_fastcall to PyTypeObject: support FASTCALL calling convention for all callable objects
Patch Set: Created 3 years ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 1
2 /* Method object implementation */ 2 /* Method object implementation */
3 3
4 #include "Python.h" 4 #include "Python.h"
5 #include "structmember.h" 5 #include "structmember.h"
6 6
7 /* Free list for method objects to safe malloc/free overhead 7 /* Free list for method objects to safe malloc/free overhead
8 * The m_self element is used to chain the objects. 8 * The m_self element is used to chain the objects.
9 */ 9 */
10 static PyCFunctionObject *free_list = NULL; 10 static PyCFunctionObject *free_list = NULL;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 PyObject * 80 PyObject *
81 PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) 81 PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs)
82 { 82 {
83 return _PyCFunction_FastCallDict(func, 83 return _PyCFunction_FastCallDict(func,
84 &PyTuple_GET_ITEM(args, 0), 84 &PyTuple_GET_ITEM(args, 0),
85 PyTuple_GET_SIZE(args), 85 PyTuple_GET_SIZE(args),
86 kwargs); 86 kwargs);
87 } 87 }
88 88
89 PyObject * 89 PyObject *
90 _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg s, 90 _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
91 Py_ssize_t nargs, PyObject *kwargs) 91 PyObject *kwargs)
92 { 92 {
93 PyCFunctionObject *func = (PyCFunctionObject*)func_obj;
93 PyCFunction meth; 94 PyCFunction meth;
94 PyObject *result; 95 PyObject *self, *result;
95 int flags; 96 int flags;
96 PyObject *argstuple; 97 PyObject *argstuple;
97 98
98 /* _PyMethodDef_RawFastCallDict() must not be called with an exception set, 99 /* _PyCFunction_FastCallDict() must not be called with an exception set,
99 because it can clear it (directly or indirectly) and so the 100 because it may clear it (directly or indirectly) and so the
100 caller loses its exception */ 101 caller loses its exception */
101 assert(!PyErr_Occurred()); 102 assert(!PyErr_Occurred());
102 103
103 assert(method != NULL); 104 assert(PyCFunction_Check(func_obj));
105 assert(func_obj != NULL);
haypo 2017/01/26 03:35:21 assertions in the wrong order.
104 assert(nargs >= 0); 106 assert(nargs >= 0);
105 assert(nargs == 0 || args != NULL); 107 assert(nargs == 0 || args != NULL);
106 assert(kwargs == NULL || PyDict_Check(kwargs)); 108 assert(kwargs == NULL || PyDict_Check(kwargs));
107 109
108 meth = method->ml_meth; 110 func = (PyCFunctionObject*)func_obj;
109 flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); 111 meth = PyCFunction_GET_FUNCTION(func);
112 self = PyCFunction_GET_SELF(func);
113 flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEX IST);
110 114
111 switch (flags) 115 switch (flags)
112 { 116 {
113 case METH_NOARGS: 117 case METH_NOARGS:
114 if (nargs != 0) { 118 if (nargs != 0) {
115 PyErr_Format(PyExc_TypeError, 119 PyErr_Format(PyExc_TypeError,
116 "%.200s() takes no arguments (%zd given)", 120 "%.200s() takes no arguments (%zd given)",
117 method->ml_name, nargs); 121 func->m_ml->ml_name, nargs);
118 return NULL; 122 return NULL;
119 } 123 }
120 124
121 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { 125 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
122 goto no_keyword_error; 126 goto no_keyword_error;
123 } 127 }
124 128
125 result = (*meth) (self, NULL); 129 result = (*meth) (self, NULL);
126 break; 130 break;
127 131
128 case METH_O: 132 case METH_O:
129 if (nargs != 1) { 133 if (nargs != 1) {
130 PyErr_Format(PyExc_TypeError, 134 PyErr_Format(PyExc_TypeError,
131 "%.200s() takes exactly one argument (%zd given)", 135 "%.200s() takes exactly one argument (%zd given)",
132 method->ml_name, nargs); 136 func->m_ml->ml_name, nargs);
133 return NULL; 137 return NULL;
134 } 138 }
135 139
136 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { 140 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
137 goto no_keyword_error; 141 goto no_keyword_error;
138 } 142 }
139 143
140 result = (*meth) (self, args[0]); 144 result = (*meth) (self, args[0]);
141 break; 145 break;
142 146
(...skipping 15 matching lines...) Expand all
158 result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs); 162 result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs);
159 } 163 }
160 else { 164 else {
161 result = (*meth) (self, argstuple); 165 result = (*meth) (self, argstuple);
162 } 166 }
163 Py_DECREF(argstuple); 167 Py_DECREF(argstuple);
164 break; 168 break;
165 169
166 case METH_FASTCALL: 170 case METH_FASTCALL:
167 { 171 {
168 PyObject **stack; 172 result = _Py_RawFastCallDict(self, (fastternaryfunc)meth,
169 PyObject *kwnames; 173 args, nargs, kwargs);
170 _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth;
171
172 if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) {
173 return NULL;
174 }
175
176 result = (*fastmeth) (self, stack, nargs, kwnames);
177 if (stack != args) {
178 PyMem_Free(stack);
179 }
180 Py_XDECREF(kwnames);
181 break; 174 break;
182 } 175 }
183 176
184 default: 177 default:
185 PyErr_SetString(PyExc_SystemError, 178 PyErr_SetString(PyExc_SystemError,
186 "Bad call flags in _PyMethodDef_RawFastCallDict. " 179 "Bad call flags in _PyMethodDef_RawFastCallDict. "
187 "METH_OLDARGS is no longer supported!"); 180 "METH_OLDARGS is no longer supported!");
188 return NULL; 181 return NULL;
189 } 182 }
183
184 result = _Py_CheckFunctionResult(func_obj, result, NULL);
190 185
191 return result; 186 return result;
192 187
193 no_keyword_error: 188 no_keyword_error:
194 PyErr_Format(PyExc_TypeError, 189 PyErr_Format(PyExc_TypeError,
195 "%.200s() takes no keyword arguments", 190 "%.200s() takes no keyword arguments",
196 method->ml_name, nargs); 191 func->m_ml->ml_name, nargs);
197
198 return NULL; 192 return NULL;
199 } 193 }
200 194
201 PyObject * 195 PyObject *
202 _PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, 196 _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self,
203 PyObject *kwargs) 197 PyObject **args, Py_ssize_t nargs,
198 PyObject *kwnames)
204 { 199 {
200 PyCFunction meth;
205 PyObject *result; 201 PyObject *result;
206
207 assert(func != NULL);
208 assert(PyCFunction_Check(func));
209
210 result = _PyMethodDef_RawFastCallDict(((PyCFunctionObject*)func)->m_ml,
211 PyCFunction_GET_SELF(func),
212 args, nargs, kwargs);
213 result = _Py_CheckFunctionResult(func, result, NULL);
214 return result;
215 }
216
217 PyObject *
218 _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args,
219 Py_ssize_t nargs, PyObject *kwnames)
220 {
221 PyCFunctionObject *func;
222 PyCFunction meth;
223 PyObject *self, *result;
224 Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); 202 Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
225 int flags; 203 int flags;
226 204
227 assert(func_obj != NULL);
228 assert(PyCFunction_Check(func_obj));
229 assert(nargs >= 0); 205 assert(nargs >= 0);
haypo 2017/01/26 03:35:21 assert(method != NULL);
230 assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); 206 assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
231 assert((nargs == 0 && nkwargs == 0) || args != NULL); 207 assert((nargs == 0 && nkwargs == 0) || args != NULL);
232 /* kwnames must only contains str strings, no subclass, and all keys must 208 /* kwnames must only contains str strings, no subclass, and all keys must
233 be unique */ 209 be unique */
234 210
235 /* _PyCFunction_FastCallKeywords() must not be called with an exception 211 /* _PyCFunction_FastCallKeywords() must not be called with an exception
236 set, because it can clear it (directly or indirectly) and so the caller 212 set, because it can clear it (directly or indirectly) and so the caller
237 loses its exception */ 213 loses its exception */
238 assert(!PyErr_Occurred()); 214 assert(!PyErr_Occurred());
239 215
240 func = (PyCFunctionObject*)func_obj; 216 meth = method->ml_meth;
241 meth = PyCFunction_GET_FUNCTION(func); 217 flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
242 self = PyCFunction_GET_SELF(func);
243 flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEX IST);
244 218
245 switch (flags) 219 switch (flags)
246 { 220 {
247 case METH_NOARGS: 221 case METH_NOARGS:
248 if (nargs != 0) { 222 if (nargs != 0) {
249 PyErr_Format(PyExc_TypeError, 223 PyErr_Format(PyExc_TypeError,
250 "%.200s() takes no arguments (%zd given)", 224 "%.200s() takes no arguments (%zd given)",
251 func->m_ml->ml_name, nargs); 225 method->ml_name, nargs);
252 return NULL; 226 return NULL;
253 } 227 }
254 228
255 if (nkwargs) { 229 if (nkwargs) {
256 goto no_keyword_error; 230 goto no_keyword_error;
257 } 231 }
258 232
259 result = (*meth) (self, NULL); 233 result = (*meth) (self, NULL);
260 break; 234 break;
261 235
262 case METH_O: 236 case METH_O:
263 if (nargs != 1) { 237 if (nargs != 1) {
264 PyErr_Format(PyExc_TypeError, 238 PyErr_Format(PyExc_TypeError,
265 "%.200s() takes exactly one argument (%zd given)", 239 "%.200s() takes exactly one argument (%zd given)",
266 func->m_ml->ml_name, nargs); 240 method->ml_name, nargs);
267 return NULL; 241 return NULL;
268 } 242 }
269 243
270 if (nkwargs) { 244 if (nkwargs) {
271 goto no_keyword_error; 245 goto no_keyword_error;
272 } 246 }
273 247
274 result = (*meth) (self, args[0]); 248 result = (*meth) (self, args[0]);
275 break; 249 break;
276 250
277 case METH_FASTCALL: 251 case METH_FASTCALL:
278 /* Fast-path: avoid temporary dict to pass keyword arguments */ 252 /* Fast-path: avoid temporary dict to pass keyword arguments */
279 result = ((_PyCFunctionFast)meth) (self, args, nargs, kwnames); 253 result = ((fastternaryfunc)meth) (self, args, nargs, kwnames);
280 break; 254 break;
281 255
282 case METH_VARARGS: 256 case METH_VARARGS:
283 case METH_VARARGS | METH_KEYWORDS: 257 case METH_VARARGS | METH_KEYWORDS:
284 { 258 {
285 /* Slow-path: create a temporary tuple for positional arguments 259 /* Slow-path: create a temporary tuple for positional arguments
286 and a temporary dict for keyword arguments */ 260 and a temporary dict for keyword arguments */
287 PyObject *argtuple; 261 PyObject *argtuple;
288 262
289 if (!(flags & METH_KEYWORDS) && nkwargs) { 263 if (!(flags & METH_KEYWORDS) && nkwargs) {
(...skipping 29 matching lines...) Expand all
319 break; 293 break;
320 } 294 }
321 295
322 default: 296 default:
323 PyErr_SetString(PyExc_SystemError, 297 PyErr_SetString(PyExc_SystemError,
324 "Bad call flags in _PyCFunction_FastCallKeywords. " 298 "Bad call flags in _PyCFunction_FastCallKeywords. "
325 "METH_OLDARGS is no longer supported!"); 299 "METH_OLDARGS is no longer supported!");
326 return NULL; 300 return NULL;
327 } 301 }
328 302
329 result = _Py_CheckFunctionResult(func_obj, result, NULL);
330 return result; 303 return result;
331 304
332 no_keyword_error: 305 no_keyword_error:
333 PyErr_Format(PyExc_TypeError, 306 PyErr_Format(PyExc_TypeError,
334 "%.200s() takes no keyword arguments", 307 "%.200s() takes no keyword arguments",
335 func->m_ml->ml_name); 308 method->ml_name);
336 return NULL; 309 return NULL;
310 }
311
312 PyObject *
313 _PyCFunction_FastCallKeywords(PyObject *func, PyObject **args,
314 Py_ssize_t nargs, PyObject *kwnames)
315 {
316 PyObject *result;
317
318 assert(func != NULL);
319 assert(PyCFunction_Check(func));
320
321 result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml,
322 PyCFunction_GET_SELF(func),
323 args, nargs, kwnames);
324 result = _Py_CheckFunctionResult(func, result, NULL);
325 return result;
337 } 326 }
338 327
339 /* Methods (the standard built-in methods, that is) */ 328 /* Methods (the standard built-in methods, that is) */
340 329
341 static void 330 static void
342 meth_dealloc(PyCFunctionObject *m) 331 meth_dealloc(PyCFunctionObject *m)
343 { 332 {
344 _PyObject_GC_UNTRACK(m); 333 _PyObject_GC_UNTRACK(m);
345 if (m->m_weakreflist != NULL) { 334 if (m->m_weakreflist != NULL) {
346 PyObject_ClearWeakRefs((PyObject*) m); 335 PyObject_ClearWeakRefs((PyObject*) m);
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
549 0, /* tp_doc */ 538 0, /* tp_doc */
550 (traverseproc)meth_traverse, /* tp_traverse */ 539 (traverseproc)meth_traverse, /* tp_traverse */
551 0, /* tp_clear */ 540 0, /* tp_clear */
552 meth_richcompare, /* tp_richcompare */ 541 meth_richcompare, /* tp_richcompare */
553 offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */ 542 offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */
554 0, /* tp_iter */ 543 0, /* tp_iter */
555 0, /* tp_iternext */ 544 0, /* tp_iternext */
556 meth_methods, /* tp_methods */ 545 meth_methods, /* tp_methods */
557 meth_members, /* tp_members */ 546 meth_members, /* tp_members */
558 meth_getsets, /* tp_getset */ 547 meth_getsets, /* tp_getset */
559 0, /* tp_base */ 548
560 0, /* tp_dict */ 549 .tp_fastcall = _PyCFunction_FastCallKeywords,
561 }; 550 };
562 551
563 /* Clear out the free list */ 552 /* Clear out the free list */
564 553
565 int 554 int
566 PyCFunction_ClearFreeList(void) 555 PyCFunction_ClearFreeList(void)
567 { 556 {
568 int freelist_size = numfree; 557 int freelist_size = numfree;
569 558
570 while (free_list) { 559 while (free_list) {
(...skipping 13 matching lines...) Expand all
584 } 573 }
585 574
586 /* Print summary info about the state of the optimized allocator */ 575 /* Print summary info about the state of the optimized allocator */
587 void 576 void
588 _PyCFunction_DebugMallocStats(FILE *out) 577 _PyCFunction_DebugMallocStats(FILE *out)
589 { 578 {
590 _PyDebugAllocatorStats(out, 579 _PyDebugAllocatorStats(out,
591 "free PyCFunctionObject", 580 "free PyCFunctionObject",
592 numfree, sizeof(PyCFunctionObject)); 581 numfree, sizeof(PyCFunctionObject));
593 } 582 }
OLDNEW

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+