mirror of https://github.com/python/cpython
GH-92239: Make sure that PEP 523 is supported, even when specializing first. (GH-92245)
This commit is contained in:
parent
9d20e1af40
commit
f8a2fab212
|
@ -1142,5 +1142,33 @@ class Test_FrameAPI(unittest.TestCase):
|
||||||
self.assertIs(gen, _testcapi.frame_getgenerator(frame))
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -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.
|
|
@ -15,6 +15,7 @@
|
||||||
#include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
|
#include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
|
||||||
#include "pycore_bitutils.h" // _Py_bswap32()
|
#include "pycore_bitutils.h" // _Py_bswap32()
|
||||||
#include "pycore_fileutils.h" // _Py_normpath
|
#include "pycore_fileutils.h" // _Py_normpath
|
||||||
|
#include "pycore_frame.h" // _PyInterpreterFrame
|
||||||
#include "pycore_gc.h" // PyGC_Head
|
#include "pycore_gc.h" // PyGC_Head
|
||||||
#include "pycore_hashtable.h" // _Py_hashtable_new()
|
#include "pycore_hashtable.h" // _Py_hashtable_new()
|
||||||
#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
|
#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
|
||||||
|
@ -22,7 +23,7 @@
|
||||||
#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy()
|
#include "pycore_interp.h" // _PyInterpreterState_GetConfigCopy()
|
||||||
#include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost()
|
#include "pycore_pyerrors.h" // _Py_UTF8_Edit_Cost()
|
||||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||||
#include "osdefs.h" // MAXPATHLEN
|
#include "osdefs.h" // MAXPATHLEN
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -491,6 +492,38 @@ decode_locale_ex(PyObject *self, PyObject *args)
|
||||||
return res;
|
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[] = {
|
static PyMethodDef TestMethods[] = {
|
||||||
{"get_configs", get_configs, METH_NOARGS},
|
{"get_configs", get_configs, METH_NOARGS},
|
||||||
|
@ -508,6 +541,8 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"get_getpath_codeobject", get_getpath_codeobject, METH_NOARGS, NULL},
|
{"get_getpath_codeobject", get_getpath_codeobject, METH_NOARGS, NULL},
|
||||||
{"EncodeLocaleEx", encode_locale_ex, METH_VARARGS},
|
{"EncodeLocaleEx", encode_locale_ex, METH_VARARGS},
|
||||||
{"DecodeLocaleEx", decode_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 */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4890,6 +4890,7 @@ handle_eval_breaker:
|
||||||
|
|
||||||
TARGET(CALL_PY_EXACT_ARGS) {
|
TARGET(CALL_PY_EXACT_ARGS) {
|
||||||
assert(call_shape.kwnames == NULL);
|
assert(call_shape.kwnames == NULL);
|
||||||
|
DEOPT_IF(tstate->interp->eval_frame, CALL);
|
||||||
_PyCallCache *cache = (_PyCallCache *)next_instr;
|
_PyCallCache *cache = (_PyCallCache *)next_instr;
|
||||||
int is_meth = is_method(stack_pointer, oparg);
|
int is_meth = is_method(stack_pointer, oparg);
|
||||||
int argcount = oparg + is_meth;
|
int argcount = oparg + is_meth;
|
||||||
|
@ -4923,6 +4924,7 @@ handle_eval_breaker:
|
||||||
|
|
||||||
TARGET(CALL_PY_WITH_DEFAULTS) {
|
TARGET(CALL_PY_WITH_DEFAULTS) {
|
||||||
assert(call_shape.kwnames == NULL);
|
assert(call_shape.kwnames == NULL);
|
||||||
|
DEOPT_IF(tstate->interp->eval_frame, CALL);
|
||||||
_PyCallCache *cache = (_PyCallCache *)next_instr;
|
_PyCallCache *cache = (_PyCallCache *)next_instr;
|
||||||
int is_meth = is_method(stack_pointer, oparg);
|
int is_meth = is_method(stack_pointer, oparg);
|
||||||
int argcount = oparg + is_meth;
|
int argcount = oparg + is_meth;
|
||||||
|
|
|
@ -440,6 +440,7 @@ initial_counter_value(void) {
|
||||||
#define SPEC_FAIL_CALL_METHOD_WRAPPER 26
|
#define SPEC_FAIL_CALL_METHOD_WRAPPER 26
|
||||||
#define SPEC_FAIL_CALL_OPERATOR_WRAPPER 27
|
#define SPEC_FAIL_CALL_OPERATOR_WRAPPER 27
|
||||||
#define SPEC_FAIL_CALL_PYFUNCTION 28
|
#define SPEC_FAIL_CALL_PYFUNCTION 28
|
||||||
|
#define SPEC_FAIL_CALL_PEP_523 29
|
||||||
|
|
||||||
/* COMPARE_OP */
|
/* COMPARE_OP */
|
||||||
#define SPEC_FAIL_COMPARE_OP_DIFFERENT_TYPES 12
|
#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);
|
assert(_Py_OPCODE(*instr) == CALL_ADAPTIVE);
|
||||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||||
int kind = function_kind(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) {
|
if (kwnames) {
|
||||||
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
|
SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
Loading…
Reference in New Issue