[Python-checkins] bpo-45711: Remove type and traceback from exc_info (GH-30122)

markshannon webhook-mailer at python.org
Fri Dec 17 09:46:33 EST 2021


https://github.com/python/cpython/commit/396b58345f81d4c8c5a52546d2288e666a1b9b8b
commit: 396b58345f81d4c8c5a52546d2288e666a1b9b8b
branch: main
author: Irit Katriel <1055913+iritkatriel at users.noreply.github.com>
committer: markshannon <mark at hotpy.org>
date: 2021-12-17T14:46:22Z
summary:

bpo-45711: Remove type and traceback from exc_info (GH-30122)

* Do not PUSH/POP traceback or type to the stack as part of exc_info

* Remove exc_traceback and exc_type from _PyErr_StackItem

* Add to what's new, because this change breaks things like Cython

files:
A Misc/NEWS.d/next/Core and Builtins/2021-12-15-15-17-04.bpo-45711.QK4QrB.rst
M Doc/library/dis.rst
M Doc/whatsnew/3.11.rst
M Include/cpython/pystate.h
M Include/internal/pycore_pyerrors.h
M Lib/importlib/_bootstrap_external.py
M Lib/test/test_dis.py
M Lib/test/test_sys.py
M Modules/_asynciomodule.c
M Objects/genobject.c
M Python/ceval.c
M Python/compile.c
M Python/errors.c
M Python/pystate.c

diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 35d9baadf6d16..ffade3c9bfe7c 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -474,13 +474,15 @@ the original TOS1.
 .. opcode:: END_ASYNC_FOR
 
    Terminates an :keyword:`async for` loop.  Handles an exception raised
-   when awaiting a next item.  If TOS is :exc:`StopAsyncIteration` pop 7
+   when awaiting a next item.  If TOS is :exc:`StopAsyncIteration` pop 3
    values from the stack and restore the exception state using the second
-   three of them.  Otherwise re-raise the exception using the three values
+   of them.  Otherwise re-raise the exception using the value
    from the stack.  An exception handler block is removed from the block stack.
 
    .. versionadded:: 3.8
 
+    .. versionchanged:: 3.11
+       Exception representation on the stack now consist of one, not three, items.
 
 .. opcode:: BEFORE_ASYNC_WITH
 
@@ -561,8 +563,10 @@ iterations of the loop.
 
 .. opcode:: POP_EXCEPT
 
-   Pops three values from the stack, which are used to restore the exception state.
+   Pops a value from the stack, which is used to restore the exception state.
 
+    .. versionchanged:: 3.11
+       Exception representation on the stack now consist of one, not three, items.
 
 .. opcode:: RERAISE
 
@@ -572,11 +576,13 @@ iterations of the loop.
 
     .. versionadded:: 3.9
 
+    .. versionchanged:: 3.11
+       Exception representation on the stack now consist of one, not three, items.
 
 .. opcode:: PUSH_EXC_INFO
 
-    Pops the three values from the stack. Pushes the current exception to the top of the stack.
-    Pushes the three values originally popped back to the stack.
+    Pops a value from the stack. Pushes the current exception to the top of the stack.
+    Pushes the value originally popped back to the stack.
     Used in exception handlers.
 
     .. versionadded:: 3.11
@@ -584,8 +590,8 @@ iterations of the loop.
 
 .. opcode:: WITH_EXCEPT_START
 
-    Calls the function in position 8 on the stack with the top three
-    items on the stack as arguments.
+    Calls the function in position 4 on the stack with arguments (type, val, tb)
+    representing the exception at the top of the stack.
     Used to implement the call ``context_manager.__exit__(*exc_info())`` when an exception
     has occurred in a :keyword:`with` statement.
 
@@ -593,6 +599,9 @@ iterations of the loop.
     .. versionchanged:: 3.11
        The ``__exit__`` function is in position 8 of the stack rather than 7.
 
+    .. versionchanged:: 3.11
+       The ``__exit__`` function is in position 4 of the stack rather than 7.
+       Exception representation on the stack now consist of one, not three, items.
 
 .. opcode:: POP_EXCEPT_AND_RERAISE
 
@@ -890,10 +899,9 @@ All of the following opcodes use their arguments.
    Performs exception matching for ``except*``. Applies ``split(TOS)`` on
    the exception group representing TOS1. Jumps if no match is found.
 
-   Pops one item from the stack. If a match was found, pops the 3 items representing
-   the exception and pushes the 3 items representing the non-matching part of
-   the exception group, followed by the 3 items representing the matching part.
-   In other words, in case of a match it pops 4 items and pushes 6.
+   Pops one item from the stack (the match type). If a match was found,
+   next item (the exception) and pushes the non-matching part of the
+   exception group followed by the matching part.
 
    .. versionadded:: 3.11
 
@@ -903,8 +911,8 @@ All of the following opcodes use their arguments.
    Combines the raised and reraised exceptions list from TOS, into an exception
    group to propagate from a try-except* block. Uses the original exception
    group from TOS1 to reconstruct the structure of reraised exceptions. Pops
-   two items from the stack and pushes a triplet representing the exception to
-   reraise or three ``None`` if there isn't one.
+   two items from the stack and pushes 0 (for lasti, which is unused) followed
+   by the exception to reraise or ``None`` if there isn't one.
 
    .. versionadded:: 3.11
 
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 3005d1d43f25b..5389ce8b258cf 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -195,6 +195,11 @@ Other CPython Implementation Changes
   reflected in the re-raised exception.
   (Contributed by Irit Katriel in :issue:`45711`.)
 
