diff options
Diffstat (limited to 'contrib/tools/python3/Objects/funcobject.c')
| -rw-r--r-- | contrib/tools/python3/Objects/funcobject.c | 457 |
1 files changed, 330 insertions, 127 deletions
diff --git a/contrib/tools/python3/Objects/funcobject.c b/contrib/tools/python3/Objects/funcobject.c index f43e3a2787b..a39b5464f4d 100644 --- a/contrib/tools/python3/Objects/funcobject.c +++ b/contrib/tools/python3/Objects/funcobject.c @@ -2,13 +2,14 @@ /* Function object implementation */ #include "Python.h" -#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals() -#include "pycore_code.h" // _Py_next_func_version -#include "pycore_object.h" // _PyObject_GC_UNTRACK() -#include "pycore_pyerrors.h" // _PyErr_Occurred() -#include "structmember.h" // PyMemberDef +#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals() +#include "pycore_dict.h" // _Py_INCREF_DICT() +#include "pycore_long.h" // _PyLong_GetOne() +#include "pycore_modsupport.h" // _PyArg_NoKeywords() +#include "pycore_object.h" // _PyObject_GC_UNTRACK() +#include "pycore_pyerrors.h" // _PyErr_Occurred() +#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS() -static PyObject* func_repr(PyFunctionObject *op); static const char * func_event_name(PyFunction_WatchEvent event) { @@ -35,21 +36,9 @@ notify_func_watchers(PyInterpreterState *interp, PyFunction_WatchEvent event, // callback must be non-null if the watcher bit is set assert(cb != NULL); if (cb(event, func, new_value) < 0) { - // Don't risk resurrecting the func if an unraisablehook keeps a - // reference; pass a string as context. - PyObject *context = NULL; - PyObject *repr = func_repr(func); - if (repr != NULL) { - context = PyUnicode_FromFormat( - "%s watcher callback for %U", - func_event_name(event), repr); - Py_DECREF(repr); - } - if (context == NULL) { - context = Py_NewRef(Py_None); - } - PyErr_WriteUnraisable(context); - Py_DECREF(context); + PyErr_FormatUnraisable( + "Exception ignored in %s watcher callback for function %U at %p", + func_event_name(event), func->func_qualname, func); } } i++; @@ -67,6 +56,15 @@ handle_func_event(PyFunction_WatchEvent event, PyFunctionObject *func, if (interp->active_func_watchers) { notify_func_watchers(interp, event, func, new_value); } + switch (event) { + case PyFunction_EVENT_MODIFY_CODE: + case PyFunction_EVENT_MODIFY_DEFAULTS: + case PyFunction_EVENT_MODIFY_KWDEFAULTS: + RARE_EVENT_INTERP_INC(interp, func_modification); + break; + default: + break; + } } int @@ -106,8 +104,8 @@ PyFunction_ClearWatcher(int watcher_id) PyFunctionObject * _PyFunction_FromConstructor(PyFrameConstructor *constr) { - PyObject *module = Py_XNewRef(PyDict_GetItemWithError(constr->fc_globals, &_Py_ID(__name__))); - if (!module && PyErr_Occurred()) { + PyObject *module; + if (PyDict_GetItemRef(constr->fc_globals, &_Py_ID(__name__), &module) < 0) { return NULL; } @@ -132,6 +130,9 @@ _PyFunction_FromConstructor(PyFrameConstructor *constr) op->func_typeparams = NULL; op->vectorcall = _PyFunction_Vectorcall; op->func_version = 0; + // NOTE: functions created via FrameConstructor do not use deferred + // reference counting because they are typically not part of cycles + // nor accessed by multiple threads. _PyObject_GC_TRACK(op); handle_func_event(PyFunction_EVENT_CREATE, op, NULL); return op; @@ -172,12 +173,11 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname Py_INCREF(doc); // __module__: Use globals['__name__'] if it exists, or NULL. - PyObject *module = PyDict_GetItemWithError(globals, &_Py_ID(__name__)); + PyObject *module; PyObject *builtins = NULL; - if (module == NULL && _PyErr_Occurred(tstate)) { + if (PyDict_GetItemRef(globals, &_Py_ID(__name__), &module) < 0) { goto error; } - Py_XINCREF(module); builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref if (builtins == NULL) { @@ -208,6 +208,12 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname op->func_typeparams = NULL; op->vectorcall = _PyFunction_Vectorcall; op->func_version = 0; + if ((code_obj->co_flags & CO_NESTED) == 0) { + // Use deferred reference counting for top-level functions, but not + // nested functions because they are more likely to capture variables, + // which makes prompt deallocation more important. + _PyObject_SetDeferredRefcount((PyObject *)op); + } _PyObject_GC_TRACK(op); handle_func_event(PyFunction_EVENT_CREATE, op, NULL); return (PyObject *)op; @@ -223,21 +229,142 @@ error: return NULL; } -uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func) +/* +(This is purely internal documentation. There are no public APIs here.) + +Function (and code) versions +---------------------------- + +The Tier 1 specializer generates CALL variants that can be invalidated +by changes to critical function attributes: + +- __code__ +- __defaults__ +- __kwdefaults__ +- __closure__ + +For this purpose function objects have a 32-bit func_version member +that the specializer writes to the specialized instruction's inline +cache and which is checked by a guard on the specialized instructions. + +The MAKE_FUNCTION bytecode sets func_version from the code object's +co_version field. The latter is initialized from a counter in the +interpreter state (interp->func_state.next_version) and never changes. +When this counter overflows, it remains zero and the specializer loses +the ability to specialize calls to new functions. + +The func_version is reset to zero when any of the critical attributes +is modified; after this point the specializer will no longer specialize +calls to this function, and the guard will always fail. + +The function and code version cache +----------------------------------- + +The Tier 2 optimizer now has a problem, since it needs to find the +function and code objects given only the version number from the inline +cache. Our solution is to maintain a cache mapping version numbers to +function and code objects. To limit the cache size we could hash +the version number, but for now we simply use it modulo the table size. + +There are some corner cases (e.g. generator expressions) where we will +be unable to find the function object in the cache but we can still +find the code object. For this reason the cache stores both the +function object and the code object. + +The cache doesn't contain strong references; cache entries are +invalidated whenever the function or code object is deallocated. + +Invariants +---------- + +These should hold at any time except when one of the cache-mutating +functions is running. + +- For any slot s at index i: + - s->func == NULL or s->func->func_version % FUNC_VERSION_CACHE_SIZE == i + - s->code == NULL or s->code->co_version % FUNC_VERSION_CACHE_SIZE == i + if s->func != NULL, then s->func->func_code == s->code + +*/ + +void +_PyFunction_SetVersion(PyFunctionObject *func, uint32_t version) { +#ifndef Py_GIL_DISABLED + PyInterpreterState *interp = _PyInterpreterState_GET(); if (func->func_version != 0) { - return func->func_version; + struct _func_version_cache_item *slot = + interp->func_state.func_version_cache + + (func->func_version % FUNC_VERSION_CACHE_SIZE); + if (slot->func == func) { + slot->func = NULL; + // Leave slot->code alone, there may be use for it. + } } - if (func->vectorcall != _PyFunction_Vectorcall) { - return 0; +#endif + func->func_version = version; +#ifndef Py_GIL_DISABLED + if (version != 0) { + struct _func_version_cache_item *slot = + interp->func_state.func_version_cache + + (version % FUNC_VERSION_CACHE_SIZE); + slot->func = func; + slot->code = func->func_code; } +#endif +} + +void +_PyFunction_ClearCodeByVersion(uint32_t version) +{ +#ifndef Py_GIL_DISABLED PyInterpreterState *interp = _PyInterpreterState_GET(); - if (interp->func_state.next_version == 0) { - return 0; + struct _func_version_cache_item *slot = + interp->func_state.func_version_cache + + (version % FUNC_VERSION_CACHE_SIZE); + if (slot->code) { + assert(PyCode_Check(slot->code)); + PyCodeObject *code = (PyCodeObject *)slot->code; + if (code->co_version == version) { + slot->code = NULL; + slot->func = NULL; + } } - uint32_t v = interp->func_state.next_version++; - func->func_version = v; - return v; +#endif +} + +PyFunctionObject * +_PyFunction_LookupByVersion(uint32_t version, PyObject **p_code) +{ +#ifdef Py_GIL_DISABLED + return NULL; +#else + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _func_version_cache_item *slot = + interp->func_state.func_version_cache + + (version % FUNC_VERSION_CACHE_SIZE); + if (slot->code) { + assert(PyCode_Check(slot->code)); + PyCodeObject *code = (PyCodeObject *)slot->code; + if (code->co_version == version) { + *p_code = slot->code; + } + } + else { + *p_code = NULL; + } + if (slot->func && slot->func->func_version == version) { + assert(slot->func->func_code == slot->code); + return slot->func; + } + return NULL; +#endif +} + +uint32_t +_PyFunction_GetVersionForCurrentState(PyFunctionObject *func) +{ + return func->func_version; } PyObject * @@ -304,7 +431,7 @@ PyFunction_SetDefaults(PyObject *op, PyObject *defaults) } handle_func_event(PyFunction_EVENT_MODIFY_DEFAULTS, (PyFunctionObject *) op, defaults); - ((PyFunctionObject *)op)->func_version = 0; + _PyFunction_SetVersion((PyFunctionObject *)op, 0); Py_XSETREF(((PyFunctionObject *)op)->func_defaults, defaults); return 0; } @@ -313,7 +440,7 @@ void PyFunction_SetVectorcall(PyFunctionObject *func, vectorcallfunc vectorcall) { assert(func != NULL); - func->func_version = 0; + _PyFunction_SetVersion(func, 0); func->vectorcall = vectorcall; } @@ -346,7 +473,7 @@ PyFunction_SetKwDefaults(PyObject *op, PyObject *defaults) } handle_func_event(PyFunction_EVENT_MODIFY_KWDEFAULTS, (PyFunctionObject *) op, defaults); - ((PyFunctionObject *)op)->func_version = 0; + _PyFunction_SetVersion((PyFunctionObject *)op, 0); Py_XSETREF(((PyFunctionObject *)op)->func_kwdefaults, defaults); return 0; } @@ -379,7 +506,7 @@ PyFunction_SetClosure(PyObject *op, PyObject *closure) Py_TYPE(closure)->tp_name); return -1; } - ((PyFunctionObject *)op)->func_version = 0; + _PyFunction_SetVersion((PyFunctionObject *)op, 0); Py_XSETREF(((PyFunctionObject *)op)->func_closure, closure); return 0; } @@ -441,7 +568,6 @@ PyFunction_SetAnnotations(PyObject *op, PyObject *annotations) "non-dict annotations"); return -1; } - ((PyFunctionObject *)op)->func_version = 0; Py_XSETREF(((PyFunctionObject *)op)->func_annotations, annotations); return 0; } @@ -451,17 +577,25 @@ PyFunction_SetAnnotations(PyObject *op, PyObject *annotations) #define OFF(x) offsetof(PyFunctionObject, x) static PyMemberDef func_memberlist[] = { - {"__closure__", T_OBJECT, OFF(func_closure), READONLY}, - {"__doc__", T_OBJECT, OFF(func_doc), 0}, - {"__globals__", T_OBJECT, OFF(func_globals), READONLY}, - {"__module__", T_OBJECT, OFF(func_module), 0}, - {"__builtins__", T_OBJECT, OFF(func_builtins), READONLY}, + {"__closure__", _Py_T_OBJECT, OFF(func_closure), Py_READONLY}, + {"__doc__", _Py_T_OBJECT, OFF(func_doc), 0}, + {"__globals__", _Py_T_OBJECT, OFF(func_globals), Py_READONLY}, + {"__module__", _Py_T_OBJECT, OFF(func_module), 0}, + {"__builtins__", _Py_T_OBJECT, OFF(func_builtins), Py_READONLY}, {NULL} /* Sentinel */ }; +/*[clinic input] +class function "PyFunctionObject *" "&PyFunction_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=70af9c90aa2e71b0]*/ + +#include "clinic/funcobject.c.h" + static PyObject * -func_get_code(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_code(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject* op = _PyFunction_CAST(self); if (PySys_Audit("object.__getattr__", "Os", op, "__code__") < 0) { return NULL; } @@ -470,8 +604,9 @@ func_get_code(PyFunctionObject *op, void *Py_UNUSED(ignored)) } static int -func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_code(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject* op = _PyFunction_CAST(self); Py_ssize_t nclosure; int nfree; @@ -494,26 +629,42 @@ func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) if (nclosure != nfree) { PyErr_Format(PyExc_ValueError, "%U() requires a code object with %zd free vars," - " not %zd", + " not %d", op->func_name, nclosure, nfree); return -1; } + + PyObject *func_code = PyFunction_GET_CODE(op); + int old_flags = ((PyCodeObject *)func_code)->co_flags; + int new_flags = ((PyCodeObject *)value)->co_flags; + int mask = CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR; + if ((old_flags & mask) != (new_flags & mask)) { + if (PyErr_Warn(PyExc_DeprecationWarning, + "Assigning a code object of non-matching type is deprecated " + "(e.g., from a generator to a plain function)") < 0) + { + return -1; + } + } + handle_func_event(PyFunction_EVENT_MODIFY_CODE, op, value); - op->func_version = 0; + _PyFunction_SetVersion(op, 0); Py_XSETREF(op->func_code, Py_NewRef(value)); return 0; } static PyObject * -func_get_name(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_name(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject* op = _PyFunction_CAST(self); return Py_NewRef(op->func_name); } static int -func_set_name(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_name(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject * op = _PyFunction_CAST(self); /* Not legal to del f.func_name or to set it to anything * other than a string object. */ if (value == NULL || !PyUnicode_Check(value)) { @@ -526,14 +677,16 @@ func_set_name(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) } static PyObject * -func_get_qualname(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_qualname(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject *op = _PyFunction_CAST(self); return Py_NewRef(op->func_qualname); } static int -func_set_qualname(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_qualname(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject *op = _PyFunction_CAST(self); /* Not legal to del f.__qualname__ or to set it to anything * other than a string object. */ if (value == NULL || !PyUnicode_Check(value)) { @@ -546,8 +699,9 @@ func_set_qualname(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored } static PyObject * -func_get_defaults(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_defaults(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject * op = _PyFunction_CAST(self); if (PySys_Audit("object.__getattr__", "Os", op, "__defaults__") < 0) { return NULL; } @@ -558,8 +712,9 @@ func_get_defaults(PyFunctionObject *op, void *Py_UNUSED(ignored)) } static int -func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_defaults(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject *op = _PyFunction_CAST(self); /* Legal to del f.func_defaults. * Can only set func_defaults to NULL or a tuple. */ if (value == Py_None) @@ -580,14 +735,15 @@ func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored } handle_func_event(PyFunction_EVENT_MODIFY_DEFAULTS, op, value); - op->func_version = 0; + _PyFunction_SetVersion(op, 0); Py_XSETREF(op->func_defaults, Py_XNewRef(value)); return 0; } static PyObject * -func_get_kwdefaults(PyFunctionObject *op, void *Py_UNUSED(ignored)) +func_get_kwdefaults(PyObject *self, void *Py_UNUSED(ignored)) { + PyFunctionObject * op = _PyFunction_CAST(self); if (PySys_Audit("object.__getattr__", "Os", op, "__kwdefaults__") < 0) { return NULL; @@ -599,8 +755,9 @@ func_get_kwdefaults(PyFunctionObject *op, void *Py_UNUSED(ignored)) } static int -func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +func_set_kwdefaults(PyObject *self, PyObject *value, void *Py_UNUSED(ignored)) { + PyFunctionObject* op = _PyFunction_CAST(self); if (value == Py_None) value = NULL; /* Legal to del f.func_kwdefaults. @@ -621,25 +778,43 @@ func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignor } handle_func_event(PyFunction_EVENT_MODIFY_KWDEFAULTS, op, value); - op->func_version = 0; + _PyFunction_SetVersion(op, 0); Py_XSETREF(op->func_kwdefaults, Py_XNewRef(value)); return 0; } + +/*[clinic input] +@critical_section +@getter +function.__annotations__ + +Dict of annotations in a function object. +[clinic start generated code]*/ + static PyObject * -func_get_annotations(PyFunctionObject *op, void *Py_UNUSED(ignored)) +function___annotations___get_impl(PyFunctionObject *self) +/*[clinic end generated code: output=a4cf4c884c934cbb input=92643d7186c1ad0c]*/ { - if (op->func_annotations == NULL) { - op->func_annotations = PyDict_New(); - if (op->func_annotations == NULL) + PyObject *d = NULL; + if (self->func_annotations == NULL) { + self->func_annotations = PyDict_New(); + if (self->func_annotations == NULL) return NULL; } - PyObject *d = func_get_annotation_dict(op); + d = func_get_annotation_dict(self); return Py_XNewRef(d); } +/*[clinic input] +@critical_section +@setter +function.__annotations__ +[clinic start generated code]*/ + static int -func_set_annotations(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +function___annotations___set_impl(PyFunctionObject *self, PyObject *value) +/*[clinic end generated code: output=a61795d4a95eede4 input=5302641f686f0463]*/ { if (value == Py_None) value = NULL; @@ -651,24 +826,39 @@ func_set_annotations(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(igno "__annotations__ must be set to a dict object"); return -1; } - op->func_version = 0; - Py_XSETREF(op->func_annotations, Py_XNewRef(value)); + Py_XSETREF(self->func_annotations, Py_XNewRef(value)); return 0; } +/*[clinic input] +@critical_section +@getter +function.__type_params__ + +Get the declared type parameters for a function. +[clinic start generated code]*/ + static PyObject * -func_get_type_params(PyFunctionObject *op, void *Py_UNUSED(ignored)) +function___type_params___get_impl(PyFunctionObject *self) +/*[clinic end generated code: output=eb844d7ffca517a8 input=0864721484293724]*/ { - if (op->func_typeparams == NULL) { + if (self->func_typeparams == NULL) { return PyTuple_New(0); } - assert(PyTuple_Check(op->func_typeparams)); - return Py_NewRef(op->func_typeparams); + assert(PyTuple_Check(self->func_typeparams)); + return Py_NewRef(self->func_typeparams); } +/*[clinic input] +@critical_section +@setter +function.__type_params__ +[clinic start generated code]*/ + static int -func_set_type_params(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored)) +function___type_params___set_impl(PyFunctionObject *self, PyObject *value) +/*[clinic end generated code: output=038b4cda220e56fb input=3862fbd4db2b70e8]*/ { /* Not legal to del f.__type_params__ or to set it to anything * other than a tuple object. */ @@ -677,7 +867,7 @@ func_set_type_params(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(igno "__type_params__ must be set to a tuple"); return -1; } - Py_XSETREF(op->func_typeparams, Py_NewRef(value)); + Py_XSETREF(self->func_typeparams, Py_NewRef(value)); return 0; } @@ -693,28 +883,17 @@ _Py_set_function_type_params(PyThreadState *Py_UNUSED(ignored), PyObject *func, } static PyGetSetDef func_getsetlist[] = { - {"__code__", (getter)func_get_code, (setter)func_set_code}, - {"__defaults__", (getter)func_get_defaults, - (setter)func_set_defaults}, - {"__kwdefaults__", (getter)func_get_kwdefaults, - (setter)func_set_kwdefaults}, - {"__annotations__", (getter)func_get_annotations, - (setter)func_set_annotations}, + {"__code__", func_get_code, func_set_code}, + {"__defaults__", func_get_defaults, func_set_defaults}, + {"__kwdefaults__", func_get_kwdefaults, func_set_kwdefaults}, + FUNCTION___ANNOTATIONS___GETSETDEF {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict}, - {"__name__", (getter)func_get_name, (setter)func_set_name}, - {"__qualname__", (getter)func_get_qualname, (setter)func_set_qualname}, - {"__type_params__", (getter)func_get_type_params, - (setter)func_set_type_params}, + {"__name__", func_get_name, func_set_name}, + {"__qualname__", func_get_qualname, func_set_qualname}, + FUNCTION___TYPE_PARAMS___GETSETDEF {NULL} /* Sentinel */ }; -/*[clinic input] -class function "PyFunctionObject *" "&PyFunction_Type" -[clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=70af9c90aa2e71b0]*/ - -#include "clinic/funcobject.c.h" - /* function.__new__() maintains the following invariants for closures. The closure must correspond to the free variables of the code object. @@ -738,14 +917,17 @@ function.__new__ as func_new a tuple that specifies the default argument values closure: object = None a tuple that supplies the bindings for free variables + kwdefaults: object = None + a dictionary that specifies the default keyword argument values Create a function object. [clinic start generated code]*/ static PyObject * func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals, - PyObject *name, PyObject *defaults, PyObject *closure) -/*[clinic end generated code: output=99c6d9da3a24e3be input=93611752fc2daf11]*/ + PyObject *name, PyObject *defaults, PyObject *closure, + PyObject *kwdefaults) +/*[clinic end generated code: output=de72f4c22ac57144 input=20c9c9f04ad2d3f2]*/ { PyFunctionObject *newfunc; Py_ssize_t nclosure; @@ -772,12 +954,17 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals, return NULL; } } + if (kwdefaults != Py_None && !PyDict_Check(kwdefaults)) { + PyErr_SetString(PyExc_TypeError, + "arg 6 (kwdefaults) must be None or dict"); + return NULL; + } /* check that the closure is well-formed */ nclosure = closure == Py_None ? 0 : PyTuple_GET_SIZE(closure); if (code->co_nfreevars != nclosure) return PyErr_Format(PyExc_ValueError, - "%U requires closure of length %zd, not %zd", + "%U requires closure of length %d, not %zd", code->co_name, code->co_nfreevars, nclosure); if (nclosure) { Py_ssize_t i; @@ -808,6 +995,9 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals, if (closure != Py_None) { newfunc->func_closure = Py_NewRef(closure); } + if (kwdefaults != Py_None) { + newfunc->func_kwdefaults = Py_NewRef(kwdefaults); + } return (PyObject *)newfunc; } @@ -815,7 +1005,7 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals, static int func_clear(PyFunctionObject *op) { - op->func_version = 0; + _PyFunction_SetVersion(op, 0); Py_CLEAR(op->func_globals); Py_CLEAR(op->func_builtins); Py_CLEAR(op->func_module); @@ -831,26 +1021,22 @@ func_clear(PyFunctionObject *op) // However, name and qualname could be str subclasses, so they // could have reference cycles. The solution is to replace them // with a genuinely immutable string. - Py_SETREF(op->func_name, Py_NewRef(&_Py_STR(empty))); - Py_SETREF(op->func_qualname, Py_NewRef(&_Py_STR(empty))); + Py_SETREF(op->func_name, &_Py_STR(empty)); + Py_SETREF(op->func_qualname, &_Py_STR(empty)); return 0; } static void func_dealloc(PyFunctionObject *op) { - assert(Py_REFCNT(op) == 0); - Py_SET_REFCNT(op, 1); + _PyObject_ResurrectStart((PyObject *)op); handle_func_event(PyFunction_EVENT_DESTROY, op, NULL); - if (Py_REFCNT(op) > 1) { - Py_SET_REFCNT(op, Py_REFCNT(op) - 1); + if (_PyObject_ResurrectEnd((PyObject *)op)) { return; } - Py_SET_REFCNT(op, 0); _PyObject_GC_UNTRACK(op); - if (op->func_weakreflist != NULL) { - PyObject_ClearWeakRefs((PyObject *) op); - } + FT_CLEAR_WEAKREFS((PyObject *) op, op->func_weakreflist); + _PyFunction_SetVersion(op, 0); (void)func_clear(op); // These aren't cleared by func_clear(). Py_DECREF(op->func_code); @@ -942,17 +1128,12 @@ PyTypeObject PyFunction_Type = { static int functools_copy_attr(PyObject *wrapper, PyObject *wrapped, PyObject *name) { - PyObject *value = PyObject_GetAttr(wrapped, name); - if (value == NULL) { - if (PyErr_ExceptionMatches(PyExc_AttributeError)) { - PyErr_Clear(); - return 0; - } - return -1; + PyObject *value; + int res = PyObject_GetOptionalAttr(wrapped, name, &value); + if (value != NULL) { + res = PyObject_SetAttr(wrapper, name, value); + Py_DECREF(value); } - - int res = PyObject_SetAttr(wrapper, name, value); - Py_DECREF(value); return res; } @@ -1042,13 +1223,21 @@ cm_descr_get(PyObject *self, PyObject *obj, PyObject *type) } if (type == NULL) type = (PyObject *)(Py_TYPE(obj)); - if (Py_TYPE(cm->cm_callable)->tp_descr_get != NULL) { - return Py_TYPE(cm->cm_callable)->tp_descr_get(cm->cm_callable, type, - type); - } return PyMethod_New(cm->cm_callable, type); } +static PyObject * +cm_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + classmethod *cm = (classmethod *)PyType_GenericAlloc(type, 0); + if (cm == NULL) { + return NULL; + } + cm->cm_callable = Py_None; + cm->cm_dict = NULL; + return (PyObject *)cm; +} + static int cm_init(PyObject *self, PyObject *args, PyObject *kwds) { @@ -1068,8 +1257,8 @@ cm_init(PyObject *self, PyObject *args, PyObject *kwds) } static PyMemberDef cm_memberlist[] = { - {"__func__", T_OBJECT, offsetof(classmethod, cm_callable), READONLY}, - {"__wrapped__", T_OBJECT, offsetof(classmethod, cm_callable), READONLY}, + {"__func__", _Py_T_OBJECT, offsetof(classmethod, cm_callable), Py_READONLY}, + {"__wrapped__", _Py_T_OBJECT, offsetof(classmethod, cm_callable), Py_READONLY}, {NULL} /* Sentinel */ }; @@ -1100,7 +1289,8 @@ cm_repr(classmethod *cm) } PyDoc_STRVAR(classmethod_doc, -"classmethod(function) -> method\n\ +"classmethod(function, /)\n\ +--\n\ \n\ Convert a function to be a class method.\n\ \n\ @@ -1159,7 +1349,7 @@ PyTypeObject PyClassMethod_Type = { offsetof(classmethod, cm_dict), /* tp_dictoffset */ cm_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ + cm_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ }; @@ -1237,6 +1427,18 @@ sm_descr_get(PyObject *self, PyObject *obj, PyObject *type) return Py_NewRef(sm->sm_callable); } +static PyObject * +sm_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + staticmethod *sm = (staticmethod *)PyType_GenericAlloc(type, 0); + if (sm == NULL) { + return NULL; + } + sm->sm_callable = Py_None; + sm->sm_dict = NULL; + return (PyObject *)sm; +} + static int sm_init(PyObject *self, PyObject *args, PyObject *kwds) { @@ -1263,8 +1465,8 @@ sm_call(PyObject *callable, PyObject *args, PyObject *kwargs) } static PyMemberDef sm_memberlist[] = { - {"__func__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY}, - {"__wrapped__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY}, + {"__func__", _Py_T_OBJECT, offsetof(staticmethod, sm_callable), Py_READONLY}, + {"__wrapped__", _Py_T_OBJECT, offsetof(staticmethod, sm_callable), Py_READONLY}, {NULL} /* Sentinel */ }; @@ -1295,7 +1497,8 @@ sm_repr(staticmethod *sm) } PyDoc_STRVAR(staticmethod_doc, -"staticmethod(function) -> method\n\ +"staticmethod(function, /)\n\ +--\n\ \n\ Convert a function to be a static method.\n\ \n\ @@ -1352,7 +1555,7 @@ PyTypeObject PyStaticMethod_Type = { offsetof(staticmethod, sm_dict), /* tp_dictoffset */ sm_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ + sm_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ }; |
