mirror of https://github.com/python/cpython
gh-118702: Implement vectorcall for BaseException (#118703)
* BaseException_vectorcall() now creates a tuple from 'args' array. * Creation an exception using BaseException_vectorcall() is now a single function call, rather than having to call BaseException_new() and then BaseException_init(). Calling BaseException_init() is inefficient since it overrides the 'args' attribute. * _PyErr_SetKeyError() now uses PyObject_CallOneArg() to create the KeyError instance to use BaseException_vectorcall().
This commit is contained in:
parent
ec9d12be96
commit
aa36f83c16
|
@ -1817,6 +1817,29 @@ class ExceptionTests(unittest.TestCase):
|
||||||
rc, _, err = script_helper.assert_python_ok("-c", code)
|
rc, _, err = script_helper.assert_python_ok("-c", code)
|
||||||
self.assertIn(b'MemoryError', err)
|
self.assertIn(b'MemoryError', err)
|
||||||
|
|
||||||
|
def test_keyerror_context(self):
|
||||||
|
# Make sure that _PyErr_SetKeyError() chains exceptions
|
||||||
|
try:
|
||||||
|
err1 = None
|
||||||
|
err2 = None
|
||||||
|
try:
|
||||||
|
d = {}
|
||||||
|
try:
|
||||||
|
raise ValueError("bug")
|
||||||
|
except Exception as exc:
|
||||||
|
err1 = exc
|
||||||
|
d[1]
|
||||||
|
except Exception as exc:
|
||||||
|
err2 = exc
|
||||||
|
|
||||||
|
self.assertIsInstance(err1, ValueError)
|
||||||
|
self.assertIsInstance(err2, KeyError)
|
||||||
|
self.assertEqual(err2.__context__, err1)
|
||||||
|
finally:
|
||||||
|
# Break any potential reference cycle
|
||||||
|
exc1 = None
|
||||||
|
exc2 = None
|
||||||
|
|
||||||
|
|
||||||
class NameErrorTests(unittest.TestCase):
|
class NameErrorTests(unittest.TestCase):
|
||||||
def test_name_error_has_name(self):
|
def test_name_error_has_name(self):
|
||||||
|
|
|
@ -78,6 +78,40 @@ BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
BaseException_vectorcall(PyObject *type_obj, PyObject * const*args,
|
||||||
|
size_t nargsf, PyObject *kwnames)
|
||||||
|
{
|
||||||
|
PyTypeObject *type = _PyType_CAST(type_obj);
|
||||||
|
if (!_PyArg_NoKwnames(type->tp_name, kwnames)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyBaseExceptionObject *self;
|
||||||
|
self = (PyBaseExceptionObject *)type->tp_alloc(type, 0);
|
||||||
|
if (!self) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The dict is created on the fly in PyObject_GenericSetAttr()
|
||||||
|
self->dict = NULL;
|
||||||
|
self->notes = NULL;
|
||||||
|
self->traceback = NULL;
|
||||||
|
self->cause = NULL;
|
||||||
|
self->context = NULL;
|
||||||
|
self->suppress_context = 0;
|
||||||
|
|
||||||
|
self->args = _PyTuple_FromArray(args, PyVectorcall_NARGS(nargsf));
|
||||||
|
if (!self->args) {
|
||||||
|
Py_DECREF(self);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PyObject *)self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
BaseException_clear(PyBaseExceptionObject *self)
|
BaseException_clear(PyBaseExceptionObject *self)
|
||||||
{
|
{
|
||||||
|
@ -486,6 +520,7 @@ static PyTypeObject _PyExc_BaseException = {
|
||||||
(initproc)BaseException_init, /* tp_init */
|
(initproc)BaseException_init, /* tp_init */
|
||||||
0, /* tp_alloc */
|
0, /* tp_alloc */
|
||||||
BaseException_new, /* tp_new */
|
BaseException_new, /* tp_new */
|
||||||
|
.tp_vectorcall = BaseException_vectorcall,
|
||||||
};
|
};
|
||||||
/* the CPython API expects exceptions to be (PyObject *) - both a hold-over
|
/* the CPython API expects exceptions to be (PyObject *) - both a hold-over
|
||||||
from the previous implementation and also allowing Python objects to be used
|
from the previous implementation and also allowing Python objects to be used
|
||||||
|
@ -3675,6 +3710,11 @@ _PyExc_InitTypes(PyInterpreterState *interp)
|
||||||
if (_PyStaticType_InitBuiltin(interp, exc) < 0) {
|
if (_PyStaticType_InitBuiltin(interp, exc) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (exc->tp_new == BaseException_new
|
||||||
|
&& exc->tp_init == (initproc)BaseException_init)
|
||||||
|
{
|
||||||
|
exc->tp_vectorcall = BaseException_vectorcall;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,13 +257,14 @@ void
|
||||||
_PyErr_SetKeyError(PyObject *arg)
|
_PyErr_SetKeyError(PyObject *arg)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
PyObject *tup = PyTuple_Pack(1, arg);
|
PyObject *exc = PyObject_CallOneArg(PyExc_KeyError, arg);
|
||||||
if (!tup) {
|
if (!exc) {
|
||||||
/* caller will expect error to be set anyway */
|
/* caller will expect error to be set anyway */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_PyErr_SetObject(tstate, PyExc_KeyError, tup);
|
|
||||||
Py_DECREF(tup);
|
_PyErr_SetObject(tstate, (PyObject*)Py_TYPE(exc), exc);
|
||||||
|
Py_DECREF(exc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Loading…
Reference in New Issue