+* The interpreter state's representation of handled exceptions (a.k.a exc_info, or
+  _PyErr_StackItem) now has only the ``exc_value`` field, ``exc_type`` and ``exc_traceback``
+  have been removed as their values can be derived from ``exc_value``.
+  (Contributed by Irit Katriel in :issue:`45711`.)
+
 New Modules
 ===========
 
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index aa518281c80f5..c37123c4f6922 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -56,7 +56,7 @@ typedef struct _err_stackitem {
      * This ensures that the exception state is not impacted by "yields"
      * from an except handler.
      */
-    PyObject *exc_type, *exc_value, *exc_traceback;
+    PyObject *exc_value;
 
     struct _err_stackitem *previous_item;
 
diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h
index 5e8d2025dfaf0..b9fc36cf06760 100644
--- a/Include/internal/pycore_pyerrors.h
+++ b/Include/internal/pycore_pyerrors.h
@@ -24,16 +24,7 @@ static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)
 
 static inline void _PyErr_ClearExcState(_PyErr_StackItem *exc_state)
 {
-    PyObject *t, *v, *tb;
-    t = exc_state->exc_type;
-    v = exc_state->exc_value;
-    tb = exc_state->exc_traceback;
-    exc_state->exc_type = NULL;
-    exc_state->exc_value = NULL;
-    exc_state->exc_traceback = NULL;
-    Py_XDECREF(t);
-    Py_XDECREF(v);
-    Py_XDECREF(tb);
+    Py_CLEAR(exc_state->exc_value);
 }
 
 PyAPI_FUNC(PyObject*) _PyErr_StackItemToExcInfoTuple(
@@ -114,6 +105,7 @@ PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
 
 #define _Py_FatalRefcountError(message) _Py_FatalRefcountErrorFunc(__func__, message)
 
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index 0c1078accc819..5ead6caf9f3c7 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -371,9 +371,10 @@ def _write_atomic(path, data, mode=0o666):
 #     Python 3.11a3 3464 (bpo-45636: Merge numeric BINARY_*/INPLACE_* into
 #                         BINARY_OP)
 #     Python 3.11a3 3465 (Add COPY_FREE_VARS opcode)
-#     Python 3.11a3 3466 (bpo-45292: PEP-654 except*)
+#     Python 3.11a4 3466 (bpo-45292: PEP-654 except*)
 #     Python 3.11a4 3467 (Change CALL_xxx opcodes)
 #     Python 3.11a4 3468 (Add SEND opcode)
+#     Python 3.11a4 3469 (bpo-45711: remove type, traceback from exc_info)
 
 #
 # MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -383,7 +384,7 @@ def _write_atomic(path, data, mode=0o666):
 # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
 # in PC/launcher.c must also be updated.
 
-MAGIC_NUMBER = (3468).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3469).to_bytes(2, 'little') + b'\r\n'
 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c
 
 _PYCACHE = '__pycache__'
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index c35f1d3ec8bd7..93b24da317575 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -310,33 +310,31 @@ def bug42562():
         >>   14 PUSH_EXC_INFO
 
 %3d          16 LOAD_GLOBAL              0 (Exception)
-             18 JUMP_IF_NOT_EXC_MATCH    26 (to 52)
-             20 POP_TOP
-             22 STORE_FAST               0 (e)
-             24 POP_TOP
-
-%3d          26 LOAD_FAST                0 (e)
-             28 LOAD_ATTR                1 (__traceback__)
-             30 STORE_FAST               1 (tb)
-             32 POP_EXCEPT
-             34 LOAD_CONST               0 (None)
-             36 STORE_FAST               0 (e)
-             38 DELETE_FAST              0 (e)
-
-%3d          40 LOAD_FAST                1 (tb)
-             42 RETURN_VALUE
-        >>   44 LOAD_CONST               0 (None)
-             46 STORE_FAST               0 (e)
-             48 DELETE_FAST              0 (e)
-             50 RERAISE                  1
-
-%3d     >>   52 RERAISE                  0
-        >>   54 POP_EXCEPT_AND_RERAISE
+             18 JUMP_IF_NOT_EXC_MATCH    24 (to 48)
+             20 STORE_FAST               0 (e)
+
+%3d          22 LOAD_FAST                0 (e)
+             24 LOAD_ATTR                1 (__traceback__)
+             26 STORE_FAST               1 (tb)
+             28 POP_EXCEPT
+             30 LOAD_CONST               0 (None)
+             32 STORE_FAST               0 (e)
+             34 DELETE_FAST              0 (e)
+
+%3d          36 LOAD_FAST                1 (tb)
+             38 RETURN_VALUE
+        >>   40 LOAD_CONST               0 (None)
+             42 STORE_FAST               0 (e)
+             44 DELETE_FAST              0 (e)
+             46 RERAISE                  1
+
+%3d     >>   48 RERAISE                  0
+        >>   50 POP_EXCEPT_AND_RERAISE
 ExceptionTable:
   2 to 8 -> 14 [0]
