dean.long at oracle.com
dean.long at oracle.com
Wed Dec 5 08:29:04 UTC 2018
On 12/4/18 4:33 PM, John Rose wrote:
>> Currently the stack
>> is kept when the continuation is unmounted. The cache keeps track of the stack
>> that has the most recent binding. This is because the most recent binding could
>> be in a parent continuation or parent thread.
> Good that you are covering that case. These things need to span all the
> way up the callee-to-caller relation, not stop at continuation boundaries.
> It also adds complexity: If a parent frame returns, perhaps during concurrent
> execution in a different fiber, but a child frame still needs access to a frame
> local, the frame local binding must be preserved somehow for the child's use.
> Suggestion: This is one reason*constant* bindings are preferable to*variable*
> bindings. It's easier to "fork" a constant to distinct clients than share a link to
> a variable, and there's no loss of generality.
In order for the parent frame to return without the child frame
returning first, I believe
they must be in separate continuations. When the child frame tries to
frame local, the logic should match what a stack walk would find. If
there is no binding
in the child frame's continuation, we go to the parent continuation. If
the top binding in
the parent went away because a frame returned, we keep walking frames.
prototype, we would miss in the cache, and then look in the stack associated
with each parent continuation. If I understand correctly, in my
prototype, the opportunity
for binding "forking" and added complexity on mount/unmount would show up in
trying to cleverly preserve existing cache entries rather rebuilding
from a clean cache
each time, which is something I considered but haven't attempted.
>> Without fibers, continuations, or
>> global bindings, then the most recent binding reduces to the thread binding, and
>> there shouldn't be any need for a cache.
> (The model can be thread-agnostic, right? You just have to find the frame that
> defined the local; doesn't matter who owns it or how.)
Yes, it can be thread-agnostic. In the loom world, if there was always
continuation, even for threads, then I could use that. But for now, I
put the binding
stacks and cache in what I call a FrameLocalsProvider object, which is
stored as close
to where the frames live as possible: in Threads and Continuations in
getParent() operation returns a FrameLocalsProvider as well.
>> The cache is a map and is reset every time the continuation is mounted/unmounted.
> Yep. We could also try to salvage the cache at unmount and reuse it at remount.
> This would be pretty easy if the structure of the cache is (a) rooted in the fiber and
> (b) allocated in the frames of the fiber. Major events like JIT or deopt could reset the
> cache by zeroing out the root variables in the fiber.
I think it would be safe to clone the parent cache when a fresh
continuation is mounted.
On a resume, perhaps we could salvage the old cache if 1) we have the
and 2) that parent is not "dirty" (hasn't been umounted and remounted).
>> The stack is looked up in a WeakHashMap, making it basically equivalent to a
>> ThreadLocal. If we had long-lived frame locals, then perhaps we could simply look
>> them up in an array, but then why not use a long-lived thread local instead that
>> could also be looked up in an array?
> That smells like footprint to me. There's a WHM per active fiber?
Yes, it's per FrameLocalsProvider.
> I suppose it's
> OK if the WHM is discarded when the fiber unmounts. (Or keep it in a weak
> reference field on the fiber?)
>> To reduce Continuation storage requirements, we could choose not to retain the
>> stacks after an unmount, but instead lazily rebuild using stack walks. Right now
>> I'm only using the deep stack walk to verify the results of the cache + stack
> Yep. That's the sort of trade-off that faces us. Another point about allocating
> stacks inside of actual stack frames: Reconstructing them simply requires
> walking the stack and noticing where they were.
I did try to approximate having slots in native stack frames, using
Our current stackwalk code allows us to read locals in frames but not
write to them
(at least not without deoptimizing), so I do use the mutable "box" you
store stack nodes, and those are linked to earlier nodes.
Thanks for all the feedback!
> — John
More information about the loom-dev