|
| 1 | + |
1 | 2 | Description of exception handling
|
2 | 3 | ---------------------------------
|
3 | 4 |
|
@@ -67,14 +68,18 @@ handler located at label `L1`.
|
67 | 68 | Handling Exceptions
|
68 | 69 | -------------------
|
69 | 70 |
|
70 |
| -At runtime, when an exception occurs, the interpreter looks up |
71 |
| -the offset of the current instruction in the exception table. If |
72 |
| -it finds a handler, control flow transfers to it. Otherwise, the |
| 71 | +At runtime, when an exception occurs, the interpreter calls |
| 72 | +``get_exception_handler()`` in |
| 73 | +[Python/ceval.c](https://github.com/python/cpython/blob/main/Python/ceval.c) |
| 74 | +to look up the offset of the current instruction in the exception |
| 75 | +table. If it finds a handler, control flow transfers to it. Otherwise, the |
73 | 76 | exception bubbles up to the caller, and the caller's frame is
|
74 | 77 | checked for a handler covering the `CALL` instruction. This
|
75 | 78 | repeats until a handler is found or the topmost frame is reached.
|
76 | 79 | If no handler is found, the program terminates. During unwinding,
|
77 |
| -the traceback is constructed as each frame is added to it. |
| 80 | +the traceback is constructed as each frame is added to it by |
| 81 | +``PyTraceBack_Here()``, which is in |
| 82 | +[Python/traceback.c](https://github.com/python/cpython/blob/main/Python/traceback.c). |
78 | 83 |
|
79 | 84 | Along with the location of an exception handler, each entry of the
|
80 | 85 | exception table also contains the stack depth of the `try` instruction
|
@@ -169,33 +174,12 @@ which is then encoded as:
|
169 | 174 |
|
170 | 175 | for a total of five bytes.
|
171 | 176 |
|
| 177 | +The code to construct the exception table is in ``assemble_exception_table()`` |
| 178 | +in [Python/assemble.c](https://github.com/python/cpython/blob/main/Python/assemble.c). |
172 | 179 |
|
173 |
| -Script to parse the exception table |
174 |
| ------------------------------------ |
175 |
| - |
176 |
| -``` |
177 |
| -def parse_varint(iterator): |
178 |
| - b = next(iterator) |
179 |
| - val = b & 63 |
180 |
| - while b&64: |
181 |
| - val <<= 6 |
182 |
| - b = next(iterator) |
183 |
| - val |= b&63 |
184 |
| - return val |
185 |
| -``` |
186 |
| -``` |
187 |
| -def parse_exception_table(code): |
188 |
| - iterator = iter(code.co_exceptiontable) |
189 |
| - try: |
190 |
| - while True: |
191 |
| - start = parse_varint(iterator)*2 |
192 |
| - length = parse_varint(iterator)*2 |
193 |
| - end = start + length - 2 # Present as inclusive, not exclusive |
194 |
| - target = parse_varint(iterator)*2 |
195 |
| - dl = parse_varint(iterator) |
196 |
| - depth = dl >> 1 |
197 |
| - lasti = bool(dl&1) |
198 |
| - yield start, end, target, depth, lasti |
199 |
| - except StopIteration: |
200 |
| - return |
201 |
| -``` |
| 180 | +The interpreter's function to lookup the table by instruction offset is |
| 181 | +``get_exception_handler()`` in |
| 182 | +[Python/ceval.c](https://github.com/python/cpython/blob/main/Python/ceval.c). |
| 183 | +The Python function ``_parse_exception_table()`` in |
| 184 | +[Lib/dis.py](https://github.com/python/cpython/blob/main/Lib/dis.py) |
| 185 | +returns the exception table content as a list of namedtuple instances. |
0 commit comments