mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
GH-120507: Lower the BEFORE_WITH
and BEFORE_ASYNC_WITH
instructions. (#120640)
* Remove BEFORE_WITH and BEFORE_ASYNC_WITH instructions. * Add LOAD_SPECIAL instruction * Reimplement `with` and `async with` statements using LOAD_SPECIAL
This commit is contained in:
parent
73dc1c678e
commit
9cefcc0ee7
22 changed files with 663 additions and 651 deletions
128
Python/generated_cases.c.h
generated
128
Python/generated_cases.c.h
generated
|
@ -9,95 +9,6 @@
|
|||
#define TIER_ONE 1
|
||||
|
||||
|
||||
TARGET(BEFORE_ASYNC_WITH) {
|
||||
frame->instr_ptr = next_instr;
|
||||
next_instr += 1;
|
||||
INSTRUCTION_STATS(BEFORE_ASYNC_WITH);
|
||||
PyObject *mgr;
|
||||
PyObject *exit;
|
||||
PyObject *res;
|
||||
mgr = stack_pointer[-1];
|
||||
PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__));
|
||||
if (enter == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"'%.200s' object does not support the "
|
||||
"asynchronous context manager protocol",
|
||||
Py_TYPE(mgr)->tp_name);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__aexit__));
|
||||
if (exit == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"'%.200s' object does not support the "
|
||||
"asynchronous context manager protocol "
|
||||
"(missed __aexit__ method)",
|
||||
Py_TYPE(mgr)->tp_name);
|
||||
}
|
||||
Py_DECREF(enter);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(mgr);
|
||||
res = PyObject_CallNoArgs(enter);
|
||||
Py_DECREF(enter);
|
||||
if (res == NULL) {
|
||||
Py_DECREF(exit);
|
||||
if (true) goto pop_1_error;
|
||||
}
|
||||
stack_pointer[-1] = exit;
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(BEFORE_WITH) {
|
||||
frame->instr_ptr = next_instr;
|
||||
next_instr += 1;
|
||||
INSTRUCTION_STATS(BEFORE_WITH);
|
||||
PyObject *mgr;
|
||||
PyObject *exit;
|
||||
PyObject *res;
|
||||
mgr = stack_pointer[-1];
|
||||
/* pop the context manager, push its __exit__ and the
|
||||
* value returned from calling its __enter__
|
||||
*/
|
||||
PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__enter__));
|
||||
if (enter == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"'%.200s' object does not support the "
|
||||
"context manager protocol",
|
||||
Py_TYPE(mgr)->tp_name);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__exit__));
|
||||
if (exit == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"'%.200s' object does not support the "
|
||||
"context manager protocol "
|
||||
"(missed __exit__ method)",
|
||||
Py_TYPE(mgr)->tp_name);
|
||||
}
|
||||
Py_DECREF(enter);
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(mgr);
|
||||
res = PyObject_CallNoArgs(enter);
|
||||
Py_DECREF(enter);
|
||||
if (res == NULL) {
|
||||
Py_DECREF(exit);
|
||||
if (true) goto pop_1_error;
|
||||
}
|
||||
stack_pointer[-1] = exit;
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(BINARY_OP) {
|
||||
frame->instr_ptr = next_instr;
|
||||
next_instr += 2;
|
||||
|
@ -4635,6 +4546,31 @@
|
|||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(LOAD_SPECIAL) {
|
||||
frame->instr_ptr = next_instr;
|
||||
next_instr += 1;
|
||||
INSTRUCTION_STATS(LOAD_SPECIAL);
|
||||
PyObject *owner;
|
||||
PyObject *attr;
|
||||
PyObject *self_or_null;
|
||||
owner = stack_pointer[-1];
|
||||
assert(oparg <= SPECIAL_MAX);
|
||||
PyObject *name = _Py_SpecialMethods[oparg].name;
|
||||
attr = _PyObject_LookupSpecialMethod(owner, name, &self_or_null);
|
||||
if (attr == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
_Py_SpecialMethods[oparg].error,
|
||||
Py_TYPE(owner)->tp_name);
|
||||
}
|
||||
}
|
||||
if (attr == NULL) goto pop_1_error;
|
||||
stack_pointer[-1] = attr;
|
||||
stack_pointer[0] = self_or_null;
|
||||
stack_pointer += 1;
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(LOAD_SUPER_ATTR) {
|
||||
frame->instr_ptr = next_instr;
|
||||
next_instr += 2;
|
||||
|
@ -6210,16 +6146,19 @@
|
|||
INSTRUCTION_STATS(WITH_EXCEPT_START);
|
||||
PyObject *val;
|
||||
PyObject *lasti;
|
||||
PyObject *exit_self;
|
||||
PyObject *exit_func;
|
||||
PyObject *res;
|
||||
val = stack_pointer[-1];
|
||||
lasti = stack_pointer[-3];
|
||||
exit_func = stack_pointer[-4];
|
||||
exit_self = stack_pointer[-4];
|
||||
exit_func = stack_pointer[-5];
|
||||
/* At the top of the stack are 4 values:
|
||||
- val: TOP = exc_info()
|
||||
- unused: SECOND = previous exception
|
||||
- lasti: THIRD = lasti of exception in exc_info()
|
||||
- exit_func: FOURTH = the context.__exit__ bound method
|
||||
- exit_self: FOURTH = the context or NULL
|
||||
- exit_func: FIFTH = the context.__exit__ function or context.__exit__ bound method
|
||||
We call FOURTH(type(TOP), TOP, GetTraceback(TOP)).
|
||||
Then we push the __exit__ return value.
|
||||
*/
|
||||
|
@ -6235,9 +6174,10 @@
|
|||
}
|
||||
assert(PyLong_Check(lasti));
|
||||
(void)lasti; // Shut up compiler warning if asserts are off
|
||||
PyObject *stack[4] = {NULL, exc, val, tb};
|
||||
res = PyObject_Vectorcall(exit_func, stack + 1,
|
||||
3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
|
||||
PyObject *stack[5] = {NULL, exit_self, exc, val, tb};
|
||||
int has_self = (exit_self != NULL);
|
||||
res = PyObject_Vectorcall(exit_func, stack + 2 - has_self,
|
||||
(3 + has_self) | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
|
||||
if (res == NULL) goto error;
|
||||
stack_pointer[0] = res;
|
||||
stack_pointer += 1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue