diff options
author | Mark Shannon <mark@hotpy.org> | 2024-06-18 12:17:46 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-18 12:17:46 +0100 |
commit | 9cefcc0ee781a1bef9e0685c2271237005fb488b (patch) | |
tree | 7c02067f4e021d90ec4fd850d9a06315b8fc39ab /Python/executor_cases.c.h | |
parent | 73dc1c678eb720c2ced94d2f435a908bb6d18566 (diff) | |
download | cpython-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/executor_cases.c.h')
-rw-r--r-- | Python/executor_cases.c.h | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index d390c9fc2f6..b4e5261f57a 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2883,23 +2883,45 @@ break; } - /* _BEFORE_ASYNC_WITH is not a viable micro-op for tier 2 because it has both popping and not-popping errors */ - - /* _BEFORE_WITH is not a viable micro-op for tier 2 because it has both popping and not-popping errors */ + case _LOAD_SPECIAL: { + PyObject *owner; + PyObject *attr; + PyObject *self_or_null; + oparg = CURRENT_OPARG(); + 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) JUMP_TO_ERROR(); + stack_pointer[-1] = attr; + stack_pointer[0] = self_or_null; + stack_pointer += 1; + break; + } case _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. */ @@ -2915,9 +2937,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) JUMP_TO_ERROR(); stack_pointer[0] = res; stack_pointer += 1; |