/Objects/methodobject.c
C | 492 lines | 415 code | 51 blank | 26 comment | 106 complexity | 0de397c7faf3941acc6e537f1d0af34c MD5 | raw file
Possible License(s): 0BSD, BSD-3-Clause
1
2/* Method object implementation */
3
4#include "Python.h"
5#include "structmember.h"
6
7/* Free list for method objects to safe malloc/free overhead
8 * The m_self element is used to chain the objects.
9 */
10static PyCFunctionObject *free_list = NULL;
11static int numfree = 0;
12#ifndef PyCFunction_MAXFREELIST
13#define PyCFunction_MAXFREELIST 256
14#endif
15
16int
17PyMethodDef_Ready(PyMethodDef *ml)
18{
19 /* Rewrite the old METH_O/METH_NOARGS flags to the new METH_ARG_RANGE
20 so we only have to implement METH_ARG_RANGE. */
21 if (ml->ml_flags & METH_NOARGS) {
22 ml->ml_flags &= ~METH_NOARGS;
23 ml->ml_flags |= METH_ARG_RANGE;
24 ml->ml_min_arity = 0;
25 ml->ml_max_arity = 0;
26 }
27 else if (ml->ml_flags & METH_O) {
28 ml->ml_flags &= ~METH_O;
29 ml->ml_flags |= METH_ARG_RANGE;
30 ml->ml_min_arity = 1;
31 ml->ml_max_arity = 1;
32 }
33
34 /* Check that METH_ARG_RANGE methods have valid arities. */
35 if (ml->ml_flags & METH_ARG_RANGE) {
36 if (ml->ml_min_arity < 0 || ml->ml_min_arity > PY_MAX_ARITY ||
37 ml->ml_max_arity < 0 || ml->ml_max_arity > PY_MAX_ARITY ||
38 ml->ml_max_arity < ml->ml_min_arity) {
39 PyErr_BadInternalCall();
40 return -1;
41 }
42 }
43
44 return 0;
45}
46
47PyObject *
48PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
49{
50 PyCFunctionObject *op;
51
52 /* Sanity check early, to avoid having to clean up from the mixed
53 free list/allocation scheme below. */
54 if (PyMethodDef_Ready(ml) < 0) {
55 return NULL;
56 }
57
58 op = free_list;
59 if (op != NULL) {
60 free_list = (PyCFunctionObject *)(op->m_self);
61 PyObject_INIT(op, &PyCFunction_Type);
62 numfree--;
63 }
64 else {
65 op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
66 if (op == NULL)
67 return NULL;
68 }
69
70 op->m_ml = ml;
71 Py_XINCREF(self);
72 op->m_self = self;
73 Py_XINCREF(module);
74 op->m_module = module;
75 _PyObject_GC_TRACK(op);
76 return (PyObject *)op;
77}
78
79PyCFunction
80PyCFunction_GetFunction(PyObject *op)
81{
82 if (!PyCFunction_Check(op)) {
83 PyErr_BadInternalCall();
84 return NULL;
85 }
86 return ((PyCFunctionObject *)op) -> m_ml -> ml_meth;
87}
88
89PyObject *
90PyCFunction_GetSelf(PyObject *op)
91{
92 if (!PyCFunction_Check(op)) {
93 PyErr_BadInternalCall();
94 return NULL;
95 }
96 return ((PyCFunctionObject *)op) -> m_self;
97}
98
99int
100PyCFunction_GetFlags(PyObject *op)
101{
102 if (!PyCFunction_Check(op)) {
103 PyErr_BadInternalCall();
104 return -1;
105 }
106 return ((PyCFunctionObject *)op) -> m_ml -> ml_flags;
107}
108
109PyObject *
110PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw)
111{
112 return PyMethodDef_Call(PyCFunction_GET_METHODDEF(func),
113 PyCFunction_GET_SELF(func), arg, kw);
114}
115
116PyObject *
117PyMethodDef_Call(PyMethodDef *ml, PyObject *self, PyObject *arg, PyObject *kw)
118{
119 PyCFunction meth = ml->ml_meth;
120 Py_ssize_t size;
121
122 switch (ml->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) {
123 case METH_VARARGS:
124 if (kw == NULL || PyDict_Size(kw) == 0)
125 return (*meth)(self, arg);
126 break;
127 case METH_VARARGS | METH_KEYWORDS:
128 case METH_OLDARGS | METH_KEYWORDS:
129 return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
130 case METH_ARG_RANGE:
131 {
132 if (kw == NULL || PyDict_Size(kw) == 0) {
133 PyObject *args[PY_MAX_ARITY] = {NULL};
134 int min_arity = ml->ml_min_arity;
135 int max_arity = ml->ml_max_arity;
136 size = PyTuple_GET_SIZE(arg);
137 switch (size) {
138 default:
139 PyErr_BadInternalCall();
140 return NULL;
141 case 3: args[2] = PyTuple_GET_ITEM(arg, 2);
142 case 2: args[1] = PyTuple_GET_ITEM(arg, 1);
143 case 1: args[0] = PyTuple_GET_ITEM(arg, 0);
144 case 0: break;
145 }
146
147 /* But wait, you ask, what about {un,bin}ary functions?
148 Aren't we passing more arguments than it expects?
149 Yes, but C allows this. Go C. */
150 if (min_arity <= size && size <= max_arity)
151 return (*(PyCFunctionThreeArgs)meth)
152 (self, args[0], args[1], args[2]);
153
154 if (max_arity == min_arity)
155 PyErr_Format(PyExc_TypeError,
156 "%.200s() takes exactly %d argument(s)"
157 " (%zd given)",
158 ml->ml_name, max_arity, size);
159 else
160 PyErr_Format(PyExc_TypeError,
161 "%.200s() takes %d-%d arguments"
162 " (%zd given)",
163 ml->ml_name, min_arity, max_arity,
164 size);
165
166 return NULL;
167 }
168 break;
169 }
170 case METH_OLDARGS:
171 /* the really old style */
172 if (kw == NULL || PyDict_Size(kw) == 0) {
173 size = PyTuple_GET_SIZE(arg);
174 if (size == 1)
175 arg = PyTuple_GET_ITEM(arg, 0);
176 else if (size == 0)
177 arg = NULL;
178 return (*meth)(self, arg);
179 }
180 break;
181 /* METH_O is deprecated; PyCFunction_NewEx is supposed to convert it to
182 METH_ARG_RANGE and set ml_{min,max}_arity correctly. */
183 case METH_O:
184 default:
185 PyErr_BadInternalCall();
186 return NULL;
187 }
188 PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
189 ml->ml_name);
190 return NULL;
191}
192
193/* Methods (the standard built-in methods, that is) */
194
195static void
196meth_dealloc(PyCFunctionObject *m)
197{
198 _PyObject_GC_UNTRACK(m);
199 Py_XDECREF(m->m_self);
200 Py_XDECREF(m->m_module);
201 if (numfree < PyCFunction_MAXFREELIST) {
202 m->m_self = (PyObject *)free_list;
203 free_list = m;
204 numfree++;
205 }
206 else {
207 PyObject_GC_Del(m);
208 }
209}
210
211static PyObject *
212meth_get__doc__(PyCFunctionObject *m, void *closure)
213{
214 const char *doc = m->m_ml->ml_doc;
215
216 if (doc != NULL)
217 return PyString_FromString(doc);
218 Py_INCREF(Py_None);
219 return Py_None;
220}
221
222static PyObject *
223meth_get__name__(PyCFunctionObject *m, void *closure)
224{
225 return PyString_FromString(m->m_ml->ml_name);
226}
227
228static int
229meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
230{
231 Py_VISIT(m->m_self);
232 Py_VISIT(m->m_module);
233 return 0;
234}
235
236static PyObject *
237meth_get__self__(PyCFunctionObject *m, void *closure)
238{
239 PyObject *self;
240 if (PyEval_GetRestricted()) {
241 PyErr_SetString(PyExc_RuntimeError,
242 "method.__self__ not accessible in restricted mode");
243 return NULL;
244 }
245 self = m->m_self;
246 if (self == NULL)
247 self = Py_None;
248 Py_INCREF(self);
249 return self;
250}
251
252static PyGetSetDef meth_getsets [] = {
253 {"__doc__", (getter)meth_get__doc__, NULL, NULL},
254 {"__name__", (getter)meth_get__name__, NULL, NULL},
255 {"__self__", (getter)meth_get__self__, NULL, NULL},
256 {0}
257};
258
259#define OFF(x) offsetof(PyCFunctionObject, x)
260
261static PyMemberDef meth_members[] = {
262 {"__module__", T_OBJECT, OFF(m_module), PY_WRITE_RESTRICTED},
263 {NULL}
264};
265
266static PyObject *
267meth_repr(PyCFunctionObject *m)
268{
269 if (m->m_self == NULL)
270 return PyString_FromFormat("<built-in function %s>",
271 m->m_ml->ml_name);
272 return PyString_FromFormat("<built-in method %s of %s object at %p>",
273 m->m_ml->ml_name,
274 m->m_self->ob_type->tp_name,
275 m->m_self);
276}
277
278static int
279meth_compare(PyCFunctionObject *a, PyCFunctionObject *b)
280{
281 if (a->m_self != b->m_self)
282 return (a->m_self < b->m_self) ? -1 : 1;
283 if (a->m_ml->ml_meth == b->m_ml->ml_meth)
284 return 0;
285 if (strcmp(a->m_ml->ml_name, b->m_ml->ml_name) < 0)
286 return -1;
287 else
288 return 1;
289}
290
291static PyObject *
292meth_richcompare(PyObject *self, PyObject *other, int op)
293{
294 PyCFunctionObject *a, *b;
295 PyObject *res;
296 int eq;
297
298 if (op != Py_EQ && op != Py_NE) {
299 /* Py3K warning if comparison isn't == or !=. */
300 if (PyErr_WarnPy3k("builtin_function_or_method order "
301 "comparisons not supported in 3.x", 1) < 0) {
302 return NULL;
303 }
304
305 Py_INCREF(Py_NotImplemented);
306 return Py_NotImplemented;
307 }
308 else if (!PyCFunction_Check(self) || !PyCFunction_Check(other)) {
309 Py_INCREF(Py_NotImplemented);
310 return Py_NotImplemented;
311 }
312 a = (PyCFunctionObject *)self;
313 b = (PyCFunctionObject *)other;
314 eq = a->m_self == b->m_self;
315 if (eq)
316 eq = a->m_ml->ml_meth == b->m_ml->ml_meth;
317 if (op == Py_EQ)
318 res = eq ? Py_True : Py_False;
319 else
320 res = eq ? Py_False : Py_True;
321 Py_INCREF(res);
322 return res;
323}
324
325static long
326meth_hash(PyCFunctionObject *a)
327{
328 long x,y;
329 if (a->m_self == NULL)
330 x = 0;
331 else {
332 x = PyObject_Hash(a->m_self);
333 if (x == -1)
334 return -1;
335 }
336 y = _Py_HashPointer((void*)(a->m_ml->ml_meth));
337 if (y == -1)
338 return -1;
339 x ^= y;
340 if (x == -1)
341 x = -2;
342 return x;
343}
344
345
346PyTypeObject PyCFunction_Type = {
347 PyVarObject_HEAD_INIT(&PyType_Type, 0)
348 "builtin_function_or_method",
349 sizeof(PyCFunctionObject),
350 0,
351 (destructor)meth_dealloc, /* tp_dealloc */
352 0, /* tp_print */
353 0, /* tp_getattr */
354 0, /* tp_setattr */
355 (cmpfunc)meth_compare, /* tp_compare */
356 (reprfunc)meth_repr, /* tp_repr */
357 0, /* tp_as_number */
358 0, /* tp_as_sequence */
359 0, /* tp_as_mapping */
360 (hashfunc)meth_hash, /* tp_hash */
361 PyCFunction_Call, /* tp_call */
362 0, /* tp_str */
363 PyObject_GenericGetAttr, /* tp_getattro */
364 0, /* tp_setattro */
365 0, /* tp_as_buffer */
366 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
367 0, /* tp_doc */
368 (traverseproc)meth_traverse, /* tp_traverse */
369 0, /* tp_clear */
370 meth_richcompare, /* tp_richcompare */
371 0, /* tp_weaklistoffset */
372 0, /* tp_iter */
373 0, /* tp_iternext */
374 0, /* tp_methods */
375 meth_members, /* tp_members */
376 meth_getsets, /* tp_getset */
377 0, /* tp_base */
378 0, /* tp_dict */
379};
380
381/* List all methods in a chain -- helper for findmethodinchain */
382
383static PyObject *
384listmethodchain(PyMethodChain *chain)
385{
386 PyMethodChain *c;
387 PyMethodDef *ml;
388 int i, n;
389 PyObject *v;
390
391 n = 0;
392 for (c = chain; c != NULL; c = c->link) {
393 for (ml = c->methods; ml->ml_name != NULL; ml++)
394 n++;
395 }
396 v = PyList_New(n);
397 if (v == NULL)
398 return NULL;
399 i = 0;
400 for (c = chain; c != NULL; c = c->link) {
401 for (ml = c->methods; ml->ml_name != NULL; ml++) {
402 PyList_SetItem(v, i, PyString_FromString(ml->ml_name));
403 i++;
404 }
405 }
406 if (PyErr_Occurred()) {
407 Py_DECREF(v);
408 return NULL;
409 }
410 PyList_Sort(v);
411 return v;
412}
413
414/* Find a method in a method chain */
415
416PyObject *
417Py_FindMethodInChain(PyMethodChain *chain, PyObject *self, const char *name)
418{
419 if (name[0] == '_' && name[1] == '_') {
420 if (strcmp(name, "__methods__") == 0) {
421 if (PyErr_WarnPy3k("__methods__ not supported in 3.x",
422 1) < 0)
423 return NULL;
424 return listmethodchain(chain);
425 }
426 if (strcmp(name, "__doc__") == 0) {
427 const char *doc = self->ob_type->tp_doc;
428 if (doc != NULL)
429 return PyString_FromString(doc);
430 }
431 }
432 while (chain != NULL) {
433 PyMethodDef *ml = chain->methods;
434 for (; ml->ml_name != NULL; ml++) {
435 if (name[0] == ml->ml_name[0] &&
436 strcmp(name+1, ml->ml_name+1) == 0)
437 /* XXX */
438 return PyCFunction_New(ml, self);
439 }
440 chain = chain->link;
441 }
442 PyErr_SetString(PyExc_AttributeError, name);
443 return NULL;
444}
445
446/* Find a method in a single method list */
447
448PyObject *
449Py_FindMethod(PyMethodDef *methods, PyObject *self, const char *name)
450{
451 PyMethodChain chain;
452 chain.methods = methods;
453 chain.link = NULL;
454 return Py_FindMethodInChain(&chain, self, name);
455}
456
457/* Clear out the free list */
458
459int
460PyCFunction_ClearFreeList(void)
461{
462 int freelist_size = numfree;
463
464 while (free_list) {
465 PyCFunctionObject *v = free_list;
466 free_list = (PyCFunctionObject *)(v->m_self);
467 PyObject_GC_Del(v);
468 numfree--;
469 }
470 assert(numfree == 0);
471 return freelist_size;
472}
473
474void
475PyCFunction_Fini(void)
476{
477 (void)PyCFunction_ClearFreeList();
478}
479
480/* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(),
481 but it's part of the API so we need to keep a function around that
482 existing C extensions can call.
483*/
484
485#undef PyCFunction_New
486PyAPI_FUNC(PyObject *) PyCFunction_New(PyMethodDef *, PyObject *);
487
488PyObject *
489PyCFunction_New(PyMethodDef *ml, PyObject *self)
490{
491 return PyCFunction_NewEx(ml, self, NULL);
492}