summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Objects/funcobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Objects/funcobject.c')
-rw-r--r--contrib/tools/python3/Objects/funcobject.c457
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 */
};