[Python-Dev] 'stackless' python?

Christian Tismer tismer at appliedbiometrics.com
Thu May 20 18:52:21 CEST 1999

Cleaning up, clarifying, trying to understand...

Tim Peters wrote:
> [Christian Tismer]
> > I tried the most simple thing, and this seemed to be duplicating
> > the current state of the machine. The frame holds the stack,
> > and references to all objects.
> > By chance, the locals are not in a dict, but unpacked into
> > the frame. (Sometimes I agree with Guido, that optimization
> > is considered harmful :-)
> I don't see that the locals are a problem here -- provided you simply leave
> them alone <wink>.

This depends on wether I have to duplicate frames
or not. Below...

> > The Python stack, besides its intermingledness with the machine
> > stack, is basically its chain of frames.
> Right.
> > The value stack pointer still hides in the machine stack, but
> > that's easy to change.
> I'm not sure what "value stack" means here, or "machine stack".  The latter
> means the C stack?  Then I don't know which values you have in mind that are
> hiding in it (the locals are, as you say, unpacked in the frame, and the
> evaluation stack too).  By "evaluation stack" I mean specifically
> f->f_valuestack; the current *top* of stack pointer (specifically
> stack_pointer) lives in the C stack -- is that what we're talking about?


> Whichever, when we're talking about the code, let's use the names the code
> uses <wink>.

The evaluation stack pointer is a local variable in the
C stack and must be written to the frame to become independant
from the C stack. Sounds better now?

> > So the real Scheme-like part is this chain, methinks, with
> > the current bytecode offset and value stack info.
> Curiously, f->f_lasti is already materialized every time we make a call, in
> order to support tracing.  So if capturing a continuation is done via a
> function call (hard to see any other way it could be done <wink>), a
> bytecode offset is already getting saved in the frame object.

You got me. I'm just completing what is partially there.

> > Making a copy of this in a restartable way means to increase
> > the refcount of all objects in a frame.
> You later had a vision of splitting the frame into two objects -- I think.

My wrong wording. Not splitting, but duplicting. If a frame is the
current state, I make it two frames to have two current states.
One will be saved, the other will be run. This is what I call
Actually, splitting must occour whenever a frame can be reached twice,
in order to keep elements alive.

> Whichever part the locals live in should not be copied at all, but merely
> have its (single) refcount increased.  The other part hinges on details of
> your approach I don't know.  The nastiest part seems to be f->f_valuestack,
> which conceptually needs to be (shallow) copied in the current frame and in
> all other frames reachable from the current frame's continuation (the chain
> rooted at f->f_back today); that's the sum total (along with the same
> frames' bytecode offsets) of capturing the control flow state.

Well, I see. You want one locals and one globals, shared by two
incarnations. Gets me into trouble.

> > Would it be correct to undo the effect of fast locals before
> > splitting, and redoing it on activation?
> Unsure what splitting means, but in any case I can't conceive of a reason
> for doing anything to the locals.  Their values aren't *supposed* to get
> restored upon continuation invocation, so there's no reason to do anything
> with their values upon continuation creation either.  Right?  Or are we
> talking about different things?

Let me explain. What Python does right now is:
When a function is invoked, all local variables are copied
into fast_locals, well of course just references are copied
and counts increased. These fast locals give a lot of speed
today, we must have them.
You are saying I have to share locals between frames. Besides
that will be a reasonable slowdown, since an extra structure
must be built and accessed indirectly (right now, i's all fast,
living in the one frame buffer), I cannot say that I'm convinced
that this is what we need.

Suppose you have a function

def f(x):
    # do something
    # in some context, wanna have a snapshot
    global snapshot  # initialized to None
    if not snapshot:
        snapshot = callcc.new()
    # continue computation
    x = x+1

What I want to achieve is that I can run this again, from my
snapshot. But with shared locals, my parameter x of the
snapshot would have changed to x+1, which I don't find useful.
I want to fix a state of the current frame and still think
it should "own" its locals. Globals are borrowed, anyway.
Class instances will anyway do what you want, since
the local "self" is a mutable object.

How do you want to keep computations independent
when locals are shared? For me it's just easier to
implement and also to think with the shallow copy.
Otherwise, where is my private place?
Open for becoming convinced, of course :-)

ciao - chris

Christian Tismer             :^)   <mailto:tismer at appliedbiometrics.com>
Applied Biometrics GmbH      :     Have a break! Take a ride on Python's
Kaiserin-Augusta-Allee 101   :    *Starship* http://starship.python.net
10553 Berlin                 :     PGP key -> http://wwwkeys.pgp.net
PGP Fingerprint       E182 71C7 1A9D 66E9 9D15  D3CC D4D7 93E2 1FAE F6DF
     we're tired of banana software - shipped green, ripens at home

More information about the Python-Dev mailing list