savannahostrowski · GitHub

The main branch's JIT doesn't seem to want to compile the example due to trace stack underflow. So I reduced the side exit count on my tracing JIT example and tried. Seems like LLVM 21 doesn't fix the problem :(

PYTHON_JIT=0
-----------
Testing various unwinding methods on the same deep call stack...
[GNU backtrace]
Total frames: 27
Showing first 10 frames:
  # 0  /home/ken/Documents/GitHub/cpython-unwind/stackunwind.cpython-315-x86_64-linux-gnu.so(+0x280a) [0x78674f7a580a]
  # 1  ../cpython/python(PyObject_Vectorcall+0x33) [0x58c0e08d2303]
  # 2  ../cpython/python(_PyEval_EvalFrameDefault+0xf7a1) [0x58c0e086b141]
  # 3  ../cpython/python(+0x2860aa) [0x58c0e0a430aa]
  # 4  ../cpython/python(PyObject_Vectorcall+0x33) [0x58c0e08d2303]
  # 5  ../cpython/python(_PyEval_EvalFrameDefault+0x3fb3) [0x58c0e085f953]
  # 6  ../cpython/python(+0x2860aa) [0x58c0e0a430aa]
  # 7  ../cpython/python(PyObject_Vectorcall+0x33) [0x58c0e08d2303]
  # 8  ../cpython/python(_PyEval_EvalFrameDefault+0x3fb3) [0x58c0e085f953]
  # 9  ../cpython/python(+0x2860aa) [0x58c0e0a430aa]
  ... (17 more frames)
[libunwind]
Total frames: 26
Showing first 10 frames:
  # 0  PyObject_Vectorcall+0x33
  # 1  _PyEval_EvalFrameDefault+0xf7a1
  # 2  _PyEval_Vector+0x21a
  # 3  PyObject_Vectorcall+0x33
  # 4  _PyEval_EvalFrameDefault+0x3fb3
  # 5  _PyEval_Vector+0x21a
  # 6  PyObject_Vectorcall+0x33
  # 7  _PyEval_EvalFrameDefault+0x3fb3
  # 8  _PyEval_Vector+0x21a
  # 9  PyObject_Vectorcall+0x33
  ... (16 more frames)
[libdw (DWARF)]
Total frames: 26
Showing first 10 frames:
  # 0  PyObject_Vectorcall
  # 1  _PyEval_EvalFrameDefault
  # 2  _PyEval_Vector
  # 3  PyObject_Vectorcall
  # 4  _PyEval_EvalFrameDefault
  # 5  _PyEval_Vector
  # 6  PyObject_Vectorcall
  # 7  _PyEval_EvalFrameDefault
  # 8  _PyEval_Vector
  # 9  PyObject_Vectorcall
  ... (16 more frames)
[Manual frame pointers]
Total frames: 4
Showing first 4 frames:
  # 0  0x58c0e08d2303
  # 1  0x2
  # 2  0x58c0e0dbb7e0
  # 3  0x2
PYTHON_JIT=1
------------
[GNU backtrace]
Total frames: 6
Showing first 6 frames:
  # 0  /home/ken/Documents/GitHub/cpython-unwind/stackunwind.cpython-315-x86_64-linux-gnu.so(+0x280a) [0x7a0a357d080a]
  # 1  ../cpython/python(PyObject_Vectorcall+0x33) [0x57385e3d3303]
  # 2  ../cpython/python(_PyEval_EvalFrameDefault+0xf7a1) [0x57385e36c141]
  # 3  ../cpython/python(+0x2860aa) [0x57385e5440aa]
  # 4  ../cpython/python(PyObject_Vectorcall+0x33) [0x57385e3d3303]
  # 5  [0x7a0a3398d4fb]
[libunwind]
Total frames: 5
Showing first 5 frames:
  # 0  PyObject_Vectorcall+0x33
  # 1  _PyEval_EvalFrameDefault+0xf7a1
  # 2  _PyEval_Vector+0x21a
  # 3  PyObject_Vectorcall+0x33
  # 4  <unknown>
[libdw (DWARF)]
Total frames: 5
Showing first 5 frames:
  # 0  PyObject_Vectorcall
  # 1  _PyEval_EvalFrameDefault
  # 2  _PyEval_Vector
  # 3  PyObject_Vectorcall
  # 4  <unknown>
[Manual frame pointers]
Total frames: 4
Showing first 4 frames:
  # 0  0x57385e3d3303
  # 1  0x(nil)
  # 2  0x57385e8bc7e0
  # 3  0x(nil)

Notice the missing frames!

However, I have made a very interesting discovery --- compiling the interpreter with a recent enough clang version (tested with clang-20/21) to the JIT restores the frames!!!

[GNU backtrace]
Total frames: 29
Showing first 10 frames:
  # 0  /home/ken/Documents/GitHub/cpython-unwind/stackunwind.cpython-315-x86_64-linux-gnu.so(+0x280a) [0x797cf3f7c80a]
  # 1  ../cpython/python(PyObject_Vectorcall+0x43) [0x64be6334e693]
  # 2  ../cpython/python(_PyEval_EvalFrameDefault+0x5d3e) [0x64be6347f63e]
  # 3  ../cpython/python(+0x217706) [0x64be63479706]
  # 4  ../cpython/python(PyObject_Vectorcall+0x43) [0x64be6334e693]
  # 5  ../cpython/python(_PyEval_EvalFrameDefault+0x3768) [0x64be6347d068]
  # 6  ../cpython/python(+0x217706) [0x64be63479706]
  # 7  ../cpython/python(PyObject_Vectorcall+0x43) [0x64be6334e693]
  # 8  ../cpython/python(_PyEval_EvalFrameDefault+0x3768) [0x64be6347d068]
  # 9  ../cpython/python(+0x217706) [0x64be63479706]
  ... (19 more frames)
[libunwind]
Total frames: 28
Showing first 10 frames:
  # 0  PyObject_Vectorcall+0x43
  # 1  _PyEval_EvalFrameDefault+0x5d3e
  # 2  _PyEval_Vector+0x266
  # 3  PyObject_Vectorcall+0x43
  # 4  _PyEval_EvalFrameDefault+0x3768
  # 5  _PyEval_Vector+0x266
  # 6  PyObject_Vectorcall+0x43
  # 7  _PyEval_EvalFrameDefault+0x3768
  # 8  _PyEval_Vector+0x266
  # 9  PyObject_Vectorcall+0x43
  ... (18 more frames)
[libdw (DWARF)]
Total frames: 28
Showing first 10 frames:
  # 0  PyObject_Vectorcall
  # 1  _PyEval_EvalFrameDefault
  # 2  _PyEval_Vector
  # 3  PyObject_Vectorcall
  # 4  _PyEval_EvalFrameDefault
  # 5  _PyEval_Vector
  # 6  PyObject_Vectorcall
  # 7  _PyEval_EvalFrameDefault
  # 8  _PyEval_Vector
  # 9  PyObject_Vectorcall
  ... (18 more frames)
[Manual frame pointers]
Total frames: 16
Showing first 10 frames:
  # 0  0x64be6334e693
  # 1  0x2
  # 2  0x64be63479706
  # 3  0x2
  # 4  0x64be63479706
  # 5  0x2
  # 6  0x64be63479706
  # 7  0x(nil)
  # 8  0x64be63479706
  # 9  0x(nil)
  ... (6 more frames)

So the solution to the stack unwinding seems to be to mandate compiilng CPython with the same clang as the JIT!

Read the original on github.com ↗