pickling of frames without a tasklet #62

Description
Originally reported by: Anselm Kruis (Bitbucket: akruis, GitHub: akruis)
Hi,
now that #61 is resolved, I can look after another long standing problem. If Stackless pickles a frame, it does not save or restore the f_back attribute. This is not a problem, if the frame is part of a taklet, because tasklet.setstate() sets f_back. But in every other case, current behaviour violates the premise that the unpickled object has the same internal structure as the original object.
Use Cases
trace backs
The most prominent use case for pickling frames (besides tasklets) are trace-backs. I assume that the internal structure of a trace-back is well known.
If you pickle/unpickle a trace back, the missing f_back has two consequences:
- A (post mortem) debugger can't analyse/display the trace-back. This could be fixed by setting the frame.f_back attributes in tb_setstate().
- The frame objects above the frame, where the exception was caught, are not available.
pyheapdump
pyheapdump is a library to support post mortem debugging using a dump file. It works similar to the well known UNIX core dumps, but the format of the pyheapdump files is based on pickle. pyheapdump uses an extended pickler (sPickle). For vanilla C-Python a frame gets (un)pickled as a fake-frame that has the same attributes as a frame but is really a plain Python object.
But for Stackless I have a problem. If I pickle frame-objects as a fake frame, I break (un)pickling of tasklets. And if I don't change the pickling of frames, trace-backs a broken.
How to fix this probelm
Obviously a fix needs to meet a few conditions:
- It must not break anything, especially a pickle created by a current version of Stackless must stay readable and vice versa.
- We must add the f_back frame to the state-part of the result of frameobject_reduce()
For a long time I thought that it would be impossible to meet both conditions. Only recently I discovered a possibility to add f_back so to the frame-state that current versions of Stackless simply ignore this additional information. A fixed version would detect the presence of f_back and use it.
How? The (c)frame-state as returned by frameobject_reduce() or cframe_reduce() always contains a "tuple with nulls" structure which is created by slp_into_tuple_with_nulls() and processed by slp_from_tuple_with_nulls(). Fortunately slp_from_tuple_with_nulls() ignores/skips non integer items in the inner "nulls"-tuple. This is our chance to add additional information to the frame-state without breaking unpickling of the enriched state with the current code-base.
I created a preliminary patch to verify that it is indeed possible to fix this problem. The patch is meant as a starting point for a discussion. I'll create a pull request.