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

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 2 years, 12 months 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 may 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 = (PyCFunctionObject*)func_obj; 93 PyCFunctionObject *func = (PyCFunctionObject*)func_obj;
159 PyCFunction meth = PyCFunction_GET_FUNCTION(func); 94 PyCFunction meth;
160 PyObject *self = PyCFunction_GET_SELF(func); 95 PyObject *self, *result;
161 PyObject *result;
162 int flags; 96 int flags;
163 97 PyObject *argstuple;
164 assert(PyCFunction_Check(func));
165 assert(func != NULL);
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
110 func = (PyCFunctionObject*)func_obj;
111 meth = PyCFunction_GET_FUNCTION(func);
112 self = PyCFunction_GET_SELF(func);
175 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);
176 114
177 switch (flags) 115 switch (flags)
178 { 116 {
179 case METH_NOARGS: 117 case METH_NOARGS:
180 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { 118 if (nargs != 0) {
181 PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
182 func->m_ml->ml_name);
183 return NULL;
184 }
185
186 if (nargs != 0) {
187 PyErr_Format(PyExc_TypeError, 119 PyErr_Format(PyExc_TypeError,
188 "%.200s() takes no arguments (%zd given)", 120 "%.200s() takes no arguments (%zd given)",
189 func->m_ml->ml_name, nargs); 121 func->m_ml->ml_name, nargs);
190 return NULL; 122 return NULL;
123 }
124
125 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
126 goto no_keyword_error;
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 (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
198 PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
199 func->m_ml->ml_name);
200 return NULL;
201 }
202
203 if (nargs != 1) { 133 if (nargs != 1) {
204 PyErr_Format(PyExc_TypeError, 134 PyErr_Format(PyExc_TypeError,
205 "%.200s() takes exactly one argument (%zd given)", 135 "%.200s() takes exactly one argument (%zd given)",
206 func->m_ml->ml_name, nargs); 136 func->m_ml->ml_name, nargs);
207 return NULL; 137 return NULL;
208 } 138 }
209 139
140 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
141 goto no_keyword_error;
142 }
143
210 result = (*meth) (self, args[0]); 144 result = (*meth) (self, args[0]);
145 break;
146
147 case METH_VARARGS:
148 if (!(flags & METH_KEYWORDS)
149 && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
150 goto no_keyword_error;
151 }
152 /* fall through next case */
153
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) {
158 return NULL;
159 }
160
161 if (flags & METH_KEYWORDS) {
162 result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs);
163 }
164 else {
165 result = (*meth) (self, argstuple);
166 }
167 Py_DECREF(argstuple);
168 break;
169
170 case METH_FASTCALL:
171 {
172 result = _Py_RawFastCallDict(self, (fastternaryfunc)meth,
173 args, nargs, kwargs);
174 break;
175 }
176
177 default:
178 PyErr_SetString(PyExc_SystemError,
179 "Bad call flags in _PyMethodDef_RawFastCallDict. "
180 "METH_OLDARGS is no longer supported!");
181 return NULL;
182 }
183
184 result = _Py_CheckFunctionResult(func_obj, result, NULL);
185
186 return result;
187
188 no_keyword_error:
189 PyErr_Format(PyExc_TypeError,
190 "%.200s() takes no keyword arguments",
191 func->m_ml->ml_name, nargs);
192 return NULL;
193 }
194
195 PyObject *
196 _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self,
197 PyObject **args, Py_ssize_t nargs,
198 PyObject *kwnames)
199 {
200 PyCFunction meth;
201 PyObject *result;
202 Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
203 int flags;
204
205 assert(nargs >= 0);
haypo 2017/01/26 03:35:21 assert(method != NULL);
206 assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
207 assert((nargs == 0 && nkwargs == 0) || args != NULL);
208 /* kwnames must only contains str strings, no subclass, and all keys must
209 be unique */
210
211 /* _PyCFunction_FastCallKeywords() must not be called with an exception
212 set, because it can clear it (directly or indirectly) and so the caller
213 loses its exception */
214 assert(!PyErr_Occurred());
215
216 meth = method->ml_meth;
217 flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
218
219 switch (flags)
220 {
221 case METH_NOARGS:
222 if (nargs != 0) {
223 PyErr_Format(PyExc_TypeError,
224 "%.200s() takes no arguments (%zd given)",
225 method->ml_name, nargs);
226 return NULL;
227 }
228
229 if (nkwargs) {
230 goto no_keyword_error;
231 }
232
233 result = (*meth) (self, NULL);
234 break;
235
236 case METH_O:
237 if (nargs != 1) {
238 PyErr_Format(PyExc_TypeError,
239 "%.200s() takes exactly one argument (%zd given)",
240 method->ml_name, nargs);
241 return NULL;
242 }
243
244 if (nkwargs) {
245 goto no_keyword_error;
246 }
247
248 result = (*meth) (self, args[0]);
249 break;
250
251 case METH_FASTCALL:
252 /* Fast-path: avoid temporary dict to pass keyword arguments */
253 result = ((fastternaryfunc)meth) (self, args, nargs, kwnames);
211 break; 254 break;
212 255
213 case METH_VARARGS: 256 case METH_VARARGS:
214 case METH_VARARGS | METH_KEYWORDS: 257 case METH_VARARGS | METH_KEYWORDS:
215 { 258 {
216 /* Slow-path: create a temporary tuple */ 259 /* Slow-path: create a temporary tuple for positional arguments
217 PyObject *tuple; 260 and a temporary dict for keyword arguments */
218 261 PyObject *argtuple;
219 if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_GET_SIZE(kwargs ) != 0) { 262
220 PyErr_Format(PyExc_TypeError, 263 if (!(flags & METH_KEYWORDS) && nkwargs) {
221 "%.200s() takes no keyword arguments", 264 goto no_keyword_error;
222 func->m_ml->ml_name); 265 }
223 return NULL; 266
224 } 267 argtuple = _PyStack_AsTuple(args, nargs);
225 268 if (argtuple == NULL) {
226 tuple = _PyStack_AsTuple(args, nargs);
227 if (tuple == NULL) {
228 return NULL; 269 return NULL;
229 } 270 }
230 271
231 if (flags & METH_KEYWORDS) { 272 if (flags & METH_KEYWORDS) {
232 result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs); 273 PyObject *kwdict;
274
275 if (nkwargs > 0) {
276 kwdict = _PyStack_AsDict(args + nargs, kwnames);
277 if (kwdict == NULL) {
278 Py_DECREF(argtuple);
279 return NULL;
280 }
281 }
282 else {
283 kwdict = NULL;
284 }
285
286 result = (*(PyCFunctionWithKeywords)meth) (self, argtuple, kwdict);
287 Py_XDECREF(kwdict);
233 } 288 }
234 else { 289 else {
235 result = (*meth) (self, tuple); 290 result = (*meth) (self, argtuple);
236 } 291 }
237 Py_DECREF(tuple); 292 Py_DECREF(argtuple);
238 break;
239 }
240
241 case METH_FASTCALL:
242 {
243 result = _Py_FastCall_FromArgs(self, (fastternaryfunc)meth,
244 args, nargs, kwargs);
245 break; 293 break;
246 } 294 }
247 295
248 default: 296 default:
249 PyErr_SetString(PyExc_SystemError, 297 PyErr_SetString(PyExc_SystemError,
250 "Bad call flags in PyCFunction_Call. " 298 "Bad call flags in _PyCFunction_FastCallKeywords. "
251 "METH_OLDARGS is no longer supported!"); 299 "METH_OLDARGS is no longer supported!");
252 return NULL; 300 return NULL;
253 } 301 }
254 302
255 result = _Py_CheckFunctionResult(func_obj, result, NULL);
256
257 return result; 303 return result;
304
305 no_keyword_error:
306 PyErr_Format(PyExc_TypeError,
307 "%.200s() takes no keyword arguments",
308 method->ml_name);
309 return NULL;
258 } 310 }
259 311
260 PyObject * 312 PyObject *
261 _PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack, 313 _PyCFunction_FastCallKeywords(PyObject *func, PyObject **args,
262 Py_ssize_t nargs, PyObject *kwnames) 314 Py_ssize_t nargs, PyObject *kwnames)
263 { 315 {
264 PyObject *kwdict, *result; 316 PyObject *result;
265 Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); 317
266 318 assert(func != NULL);
267 assert(PyCFunction_Check(func)); 319 assert(PyCFunction_Check(func));
268 assert(nargs >= 0); 320
269 assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); 321 result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml,
270 assert((nargs == 0 && nkwargs == 0) || stack != NULL); 322 PyCFunction_GET_SELF(func),
271 /* kwnames must only contains str strings, no subclass, and all keys must 323 args, nargs, kwnames);
272 be unique */ 324 result = _Py_CheckFunctionResult(func, result, NULL);
273
274 if (nkwargs > 0) {
275 kwdict = _PyStack_AsDict(stack + nargs, kwnames);
276 if (kwdict == NULL) {
277 return NULL;
278 }
279 }
280 else {
281 kwdict = NULL;
282 }
283
284 result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict);
285 Py_XDECREF(kwdict);
286 return result; 325 return result;
287 } 326 }
288 327
289 /* Methods (the standard built-in methods, that is) */ 328 /* Methods (the standard built-in methods, that is) */
290 329
291 static void 330 static void
292 meth_dealloc(PyCFunctionObject *m) 331 meth_dealloc(PyCFunctionObject *m)
293 { 332 {
294 _PyObject_GC_UNTRACK(m); 333 _PyObject_GC_UNTRACK(m);
295 if (m->m_weakreflist != NULL) { 334 if (m->m_weakreflist != NULL) {
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 0, /* tp_doc */ 538 0, /* tp_doc */
500 (traverseproc)meth_traverse, /* tp_traverse */ 539 (traverseproc)meth_traverse, /* tp_traverse */
501 0, /* tp_clear */ 540 0, /* tp_clear */
502 meth_richcompare, /* tp_richcompare */ 541 meth_richcompare, /* tp_richcompare */
503 offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */ 542 offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */
504 0, /* tp_iter */ 543 0, /* tp_iter */
505 0, /* tp_iternext */ 544 0, /* tp_iternext */
506 meth_methods, /* tp_methods */ 545 meth_methods, /* tp_methods */
507 meth_members, /* tp_members */ 546 meth_members, /* tp_members */
508 meth_getsets, /* tp_getset */ 547 meth_getsets, /* tp_getset */
509 0, /* tp_base */ 548
510 0, /* tp_dict */ 549 .tp_fastcall = _PyCFunction_FastCallKeywords,
511 0, /* tp_descr_get */
512 0, /* tp_descr_set */
513 0, /* tp_dictoffset */
514 0, /* tp_init */
515 0, /* tp_alloc */
516 0, /* tp_new */
517 0, /* tp_free */
518 0, /* tp_is_gc */
519 0, /* tp_bases */
520 0, /* tp_mro */
521 0, /* tp_cache */
522 0, /* tp_subclasses */
523 0, /* tp_weaklist */
524 0, /* tp_del */
525 0, /* tp_version_tag */
526 0, /* tp_finalize */
527 _PyCFunction_FastCallKeywords, /* tp_fastcall */
528 }; 550 };
529 551
530 /* Clear out the free list */ 552 /* Clear out the free list */
531 553
532 int 554 int
533 PyCFunction_ClearFreeList(void) 555 PyCFunction_ClearFreeList(void)
534 { 556 {
535 int freelist_size = numfree; 557 int freelist_size = numfree;
536 558
537 while (free_list) { 559 while (free_list) {
(...skipping 13 matching lines...) Expand all
551 } 573 }
552 574
553 /* Print summary info about the state of the optimized allocator */ 575 /* Print summary info about the state of the optimized allocator */
554 void 576 void
555 _PyCFunction_DebugMallocStats(FILE *out) 577 _PyCFunction_DebugMallocStats(FILE *out)
556 { 578 {
557 _PyDebugAllocatorStats(out, 579 _PyDebugAllocatorStats(out,
558 "free PyCFunctionObject", 580 "free PyCFunctionObject",
559 numfree, sizeof(PyCFunctionObject)); 581 numfree, sizeof(PyCFunctionObject));
560 } 582 }
LEFTRIGHT

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