Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Include/internal/pycore_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ static inline PyObject* _PyFunction_GET_BUILTINS(PyObject *func) {
#define _PyFunction_GET_BUILTINS(func) _PyFunction_GET_BUILTINS(_PyObject_CAST(func))


/* Get the callable wrapped by a staticmethod.
Returns a borrowed reference, or NULL if uninitialized.
The caller must ensure 'sm' is a staticmethod object. */
extern PyObject *_PyStaticMethod_GetFunc(PyObject *sm);


#ifdef __cplusplus
}
#endif
Expand Down
4 changes: 4 additions & 0 deletions Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,10 @@ _PyType_LookupStackRefAndVersion(PyTypeObject *type, PyObject *name, _PyStackRef
PyAPI_FUNC(int) _PyObject_GetMethodStackRef(PyThreadState *ts, PyObject *obj,
PyObject *name, _PyStackRef *method);

// Like PyObject_GetAttr but returns a _PyStackRef. For types, this can
// return a deferred reference to reduce reference count contention.
PyAPI_FUNC(_PyStackRef) PyObject_GetAttrStackRef(PyObject *obj, PyObject *name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please rename it to _PyObject_GetAttrStackRef() since it's private?


// Cache the provided init method in the specialization cache of type if the
// provided type version matches the current version of the type.
//
Expand Down
3 changes: 3 additions & 0 deletions Include/internal/pycore_typeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern "C" {

#include "pycore_interp_structs.h" // managed_static_type_state
#include "pycore_moduleobject.h" // PyModuleObject
#include "pycore_structs.h" // _PyStackRef


/* state */
Expand Down Expand Up @@ -112,6 +113,8 @@ _PyType_IsReady(PyTypeObject *type)
extern PyObject* _Py_type_getattro_impl(PyTypeObject *type, PyObject *name,
int *suppress_missing_attribute);
extern PyObject* _Py_type_getattro(PyObject *type, PyObject *name);
extern _PyStackRef _Py_type_getattro_stackref(PyTypeObject *type, PyObject *name,
int *suppress_missing_attribute);

extern PyObject* _Py_BaseObject_RichCompare(PyObject* self, PyObject* other, int op);

Expand Down
10 changes: 5 additions & 5 deletions Modules/_testinternalcapi/test_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 10 additions & 5 deletions Objects/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,10 @@ _PyStack_AsDict(PyObject *const *values, PyObject *kwnames)

The newly allocated argument vector supports PY_VECTORCALL_ARGUMENTS_OFFSET.

The positional arguments are borrowed references from the input array
(which must be kept alive by the caller). The keyword argument values
are new references.

When done, you must call _PyStack_UnpackDict_Free(stack, nargs, kwnames) */
PyObject *const *
_PyStack_UnpackDict(PyThreadState *tstate,
Expand Down Expand Up @@ -970,9 +974,9 @@ _PyStack_UnpackDict(PyThreadState *tstate,

stack++; /* For PY_VECTORCALL_ARGUMENTS_OFFSET */

/* Copy positional arguments */
/* Copy positional arguments (borrowed references) */
for (Py_ssize_t i = 0; i < nargs; i++) {
stack[i] = Py_NewRef(args[i]);
stack[i] = args[i];
}

PyObject **kwstack = stack + nargs;
Expand Down Expand Up @@ -1009,9 +1013,10 @@ void
_PyStack_UnpackDict_Free(PyObject *const *stack, Py_ssize_t nargs,
PyObject *kwnames)
{
Py_ssize_t n = PyTuple_GET_SIZE(kwnames) + nargs;
for (Py_ssize_t i = 0; i < n; i++) {
Py_DECREF(stack[i]);
/* Only decref kwargs values, positional args are borrowed */
Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames);
for (Py_ssize_t i = 0; i < nkwargs; i++) {
Py_DECREF(stack[nargs + i]);
}
_PyStack_UnpackDict_FreeNoDecRef(stack, kwnames);
}
Expand Down
9 changes: 9 additions & 0 deletions Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "pycore_long.h" // _PyLong_GetOne()
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_object_deferred.h" // _PyObject_SetDeferredRefcount()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_setobject.h" // _PySet_NextEntry()
#include "pycore_stats.h"
Expand Down Expand Up @@ -1868,7 +1869,15 @@ PyStaticMethod_New(PyObject *callable)
staticmethod *sm = (staticmethod *)
PyType_GenericAlloc(&PyStaticMethod_Type, 0);
if (sm != NULL) {
_PyObject_SetDeferredRefcount((PyObject *)sm);
sm->sm_callable = Py_NewRef(callable);
}
return (PyObject *)sm;
}

PyObject *
_PyStaticMethod_GetFunc(PyObject *self)
{
staticmethod *sm = _PyStaticMethod_CAST(self);
return sm->sm_callable;
}
49 changes: 49 additions & 0 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "pycore_tuple.h" // _PyTuple_DebugMallocStats()
#include "pycore_typeobject.h" // _PyBufferWrapper_Type
#include "pycore_typevarobject.h" // _PyTypeAlias_Type
#include "pycore_stackref.h" // PyStackRef_FromPyObjectSteal
#include "pycore_unionobject.h" // _PyUnion_Type


Expand Down Expand Up @@ -1334,6 +1335,54 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
return result;
}

/* Like PyObject_GetAttr but returns a _PyStackRef.
For types (tp_getattro == _Py_type_getattro), this can return
a deferred reference to reduce reference count contention. */
_PyStackRef
PyObject_GetAttrStackRef(PyObject *v, PyObject *name)
{
PyTypeObject *tp = Py_TYPE(v);
if (!PyUnicode_Check(name)) {
PyErr_Format(PyExc_TypeError,
"attribute name must be string, not '%.200s'",
Py_TYPE(name)->tp_name);
return PyStackRef_NULL;
}

/* Fast path for types - can return deferred references */
if (tp->tp_getattro == _Py_type_getattro) {
_PyStackRef result = _Py_type_getattro_stackref((PyTypeObject *)v, name, NULL);
if (PyStackRef_IsNull(result)) {
_PyObject_SetAttributeErrorContext(v, name);
}
return result;
}

/* Fall back to regular PyObject_GetAttr and convert to stackref */
PyObject *result = NULL;
if (tp->tp_getattro != NULL) {
result = (*tp->tp_getattro)(v, name);
}
else if (tp->tp_getattr != NULL) {
const char *name_str = PyUnicode_AsUTF8(name);
if (name_str == NULL) {
return PyStackRef_NULL;
}
result = (*tp->tp_getattr)(v, (char *)name_str);
}
else {
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%U'",
tp->tp_name, name);
}

if (result == NULL) {
_PyObject_SetAttributeErrorContext(v, name);
return PyStackRef_NULL;
}
return PyStackRef_FromPyObjectSteal(result);
}

int
PyObject_GetOptionalAttr(PyObject *v, PyObject *name, PyObject **result)
{
Expand Down
Loading
Loading