-  14 to 24 -> 54 [3] lasti
-  26 to 30 -> 44 [3] lasti
-  44 to 52 -> 54 [3] lasti
+  14 to 20 -> 50 [1] lasti
+  22 to 26 -> 40 [1] lasti
+  40 to 48 -> 50 [1] lasti
 """ % (TRACEBACK_CODE.co_firstlineno + 1,
        TRACEBACK_CODE.co_firstlineno + 2,
        TRACEBACK_CODE.co_firstlineno + 5,
@@ -395,7 +393,7 @@ def _tryfinallyconst(b):
         >>   22 POP_EXCEPT_AND_RERAISE
 ExceptionTable:
   2 to 2 -> 12 [0]
-  12 to 20 -> 22 [3] lasti
+  12 to 20 -> 22 [1] lasti
 """ % (_tryfinally.__code__.co_firstlineno + 1,
        _tryfinally.__code__.co_firstlineno + 2,
        _tryfinally.__code__.co_firstlineno + 4,
@@ -418,7 +416,7 @@ def _tryfinallyconst(b):
              22 RERAISE                  0
         >>   24 POP_EXCEPT_AND_RERAISE
 ExceptionTable:
-  14 to 22 -> 24 [3] lasti
+  14 to 22 -> 24 [1] lasti
 """ % (_tryfinallyconst.__code__.co_firstlineno + 1,
        _tryfinallyconst.__code__.co_firstlineno + 2,
        _tryfinallyconst.__code__.co_firstlineno + 4,
@@ -864,7 +862,7 @@ async def async_def():
 Positional-only arguments: 0
 Kw-only arguments: 0
 Number of locals:  2
-Stack size:        10
+Stack size:        6
 Flags:             OPTIMIZED, NEWLOCALS, COROUTINE
 Constants:
    0: None
@@ -1107,65 +1105,61 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=108, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='BINARY_OP', opcode=122, arg=11, argval=11, argrepr='/', offset=110, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_FORWARD', opcode=110, arg=14, argval=144, argrepr='to 144', offset=114, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=140, argrepr='to 140', offset=114, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=118, starts_line=22, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=70, argval=140, argrepr='to 140', offset=120, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_IF_NOT_EXC_MATCH', opcode=121, arg=68, argval=136, argrepr='to 136', offset=120, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=124, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=128, starts_line=23, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=130, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=132, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_FORWARD', opcode=110, arg=32, argval=204, argrepr='to 204', offset=138, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=140, starts_line=22, is_jump_target=True, positions=None),
-  Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=142, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=144, starts_line=25, is_jump_target=True, positions=None),
-  Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=148, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=150, starts_line=26, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=152, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=154, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=158, starts_line=25, is_jump_target=False, positions=None),
-  Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=192, argrepr='to 192', offset=168, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=90, argval=180, argrepr='to 180', offset=174, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='RERAISE', opcode=119, arg=4, argval=4, argrepr='', offset=176, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=178, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=180, starts_line=None, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=124, starts_line=23, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=126, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=128, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=130, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=132, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_FORWARD', opcode=110, arg=30, argval=196, argrepr='to 196', offset=134, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=136, starts_line=22, is_jump_target=True, positions=None),
+  Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=138, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=140, starts_line=25, is_jump_target=True, positions=None),
+  Instruction(opname='BEFORE_WITH', opcode=53, arg=None, argval=None, argrepr='', offset=142, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=144, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=146, starts_line=26, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=148, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=152, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=154, starts_line=25, is_jump_target=False, positions=None),
+  Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=158, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='JUMP_FORWARD', opcode=110, arg=9, argval=184, argrepr='to 184', offset=164, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='WITH_EXCEPT_START', opcode=49, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=88, argval=176, argrepr='to 176', offset=170, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='RERAISE', opcode=119, arg=2, argval=2, argrepr='', offset=172, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=True, positions=None),
+  Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=178, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=180, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=184, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=184, starts_line=28, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=186, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=188, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=192, starts_line=28, is_jump_target=True, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=194, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=196, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=198, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=200, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=204, starts_line=23, is_jump_target=True, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=206, starts_line=28, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=208, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=214, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=220, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=222, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=224, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=226, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=192, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=194, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=196, starts_line=23, is_jump_target=True, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=198, starts_line=28, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=200, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=204, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=206, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=212, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=214, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=220, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=222, starts_line=None, is_jump_target=False, positions=None),
 ]
 
 # One last piece of inspect fodder to check the default line number handling
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 41ac03b920e64..96075cf3b3473 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1340,7 +1340,7 @@ def bar(cls):
             check(bar, size('PP'))
         # generator
         def get_gen(): yield 1
-        check(get_gen(), size('P2PPP4P4c8P2iciP'))
+        check(get_gen(), size('P2P4P4c8P2iciP'))
         # iterator
         check(iter('abc'), size('lP'))
         # callable-iterator
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-12-15-15-17-04.bpo-45711.QK4QrB.rst b/Misc/NEWS.d/next/Core and Builtins/2021-12-15-15-17-04.bpo-45711.QK4QrB.rst
new file mode 100644
index 0000000000000..717f89ff0e279
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-12-15-15-17-04.bpo-45711.QK4QrB.rst	
@@ -0,0 +1 @@
+The interpreter state's representation of handled exceptions (a.k.a exc_info, or _PyErr_StackItem) now has only the ``exc_value`` field, ``exc_type`` and ``exc_traceback`` have been removed as their values can be derived from ``exc_value``.
\ No newline at end of file
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
index 267faacde8a17..978a1fdd0d852 100644
--- a/Modules/_asynciomodule.c
+++ b/Modules/_asynciomodule.c
@@ -810,9 +810,7 @@ FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg)
     Py_VISIT(fut->dict);
 
     _PyErr_StackItem *exc_state = &fut->fut_cancelled_exc_state;
-    Py_VISIT(exc_state->exc_type);
     Py_VISIT(exc_state->exc_value);
-    Py_VISIT(exc_state->exc_traceback);
 
     return 0;
 }
@@ -1376,10 +1374,6 @@ _asyncio_Future__make_cancelled_error_impl(FutureObj *self)
         PyException_SetContext(exc, Py_NewRef(exc_state->exc_value));
         _PyErr_ClearExcState(exc_state);
     }
-    else {
-        assert(exc_state->exc_type == NULL);
-        assert(exc_state->exc_traceback == NULL);
-    }
 
     return exc;
 }
@@ -2706,13 +2700,13 @@ task_step_impl(TaskObj *task, PyObject *exc)
             PyErr_NormalizeException(&et, &ev, &tb);
             if (tb != NULL) {
                 PyException_SetTraceback(ev, tb);
+                Py_DECREF(tb);
             }
+            Py_XDECREF(et);
 
             FutureObj *fut = (FutureObj*)task;
             _PyErr_StackItem *exc_state = &fut->fut_cancelled_exc_state;
-            exc_state->exc_type = et;
             exc_state->exc_value = ev;
-            exc_state->exc_traceback = tb;
 
             return future_cancel(fut, NULL);
         }
diff --git a/Objects/genobject.c b/Objects/genobject.c
index 24a4e94bfc7a2..d093f3dd7de30 100644
--- a/Objects/genobject.c
+++ b/Objects/genobject.c
@@ -25,9 +25,7 @@ static const char *ASYNC_GEN_IGNORED_EXIT_MSG =
 static inline int
 exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg)
 {
-    Py_VISIT(exc_state->exc_type);
     Py_VISIT(exc_state->exc_value);
-    Py_VISIT(exc_state->exc_traceback);
     return 0;
 }
 
@@ -886,9 +884,7 @@ make_gen(PyTypeObject *type, PyFunctionObject *func)
     gen->gi_code = (PyCodeObject *)func->func_code;
     Py_INCREF(gen->gi_code);
     gen->gi_weakreflist = NULL;
-    gen->gi_exc_state.exc_type = NULL;
     gen->gi_exc_state.exc_value = NULL;
-    gen->gi_exc_state.exc_traceback = NULL;
     gen->gi_exc_state.previous_item = NULL;
     if (func->func_name != NULL)
         gen->gi_name = func->func_name;
@@ -975,9 +971,7 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
     Py_INCREF(gen->gi_code);
     Py_DECREF(f);
     gen->gi_weakreflist = NULL;
-    gen->gi_exc_state.exc_type = NULL;
     gen->gi_exc_state.exc_value = NULL;
-    gen->gi_exc_state.exc_traceback = NULL;
     gen->gi_exc_state.previous_item = NULL;
     if (name != NULL)
         gen->gi_name = name;
diff --git a/Python/ceval.c b/Python/ceval.c
index 87d6a2288e0dd..bac57ccb7cc75 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1094,29 +1094,11 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type,
 static int do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause);
 static PyObject *do_reraise_star(PyObject *excs, PyObject *orig);
 static int exception_group_match(
-    PyObject *exc_type, PyObject* exc_value, PyObject *match_type,
+    PyObject* exc_value, PyObject *match_type,
     PyObject **match, PyObject **rest);
 
 static int unpack_iterable(PyThreadState *, PyObject *, int, int, PyObject **);
 
-#ifdef Py_DEBUG
-static void
-_assert_exception_type_is_redundant(PyObject* type, PyObject* val)
-{
-    if (type == NULL || type == Py_None) {
-        assert(val == type);
-    }
-    else {
-        assert(PyExceptionInstance_Check(val));
-        assert(PyExceptionInstance_Class(val) == type);
-    }
-}
-
-#define ASSERT_EXC_TYPE_IS_REDUNDANT(t, v) _assert_exception_type_is_redundant(t, v)
-#else
-#define ASSERT_EXC_TYPE_IS_REDUNDANT(t, v)
-#endif
-
 PyObject *
 PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
 {
@@ -2737,25 +2719,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
         }
 
         TARGET(POP_EXCEPT) {
-            PyObject *type, *value, *traceback;
-            _PyErr_StackItem *exc_info;
-            exc_info = tstate->exc_info;
-            type = exc_info->exc_type;
-            value = exc_info->exc_value;
-            traceback = exc_info->exc_traceback;
-
-            exc_info->exc_type = POP();
+            _PyErr_StackItem *exc_info = tstate->exc_info;
+            PyObject *value = exc_info->exc_value;
             exc_info->exc_value = POP();
-            exc_info->exc_traceback = POP();
-            ASSERT_EXC_TYPE_IS_REDUNDANT(exc_info->exc_type, exc_info->exc_value);
-            Py_XDECREF(type);
             Py_XDECREF(value);
-            Py_XDECREF(traceback);
             DISPATCH();
         }
 
         TARGET(POP_EXCEPT_AND_RERAISE) {
-            PyObject *lasti = PEEK(4);
+            PyObject *lasti = PEEK(2);
             if (PyLong_Check(lasti)) {
                 frame->f_lasti = PyLong_AsLong(lasti);
                 assert(!_PyErr_Occurred(tstate));
@@ -2764,31 +2736,24 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
                 _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int");
                 goto error;
             }
-            PyObject *type, *value, *traceback;
-            _PyErr_StackItem *exc_info;
-            type = POP();
-            value = POP();
-            traceback = POP();
-            ASSERT_EXC_TYPE_IS_REDUNDANT(type, value);
+            PyObject *value = POP();
+            assert(value);
+            assert(PyExceptionInstance_Check(value));
+            PyObject *type = Py_NewRef(PyExceptionInstance_Class(value));
+            PyObject *traceback = PyException_GetTraceback(value);
             Py_DECREF(POP()); /* lasti */
             _PyErr_Restore(tstate, type, value, traceback);
-            exc_info = tstate->exc_info;
-            type = exc_info->exc_type;
+
+            _PyErr_StackItem *exc_info = tstate->exc_info;
             value = exc_info->exc_value;
-            traceback = exc_info->exc_traceback;
-            exc_info->exc_type = POP();
             exc_info->exc_value = POP();
-            exc_info->exc_traceback = POP();
-            ASSERT_EXC_TYPE_IS_REDUNDANT(exc_info->exc_type, exc_info->exc_value);
-            Py_XDECREF(type);
             Py_XDECREF(value);
-            Py_XDECREF(traceback);
             goto exception_unwind;
         }
 
         TARGET(RERAISE) {
             if (oparg) {
-                PyObject *lasti = PEEK(oparg+3);
+                PyObject *lasti = PEEK(oparg + 1);
                 if (PyLong_Check(lasti)) {
                     frame->f_lasti = PyLong_AsLong(lasti);
                     assert(!_PyErr_Occurred(tstate));
@@ -2799,11 +2764,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
                     goto error;
                 }
             }
-            PyObject *exc = POP();
             PyObject *val = POP();
-            PyObject *tb = POP();
-            ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val);
-            assert(PyExceptionClass_Check(exc));
+            assert(val && PyExceptionInstance_Check(val));
+            PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val));
+            PyObject *tb = PyException_GetTraceback(val);
             _PyErr_Restore(tstate, exc, val, tb);
             goto exception_unwind;
         }
@@ -2823,35 +2787,21 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
             PyObject *lasti_unused = Py_NewRef(_PyLong_GetZero());
             PUSH(lasti_unused);
-            if (!Py_IsNone(val)) {
-                PyObject *tb = PyException_GetTraceback(val);
-                PUSH(tb ? tb : Py_NewRef(Py_None));
-                PUSH(val);
-                PUSH(Py_NewRef(Py_TYPE(val)));
-            }
-            else {
-                // nothing to reraise
-                PUSH(Py_NewRef(Py_None));
-                PUSH(val);
-                PUSH(Py_NewRef(Py_None));
-            }
+            PUSH(val);
             DISPATCH();
         }
 
         TARGET(END_ASYNC_FOR) {
-            PyObject *exc = POP();
             PyObject *val = POP();
-            PyObject *tb = POP();
-            ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val);
-            assert(PyExceptionClass_Check(exc));
-            if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) {
-                Py_DECREF(exc);
+            assert(val && PyExceptionInstance_Check(val));
+            if (PyErr_GivenExceptionMatches(val, PyExc_StopAsyncIteration)) {
                 Py_DECREF(val);
-                Py_DECREF(tb);
                 Py_DECREF(POP());
                 DISPATCH();
             }
             else {
+                PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val));
+                PyObject *tb = PyException_GetTraceback(val);
                 _PyErr_Restore(tstate, exc, val, tb);
                 goto exception_unwind;
             }
@@ -3971,16 +3921,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
         TARGET(JUMP_IF_NOT_EG_MATCH) {
             PyObject *match_type = POP();
-            PyObject *exc_type = TOP();
-            PyObject *exc_value = SECOND();
             if (check_except_star_type_valid(tstate, match_type) < 0) {
                 Py_DECREF(match_type);
                 goto error;
             }
 
+            PyObject *exc_value = TOP();
             PyObject *match = NULL, *rest = NULL;
-            int res = exception_group_match(exc_type, exc_value,
-                                            match_type, &match, &rest);
+            int res = exception_group_match(exc_value, match_type,
+                                            &match, &rest);
             Py_DECREF(match_type);
             if (res < 0) {
                 goto error;
@@ -4001,46 +3950,21 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             else {
 
                 /* Total or partial match - update the stack from
-                 * [tb, val, exc]
+                 * [val]
                  * to
-                 * [tb, rest, exc, tb, match, exc]
+                 * [rest, match]
                  * (rest can be Py_None)
                  */
 
+                PyObject *exc = TOP();
 
-                PyObject *type = TOP();
-                PyObject *val = SECOND();
-                PyObject *tb = THIRD();
-
-                if (!Py_IsNone(rest)) {
-                    /* tb remains the same */
-                    SET_TOP(Py_NewRef(Py_TYPE(rest)));
-                    SET_SECOND(Py_NewRef(rest));
-                    SET_THIRD(Py_NewRef(tb));
-                }
-                else {
-                    SET_TOP(Py_NewRef(Py_None));
-                    SET_SECOND(Py_NewRef(Py_None));
-                    SET_THIRD(Py_NewRef(Py_None));
-                }
-                /* Push match */
+                SET_TOP(rest);
+                PUSH(match);
 
-                PUSH(Py_NewRef(tb));
-                PUSH(Py_NewRef(match));
-                PUSH(Py_NewRef(Py_TYPE(match)));
+                PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL);
 
-                // set exc_info to the current match
-                PyErr_SetExcInfo(
-                    Py_NewRef(Py_TYPE(match)),
-                    Py_NewRef(match),
-                    Py_NewRef(tb));
-
-                Py_DECREF(tb);
-                Py_DECREF(val);
-                Py_DECREF(type);
+                Py_DECREF(exc);
 
-                Py_DECREF(match);
-                Py_DECREF(rest);
             }
 
             DISPATCH();
@@ -4048,8 +3972,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
         TARGET(JUMP_IF_NOT_EXC_MATCH) {
             PyObject *right = POP();
-            ASSERT_EXC_TYPE_IS_REDUNDANT(TOP(), SECOND());
-            PyObject *left = SECOND();
+            PyObject *left = TOP();
             assert(PyExceptionInstance_Check(left));
             if (check_except_type_valid(tstate, right) < 0) {
                  Py_DECREF(right);
@@ -4465,26 +4388,24 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
         }
 
         TARGET(WITH_EXCEPT_START) {
-            /* At the top of the stack are 8 values:
-               - (TOP, SECOND, THIRD) = exc_info()
-               - (FOURTH, FIFTH, SIXTH) = previous exception
-               - SEVENTH: lasti of exception in exc_info()
-               - EIGHTH: the context.__exit__ bound method
-               We call EIGHTH(TOP, SECOND, THIRD).
-               Then we push again the TOP exception and the __exit__
-               return value.
+            /* At the top of the stack are 4 values:
+               - TOP = exc_info()
+               - SECOND = previous exception
+               - THIRD: lasti of exception in exc_info()
+               - FOURTH: the context.__exit__ bound method
+               We call FOURTH(type(TOP), TOP, GetTraceback(TOP)).
+               Then we push the __exit__ return value.
             */
             PyObject *exit_func;
             PyObject *exc, *val, *tb, *res;
 
-            exc = TOP();
-            val = SECOND();
-            tb = THIRD();
-            ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val);
-            assert(!Py_IsNone(exc));
-            assert(!PyLong_Check(exc));
-            assert(PyLong_Check(PEEK(7)));
-            exit_func = PEEK(8);
+            val = TOP();
+            assert(val && PyExceptionInstance_Check(val));
+            exc = PyExceptionInstance_Class(val);
+            tb = PyException_GetTraceback(val);
+            Py_XDECREF(tb);
+            assert(PyLong_Check(PEEK(3)));
+            exit_func = PEEK(4);
             PyObject *stack[4] = {NULL, exc, val, tb};
             res = PyObject_Vectorcall(exit_func, stack + 1,
                     3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
@@ -4496,40 +4417,22 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
         }
 
         TARGET(PUSH_EXC_INFO) {
-            PyObject *type = TOP();
-            PyObject *value = SECOND();
-            PyObject *tb = THIRD();
-            ASSERT_EXC_TYPE_IS_REDUNDANT(type, value);
+            PyObject *value = TOP();
+
             _PyErr_StackItem *exc_info = tstate->exc_info;
-            SET_THIRD(exc_info->exc_traceback);
             if (exc_info->exc_value != NULL) {
-                SET_SECOND(exc_info->exc_value);
-            }
-            else {
-                Py_INCREF(Py_None);
-                SET_SECOND(Py_None);
-            }
-            if (exc_info->exc_type != NULL) {
-                SET_TOP(exc_info->exc_type);
+                SET_TOP(exc_info->exc_value);
             }
             else {
                 Py_INCREF(Py_None);
                 SET_TOP(Py_None);
             }
-            Py_INCREF(tb);
-            PUSH(tb);
-            exc_info->exc_traceback = tb;
 
             Py_INCREF(value);
             PUSH(value);
             assert(PyExceptionInstance_Check(value));
             exc_info->exc_value = value;
 
-            Py_INCREF(type);
-            PUSH(type);
-            assert(PyExceptionClass_Check(type));
-            exc_info->exc_type = type;
-
             DISPATCH();
         }
 
@@ -5518,14 +5421,9 @@ MISS_WITH_OPARG_COUNTER(STORE_SUBSCR)
             PyException_SetTraceback(val, tb);
         else
             PyException_SetTraceback(val, Py_None);
-        if (tb == NULL) {
-            tb = Py_None;
-            Py_INCREF(Py_None);
-        }
-        PUSH(tb);
+        Py_XDECREF(tb);
+        Py_XDECREF(exc);
         PUSH(val);
-        PUSH(exc);
-        ASSERT_EXC_TYPE_IS_REDUNDANT(exc, val);
         JUMPTO(handler);
         /* Resume normal execution */
         frame->f_state = FRAME_EXECUTING;
@@ -6375,19 +6273,17 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause)
 */
 
 static int
-exception_group_match(PyObject *exc_type, PyObject* exc_value,
-                      PyObject *match_type, PyObject **match, PyObject **rest)
+exception_group_match(PyObject* exc_value, PyObject *match_type,
+                      PyObject **match, PyObject **rest)
 {
-    if (Py_IsNone(exc_type)) {
-        assert(Py_IsNone(exc_value));
+    if (Py_IsNone(exc_value)) {
         *match = Py_NewRef(Py_None);
         *rest = Py_NewRef(Py_None);
         return 0;
     }
-    assert(PyExceptionClass_Check(exc_type));
     assert(PyExceptionInstance_Check(exc_value));
 
-    if (PyErr_GivenExceptionMatches(exc_type, match_type)) {
+    if (PyErr_GivenExceptionMatches(exc_value, match_type)) {
         /* Full match of exc itself */
         bool is_eg = _PyBaseExceptionGroup_Check(exc_value);
         if (is_eg) {
diff --git a/Python/compile.c b/Python/compile.c
index 6179ad980aade..8e90b1ab37037 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1048,9 +1048,9 @@ stack_effect(int opcode, int oparg, int jump)
         case POP_BLOCK:
             return 0;
         case POP_EXCEPT:
-            return -3;
+            return -1;
         case POP_EXCEPT_AND_RERAISE:
-            return -7;
+            return -3;
 
         case STORE_NAME:
             return -1;
@@ -1095,7 +1095,7 @@ stack_effect(int opcode, int oparg, int jump)
         case JUMP_IF_NOT_EXC_MATCH:
             return -1;
         case JUMP_IF_NOT_EG_MATCH:
-            return jump > 0 ? -1 : 2;
+            return jump > 0 ? -1 : 0;
         case IMPORT_NAME:
             return -1;
         case IMPORT_FROM:
@@ -1120,25 +1120,25 @@ stack_effect(int opcode, int oparg, int jump)
         /* Exception handling pseudo-instructions */
         case SETUP_FINALLY:
             /* 0 in the normal flow.
-             * Restore the stack position and push 3 values before jumping to
+             * Restore the stack position and push 1 value before jumping to
              * the handler if an exception be raised. */
-            return jump ? 3 : 0;
+            return jump ? 1 : 0;
         case SETUP_CLEANUP:
             /* As SETUP_FINALLY, but pushes lasti as well */
-            return jump ? 4 : 0;
+            return jump ? 2 : 0;
         case SETUP_WITH:
             /* 0 in the normal flow.
              * Restore the stack position to the position before the result
-             * of __(a)enter__ and push 4 values before jumping to the handler
+             * of __(a)enter__ and push 2 values before jumping to the handler
              * if an exception be raised. */
-            return jump ? -1 + 4 : 0;
+            return jump ? 1 : 0;
 
         case PREP_RERAISE_STAR:
-             return 2;
+             return 0;
         case RERAISE:
-            return -3;
+            return -1;
         case PUSH_EXC_INFO:
-            return 3;
+            return 1;
 
         case WITH_EXCEPT_START:
             return 1;
@@ -1199,7 +1199,7 @@ stack_effect(int opcode, int oparg, int jump)
         case GET_YIELD_FROM_ITER:
             return 0;
         case END_ASYNC_FOR:
-            return -4;
+            return -2;
         case FORMAT_VALUE:
             /* If there's a fmt_spec on the stack, we go from 2->1,
                else 1->1. */
@@ -1888,13 +1888,11 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
 
         case FINALLY_END:
             if (preserve_tos) {
-                ADDOP(c, ROT_FOUR);
+                ADDOP(c, ROT_TWO);
             }
-            ADDOP(c, POP_TOP);
-            ADDOP(c, POP_TOP);
-            ADDOP(c, POP_TOP);
+            ADDOP(c, POP_TOP); /* exc_value */
             if (preserve_tos) {
-                ADDOP(c, ROT_FOUR);
+                ADDOP(c, ROT_TWO);
             }
             ADDOP(c, POP_BLOCK);
             ADDOP(c, POP_EXCEPT);
@@ -1927,7 +1925,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info,
                 ADDOP(c, POP_BLOCK);
             }
             if (preserve_tos) {
-                ADDOP(c, ROT_FOUR);
+                ADDOP(c, ROT_TWO);
             }
             ADDOP(c, POP_BLOCK);
             ADDOP(c, POP_EXCEPT);
@@ -3310,18 +3308,16 @@ compiler_try_star_finally(struct compiler *c, stmt_ty s)
    []                           POP_BLOCK
    []                           JUMP_FORWARD    L0
 
-   [tb, val, exc]       L1:     <evaluate E1>                   )
-   [tb, val, exc, E1]           JUMP_IF_NOT_EXC_MATCH L2        ) only if E1
-   [tb, val, exc]               POP
-   [tb, val]                    <assign to V1>  (or POP if no V1)
-   [tb]                         POP
+   [exc]                L1:     <evaluate E1>           )
+   [exc, E1]                    JUMP_IF_NOT_EXC_MATCH L2        ) only if E1
+   [exc]                        <assign to V1>  (or POP if no V1)
    []                           <code for S1>
                                 JUMP_FORWARD    L0
 
-   [tb, val, exc]       L2:     <evaluate E2>
+   [exc]                L2:     <evaluate E2>
    .............................etc.......................
 
-   [tb, val, exc]       Ln+1:   RERAISE     # re-raise exception
+   [exc]                Ln+1:   RERAISE     # re-raise exception
 
    []                   L0:     <next statement>
 
@@ -3372,7 +3368,6 @@ compiler_try_except(struct compiler *c, stmt_ty s)
             ADDOP_JUMP(c, JUMP_IF_NOT_EXC_MATCH, except);
             NEXT_BLOCK(c);
         }
-        ADDOP(c, POP_TOP);
         if (handler->v.ExceptHandler.name) {
             basicblock *cleanup_end, *cleanup_body;
 
@@ -3383,7 +3378,6 @@ compiler_try_except(struct compiler *c, stmt_ty s)
             }
 
             compiler_nameop(c, handler->v.ExceptHandler.name, Store);
-            ADDOP(c, POP_TOP);
 
             /*
               try:
@@ -3434,8 +3428,7 @@ compiler_try_except(struct compiler *c, stmt_ty s)
             if (!cleanup_body)
                 return 0;
 
-            ADDOP(c, POP_TOP);
-            ADDOP(c, POP_TOP);
+            ADDOP(c, POP_TOP); /* exc_value */
             compiler_use_next_block(c, cleanup_body);
             if (!compiler_push_fblock(c, HANDLER_CLEANUP, cleanup_body, NULL, NULL))
                 return 0;
@@ -3467,52 +3460,42 @@ compiler_try_except(struct compiler *c, stmt_ty s)
    at the right; 'tb' is trace-back info, 'val' the exception instance,
    and 'typ' the exception's type.)
 
-   Value stack                             Label         Instruction     Argument
-   []                                                   SETUP_FINALLY         L1
-   []                                                   <code for S>
-   []                                                   POP_BLOCK
-   []                                                   JUMP_FORWARD          L0
+   Value stack                   Label         Instruction     Argument
+   []                                         SETUP_FINALLY         L1
+   []                                         <code for S>
+   []                                         POP_BLOCK
+   []                                         JUMP_FORWARD          L0
 
-   [tb, val, typ]                            L1:        DUP_TOP_TWO               )  save a copy of the
-   [tb, val, typ, orig, typ]                            POP_TOP                   )  original raised exception
-   [tb, val, typ, orig]                                 ROT_FOUR                  )
-   [orig, tb, val, typ]                                 BUILD_LIST                )  list for raised/reraised
-   [orig, tb, val, typ, res]                            ROT_FOUR                  )  exceptions ("result")
+   [exc]                            L1:       DUP_TOP      )  save copy of the original exception
+   [orig, exc]                                BUILD_LIST   )  list for raised/reraised excs ("result")
+   [orig, exc, res]                           ROT_TWO
 
-   [orig, res, tb, val, typ]                            <evaluate E1>             )
-   [orig, res, tb, val, typ, E1]                        JUMP_IF_NOT_EXC_MATCH L2  ) only if E1
+   [orig, res, exc]                           <evaluate E1>
+   [orig, res, exc, E1]                       JUMP_IF_NOT_EG_MATCH L2
 
-   [orig, res, tb, rest, typ, tb, match, typ]           POP
-   [orig, res, tb, rest, typ, tb, match]                <assign to V1>  (or POP if no V1)
-   [orig, res, tb, rest, typ, tb]                       POP
+   [orig, res, rest, match]                   <assign to V1>  (or POP if no V1)
 
-   [orig, res, tb, rest, typ]                           SETUP_FINALLY         R1
-   [orig, res, tb, rest, typ]                           <code for S1>
-   [orig, res, tb, rest, typ]                           JUMP_FORWARD          L2
+   [orig, res, rest]                          SETUP_FINALLY         R1
+   [orig, res, rest]                          <code for S1>
+   [orig, res, rest]                          JUMP_FORWARD          L2
 
-   [orig, res, tb, rest, typ, i, tb, v, t]   R1:        POP           ) exception raised in except* body
-   [orig, res, tb, rest, typ, i, tb, v]                 LIST_APPEND 6 ) add it to res
-   [orig, res, tb, rest, typ, i, tb]                    POP
-   [orig, res, tb, rest, typ, i]                        POP
+   [orig, res, rest, i, v]          R1:       LIST_APPEND   3 ) exc raised in except* body - add to res
+   [orig, res, rest, i]                       POP
 
-   [orig, res, tb, rest, typ]                L2:        <evaluate E2>
+   [orig, res, rest]                L2:       <evaluate E2>
    .............................etc.......................
 
-   [orig, res, tb, rest, typ]                Ln+1:       POP           ) add unhandled exception
-   [orig, res, tb, rest]                                 LIST_APPEND 2 ) to res (could be None)
-   [orig, res, tb]                                       POP
+   [orig, res, rest]                Ln+1:     LIST_APPEND 1  ) add unhandled exc to res (could be None)
 
-   [orig, res]                                           PREP_RERAISE_STAR
-   [i, tb, val, typ]                                     POP_JUMP_IF_TRUE      RER
-   [i, tb, val, typ]                                     POP
-   [i, tb, val]                                          POP
-   [i, tb]                                               POP
-   [i]                                                   POP
-   []                                                    JUMP_FORWARD          L0
+   [orig, res]                                PREP_RERAISE_STAR
+   [i, exc]                                   POP_JUMP_IF_TRUE      RER
+   [i, exc]                                   POP
+   [i]                                        POP
+   []                                         JUMP_FORWARD          L0
 
-   [i, tb, val, typ]                        RER:         POP_EXCEPT_AND_RERAISE
+   [i, exc]                         RER:      POP_EXCEPT_AND_RERAISE
 
-   []                                       L0:     <next statement>
+   []                               L0:       <next statement>
 */
 static int
 compiler_try_star_except(struct compiler *c, stmt_ty s)
@@ -3573,30 +3556,25 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
         if (i == 0) {
             /* Push the original EG into the stack */
             /*
-               [tb, val, exc]            DUP_TOP_TWO
-               [tb, val, exc, val, exc]  POP_TOP
-               [tb, val, exc, val]       ROT_FOUR
-               [val, tb, val, exc]
+               [exc]            DUP_TOP
+               [orig, exc]
             */
-            ADDOP(c, DUP_TOP_TWO);
-            ADDOP(c, POP_TOP);
-            ADDOP(c, ROT_FOUR);
+            ADDOP(c, DUP_TOP);
 
             /* create empty list for exceptions raised/reraise in the except* blocks */
             /*
-               [val, tb, val, exc]       BUILD_LIST
-               [val, tb, val, exc, []]   ROT_FOUR
-               [val, [], tb, val, exc]
+               [orig, exc]       BUILD_LIST
+               [orig, exc, []]   ROT_TWO
+               [orig, [], exc]
             */
             ADDOP_I(c, BUILD_LIST, 0);
-            ADDOP(c, ROT_FOUR);
+            ADDOP(c, ROT_TWO);
         }
         if (handler->v.ExceptHandler.type) {
             VISIT(c, expr, handler->v.ExceptHandler.type);
             ADDOP_JUMP(c, JUMP_IF_NOT_EG_MATCH, except);
             NEXT_BLOCK(c);
         }
-        ADDOP(c, POP_TOP);  // exc_type
 
         basicblock *cleanup_end = compiler_new_block(c);
         if (cleanup_end == NULL) {
@@ -3611,9 +3589,8 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
             compiler_nameop(c, handler->v.ExceptHandler.name, Store);
         }
         else {
-            ADDOP(c, POP_TOP);  // val
+            ADDOP(c, POP_TOP);  // exc
         }
-        ADDOP(c, POP_TOP);  // tb
 
         /*
           try:
@@ -3657,9 +3634,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
         }
 
         /* add exception raised to the res list */
-        ADDOP(c, POP_TOP); // type
-        ADDOP_I(c, LIST_APPEND, 6); // exc
-        ADDOP(c, POP_TOP); // tb
+        ADDOP_I(c, LIST_APPEND, 3); // exc
         ADDOP(c, POP_TOP); // lasti
 
         ADDOP_JUMP(c, JUMP_ABSOLUTE, except);
@@ -3667,9 +3642,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
 
         if (i == n - 1) {
             /* Add exc to the list (if not None it's the unhandled part of the EG) */
-            ADDOP(c, POP_TOP);
-            ADDOP_I(c, LIST_APPEND, 2);
-            ADDOP(c, POP_TOP);
+            ADDOP_I(c, LIST_APPEND, 1);
             ADDOP_JUMP(c, JUMP_FORWARD, reraise_star);
         }
     }
@@ -3690,8 +3663,6 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
     /* Nothing to reraise - pop it */
     ADDOP(c, POP_TOP);
     ADDOP(c, POP_TOP);
-    ADDOP(c, POP_TOP);
-    ADDOP(c, POP_TOP);
     ADDOP(c, POP_BLOCK);
     ADDOP(c, POP_EXCEPT);
     ADDOP_JUMP(c, JUMP_FORWARD, end);
@@ -5449,13 +5420,11 @@ compiler_with_except_finish(struct compiler *c, basicblock * cleanup) {
         return 0;
     ADDOP_JUMP(c, POP_JUMP_IF_TRUE, exit);
     NEXT_BLOCK(c);
-    ADDOP_I(c, RERAISE, 4);
+    ADDOP_I(c, RERAISE, 2);
     compiler_use_next_block(c, cleanup);
     ADDOP(c, POP_EXCEPT_AND_RERAISE);
     compiler_use_next_block(c, exit);
-    ADDOP(c, POP_TOP);
-    ADDOP(c, POP_TOP);
-    ADDOP(c, POP_TOP);
+    ADDOP(c, POP_TOP); /* exc_value */
     ADDOP(c, POP_BLOCK);
     ADDOP(c, POP_EXCEPT);
     ADDOP(c, POP_TOP);
@@ -5587,7 +5556,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
     E:  WITH_EXCEPT_START (calls EXPR.__exit__)
         POP_JUMP_IF_TRUE T:
         RERAISE
-    T:  POP_TOP * 3 (remove exception from stack)
+    T:  POP_TOP (remove exception from stack)
         POP_EXCEPT
         POP_TOP
     EXIT:
@@ -7368,7 +7337,10 @@ assemble_emit_exception_table_entry(struct assembler *a, int start, int end, bas
     int size = end-start;
     assert(end > start);
     int target = handler->b_offset;
-    int depth = handler->b_preserve_lasti ? handler->b_startdepth-4 : handler->b_startdepth-3;
+    int depth = handler->b_startdepth - 1;
+    if (handler->b_preserve_lasti) {
+        depth -= 1;
+    }
     assert(depth >= 0);
     int depth_lasti = (depth<<1) | handler->b_preserve_lasti;
     assemble_emit_exception_table_item(a, start, (1<<7));
diff --git a/Python/errors.c b/Python/errors.c
index 5be15e54db25b..6c5fe41142304 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -84,11 +84,8 @@ _PyErr_GetTopmostException(PyThreadState *tstate)
     while ((exc_info->exc_value == NULL || exc_info->exc_value == Py_None) &&
            exc_info->previous_item != NULL)
     {
-        assert(exc_info->exc_type == NULL || exc_info->exc_type == Py_None);
         exc_info = exc_info->previous_item;
     }
-    assert(exc_info->previous_item == NULL ||
-           (exc_info->exc_type != NULL && exc_info->exc_type != Py_None));
     return exc_info;
 }
 
@@ -524,27 +521,17 @@ PyErr_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback)
 void
 PyErr_SetExcInfo(PyObject *type, PyObject *value, PyObject *traceback)
 {
-    PyObject *oldtype, *oldvalue, *oldtraceback;
     PyThreadState *tstate = _PyThreadState_GET();
 
-    oldtype = tstate->exc_info->exc_type;
-    oldvalue = tstate->exc_info->exc_value;
-    oldtraceback = tstate->exc_info->exc_traceback;
-
+    PyObject *oldvalue = tstate->exc_info->exc_value;
 
-    tstate->exc_info->exc_type = get_exc_type(value);
-    Py_XINCREF(tstate->exc_info->exc_type);
     tstate->exc_info->exc_value = value;
-    tstate->exc_info->exc_traceback = get_exc_traceback(value);
-    Py_XINCREF(tstate->exc_info->exc_traceback);
 
     /* These args are no longer used, but we still need to steal a ref */
     Py_XDECREF(type);
     Py_XDECREF(traceback);
 
-    Py_XDECREF(oldtype);
     Py_XDECREF(oldvalue);
-    Py_XDECREF(oldtraceback);
 }
 
 
@@ -629,9 +616,6 @@ _PyErr_ChainStackItem(_PyErr_StackItem *exc_info)
         exc_info_given = 1;
     }
 
-    assert( (exc_info->exc_type == NULL || exc_info->exc_type == Py_None) ==
-            (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) );
-
     if (exc_info->exc_value == NULL || exc_info->exc_value == Py_None) {
         return;
     }
diff --git a/Python/pystate.c b/Python/pystate.c
index 463b248f22336..0301ce676950b 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1028,9 +1028,7 @@ PyThreadState_Clear(PyThreadState *tstate)
     Py_CLEAR(tstate->curexc_value);
     Py_CLEAR(tstate->curexc_traceback);
 
-    Py_CLEAR(tstate->exc_state.exc_type);
     Py_CLEAR(tstate->exc_state.exc_value);
-    Py_CLEAR(tstate->exc_state.exc_traceback);
 
     /* The stack of exception states should contain just this thread. */
     if (verbose && tstate->exc_info != &tstate->exc_state) {



More information about the Python-checkins mailing list