Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
allendowney
GitHub Repository: allendowney/cpython
Path: blob/main/Objects/methodobject.c
12 views
1
2
/* Method object implementation */
3
4
#include "Python.h"
5
#include "pycore_call.h" // _Py_CheckFunctionResult()
6
#include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate()
7
#include "pycore_object.h"
8
#include "pycore_pyerrors.h"
9
#include "pycore_pystate.h" // _PyThreadState_GET()
10
#include "structmember.h" // PyMemberDef
11
12
/* undefine macro trampoline to PyCFunction_NewEx */
13
#undef PyCFunction_New
14
/* undefine macro trampoline to PyCMethod_New */
15
#undef PyCFunction_NewEx
16
17
/* Forward declarations */
18
static PyObject * cfunction_vectorcall_FASTCALL(
19
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
20
static PyObject * cfunction_vectorcall_FASTCALL_KEYWORDS(
21
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
22
static PyObject * cfunction_vectorcall_FASTCALL_KEYWORDS_METHOD(
23
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
24
static PyObject * cfunction_vectorcall_NOARGS(
25
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
26
static PyObject * cfunction_vectorcall_O(
27
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames);
28
static PyObject * cfunction_call(
29
PyObject *func, PyObject *args, PyObject *kwargs);
30
31
32
PyObject *
33
PyCFunction_New(PyMethodDef *ml, PyObject *self)
34
{
35
return PyCFunction_NewEx(ml, self, NULL);
36
}
37
38
PyObject *
39
PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
40
{
41
return PyCMethod_New(ml, self, module, NULL);
42
}
43
44
PyObject *
45
PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *cls)
46
{
47
/* Figure out correct vectorcall function to use */
48
vectorcallfunc vectorcall;
49
switch (ml->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS |
50
METH_O | METH_KEYWORDS | METH_METHOD))
51
{
52
case METH_VARARGS:
53
case METH_VARARGS | METH_KEYWORDS:
54
/* For METH_VARARGS functions, it's more efficient to use tp_call
55
* instead of vectorcall. */
56
vectorcall = NULL;
57
break;
58
case METH_FASTCALL:
59
vectorcall = cfunction_vectorcall_FASTCALL;
60
break;
61
case METH_FASTCALL | METH_KEYWORDS:
62
vectorcall = cfunction_vectorcall_FASTCALL_KEYWORDS;
63
break;
64
case METH_NOARGS:
65
vectorcall = cfunction_vectorcall_NOARGS;
66
break;
67
case METH_O:
68
vectorcall = cfunction_vectorcall_O;
69
break;
70
case METH_METHOD | METH_FASTCALL | METH_KEYWORDS:
71
vectorcall = cfunction_vectorcall_FASTCALL_KEYWORDS_METHOD;
72
break;
73
default:
74
PyErr_Format(PyExc_SystemError,
75
"%s() method: bad call flags", ml->ml_name);
76
return NULL;
77
}
78
79
PyCFunctionObject *op = NULL;
80
81
if (ml->ml_flags & METH_METHOD) {
82
if (!cls) {
83
PyErr_SetString(PyExc_SystemError,
84
"attempting to create PyCMethod with a METH_METHOD "
85
"flag but no class");
86
return NULL;
87
}
88
PyCMethodObject *om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type);
89
if (om == NULL) {
90
return NULL;
91
}
92
om->mm_class = (PyTypeObject*)Py_NewRef(cls);
93
op = (PyCFunctionObject *)om;
94
} else {
95
if (cls) {
96
PyErr_SetString(PyExc_SystemError,
97
"attempting to create PyCFunction with class "
98
"but no METH_METHOD flag");
99
return NULL;
100
}
101
op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
102
if (op == NULL) {
103
return NULL;
104
}
105
}
106
107
op->m_weakreflist = NULL;
108
op->m_ml = ml;
109
op->m_self = Py_XNewRef(self);
110
op->m_module = Py_XNewRef(module);
111
op->vectorcall = vectorcall;
112
_PyObject_GC_TRACK(op);
113
return (PyObject *)op;
114
}
115
116
PyCFunction
117
PyCFunction_GetFunction(PyObject *op)
118
{
119
if (!PyCFunction_Check(op)) {
120
PyErr_BadInternalCall();
121
return NULL;
122
}
123
return PyCFunction_GET_FUNCTION(op);
124
}
125
126
PyObject *
127
PyCFunction_GetSelf(PyObject *op)
128
{
129
if (!PyCFunction_Check(op)) {
130
PyErr_BadInternalCall();
131
return NULL;
132
}
133
return PyCFunction_GET_SELF(op);
134
}
135
136
int
137
PyCFunction_GetFlags(PyObject *op)
138
{
139
if (!PyCFunction_Check(op)) {
140
PyErr_BadInternalCall();
141
return -1;
142
}
143
return PyCFunction_GET_FLAGS(op);
144
}
145
146
PyTypeObject *
147
PyCMethod_GetClass(PyObject *op)
148
{
149
if (!PyCFunction_Check(op)) {
150
PyErr_BadInternalCall();
151
return NULL;
152
}
153
return PyCFunction_GET_CLASS(op);
154
}
155
156
/* Methods (the standard built-in methods, that is) */
157
158
static void
159
meth_dealloc(PyCFunctionObject *m)
160
{
161
// The Py_TRASHCAN mechanism requires that we be able to
162
// call PyObject_GC_UnTrack twice on an object.
163
PyObject_GC_UnTrack(m);
164
Py_TRASHCAN_BEGIN(m, meth_dealloc);
165
if (m->m_weakreflist != NULL) {
166
PyObject_ClearWeakRefs((PyObject*) m);
167
}
168
// Dereference class before m_self: PyCFunction_GET_CLASS accesses
169
// PyMethodDef m_ml, which could be kept alive by m_self
170
Py_XDECREF(PyCFunction_GET_CLASS(m));
171
Py_XDECREF(m->m_self);
172
Py_XDECREF(m->m_module);
173
PyObject_GC_Del(m);
174
Py_TRASHCAN_END;
175
}
176
177
static PyObject *
178
meth_reduce(PyCFunctionObject *m, PyObject *Py_UNUSED(ignored))
179
{
180
if (m->m_self == NULL || PyModule_Check(m->m_self))
181
return PyUnicode_FromString(m->m_ml->ml_name);
182
183
return Py_BuildValue("N(Os)", _PyEval_GetBuiltin(&_Py_ID(getattr)),
184
m->m_self, m->m_ml->ml_name);
185
}
186
187
static PyMethodDef meth_methods[] = {
188
{"__reduce__", (PyCFunction)meth_reduce, METH_NOARGS, NULL},
189
{NULL, NULL}
190
};
191
192
static PyObject *
193
meth_get__text_signature__(PyCFunctionObject *m, void *closure)
194
{
195
return _PyType_GetTextSignatureFromInternalDoc(m->m_ml->ml_name, m->m_ml->ml_doc);
196
}
197
198
static PyObject *
199
meth_get__doc__(PyCFunctionObject *m, void *closure)
200
{
201
return _PyType_GetDocFromInternalDoc(m->m_ml->ml_name, m->m_ml->ml_doc);
202
}
203
204
static PyObject *
205
meth_get__name__(PyCFunctionObject *m, void *closure)
206
{
207
return PyUnicode_FromString(m->m_ml->ml_name);
208
}
209
210
static PyObject *
211
meth_get__qualname__(PyCFunctionObject *m, void *closure)
212
{
213
/* If __self__ is a module or NULL, return m.__name__
214
(e.g. len.__qualname__ == 'len')
215
216
If __self__ is a type, return m.__self__.__qualname__ + '.' + m.__name__
217
(e.g. dict.fromkeys.__qualname__ == 'dict.fromkeys')
218
219
Otherwise return type(m.__self__).__qualname__ + '.' + m.__name__
220
(e.g. [].append.__qualname__ == 'list.append') */
221
PyObject *type, *type_qualname, *res;
222
223
if (m->m_self == NULL || PyModule_Check(m->m_self))
224
return PyUnicode_FromString(m->m_ml->ml_name);
225
226
type = PyType_Check(m->m_self) ? m->m_self : (PyObject*)Py_TYPE(m->m_self);
227
228
type_qualname = PyObject_GetAttr(type, &_Py_ID(__qualname__));
229
if (type_qualname == NULL)
230
return NULL;
231
232
if (!PyUnicode_Check(type_qualname)) {
233
PyErr_SetString(PyExc_TypeError, "<method>.__class__."
234
"__qualname__ is not a unicode object");
235
Py_XDECREF(type_qualname);
236
return NULL;
237
}
238
239
res = PyUnicode_FromFormat("%S.%s", type_qualname, m->m_ml->ml_name);
240
Py_DECREF(type_qualname);
241
return res;
242
}
243
244
static int
245
meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg)
246
{
247
Py_VISIT(PyCFunction_GET_CLASS(m));
248
Py_VISIT(m->m_self);
249
Py_VISIT(m->m_module);
250
return 0;
251
}
252
253
static PyObject *
254
meth_get__self__(PyCFunctionObject *m, void *closure)
255
{
256
PyObject *self;
257
258
self = PyCFunction_GET_SELF(m);
259
if (self == NULL)
260
self = Py_None;
261
return Py_NewRef(self);
262
}
263
264
static PyGetSetDef meth_getsets [] = {
265
{"__doc__", (getter)meth_get__doc__, NULL, NULL},
266
{"__name__", (getter)meth_get__name__, NULL, NULL},
267
{"__qualname__", (getter)meth_get__qualname__, NULL, NULL},
268
{"__self__", (getter)meth_get__self__, NULL, NULL},
269
{"__text_signature__", (getter)meth_get__text_signature__, NULL, NULL},
270
{0}
271
};
272
273
#define OFF(x) offsetof(PyCFunctionObject, x)
274
275
static PyMemberDef meth_members[] = {
276
{"__module__", T_OBJECT, OFF(m_module), 0},
277
{NULL}
278
};
279
280
static PyObject *
281
meth_repr(PyCFunctionObject *m)
282
{
283
if (m->m_self == NULL || PyModule_Check(m->m_self))
284
return PyUnicode_FromFormat("<built-in function %s>",
285
m->m_ml->ml_name);
286
return PyUnicode_FromFormat("<built-in method %s of %s object at %p>",
287
m->m_ml->ml_name,
288
Py_TYPE(m->m_self)->tp_name,
289
m->m_self);
290
}
291
292
static PyObject *
293
meth_richcompare(PyObject *self, PyObject *other, int op)
294
{
295
PyCFunctionObject *a, *b;
296
PyObject *res;
297
int eq;
298
299
if ((op != Py_EQ && op != Py_NE) ||
300
!PyCFunction_Check(self) ||
301
!PyCFunction_Check(other))
302
{
303
Py_RETURN_NOTIMPLEMENTED;
304
}
305
a = (PyCFunctionObject *)self;
306
b = (PyCFunctionObject *)other;
307
eq = a->m_self == b->m_self;
308
if (eq)
309
eq = a->m_ml->ml_meth == b->m_ml->ml_meth;
310
if (op == Py_EQ)
311
res = eq ? Py_True : Py_False;
312
else
313
res = eq ? Py_False : Py_True;
314
return Py_NewRef(res);
315
}
316
317
static Py_hash_t
318
meth_hash(PyCFunctionObject *a)
319
{
320
Py_hash_t x, y;
321
x = _Py_HashPointer(a->m_self);
322
y = _Py_HashPointer((void*)(a->m_ml->ml_meth));
323
x ^= y;
324
if (x == -1)
325
x = -2;
326
return x;
327
}
328
329
330
PyTypeObject PyCFunction_Type = {
331
PyVarObject_HEAD_INIT(&PyType_Type, 0)
332
"builtin_function_or_method",
333
sizeof(PyCFunctionObject),
334
0,
335
(destructor)meth_dealloc, /* tp_dealloc */
336
offsetof(PyCFunctionObject, vectorcall), /* tp_vectorcall_offset */
337
0, /* tp_getattr */
338
0, /* tp_setattr */
339
0, /* tp_as_async */
340
(reprfunc)meth_repr, /* tp_repr */
341
0, /* tp_as_number */
342
0, /* tp_as_sequence */
343
0, /* tp_as_mapping */
344
(hashfunc)meth_hash, /* tp_hash */
345
cfunction_call, /* tp_call */
346
0, /* tp_str */
347
PyObject_GenericGetAttr, /* tp_getattro */
348
0, /* tp_setattro */
349
0, /* tp_as_buffer */
350
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
351
Py_TPFLAGS_HAVE_VECTORCALL, /* tp_flags */
352
0, /* tp_doc */
353
(traverseproc)meth_traverse, /* tp_traverse */
354
0, /* tp_clear */
355
meth_richcompare, /* tp_richcompare */
356
offsetof(PyCFunctionObject, m_weakreflist), /* tp_weaklistoffset */
357
0, /* tp_iter */
358
0, /* tp_iternext */
359
meth_methods, /* tp_methods */
360
meth_members, /* tp_members */
361
meth_getsets, /* tp_getset */
362
0, /* tp_base */
363
0, /* tp_dict */
364
};
365
366
PyTypeObject PyCMethod_Type = {
367
PyVarObject_HEAD_INIT(&PyType_Type, 0)
368
.tp_name = "builtin_method",
369
.tp_basicsize = sizeof(PyCMethodObject),
370
.tp_base = &PyCFunction_Type,
371
};
372
373
/* Vectorcall functions for each of the PyCFunction calling conventions,
374
* except for METH_VARARGS (possibly combined with METH_KEYWORDS) which
375
* doesn't use vectorcall.
376
*
377
* First, common helpers
378
*/
379
380
static inline int
381
cfunction_check_kwargs(PyThreadState *tstate, PyObject *func, PyObject *kwnames)
382
{
383
assert(!_PyErr_Occurred(tstate));
384
assert(PyCFunction_Check(func));
385
if (kwnames && PyTuple_GET_SIZE(kwnames)) {
386
PyObject *funcstr = _PyObject_FunctionStr(func);
387
if (funcstr != NULL) {
388
_PyErr_Format(tstate, PyExc_TypeError,
389
"%U takes no keyword arguments", funcstr);
390
Py_DECREF(funcstr);
391
}
392
return -1;
393
}
394
return 0;
395
}
396
397
typedef void (*funcptr)(void);
398
399
static inline funcptr
400
cfunction_enter_call(PyThreadState *tstate, PyObject *func)
401
{
402
if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) {
403
return NULL;
404
}
405
return (funcptr)PyCFunction_GET_FUNCTION(func);
406
}
407
408
/* Now the actual vectorcall functions */
409
static PyObject *
410
cfunction_vectorcall_FASTCALL(
411
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
412
{
413
PyThreadState *tstate = _PyThreadState_GET();
414
if (cfunction_check_kwargs(tstate, func, kwnames)) {
415
return NULL;
416
}
417
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
418
_PyCFunctionFast meth = (_PyCFunctionFast)
419
cfunction_enter_call(tstate, func);
420
if (meth == NULL) {
421
return NULL;
422
}
423
PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs);
424
_Py_LeaveRecursiveCallTstate(tstate);
425
return result;
426
}
427
428
static PyObject *
429
cfunction_vectorcall_FASTCALL_KEYWORDS(
430
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
431
{
432
PyThreadState *tstate = _PyThreadState_GET();
433
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
434
_PyCFunctionFastWithKeywords meth = (_PyCFunctionFastWithKeywords)
435
cfunction_enter_call(tstate, func);
436
if (meth == NULL) {
437
return NULL;
438
}
439
PyObject *result = meth(PyCFunction_GET_SELF(func), args, nargs, kwnames);
440
_Py_LeaveRecursiveCallTstate(tstate);
441
return result;
442
}
443
444
static PyObject *
445
cfunction_vectorcall_FASTCALL_KEYWORDS_METHOD(
446
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
447
{
448
PyThreadState *tstate = _PyThreadState_GET();
449
PyTypeObject *cls = PyCFunction_GET_CLASS(func);
450
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
451
PyCMethod meth = (PyCMethod)cfunction_enter_call(tstate, func);
452
if (meth == NULL) {
453
return NULL;
454
}
455
PyObject *result = meth(PyCFunction_GET_SELF(func), cls, args, nargs, kwnames);
456
_Py_LeaveRecursiveCallTstate(tstate);
457
return result;
458
}
459
460
static PyObject *
461
cfunction_vectorcall_NOARGS(
462
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
463
{
464
PyThreadState *tstate = _PyThreadState_GET();
465
if (cfunction_check_kwargs(tstate, func, kwnames)) {
466
return NULL;
467
}
468
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
469
if (nargs != 0) {
470
PyObject *funcstr = _PyObject_FunctionStr(func);
471
if (funcstr != NULL) {
472
_PyErr_Format(tstate, PyExc_TypeError,
473
"%U takes no arguments (%zd given)", funcstr, nargs);
474
Py_DECREF(funcstr);
475
}
476
return NULL;
477
}
478
PyCFunction meth = (PyCFunction)cfunction_enter_call(tstate, func);
479
if (meth == NULL) {
480
return NULL;
481
}
482
PyObject *result = _PyCFunction_TrampolineCall(
483
meth, PyCFunction_GET_SELF(func), NULL);
484
_Py_LeaveRecursiveCallTstate(tstate);
485
return result;
486
}
487
488
static PyObject *
489
cfunction_vectorcall_O(
490
PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames)
491
{
492
PyThreadState *tstate = _PyThreadState_GET();
493
if (cfunction_check_kwargs(tstate, func, kwnames)) {
494
return NULL;
495
}
496
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
497
if (nargs != 1) {
498
PyObject *funcstr = _PyObject_FunctionStr(func);
499
if (funcstr != NULL) {
500
_PyErr_Format(tstate, PyExc_TypeError,
501
"%U takes exactly one argument (%zd given)", funcstr, nargs);
502
Py_DECREF(funcstr);
503
}
504
return NULL;
505
}
506
PyCFunction meth = (PyCFunction)cfunction_enter_call(tstate, func);
507
if (meth == NULL) {
508
return NULL;
509
}
510
PyObject *result = _PyCFunction_TrampolineCall(
511
meth, PyCFunction_GET_SELF(func), args[0]);
512
_Py_LeaveRecursiveCallTstate(tstate);
513
return result;
514
}
515
516
517
static PyObject *
518
cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs)
519
{
520
assert(kwargs == NULL || PyDict_Check(kwargs));
521
522
PyThreadState *tstate = _PyThreadState_GET();
523
assert(!_PyErr_Occurred(tstate));
524
525
int flags = PyCFunction_GET_FLAGS(func);
526
if (!(flags & METH_VARARGS)) {
527
/* If this is not a METH_VARARGS function, delegate to vectorcall */
528
return PyVectorcall_Call(func, args, kwargs);
529
}
530
531
/* For METH_VARARGS, we cannot use vectorcall as the vectorcall pointer
532
* is NULL. This is intentional, since vectorcall would be slower. */
533
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
534
PyObject *self = PyCFunction_GET_SELF(func);
535
536
PyObject *result;
537
if (flags & METH_KEYWORDS) {
538
result = _PyCFunctionWithKeywords_TrampolineCall(
539
(*(PyCFunctionWithKeywords)(void(*)(void))meth),
540
self, args, kwargs);
541
}
542
else {
543
if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) {
544
_PyErr_Format(tstate, PyExc_TypeError,
545
"%.200s() takes no keyword arguments",
546
((PyCFunctionObject*)func)->m_ml->ml_name);
547
return NULL;
548
}
549
result = _PyCFunction_TrampolineCall(meth, self, args);
550
}
551
return _Py_CheckFunctionResult(tstate, func, result, NULL);
552
}
553
554
#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
555
#include <emscripten.h>
556
557
EM_JS(PyObject*, _PyCFunctionWithKeywords_TrampolineCall, (PyCFunctionWithKeywords func, PyObject *self, PyObject *args, PyObject *kw), {
558
return wasmTable.get(func)(self, args, kw);
559
});
560
#endif
561
562