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
2 changes: 1 addition & 1 deletion Include/internal/pycore_unicodeobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ extern int _PyUnicodeWriter_FormatV(

/* --- iconv Codec -------------------------------------------------------- */

#ifdef HAVE_ICONV
#ifdef _Py_HAVE_ICONV
extern PyObject* _PyUnicode_DecodeIconv(
const char *encoding, /* iconv encoding name */
const char *string, /* encoded string */
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
8 changes: 4 additions & 4 deletions Modules/_codecsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ _codecs_code_page_decode_impl(PyObject *module, int codepage,

#endif /* MS_WINDOWS */

#ifdef HAVE_ICONV
#ifdef _Py_HAVE_ICONV

/*[clinic input]
_codecs.iconv_decode
Expand All @@ -665,7 +665,7 @@ _codecs_iconv_decode_impl(PyObject *module, const char *encoding,
return codec_tuple(decoded, consumed);
}

#endif /* HAVE_ICONV */
#endif /* _Py_HAVE_ICONV */

/* --- Encoder ------------------------------------------------------------ */

Expand Down Expand Up @@ -977,7 +977,7 @@ _codecs_code_page_encode_impl(PyObject *module, int code_page, PyObject *str,

#endif /* MS_WINDOWS */

#ifdef HAVE_ICONV
#ifdef _Py_HAVE_ICONV

/*[clinic input]
_codecs.iconv_encode
Expand All @@ -996,7 +996,7 @@ _codecs_iconv_encode_impl(PyObject *module, const char *encoding,
PyUnicode_GET_LENGTH(str));
}

#endif /* HAVE_ICONV */
#endif /* _Py_HAVE_ICONV */

/* --- Error handler registry --------------------------------------------- */

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.

10 changes: 5 additions & 5 deletions Modules/clinic/_codecsmodule.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
6 changes: 3 additions & 3 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <windows.h>
#endif

#ifdef HAVE_ICONV
#ifdef _Py_HAVE_ICONV
#include <iconv.h> // iconv_open()
#endif

Expand Down Expand Up @@ -8220,7 +8220,7 @@ PyUnicode_AsMBCSString(PyObject *unicode)

/* --- iconv Codec -------------------------------------------------------- */

#ifdef HAVE_ICONV
#ifdef _Py_HAVE_ICONV

/* iconv pivot: native-endian UTF-32, a raw array of Py_UCS4. One input unit is
one code point, so error handlers get the exact position. A platform whose
Expand Down Expand Up @@ -8602,7 +8602,7 @@ _PyUnicode_EncodeIconv(const char *encoding, PyObject *unicode,
return result;
}

#endif /* HAVE_ICONV */
#endif /* _Py_HAVE_ICONV */

/* --- Character Mapping Codec -------------------------------------------- */

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
Loading
Loading