summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2022-05-04 15:31:21 (GMT)
committerGitHub <noreply@github.com>2022-05-04 15:31:21 (GMT)
commitf8a2fab212c4e9ea92a5b667560449904c4cf7af (patch)
treedc6c40594f776bd7d262a1b915661c253acc92d3
parent9d20e1af409c22537f096206edd330f16ab8f1f3 (diff)
downloadcpython-f8a2fab212c4e9ea92a5b667560449904c4cf7af.zip
cpython-f8a2fab212c4e9ea92a5b667560449904c4cf7af.tar.gz
cpython-f8a2fab212c4e9ea92a5b667560449904c4cf7af.tar.bz2
GH-92239: Make sure that PEP 523 is supported, even when specializing first. (GH-92245)
-rw-r--r--Lib/test/test_capi.py28
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-05-03-14-55-40.gh-issue-92245.G17-5i.rst2
-rw-r--r--Modules/_testinternalcapi.c37
-rw-r--r--Python/ceval.c2
-rw-r--r--Python/specialize.c6
5 files changed, 74 insertions, 1 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 1aed9b7..ab4caef 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -1142,5 +1142,33 @@ class Test_FrameAPI(unittest.TestCase):
self.assertIs(gen, _testcapi.frame_getgenerator(frame))
+SUFFICIENT_TO_DEOPT_AND_SPECIALIZE = 100
+
+class Test_Pep523API(unittest.TestCase):
+
+ def do_test(self, func):
+ calls = []
+ start = SUFFICIENT_TO_DEOPT_AND_SPECIALIZE
+ count = start + SUFFICIENT_TO_DEOPT_AND_SPECIALIZE
+ for i in range(count):
+ if i == start:
+ _testinternalcapi.set_eval_frame_record(calls)
+ func()
+ _testinternalcapi.set_eval_frame_default()
+ self.assertEqual(len(calls), SUFFICIENT_TO_DEOPT_AND_SPECIALIZE)
+ for name in calls:
+ self.assertEqual(name, func.__name__)
+
+ def test_pep523_with_specialization_simple(self):
+ def func1():
+ pass
+ self.do_test(func1)
+
+ def test_pep523_with_specialization_with_default(self):
+ def func2(x=None):
+ pass
+ self.do_test(func2)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-03-14-55-40.gh-issue-92245.G17-5i.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-03-14-55-40.gh-issue-92245.G17-5i.rst
new file mode 100644
index 0000000..7b1c5f5
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-03-14-55-40.gh-issue-92245.G17-5i.rst
@@ -0,0 +1,2 @@
+Make sure that PEP 523 is respected in all cases. In 3.11a7, specialization
+may have prevented Python-to-Python calls respecting PEP 523.
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 5d5b3e6..914b20b 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -15,6 +15,7 @@
#include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
#include "pycore_bitutils.h" // _Py_bswap32()
#include "pycore_fileutils.h" // _Py_normpath
+#include "pycore_frame.h" // _PyInterpreterFrame
#include "pycore_gc.h" // PyGC_Head
#include "pycore_hashtable.h" // _Py_hashtable_new()
#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
@@ -22,7 +23,7 @@
#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy()
#include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost()
#include "pycore_pystate.h" // _PyThreadState_GET()
-#include "osdefs.h" // MAXPATHLEN
+#include "osdefs.h" // MAXPATHLEN
static PyObject *
@@ -491,6 +492,38 @@ decode_locale_ex(PyObject *self, PyObject *args)
return res;
}
+static PyObject *record_list = NULL;
+
+static PyObject *
+set_eval_frame_default(PyObject *self, PyObject *Py_UNUSED(args))
+{
+ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), _PyEval_EvalFrameDefault);
+ Py_CLEAR(record_list);
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+record_eval(PyThreadState *tstate, struct _PyInterpreterFrame *f, int exc)
+{
+ PyList_Append(record_list, f->f_func->func_name);
+ return _PyEval_EvalFrameDefault(tstate, f, exc);
+}
+
+
+static PyObject *
+set_eval_frame_record(PyObject *self, PyObject *list)
+{
+ if (!PyList_Check(list)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be a list");
+ return NULL;
+ }
+ Py_CLEAR(record_list);
+ Py_INCREF(list);
+ record_list = list;
+ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState_Get(), record_eval);
+ Py_RETURN_NONE;
+}
+
static PyMethodDef TestMethods[] = {
{"get_configs", get_configs, METH_NOARGS},
@@ -508,6 +541,8 @@ static PyMethodDef TestMethods[] = {
{"get_getpath_codeobject", get_getpath_codeobject, METH_NOARGS, NULL},
{"EncodeLocaleEx", encode_locale_ex, METH_VARARGS},
{"DecodeLocaleEx", decode_locale_ex, METH_VARARGS},
+ {"set_eval_frame_default", set_eval_frame_default, METH_NOARGS, NULL},
+ {"set_eval_frame_record", set_eval_frame_record, METH_O, NULL},
{NULL, NULL} /* sentinel */
};
diff --git a/Python/ceval.c b/Python/ceval.c
index 6f46c7f..b2735a1 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -4890,6 +4890,7 @@ handle_eval_breaker:
TARGET(CALL_PY_EXACT_ARGS) {
assert(call_shape.kwnames == NULL);
+ DEOPT_IF(tstate->interp->eval_frame, CALL);
_PyCallCache *cache = (_PyCallCache *)next_instr;
int is_meth = is_method(stack_pointer, oparg);
int argcount = oparg + is_meth;
@@ -4923,6 +4924,7 @@ handle_eval_breaker:
TARGET(CALL_PY_WITH_DEFAULTS) {
assert(call_shape.kwnames == NULL);
+ DEOPT_IF(tstate->interp->eval_frame, CALL);
_PyCallCache *cache = (_PyCallCache *)next_instr;
int is_meth = is_method(stack_pointer, oparg);
int argcount = oparg + is_meth;
diff --git a/Python/specialize.c b/Python/specialize.c
index 12871ce..fa42993 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -440,6 +440,7 @@ initial_counter_value(void) {
#define SPEC_FAIL_CALL_METHOD_WRAPPER 26
#define SPEC_FAIL_CALL_OPERATOR_WRAPPER 27
#define SPEC_FAIL_CALL_PYFUNCTION 28
+#define SPEC_FAIL_CALL_PEP_523 29
/* COMPARE_OP */
#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12
@@ -1471,6 +1472,11 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
assert(_Py_OPCODE(*instr) == CALL_ADAPTIVE);
PyCodeObject *code = (PyCodeObject *)func->func_code;
int kind = function_kind(code);
+ /* Don't specialize if PEP 523 is active */
+ if (_PyInterpreterState_GET()->eval_frame) {
+ SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523);
+ return -1;
+ }
if (kwnames) {
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
return -1;