aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Python/generated_cases.c.h
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2024-06-18 12:17:46 +0100
committerGitHub <noreply@github.com>2024-06-18 12:17:46 +0100
commit9cefcc0ee781a1bef9e0685c2271237005fb488b (patch)
tree7c02067f4e021d90ec4fd850d9a06315b8fc39ab /Python/generated_cases.c.h
parent73dc1c678eb720c2ced94d2f435a908bb6d18566 (diff)
downloadcpython-9cefcc0ee781a1bef9e0685c2271237005fb488b.tar.gz
cpython-9cefcc0ee781a1bef9e0685c2271237005fb488b.zip
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
Diffstat (limited to 'Python/generated_cases.c.h')
-rw-r--r--Python/generated_cases.c.h128
1 files changed, 34 insertions, 94 deletions
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 8a6f5ff784f..3980f9852e6 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -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;