Skip to content
Merged
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
3 changes: 2 additions & 1 deletion Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,8 @@ extern int _PyObject_IsInstanceDictEmpty(PyObject *);

// Export for 'math' shared extension
PyAPI_FUNC(PyObject*) _PyObject_LookupSpecial(PyObject *, PyObject *);
PyAPI_FUNC(int) _PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method_and_self);
PyAPI_FUNC(int) _PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method,
_PyStackRef *self);

// Calls the method named `attr` on `self`, but does not set an exception if
// the attribute does not exist.
Expand Down
7 changes: 4 additions & 3 deletions Lib/test/test_external_inspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,14 +447,15 @@ def test_long_task_name_is_truncated(self):
async def main():
asyncio.create_task(asyncio.sleep(10_000), name="x" * 300)
await asyncio.sleep(0)
return [
names = [
task.task_name
for info in RemoteUnwinder(os.getpid()).get_all_awaited_by()
for task in info.awaited_by
]
return asyncio.current_task().get_name(), names

names = asyncio.run(main())
self.assertIn("Task-1", names)
main_name, names = asyncio.run(main())
self.assertIn(main_name, names)
self.assertEqual([len(n) for n in names if n.startswith("x")], [255])

@skip_if_not_supported
Expand Down
3 changes: 2 additions & 1 deletion Modules/_testinternalcapi/test_cases.c.h

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

14 changes: 7 additions & 7 deletions Modules/mathmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ static const double logpi = 1.144729885849400174143427351353058711647;
} \
}

#ifndef HAVE_ACOSPI
#ifndef _Py_HAVE_ACOSPI
/*
acos(x)/pi. It conforms to C23 Annex 'F'.
*/
Expand All @@ -236,7 +236,7 @@ m_acospi(double x)
#define m_acospi acospi
#endif

#ifndef HAVE_ASINPI
#ifndef _Py_HAVE_ASINPI
/*
asin(x)/pi. It conforms to C23 Annex 'F'.
*/
Expand All @@ -254,7 +254,7 @@ m_asinpi(double x)
#define m_asinpi asinpi
#endif

#ifndef HAVE_ATANPI
#ifndef _Py_HAVE_ATANPI
/*
atan(x)/pi. It conforms to C23 Annex 'F'.
*/
Expand All @@ -272,7 +272,7 @@ m_atanpi(double x)
#define m_atanpi atanpi
#endif

#ifndef HAVE_ATAN2PI
#ifndef _Py_HAVE_ATAN2PI
/*
atan2(y, x)/pi. It conforms to C23 Annex 'F'.
*/
Expand All @@ -290,7 +290,7 @@ m_atan2pi(double y, double x)
#define m_atan2pi atan2pi
#endif

#ifndef HAVE_COSPI
#ifndef _Py_HAVE_COSPI
/*
cos(pi*x), giving accurate results for all finite x (especially x
integral or close to an integer). It conforms to C23 Annex 'F'.
Expand Down Expand Up @@ -318,7 +318,7 @@ m_cospi(double x)
#define m_cospi cospi
#endif

#ifndef HAVE_SINPI
#ifndef _Py_HAVE_SINPI
/*
sin(pi*x), giving accurate results for all finite x (especially x
integral or close to an integer). It conforms to C23 Annex 'F'.
Expand Down Expand Up @@ -362,7 +362,7 @@ m_sinpi(double x)
#define m_sinpi sinpi
#endif

#ifndef HAVE_TANPI
#ifndef _Py_HAVE_TANPI
/*
tan(pi*x), giving accurate results for all finite x (especially x
integral or close to an integer). It conforms to C23 Annex 'F'.
Expand Down
76 changes: 44 additions & 32 deletions Objects/abstract.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "pycore_list.h" // _PyList_AppendTakeRef()
#include "pycore_long.h" // _PyLong_IsNegative()
#include "pycore_object.h" // _Py_CheckSlotResult()
#include "pycore_stackref.h" // _PyStackRef
#include "pycore_pybuffer.h" // _PyBuffer_ReleaseInInterpreterAndRawFree()
#include "pycore_pyerrors.h" // _PyErr_Occurred()
#include "pycore_pystate.h" // _PyThreadState_GET()
Expand Down Expand Up @@ -2635,6 +2636,37 @@ object_isinstance(PyObject *inst, PyObject *cls)
return retval;
}

static int
call_special_method(PyThreadState *tstate, PyObject *cls, PyObject *name,
const char *where, PyObject *arg, PyObject **res)
{
_PyCStackRef cref;
_PyThreadState_PushCStackRef(tstate, &cref);
_PyStackRef self = PyStackRef_FromPyObjectBorrow(cls);
int found = _PyObject_LookupSpecialMethod(name, &cref.ref, &self);
if (found > 0) {
*res = NULL;
if (!_Py_EnterRecursiveCallTstate(tstate, where)) {
PyObject *method = PyStackRef_AsPyObjectBorrow(cref.ref);
PyObject *args[2] = {PyStackRef_AsPyObjectBorrow(self), arg};
if (args[0] != NULL) {
/* Unbound method: prepend self. */
*res = PyObject_Vectorcall(method, args, 2, NULL);
}
else {
*res = PyObject_Vectorcall(method, args + 1, 1, NULL);
}
_Py_LeaveRecursiveCallTstate(tstate);
}
if (*res == NULL) {
found = -1;
}
}
PyStackRef_XCLOSE(self);
_PyThreadState_PopCStackRef(tstate, &cref);
return found;
}

static int
object_recursive_isinstance(PyThreadState *tstate, PyObject *inst, PyObject *cls)
{
Expand Down Expand Up @@ -2672,26 +2704,16 @@ object_recursive_isinstance(PyThreadState *tstate, PyObject *inst, PyObject *cls
return r;
}

PyObject *checker = _PyObject_LookupSpecial(cls, &_Py_ID(__instancecheck__));
if (checker != NULL) {
if (_Py_EnterRecursiveCallTstate(tstate, " in __instancecheck__")) {
Py_DECREF(checker);
return -1;
}

PyObject *res = PyObject_CallOneArg(checker, inst);
_Py_LeaveRecursiveCallTstate(tstate);
Py_DECREF(checker);

if (res == NULL) {
return -1;
}
PyObject *res;
int found = call_special_method(tstate, cls, &_Py_ID(__instancecheck__),
" in __instancecheck__", inst, &res);
if (found > 0) {
int ok = PyObject_IsTrue(res);
Py_DECREF(res);

return ok;
}
else if (_PyErr_Occurred(tstate)) {
else if (found < 0) {
return -1;
}

Expand Down Expand Up @@ -2731,8 +2753,6 @@ recursive_issubclass(PyObject *derived, PyObject *cls)
static int
object_issubclass(PyThreadState *tstate, PyObject *derived, PyObject *cls)
{
PyObject *checker;

/* We know what type's __subclasscheck__ does. */
if (PyType_CheckExact(cls)) {
/* Quick test for an exact match */
Expand Down Expand Up @@ -2763,23 +2783,15 @@ object_issubclass(PyThreadState *tstate, PyObject *derived, PyObject *cls)
return r;
}

checker = _PyObject_LookupSpecial(cls, &_Py_ID(__subclasscheck__));
if (checker != NULL) {
int ok = -1;
if (_Py_EnterRecursiveCallTstate(tstate, " in __subclasscheck__")) {
Py_DECREF(checker);
return ok;
}
PyObject *res = PyObject_CallOneArg(checker, derived);
_Py_LeaveRecursiveCallTstate(tstate);
Py_DECREF(checker);
if (res != NULL) {
ok = PyObject_IsTrue(res);
Py_DECREF(res);
}
PyObject *res;
int found = call_special_method(tstate, cls, &_Py_ID(__subclasscheck__),
" in __subclasscheck__", derived, &res);
if (found > 0) {
int ok = PyObject_IsTrue(res);
Py_DECREF(res);
return ok;
}
else if (_PyErr_Occurred(tstate)) {
else if (found < 0) {
return -1;
}

Expand Down
29 changes: 17 additions & 12 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2931,17 +2931,22 @@ _PyObject_LookupSpecial(PyObject *self, PyObject *attr)
return res;
}

// Lookup the method name `attr` on `self`. On entry, `method_and_self[0]`
// is null and `method_and_self[1]` is `self`. On exit, `method_and_self[0]`
// is the method object and `method_and_self[1]` is `self` if the method is
// not bound.
// Lookup the method name `attr` on `*self`. On entry, `*method` is null.
// On exit, `*method` is the method object and `*self` is cleared if the
// method is bound.
// Return 1 on success, -1 on error, and 0 if the method is missing.
//
// `method` must point to a location that the garbage collector can see,
// such as the `ref` field of a `_PyCStackRef` or a slot on the interpreter
// stack. A descriptor may be invoked while `*method` holds the only
// reference to the method object, and that can trigger a collection.
int
_PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method_and_self)
_PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method,
_PyStackRef *self)
{
PyObject *self = PyStackRef_AsPyObjectBorrow(method_and_self[1]);
_PyType_LookupStackRefAndVersion(Py_TYPE(self), attr, &method_and_self[0]);
PyObject *method_o = PyStackRef_AsPyObjectBorrow(method_and_self[0]);
PyObject *self_o = PyStackRef_AsPyObjectBorrow(*self);
_PyType_LookupStackRefAndVersion(Py_TYPE(self_o), attr, method);
PyObject *method_o = PyStackRef_AsPyObjectBorrow(*method);
if (method_o == NULL) {
return 0;
}
Expand All @@ -2953,14 +2958,14 @@ _PyObject_LookupSpecialMethod(PyObject *attr, _PyStackRef *method_and_self)

descrgetfunc f = Py_TYPE(method_o)->tp_descr_get;
if (f != NULL) {
PyObject *func = f(method_o, self, (PyObject *)(Py_TYPE(self)));
PyObject *func = f(method_o, self_o, (PyObject *)(Py_TYPE(self_o)));
if (func == NULL) {
return -1;
}
PyStackRef_CLEAR(method_and_self[0]); // clear method
method_and_self[0] = PyStackRef_FromPyObjectSteal(func);
PyStackRef_CLEAR(*method); // clear method
*method = PyStackRef_FromPyObjectSteal(func);
}
PyStackRef_CLEAR(method_and_self[1]); // clear self
PyStackRef_CLEAR(*self); // clear self
return 1;
}

Expand Down
3 changes: 2 additions & 1 deletion Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -4141,7 +4141,8 @@ dummy_func(

op(_LOAD_SPECIAL, (method_and_self[2] -- method_and_self[2])) {
PyObject *name = _Py_SpecialMethods[oparg].name;
int err = _PyObject_LookupSpecialMethod(name, method_and_self);
int err = _PyObject_LookupSpecialMethod(name, &method_and_self[0],
&method_and_self[1]);
if (err <= 0) {
if (err == 0) {
PyObject *owner = PyStackRef_AsPyObjectBorrow(method_and_self[1]);
Expand Down
3 changes: 2 additions & 1 deletion Python/executor_cases.c.h

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

3 changes: 2 additions & 1 deletion Python/generated_cases.c.h

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

7 changes: 0 additions & 7 deletions Tools/build/check_capi_macros_ignored.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,18 +73,14 @@ GETPGRP_HAVE_ARG
HAVE_ACCEPT
HAVE_ACCEPT4
HAVE_ACOSH
HAVE_ACOSPI
HAVE_ADDRINFO
HAVE_ALARM
HAVE_ALIGNED_REQUIRED
HAVE_ALLOCA_H
HAVE_ALTZONE
HAVE_ASINH
HAVE_ASINPI
HAVE_ASM_TYPES_H
HAVE_ATAN2PI
HAVE_ATANH
HAVE_ATANPI
HAVE_BACKTRACE
HAVE_BIND
HAVE_BIND_TEXTDOMAIN_CODESET
Expand Down Expand Up @@ -118,7 +114,6 @@ HAVE_CONFSTR
HAVE_CONIO_H
HAVE_CONNECT
HAVE_COPY_FILE_RANGE
HAVE_COSPI
HAVE_CTERMID
HAVE_CTERMID_R
HAVE_CURSES_DEFINE_KEY
Expand Down Expand Up @@ -510,7 +505,6 @@ HAVE_SIGRELSE
HAVE_SIGTIMEDWAIT
HAVE_SIGWAIT
HAVE_SIGWAITINFO
HAVE_SINPI
HAVE_SNPRINTF
HAVE_SOCKADDR_ALG
HAVE_SOCKADDR_SA_LEN
Expand Down Expand Up @@ -602,7 +596,6 @@ HAVE_SYS_UN_H
HAVE_SYS_UTSNAME_H
HAVE_SYS_WAIT_H
HAVE_SYS_XATTR_H
HAVE_TANPI
HAVE_TCGETPGRP
HAVE_TCSETPGRP
HAVE_TEMPNAM
Expand Down
Loading
Loading