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

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, 2 months ago
Right Patch Set: Created 3 years, 2 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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 *kwargs) 81 PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs)
82 { 82 {
83 PyCFunctionObject* f; 83 return _PyCFunction_FastCallDict(func,
84 PyCFunction meth; 84 &PyTuple_GET_ITEM(args, 0),
85 PyObject *self; 85 PyTuple_GET_SIZE(args),
86 PyObject *arg, *res; 86 kwargs);
87 Py_ssize_t size;
88 int flags;
89
90 assert(func != NULL);
91 assert(PyCFunction_Check(func));
92 assert(PyTuple_Check(args));
93 assert(kwargs == NULL || PyDict_Check(kwargs));
94 /* PyCFunction_Call() must not be called with an exception set,
95 because it can clear it (directly or indirectly) and so the
96 caller loses its exception */
97 assert(!PyErr_Occurred());
98
99 f = (PyCFunctionObject*)func;
100 meth = PyCFunction_GET_FUNCTION(func);
101 self = PyCFunction_GET_SELF(func);
102 flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEX IST);
103
104 if (flags == (METH_VARARGS | METH_KEYWORDS)) {
105 res = (*(PyCFunctionWithKeywords)meth)(self, args, kwargs);
106 }
107 else if (flags == METH_FASTCALL) {
108 res = _Py_RawFastCallDict(self,
109 (fastternaryfunc)meth,
110 &PyTuple_GET_ITEM(args, 0),
111 PyTuple_GET_SIZE(args),
112 kwargs);
113 }
114 else {
115 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
116 PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
117 f->m_ml->ml_name);
118 return NULL;
119 }
120
121 switch (flags) {
122 case METH_VARARGS:
123 res = (*meth)(self, args);
124 break;
125
126 case METH_NOARGS:
127 size = PyTuple_GET_SIZE(args);
128 if (size != 0) {
129 PyErr_Format(PyExc_TypeError,
130 "%.200s() takes no arguments (%zd given)",
131 f->m_ml->ml_name, size);
132 return NULL;
133 }
134
135 res = (*meth)(self, NULL);
136 break;
137
138 case METH_O:
139 size = PyTuple_GET_SIZE(args);
140 if (size != 1) {
141 PyErr_Format(PyExc_TypeError,
142 "%.200s() takes exactly one argument (%zd given)",
143 f->m_ml->ml_name, size);
144 return NULL;
145 }
146
147 arg = PyTuple_GET_ITEM(args, 0);
148 res = (*meth)(self, arg);
149 break;
150
151 default:
152 PyErr_SetString(PyExc_SystemError,
153 "Bad call flags in PyCFunction_Call. "
154 "METH_OLDARGS is no longer supported!");
155 return NULL;
156 }
157 }
158
159 return _Py_CheckFunctionResult(func, res, NULL);
160 } 87 }
161 88
162 PyObject * 89 PyObject *
163 _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, 90 _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
164 PyObject *kwargs) 91 PyObject *kwargs)
165 { 92 {
166 PyCFunctionObject *func; 93 PyCFunctionObject *func = (PyCFunctionObject*)func_obj;
167 PyCFunction meth; 94 PyCFunction meth;
168 PyObject *self; 95 PyObject *self, *result;
169 PyObject *result;
170 int flags; 96 int flags;
171 97 PyObject *argstuple;
172 assert(func_obj != NULL);
173 assert(PyCFunction_Check(func_obj));
174 assert(nargs >= 0);
175 assert(nargs == 0 || args != NULL);
176 assert(kwargs == NULL || PyDict_Check(kwargs));
177 98
178 /* _PyCFunction_FastCallDict() must not be called with an exception set, 99 /* _PyCFunction_FastCallDict() must not be called with an exception set,
179 because it may clear it (directly or indirectly) and so the 100 because it may clear it (directly or indirectly) and so the
180 caller loses its exception */ 101 caller loses its exception */
181 assert(!PyErr_Occurred()); 102 assert(!PyErr_Occurred());
182 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
183 func = (PyCFunctionObject*)func_obj; 110 func = (PyCFunctionObject*)func_obj;
184 meth = PyCFunction_GET_FUNCTION(func); 111 meth = PyCFunction_GET_FUNCTION(func);
185 self = PyCFunction_GET_SELF(func); 112 self = PyCFunction_GET_SELF(func);
186 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);
187 114
188 switch (flags) 115 switch (flags)
189 { 116 {
190 case METH_NOARGS: 117 case METH_NOARGS:
191 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) {
192 goto no_keyword_error; 126 goto no_keyword_error;
193 }
194
195 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
196 PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
197 func->m_ml->ml_name);
198 return NULL;
199 } 127 }
200 128
201 result = (*meth) (self, NULL); 129 result = (*meth) (self, NULL);
202 break; 130 break;
203 131
204 case METH_O: 132 case METH_O:
205 if (nargs != 1) { 133 if (nargs != 1) {
206 PyErr_Format(PyExc_TypeError, 134 PyErr_Format(PyExc_TypeError,
207 "%.200s() takes exactly one argument (%zd given)", 135 "%.200s() takes exactly one argument (%zd given)",
208 func->m_ml->ml_name, nargs); 136 func->m_ml->ml_name, nargs);
209 return NULL; 137 return NULL;
210 } 138 }
211 139
212 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { 140 if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
213 goto no_keyword_error; 141 goto no_keyword_error;
214 } 142 }
215 143
216 result = (*meth) (self, args[0]); 144 result = (*meth) (self, args[0]);
217 break; 145 break;
218 146
219 case METH_VARARGS: 147 case METH_VARARGS:
220 case METH_VARARGS | METH_KEYWORDS:
221 {
222 /* Slow-path: create a temporary tuple for positional arguments */
223 PyObject *tuple;
224
225 if (!(flags & METH_KEYWORDS) 148 if (!(flags & METH_KEYWORDS)
226 && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { 149 && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
227 goto no_keyword_error; 150 goto no_keyword_error;
228 } 151 }
229 152 /* fall through next case */
230 tuple = _PyStack_AsTuple(args, nargs); 153
231 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) {
232 return NULL; 158 return NULL;
233 } 159 }
234 160
235 if (flags & METH_KEYWORDS) { 161 if (flags & METH_KEYWORDS) {
236 result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs); 162 result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs);
237 } 163 }
238 else { 164 else {
239 result = (*meth) (self, tuple); 165 result = (*meth) (self, argstuple);
240 } 166 }
241 Py_DECREF(tuple); 167 Py_DECREF(argstuple);
242 break; 168 break;
243 }
244 169
245 case METH_FASTCALL: 170 case METH_FASTCALL:
246 { 171 {
247 result = _Py_RawFastCallDict(self, (fastternaryfunc)meth, 172 result = _Py_RawFastCallDict(self, (fastternaryfunc)meth,
248 args, nargs, kwargs); 173 args, nargs, kwargs);
249 break; 174 break;
250 } 175 }
251 176
252 default: 177 default:
253 PyErr_SetString(PyExc_SystemError, 178 PyErr_SetString(PyExc_SystemError,
254 "Bad call flags in PyCFunction_Call. " 179 "Bad call flags in _PyMethodDef_RawFastCallDict. "
255 "METH_OLDARGS is no longer supported!"); 180 "METH_OLDARGS is no longer supported!");
256 return NULL; 181 return NULL;
257 } 182 }
258 183
259 result = _Py_CheckFunctionResult(func_obj, result, NULL); 184 result = _Py_CheckFunctionResult(func_obj, result, NULL);
260 185
261 return result; 186 return result;
262 187
263 no_keyword_error: 188 no_keyword_error:
264 PyErr_Format(PyExc_TypeError, 189 PyErr_Format(PyExc_TypeError,
265 "%.200s() takes no arguments (%zd given)", 190 "%.200s() takes no keyword arguments",
266 func->m_ml->ml_name, nargs); 191 func->m_ml->ml_name, nargs);
267 return NULL; 192 return NULL;
268 } 193 }
269 194
270 PyObject * 195 PyObject *
271 _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, 196 _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self,
272 Py_ssize_t nargs, PyObject *kwnames) 197 PyObject **args, Py_ssize_t nargs,
273 { 198 PyObject *kwnames)
274 PyCFunctionObject *func; 199 {
275 PyCFunction meth; 200 PyCFunction meth;
276 PyObject *self, *result; 201 PyObject *result;
277 Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); 202 Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
278 int flags; 203 int flags;
279 204
280 assert(func_obj != NULL);
281 assert(PyCFunction_Check(func_obj));
282 assert(nargs >= 0); 205 assert(nargs >= 0);
haypo 2017/01/26 03:35:21 assert(method != NULL);
283 assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); 206 assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
284 assert((nargs == 0 && nkwargs == 0) || args != NULL); 207 assert((nargs == 0 && nkwargs == 0) || args != NULL);
285 /* 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
286 be unique */ 209 be unique */
287 210
288 /* _PyCFunction_FastCallKeywords() must not be called with an exception 211 /* _PyCFunction_FastCallKeywords() must not be called with an exception
289 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
290 loses its exception */ 213 loses its exception */
291 assert(!PyErr_Occurred()); 214 assert(!PyErr_Occurred());
292 215
293 func = (PyCFunctionObject*)func_obj; 216 meth = method->ml_meth;
294 meth = PyCFunction_GET_FUNCTION(func); 217 flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
295 self = PyCFunction_GET_SELF(func);
296 flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEX IST);
297 218
298 switch (flags) 219 switch (flags)
299 { 220 {
300 case METH_NOARGS: 221 case METH_NOARGS:
301 if (nargs != 0) { 222 if (nargs != 0) {
302 PyErr_Format(PyExc_TypeError, 223 PyErr_Format(PyExc_TypeError,
303 "%.200s() takes no arguments (%zd given)", 224 "%.200s() takes no arguments (%zd given)",
304 func->m_ml->ml_name, nargs); 225 method->ml_name, nargs);
305 return NULL; 226 return NULL;
306 } 227 }
307 228
308 if (nkwargs) { 229 if (nkwargs) {
309 goto no_keyword_error; 230 goto no_keyword_error;
310 } 231 }
311 232
312 result = (*meth) (self, NULL); 233 result = (*meth) (self, NULL);
313 break; 234 break;
314 235
315 case METH_O: 236 case METH_O:
316 if (nargs != 1) { 237 if (nargs != 1) {
317 PyErr_Format(PyExc_TypeError, 238 PyErr_Format(PyExc_TypeError,
318 "%.200s() takes exactly one argument (%zd given)", 239 "%.200s() takes exactly one argument (%zd given)",
319 func->m_ml->ml_name, nargs); 240 method->ml_name, nargs);
320 return NULL; 241 return NULL;
321 } 242 }
322 243
323 if (nkwargs) { 244 if (nkwargs) {
324 goto no_keyword_error; 245 goto no_keyword_error;
325 } 246 }
326 247
327 result = (*meth) (self, args[0]); 248 result = (*meth) (self, args[0]);
328 break; 249 break;
329 250
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 break; 293 break;
373 } 294 }
374 295
375 default: 296 default:
376 PyErr_SetString(PyExc_SystemError, 297 PyErr_SetString(PyExc_SystemError,
377 "Bad call flags in _PyCFunction_FastCallKeywords. " 298 "Bad call flags in _PyCFunction_FastCallKeywords. "
378 "METH_OLDARGS is no longer supported!"); 299 "METH_OLDARGS is no longer supported!");
379 return NULL; 300 return NULL;
380 } 301 }
381 302
382 result = _Py_CheckFunctionResult(func_obj, result, NULL);
383 return result; 303 return result;
384 304
385 no_keyword_error: 305 no_keyword_error:
386 PyErr_Format(PyExc_TypeError, 306 PyErr_Format(PyExc_TypeError,
387 "%.200s() takes no keyword arguments", 307 "%.200s() takes no keyword arguments",
388 func->m_ml->ml_name); 308 method->ml_name);
389 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;
390 } 326 }
391 327
392 /* Methods (the standard built-in methods, that is) */ 328 /* Methods (the standard built-in methods, that is) */
393 329
394 static void 330 static void
395 meth_dealloc(PyCFunctionObject *m) 331 meth_dealloc(PyCFunctionObject *m)
396 { 332 {
397 _PyObject_GC_UNTRACK(m); 333 _PyObject_GC_UNTRACK(m);
398 if (m->m_weakreflist != NULL) { 334 if (m->m_weakreflist != NULL) {
399 PyObject_ClearWeakRefs((PyObject*) m); 335 PyObject_ClearWeakRefs((PyObject*) m);
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after
637 } 573 }
638 574
639 /* Print summary info about the state of the optimized allocator */ 575 /* Print summary info about the state of the optimized allocator */
640 void 576 void
641 _PyCFunction_DebugMallocStats(FILE *out) 577 _PyCFunction_DebugMallocStats(FILE *out)
642 { 578 {
643 _PyDebugAllocatorStats(out, 579 _PyDebugAllocatorStats(out,
644 "free PyCFunctionObject", 580 "free PyCFunctionObject",
645 numfree, sizeof(PyCFunctionObject)); 581 numfree, sizeof(PyCFunctionObject));
646 } 582 }
LEFTRIGHT

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