[squeak-dev] Questions about FullBlock closures

Jaromir Matas mail at jaromir.net
Sun Feb 19 07:04:34 UTC 2023


> No, the difference is that the pc and sender of the contexts between the receiver and argument contexts are set to nil when one does terminateTo: but not when one does privSender:.

This is crystal clear, no problem here

> Clearly they *must* be do professed yo be marked as having been returned from

And this is precisely where I‘m lost: Why do the (cut out) contexts *need* to be marked as returned from? In order to be GC’d? Otherwise they’d get stuck? Looking at StackInterpreterPrimitives >> #primitiveTerminateTo there’s a lot going on with frames and pages too but when I replace terminateTo: with privSender: in my image (two/three senders only), seemingly everything works as before (tests ok etc) which drives me crazy :)

Thanks for your patience,
Jaromir


On Feb 17, 2023, at 2:45 PM, Jaromir Matas <mail at jaromir.net> wrote:

Hi Eliot, Tim, all

> Eliot: But I suspect that atomicity is not crucial and that therefore the terminateTo: primitive is only an optimization.

That explains why the *primitive* is not essential; another question is whether #terminateTo: as such (primitive or not) is essential for e.g. freeing the stack frames/pages or "just" an optimization.

I'll try to answer this question. After reading Eliot's post at http://www.mirandabanda.org/cogblog/2009/01/14/under-cover-contexts-and-the-big-frame-up/ and checking Tim's primitiveTerminateTo: code, my guess is that the difference between

thisContext terminateTo: someContext.

and

thisContext privSender: someContext.

is that in the former case the stack frames/pages are being freed immediately, while in the latter case the whole sender chain remains intact until it is, sooner or later, GCd or, if referenced, remains available for further use (whatever it may be).

No, the difference is that the pc and sender of the contexts between the receiver and argument contexts are set to nil when one does terminateTo: but not when one does privSender:.  Clearly they *must* be do professed yo be marked as having been returned from (c.f. earlier parts of the conversation).



That may be why using #terminateTo: (primitive or not) is not essential, but an optimization. Too naive? :) Could there be, perhaps, some circularities that need breaking? Or is GC too slow to clean up after non-local returns? (btw I only found two senders of #terminateTo: - #runUntilErrorOrReturnFrom: and #resume:[through:]).

Oops… more questions popping up :)

Best,
Jaromir


--

Jaromír Matas

mail at jaromir.net


From: Jaromir Matas<mailto:mail at jaromir.net>
Sent: Sunday, February 12, 2023 21:06
To: The general-purpose Squeak developers list<mailto:squeak-dev at lists.squeakfoundation.org>
Subject: Re: [squeak-dev] Questions about FullBlock closures

Hi Eliot, Tim,

thanks a lot for your answers.

> peek at the generated gcc3x-cointerp.c file and find the primitiveTerminateTo() routine

Awfully complex :)

> But I suspect that atomicity is not crucial and that therefore the terminateTo: primitive is only an optimization.

To be sure I understand, please let me try from another angle:
Consider a thought experiment: What happens if, in Context >> #resumeEvaluating:, we replace

                thisContext terminateTo: self.

with:

                thisContext privSender: self.

Would garbage collection/the vm take care of freeing the intervening contexts/frames or is in fact #terminateTo: prim 196 essential for this?

When I try that, nothing wrong seems to happen and all tests (Exception, Process, Methods, Object, Classes) work fine but I'm only looking at the surface of things indeed.

What I'm trying to achieve is to reuse the existing #unwindTo: method in #resumeEvaluating:, which seems to work fine, and just wonder whether replacing the #terminateTo: with #privSender: would further simplify the method (or made the system less efficient):

Context>>resumeEvaluating: aBlock
                "Unwind thisContext to self and resume with value as result of last send.
                 Execute unwind blocks when unwinding.
                ASSUMES self is a sender of thisContext"

                self isDead ifTrue: [self cannotReturn: aBlock value to: self].
                thisContext
                                unwindTo: self safely: false;
                                terminateTo: self.
                ^aBlock value

