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

Delta Between Two Patch Sets: Objects/methodobject.c

Issue 29259: Add tp_fastcall to PyTypeObject: support FASTCALL calling convention for all callable objects
Left Patch Set: Created 3 years ago
Right 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 PyCFunction_GetFlags(PyObject *op) 71 PyCFunction_GetFlags(PyObject *op)
72 { 72 {
73 if (!PyCFunction_Check(op)) { 73 if (!PyCFunction_Check(op)) {
74 PyErr_BadInternalCall(); 74 PyErr_BadInternalCall();
75 return -1; 75 return -1;
76 } 76 }
77 return PyCFunction_GET_FLAGS(op); 77 return PyCFunction_GET_FLAGS(op);
78 } 78 }
79 79
80 PyObject * 80 PyObject *
81 PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) 81 PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs)
82 { 82 {
83 PyCFunctionObject* f = (PyCFunctionObject*)func; 83 return _PyCFunction_FastCallDict(func,
84 PyCFunction meth = PyCFunction_GET_FUNCTION(func); 84 &PyTuple_GET_ITEM(args, 0),
85 PyObject *self = PyCFunction_GET_SELF(func); 85 PyTuple_GET_SIZE(args),
86 PyObject *arg, *res; 86 kwargs);
87 Py_ssize_t size;
88 int flags;
89
90 assert(kwds == NULL || PyDict_Check(kwds));
91 /* PyCFunction_Call() must not be called with an exception set,
92 because it can clear it (directly or indirectly) and so the
93 caller loses its exception */
94 assert(!PyErr_Occurred());
95
96 flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEX IST);
97
98 if (flags == (METH_VARARGS | METH_KEYWORDS)) {
99 res = (*(PyCFunctionWithKeywords)meth)(self, args, kwds);
100 }
101 else if (flags == METH_FASTCALL) {
102 PyObject **stack = &PyTuple_GET_ITEM(args, 0);
103 Py_ssize_t nargs = PyTuple_GET_SIZE(args);
104 res = _PyCFunction_FastCallDict(func, stack, nargs, kwds);
105 }
106 else {
107 if (kwds != NULL && PyDict_GET_SIZE(kwds) != 0) {
108 PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
109 f->m_ml->ml_name);
110 return NULL;
111 }
112
113 switch (flags) {
114 case METH_VARARGS:
115 res = (*meth)(self, args);
116 break;
117
118 case METH_NOARGS:
119 size = PyTuple_GET_SIZE(args);
120 if (size != 0) {
121 PyErr_Format(PyExc_TypeError,
122 "%.200s() takes no arguments (%zd given)",
123 f->m_ml->ml_name, size);
124 return NULL;
125 }
126
127 res = (*meth)(self, NULL);
128 break;
129
130 case METH_O:
131 size = PyTuple_GET_SIZE(args);
132 if (size != 1) {
133 PyErr_Format(PyExc_TypeError,
134 "%.200s() takes exactly one argument (%zd given)",
135 f->m_ml->ml_name, size);
136 return NULL;
137 }
138
139 arg = PyTuple_GET_ITEM(args, 0);
140 res = (*meth)(self, arg);
141 break;
142
143 default:
144 PyErr_SetString(PyExc_SystemError,
145 "Bad call flags in PyCFunction_Call. "
146 "METH_OLDARGS is no longer supported!");
147 return NULL;
148 }
149 }
150
151 return _Py_CheckFunctionResult(func, res, NULL);
152 } 87 }
153 88
154 PyObject * 89 PyObject *
155 _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, 90 _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
156 PyObject *kwargs) 91 PyObject *kwargs)
157 { 92 {
158 PyCFunctionObject *func; 93 PyCFunctionObject *func = (PyCFunctionObject*)func_obj;
159 PyCFunction meth; 94 PyCFunction meth;
160 PyObject *self; 95 PyObject *self, *result;
161 PyObject *result;
162 int flags; 96 int flags;
163 97 PyObject *argstuple;
164 assert(func_obj != NULL);
165 assert(PyCFunction_Check(func_obj));
166 assert(nargs >= 0);
167 assert(nargs == 0 || args != NULL);
168 assert(kwargs == NULL || PyDict_Check(kwargs));
169 98
170 /* _PyCFunction_FastCallDict() must not be called with an exception set, 99 /* _PyCFunction_FastCallDict() must not be called with an exception set,
171 because it may clear it (directly or indirectly) and so the 100 because it may clear it (directly or indirectly) and so the
172 caller loses its exception */ 101 caller loses its exception */
173 assert(!PyErr_Occurred()); 102 assert(!PyErr_Occurred());
174 103
104 assert(PyCFunction_Check(func_obj));
105 assert(func_obj != NULL);
haypo 2017/01/26 03:35:21 assertions in the wrong order.
106 assert(nargs >= 0);
107 assert(nargs == 0 || args != NULL);
108 assert(kwargs == NULL || PyDict_Check(kwargs));
109
175 func = (PyCFunctionObject*)func_obj; 110 func = (PyCFunctionObject*)func_obj;
176 meth = PyCFunction_GET_FUNCTION(func); 111 meth = PyCFunction_GET_FUNCTION(func);
177 self = PyCFunction_GET_SELF(func); 112 self = PyCFunction_GET_SELF(func);
178 flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEX IST); 113 flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEX IST);
179 114
180 switch (flags) 115 switch (flags)
181 { 116 {
182 case METH_NOARGS: 117 case METH_NOARGS:
183 if (nargs != 0) { 118 if (nargs != 0) {
119 PyErr_Format(PyExc_TypeError,
120 "%.200s() takes no arguments (%zd given)",
121 func->m_ml->ml_name, nargs);
122 return NULL;
123 }
124
125 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
184 goto no_keyword_error; 126 goto no_keyword_error;
185 }
186
187 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
188 PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
189 func->m_ml->ml_name);
190 return NULL;
191 } 127 }
192 128
193 result = (*meth) (self, NULL); 129 result = (*meth) (self, NULL);
194 break; 130 break;
195 131
196 case METH_O: 132 case METH_O:
197 if (nargs != 1) { 133 if (nargs != 1) {
198 PyErr_Format(PyExc_TypeError, 134 PyErr_Format(PyExc_TypeError,
199 "%.200s() takes exactly one argument (%zd given)", 135 "%.200s() takes exactly one argument (%zd given)",
200 func->m_ml->ml_name, nargs); 136 func->m_ml->ml_name, nargs);
201 return NULL; 137 return NULL;
202 } 138 }
203 139
204 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { 140 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
205 goto no_keyword_error; 141 goto no_keyword_error;
206 } 142 }
207 143
208 result = (*meth) (self, args[0]); 144 result = (*meth) (self, args[0]);
209 break; 145 break;
210 146
211 case METH_VARARGS: 147 case METH_VARARGS:
212 case METH_VARARGS | METH_KEYWORDS:
213 {
214 /* Slow-path: create a temporary tuple for positional arguments */
215 PyObject *tuple;
216
217 if (!(flags & METH_KEYWORDS) 148 if (!(flags & METH_KEYWORDS)
218 && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { 149 && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
219 goto no_keyword_error; 150 goto no_keyword_error;
220 } 151 }
221 152 /* fall through next case */
222 tuple = _PyStack_AsTuple(args, nargs); 153
223 if (tuple == NULL) { 154 case METH_VARARGS | METH_KEYWORDS:
155 /* Slow-path: create a temporary tuple for positional arguments */
156 argstuple = _PyStack_AsTuple(args, nargs);
157 if (argstuple == NULL) {
224 return NULL; 158 return NULL;
225 } 159 }
226 160
227 if (flags & METH_KEYWORDS) { 161 if (flags & METH_KEYWORDS) {
228 result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs); 162 result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs);
229 } 163 }
230 else { 164 else {
231 result = (*meth) (self, tuple); 165 result = (*meth) (self, argstuple);
232 } 166 }
233 Py_DECREF(tuple); 167 Py_DECREF(argstuple);
234 break; 168 break;
235 }
236 169
237 case METH_FASTCALL: 170 case METH_FASTCALL:
238 { 171 {
239 result = _Py_FastCall_FromArgs(self, (fastternaryfunc)meth, 172 result = _Py_RawFastCallDict(self, (fastternaryfunc)meth,
240 args, nargs, kwargs); 173 args, nargs, kwargs);
241 break; 174 break;
242 } 175 }
243 176
244 default: 177 default:
245 PyErr_SetString(PyExc_SystemError, 178 PyErr_SetString(PyExc_SystemError,
246 "Bad call flags in PyCFunction_Call. " 179 "Bad call flags in _PyMethodDef_RawFastCallDict. "
247 "METH_OLDARGS is no longer supported!"); 180 "METH_OLDARGS is no longer supported!");
248 return NULL; 181 return NULL;
249 } 182 }
250 183
251 result = _Py_CheckFunctionResult(func_obj, result, NULL); 184 result = _Py_CheckFunctionResult(func_obj, result, NULL);
252 185
253 return result; 186 return result;
254 187
255 no_keyword_error: 188 no_keyword_error:
256 PyErr_Format(PyExc_TypeError, 189 PyErr_Format(PyExc_TypeError,
257 "%.200s() takes no arguments (%zd given)", 190 "%.200s() takes no keyword arguments",
258 func->m_ml->ml_name, nargs); 191 func->m_ml->ml_name, nargs);
259 return NULL; 192 return NULL;
260 } 193 }
261 194
262 PyObject * 195 PyObject *
263 _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, 196 _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self,
264 Py_ssize_t nargs, PyObject *kwnames) 197 PyObject **args, Py_ssize_t nargs,
265 { 198 PyObject *kwnames)
266 PyCFunctionObject *func; 199 {
267 PyCFunction meth; 200 PyCFunction meth;
268 PyObject *self, *result; 201 PyObject *result;
269 Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); 202 Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
270 int flags; 203 int flags;
271 204
272 assert(func_obj != NULL);
273 assert(PyCFunction_Check(func_obj));
274 assert(nargs >= 0); 205 assert(nargs >= 0);
haypo 2017/01/26 03:35:21 assert(method != NULL);
275 assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); 206 assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
276 assert((nargs == 0 && nkwargs == 0) || args != NULL); 207 assert((nargs == 0 && nkwargs == 0) || args != NULL);
277 /* 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
278 be unique */ 209 be unique */
279 210
280 /* _PyCFunction_FastCallKeywords() must not be called with an exception 211 /* _PyCFunction_FastCallKeywords() must not be called with an exception
281 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
282 loses its exception */ 213 loses its exception */
283 assert(!PyErr_Occurred()); 214 assert(!PyErr_Occurred());
284 215
285 func = (PyCFunctionObject*)func_obj; 216 meth = method->ml_meth;
286 meth = PyCFunction_GET_FUNCTION(func); 217 flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
287 self = PyCFunction_GET_SELF(func);
288 flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEX IST);
289 218
290 switch (flags) 219 switch (flags)
291 { 220 {
292 case METH_NOARGS: 221 case METH_NOARGS:
293 if (nargs != 0) { 222 if (nargs != 0) {
294 PyErr_Format(PyExc_TypeError, 223 PyErr_Format(PyExc_TypeError,
295 "%.200s() takes no arguments (%zd given)", 224 "%.200s() takes no arguments (%zd given)",
296 func->m_ml->ml_name, nargs); 225 method->ml_name, nargs);
297 return NULL; 226 return NULL;
298 } 227 }
299 228
300 if (nkwargs) { 229 if (nkwargs) {
301 goto no_keyword_error; 230 goto no_keyword_error;
302 } 231 }
303 232
304 result = (*meth) (self, NULL); 233 result = (*meth) (self, NULL);
305 break; 234 break;
306 235
307 case METH_O: 236 case METH_O:
308 if (nargs != 1) { 237 if (nargs != 1) {
309 PyErr_Format(PyExc_TypeError, 238 PyErr_Format(PyExc_TypeError,
310 "%.200s() takes exactly one argument (%zd given)", 239 "%.200s() takes exactly one argument (%zd given)",
311 func->m_ml->ml_name, nargs); 240 method->ml_name, nargs);
312 return NULL; 241 return NULL;
313 } 242 }
314 243
315 if (nkwargs) { 244 if (nkwargs) {
316 goto no_keyword_error; 245 goto no_keyword_error;
317 } 246 }
318 247
319 result = (*meth) (self, args[0]); 248 result = (*meth) (self, args[0]);
320 break; 249 break;
321 250
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
364 break; 293 break;
365 } 294 }
366 295
367 default: 296 default:
368 PyErr_SetString(PyExc_SystemError, 297 PyErr_SetString(PyExc_SystemError,
369 "Bad call flags in _PyCFunction_FastCallKeywords. " 298 "Bad call flags in _PyCFunction_FastCallKeywords. "
370 "METH_OLDARGS is no longer supported!"); 299 "METH_OLDARGS is no longer supported!");
371 return NULL; 300 return NULL;
372 } 301 }
373 302
374 result = _Py_CheckFunctionResult(func_obj, result, NULL);
375 return result; 303 return result;
376 304
377 no_keyword_error: 305 no_keyword_error:
378 PyErr_Format(PyExc_TypeError, 306 PyErr_Format(PyExc_TypeError,
379 "%.200s() takes no keyword arguments", 307 "%.200s() takes no keyword arguments",
380 func->m_ml->ml_name); 308 method->ml_name);
381 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;
382 } 326 }
383 327
384 /* Methods (the standard built-in methods, that is) */ 328 /* Methods (the standard built-in methods, that is) */
385 329
386 static void 330 static void
387 meth_dealloc(PyCFunctionObject *m) 331 meth_dealloc(PyCFunctionObject *m)
388 { 332 {
389 _PyObject_GC_UNTRACK(m); 333 _PyObject_GC_UNTRACK(m);
390 if (m->m_weakreflist != NULL) { 334 if (m->m_weakreflist != NULL) {
391 PyObject_ClearWeakRefs((PyObject*) m); 335 PyObject_ClearWeakRefs((PyObject*) m);
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
583 (reprfunc)meth_repr, /* tp_repr */ 527 (reprfunc)meth_repr, /* tp_repr */
584 0, /* tp_as_number */ 528 0, /* tp_as_number */
585 0, /* tp_as_sequence */ 529 0, /* tp_as_sequence */
586 0, /* tp_as_mapping */ 530 0, /* tp_as_mapping */
587 (hashfunc)meth_hash, /* tp_hash */ 531 (hashfunc)meth_hash, /* tp_hash */
588 PyCFunction_Call, /* tp_call */ 532 PyCFunction_Call, /* tp_call */
589 0, /* tp_str */ 533 0, /* tp_str */
590 PyObject_GenericGetAttr, /* tp_getattro */ 534 PyObject_GenericGetAttr, /* tp_getattro */
591 0, /* tp_setattro */ 535 0, /* tp_setattro */
592 0, /* tp_as_buffer */ 536 0, /* tp_as_buffer */
593 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC 537 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
594 | Py_TPFLAGS_HAVE_FASTCALL, /* tp_flags */
595 0, /* tp_doc */ 538 0, /* tp_doc */
596 (traverseproc)meth_traverse, /* tp_traverse */ 539 (traverseproc)meth_traverse, /* tp_traverse */
597 0, /* tp_clear */ 540 0, /* tp_clear */
598 meth_richcompare, /* tp_richcompare */ 541 meth_richcompare, /* tp_richcompare */
599 offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */ 542 offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */
600 0, /* tp_iter */ 543 0, /* tp_iter */
601 0, /* tp_iternext */ 544 0, /* tp_iternext */
602 meth_methods, /* tp_methods */ 545 meth_methods, /* tp_methods */
603 meth_members, /* tp_members */ 546 meth_members, /* tp_members */
604 meth_getsets, /* tp_getset */ 547 meth_getsets, /* tp_getset */
605 0, /* tp_base */ 548
606 0, /* tp_dict */ 549 .tp_fastcall = _PyCFunction_FastCallKeywords,
607 0, /* tp_descr_get */
608 0, /* tp_descr_set */
609 0, /* tp_dictoffset */
610 0, /* tp_init */
611 0, /* tp_alloc */
612 0, /* tp_new */
613 0, /* tp_free */
614 0, /* tp_is_gc */
615 0, /* tp_bases */
616 0, /* tp_mro */
617 0, /* tp_cache */
618 0, /* tp_subclasses */
619 0, /* tp_weaklist */
620 0, /* tp_del */
621 0, /* tp_version_tag */
622 0, /* tp_finalize */
623 _PyCFunction_FastCallKeywords, /* tp_fastcall */
624 }; 550 };
625 551
626 /* Clear out the free list */ 552 /* Clear out the free list */
627 553
628 int 554 int
629 PyCFunction_ClearFreeList(void) 555 PyCFunction_ClearFreeList(void)
630 { 556 {
631 int freelist_size = numfree; 557 int freelist_size = numfree;
632 558
633 while (free_list) { 559 while (free_list) {
(...skipping 13 matching lines...) Expand all
647 } 573 }
648 574
649 /* Print summary info about the state of the optimized allocator */ 575 /* Print summary info about the state of the optimized allocator */
650 void 576 void
651 _PyCFunction_DebugMallocStats(FILE *out) 577 _PyCFunction_DebugMallocStats(FILE *out)
652 { 578 {
653 _PyDebugAllocatorStats(out, 579 _PyDebugAllocatorStats(out,
654 "free PyCFunctionObject", 580 "free PyCFunctionObject",
655 numfree, sizeof(PyCFunctionObject)); 581 numfree, sizeof(PyCFunctionObject));
656 } 582 }
LEFTRIGHT

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