Thanks,
best,
Jaromir


--

Jaromír Matas

mail at jaromir.net


From: Eliot Miranda<mailto:eliot.miranda at gmail.com>
Sent: Sunday, February 12, 2023 16:54
To: The general-purpose Squeak developers list<mailto:squeak-dev at lists.squeakfoundation.org>
Subject: Re: [squeak-dev] Questions about FullBlock closures

Hi Jaromir,

On Feb 12, 2023, at 5:13 AM, Jaromir Matas <mail at jaromir.net> wrote:

Hi,

>> What is the purpose of the primitive 196 Context>>#terminateTo:?

> Strongly related to prim 195 & 197. You have to check each context up the chain to see what exceptions might be dealt with & by which context.

My understanding is prim 195 (#findNextUnwindContextUpTo:) searches for unwind contexts and prim 197 (#findNextHandlerContextStarting) searches for handler context. But prim 195 (#terminateTo:) is unclear to me. #terminateTo comment says:

"Terminate all the Contexts between me and previousContext, if previousContext is on my Context stack. Make previousContext my sender."

Which doesn't say much except it's nilling all context's pc and sender between self and the argument. I wonder what else it does behind the scenes and why :)

In a paper from 2009 Eliot wrote:
"[...] there’s a primitive terminateTo: that does something similar to the context nilling in non-local return. It is a little simpler than non-local return (although not much) but it is just a variation on the same theme so I’ll spare you."

I wish Eliot didn't spare us :) Other than that I haven't found any further info.

Because the primitive 196 dates back to 2001 I'm unable to judge whether it's still essential to nil the intermediate contexts (to free stack pages or something).

In particular I'm trying to understand whether the use of #terminateTo *primitive* in #resumeEvaluating: and #resume:through: is essential or not.

There are three things that primitive 296, Context>>terminateTo: does, or rather there are two things it does, and it does them in a particular way. It sets senders and pcs of intervening contexts to nil. It sets the sender of the receiver to the argument. If does this atomically.

I can’t say whether the last of these is necessary. If it is, then the primitive is needed, essential. But the primitive merely optimized the former two operations.

In the StackInterpreter & CoInterpreter it provides a significant optimization because

- the primitive avoids creating any contexts; if if were not implemented primitively then  contexts would have to be created for all intervening frames, merely to throw unreferenced ones away

- intervening stack pages can be freed without looking at their contents

So the primitive is an important optimization for Stack/CoInterpreter.

But I suspect that atomicity is not crucial and that therefore the terminateTo: primitive is only an optimization.

 Any additional info greatly appreciated.

HTH

Thanks,
Jaromir


--

Jaromír Matas

mail at jaromir.net


From: tim Rowledge<mailto:tim at rowledge.org>
Sent: Sunday, February 12, 2023 5:18
To: The general-purpose Squeak developers list<mailto:squeak-dev at lists.squeakfoundation.org>
Subject: Re: [squeak-dev] Questions about FullBlock closures



> On 2023-02-11, at 4:04 PM, Jaromir Matas <mail at jaromir.net> wrote:
>
> If I may, I have a question here: What is the purpose of the primitive 196 Context>>#terminateTo:? Why primitive and why terminating each context along the way? Naively, I'd think checking the two contexts are in the same sender chain and patching them via privSender should do but I'm sure I'm missing something here :)
>

Exception handling stuff. Strongly related to prim 195 & 197. You have to check each context up the chain to see what exceptions might be dealt with & by which context. Look at e.g. Process>>#terminate for some context.


tim
--
tim Rowledge; tim at rowledge.org; http://www.rowledge.org/tim
When flying inverted, remember that down is up and up is expensive




-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20230219/840b3916/attachment.html>


More information about the Squeak-dev mailing list