Hi Christoph, all

I've just sent a minor fix to the Inbox I missed previously - Kernel-jar.1550.

if you debug and do step through to ^2 and then step over in
    [^2] ensure: []
the debugger incorrectly stops at #resume:through:. 

This is an old issue predating any of my changes. I'm sending the fix as part of this thread because it's closely related (but independent).

I think it can be safely merged.

Thanks,
Jaromir

On 30-Dec-23 6:15:25 PM, christoph.thiede@student.hpi.uni-potsdam.de wrote:

Hi Jaromir, hi all,

finally I have found the time to review these suggestions. Kernel-jar.1537, Kernel-jar.1538, and Kernel-jar.1539 look excellent to me as well. Clear, straightforward, useful. :-) I have merged them into the trunk via Kernel-ct.1545.

Regarding DebuggerTests>>test16HandleSimulationError, I have patched it via ToolsTests-ct.125. Nothing to rack your brains over: "thisContext pc: nil" just mimicks any kind of unhandled error inside the simulator - since we now gently handle this via #cannotReturn:, I just replaced it with "thisContext pc: false". :-) Sorry for not clarifying that earlier and letting you speculate.

Thanks for your work, and I already wish you a happy new year!

Best,
Christoph

---
Sent from Squeak Inbox Talk

On 2023-11-29T13:31:09+00:00, mail@jaromir.net wrote:

> Hi Marcel,
>
> > [myself] whether the patch would have been necessary should the
> #return:from: had been fixed then
>
> Nonsense, I just mixed it up with another issue :)
>
>
> On 29-Nov-23 1:51:21 PM, "Jaromir Matas" <mail(a)jaromir.net> wrote:
>
> >Thanks Marcel! This test somehow slipped my attention :)
> >
> >The test can no longer work as is. It takes advantage of the erroneous
> >behavior of #return:from: in the sense that if you simulate
> >
> > thisContext pc: nil
> >
> >it'll happily return to a dead context (i.e. to thisContext from #pc:
> >nil context) - which is not what the VM does during runtime. It should
> >immediately raise an illegal return exception not only during runtime
> >but also during simulation.
> >
> >The test mentions a patch for an infinite debugger chain
> >(http://forum.world.st/I-broke-the-debugger-td5110752.html). I wonder
> >whether the problem could have something to do with this simulation bug
> >in return:from:; and a terrible idea occurred to me whether the patch
> >would have been necessary should the #return:from: had been fixed then
> >;O
> >
> >We may potentially come up with more examples like this, even in the
> >trunk, where the bug from #return:from: propagated and was taken
> >advantage of. I've found and fixed #runUntilErrorOrReturnFrom: but more
> >can still be surviving undetected...
> >
> >I'd place the test into #expectedFailures for now but maybe it's time
> >to remove it; Christoph should decide :)
> >
> >Thanks again,
> >Jaromir
> >
> >
> >On 29-Nov-23 10:28:38 AM, "Taeumel, Marcel via Squeak-dev"
> ><squeak-dev(a)lists.squeakfoundation.org> wrote:
> >
> >>Hi Jaromir --
> >>
> >>Looks good. Still, what about that #test16HandleSimulationError now?
> >>:-) It is failing with your changes ... how would you adapt it?
> >>
> >>
> >>
> >>Best,
> >>Marcel
> >>>Am 28.11.2023 01:29:39 schrieb Jaromir Matas <mail(a)jaromir.net>:
> >>>
> >>>Hi Eliot, Marcel, all,
> >>>
> >>>I've sent a fix Kernel-jar.1539 to the Inbox that solves the
> >>>remaining bit of the chain of bugs described in the previous post.
> >>>All tests are green now and I think the root cause has been found and
> >>>fixed.
> >>>
> >>>In this last bit I've created a version of stepToCallee that would
> >>>identify a potential illegal return to a nil sender and avoid it.
> >>>
> >>>Now this example can be debugged without any problems:
> >>>
> >>>[[self halt. ^ 1] on: BlockCannotReturn do: #resume ] fork
> >>>
> >>>If you're happy with the solution in Kernel-jar.1539,
> >>>Kernel-jar.1538, Kernel-jar.1537 and the test in KernelTests-jar.447,
> >>>could you please double-check and merge, please? (And remove
> >>>Kernel-mt.1534 and Tools-jar.1240 from the Inbox)
> >>>
> >>>Best,
> >>>Jaromir
> >>>
> >>>
> >>>
> >>>On 27-Nov-23 12:09:37 AM, "Jaromir Matas" <mail(a)jaromir.net> wrote:
> >>>
> >>>>Hi Eliot, Christoph, all
> >>>>
> >>>>It looks like there are some more skeletons in the closet :/
> >>>>
> >>>>If you run this example
> >>>>
> >>>>[[self halt. ^ 1] on: BlockCannotReturn do: [:ex | ex resume] ] fork
> >>>>
> >>>>and step over halt and then step over ^1 you get a nonsensical error
> >>>>as a result of decoding nil as an instruction.
> >>>>
> >>>>It turns out that the root cause is in the #return:from: method: it
> >>>>only checks whether aSender is dead but ignores the possibility that
> >>>>aSender sender may be nil or dead in which cases the VM also
> >>>>responds with sending #cannotReturn, hence I assume the simulator
> >>>>should do the same. In addition, the VM nills the pc in such
> >>>>scenario, so I added the same functionality here too:
> >>>>
> >>>>Context >> return: value from: aSender
> >>>> "For simulation. Roll back self to aSender and return value
> >>>>from it. Execute any unwind blocks on the way. ASSUMES aSender is
> >>>>a sender of self"
> >>>>
> >>>> | newTop |
> >>>> newTop := aSender sender.
> >>>> (aSender isDead or: [newTop isNil or: [newTop isDead]]) ifTrue:
> >>>> "<--------- this is extended ------"
> >>>> [^self pc: nil; send: #cannotReturn: to: self with:
> >>>>{value}]. "<------ pc: nil is added ----"
> >>>> (self findNextUnwindContextUpTo: newTop) ifNotNil:
> >>>> "Send #aboutToReturn:through: with nil as the second
> >>>>argument to avoid this bug:
> >>>> Cannot #stepOver '^2' in example '[^2] ensure: []'.
> >>>> See
> >>>>http://lists.squeakfoundation.org/pipermail/squeak-dev/2022-June/220975.html
> >>>><http://lists.squeakfoundation.org/pipermail/squeak-dev/2022-June/220975.html>"
> >>>> [^self send: #aboutToReturn:through: to: self with: {value.
> >>>>nil}].
> >>>> self releaseTo: newTop.
> >>>> newTop ifNotNil: [newTop push: value].
> >>>> ^newTop
> >>>>
> >>>>In order for this to work #cannotReturn: has to be modified as in
> >>>>Kernel-jar.1537:
> >>>>
> >>>>Context >> cannotReturn: result
> >>>>
> >>>> closureOrNil ifNotNil: [^ self cannotReturn: result to: self
> >>>>home sender].
> >>>> self error: 'Computation has been terminated!'
> >>>>"<----------- this has to be an Error -----"
> >>>>
> >>>>Then it almost works except when you keep stepping over in the
> >>>>example above, you get an MNU error on `self previousPc` in
> >>>>#cannotReturn:to:` with your solution of the VM crash. If you don't
> >>>>mind I've amended your solution and added the final context where
> >>>>the computation couldn't return along with the pc:
> >>>>
> >>>>Context >> cannotReturn: result to: homeContext
> >>>> "The receiver tried to return result to homeContext that cannot
> >>>>be returned from.
> >>>> Capture the return context/pc in a BlockCannotReturn. Nil the pc
> >>>>to prevent repeat
> >>>> attempts and/or invalid continuation. Answer the result of
> >>>>raising the exception."
> >>>>
> >>>> | exception previousPc |
> >>>> exception := BlockCannotReturn new.
> >>>> previousPc := pc ifNotNil: [self previousPc]. "<----- here's a
> >>>>fix ----"
> >>>> exception
> >>>> result: result;
> >>>> deadHome: homeContext;
> >>>> finalContext: self; "<----- here's the new state, if
> >>>>that's fine ----"
> >>>> pc: previousPc.
> >>>> pc := nil.
> >>>> ^exception signal
> >>>>
> >>>>Unfortunately, this is still not the end of the story: there are
> >>>>situations where #runUntilErrorOrReturnFrom: places the two guard
> >>>>contexts below the bottom context. And that is a problem because
> >>>>when the method tries to remove the two guard contexts before
> >>>>returning at the end it uses #stepToCalee to do the job but this
> >>>>unforotunately was (ab)using the above bug in #return:from: - I'll
> >>>>explain: #return:from: didn't check whether aSender sender was nil
> >>>>and as a result it allowed to simulate a return to a "nil context"
> >>>>which was then (ab)used in the clean-up via #stepToCalee in the
> >>>>#runUntilErrorOrReturnFrom:.
> >>>>
> >>>>When I fixed the #return:from: bug, the #runUntilErrorOrReturnFrom:
> >>>>cleanup of the guard contexts no longer works in that very special
> >>>>case where the guard contexts are below the bottom context. There's
> >>>>one case where this is being used: #terminateAggresively by
> >>>>Christoph.
> >>>>
> >>>>If I'm right with this analysis, the #runUntilErrorOrReturnFrom:
> >>>>should get fixed too but I'll be away now for a few days and I won't
> >>>>be able to respond. If you or Christoph had a chance to take a look
> >>>>at Kernel-jar.1538 and Kernel-jar.1537 I'd be very grateful. I hope
> >>>>this super long message at least makes some sense :)
> >>>>Best,
> >>>>Jaromir
> >>>>
> >>>>[1] Kernel-jar.1538, Kernel-jar.1537
> >>>>[2] KernelTests-jar.447
> >>>>
> >>>>
> >>>>PS: Christoph,
> >>>>
> >>>>With Kernel-jar.1538 + Kernel-jar.1537 your example
> >>>>
> >>>>process :=
> >>>> [(c := thisContext) pc: nil.
> >>>> 2+3] newProcess.
> >>>>process runUntil: [:ctx | ctx selector = #cannotReturn:].
> >>>>self assert: process suspendedContext sender sender = c.
> >>>>self assert: process suspendedContext arguments = {c}.
> >>>>
> >>>>works fine, I've just corrected your first assert.
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>
> >>>>On 21-Nov-23 6:40:32 PM, "Eliot Miranda" <eliot.miranda(a)gmail.com>
> >>>>wrote:
> >>>>
> >>>>>Hi Jaromir,
> >>>>>
> >>>>>>On Nov 20, 2023, at 11:51 PM, Jaromir Matas <mail(a)jaromir.net>
> >>>>>>wrote:
> >>>>>>
> >>>>>>
> >>>>>>Hi Eliot,
> >>>>>>Very elegant! Now I finally got what you meant exactly :) Thanks.
> >>>>>>
> >>>>>>Two questions:
> >>>>>>1. in order for the enclosed test to work I'd need an Error
> >>>>>>instead of Processor debugWithTitle:full: call in #cannotReturn:.
> >>>>>>Otherwise I don't know how to catch a plain invocation of the
> >>>>>>Debugger:
> >>>>>>
> >>>>>>cannotReturn: result
> >>>>>>
> >>>>>> closureOrNil ifNotNil: [^ self cannotReturn: result to: self
> >>>>>>home sender].
> >>>>>> self error: 'Computation has been terminated!'
> >>>>>
> >>>>>Much nicer.
> >>>>>
> >>>>>>2. We are capturing a pc of self which is completely different
> >>>>>>context from homeContext indeed.
> >>>>>
> >>>>>Right. The return is attempted from a specific return bytecode in a
> >>>>>specific block. This is the coordinate of the return that cannot be
> >>>>>made. This is the relevant point of origin of the cannot return
> >>>>>exception.
> >>>>>
> >>>>>Why the return fails is another matter:
> >>>>>- the home context’s sender is a dead context (cannot be resumed)
> >>>>>- the home context’s sender is nil (home already returned from)
> >>>>>- the block activation’s home is nil rather than a context (should
> >>>>>not happen)
> >>>>>
> >>>>>But in all these cases the pc of the home context is immaterial.
> >>>>>The hike is being returned through/from, rather than from; the
> >>>>>home’s pc is not relevant.
> >>>>>
> >>>>>>Maybe we could capture self in the exception too to make it more
> >>>>>>clear/explicit what is going on: what context the captured pc is
> >>>>>>actually associated with. Just a thought...
> >>>>>
> >>>>>Yes, I like that. I also like the idea of somehow passing the
> >>>>>block activation’s pc to the debugger so that the relevant return
> >>>>>expression is highlighted in the debugger.
> >>>>>
> >>>>>>
> >>>>>>Thanks again,
> >>>>>>Jaromir
> >>>>>
> >>>>>You’re welcome. I love working in this part of the system. Thanks
> >>>>>for dragging me there. I’m in a slump right now and appreciate the
> >>>>>fellowship.
> >>>>>
> >>>>>>------ Original Message ------
> >>>>>>From "Eliot Miranda" <eliot.miranda(a)gmail.com>
> >>>>>>To "Jaromir Matas" <mail(a)jaromir.net>
> >>>>>>Cc squeak-dev(a)lists.squeakfoundation.org
> >>>>>>Date 11/21/2023 2:17:21 AM
> >>>>>>Subject Re: Re[2]: [squeak-dev] Re: Resuming on BlockCannotReturn
> >>>>>>exception
> >>>>>>
> >>>>>>>Hi Jaromir,
> >>>>>>>
> >>>>>>> see Kernel-eem.1535 for what I was suggesting. This example
> >>>>>>>now has an exception with the right pc value in it:
> >>>>>>>
> >>>>>>>[[^1] on: BlockCannotReturn do: [:ex| ex pc inspect. ex resume]]
> >>>>>>>fork
> >>>>>>>
> >>>>>>>The fix is simply
> >>>>>>>
> >>>>>>>Context>>cannotReturn: result to: homeContext
> >>>>>>> "The receiver tried to return result to homeContext that
> >>>>>>>cannot be returned from.
> >>>>>>> Capture the return pc in a BlockCannotReturn. Nil the pc to
> >>>>>>>prevent repeat
> >>>>>>> attempts and/or invalid continuation. Answer the result of
> >>>>>>>raising the exception."
> >>>>>>>
> >>>>>>> | exception |
> >>>>>>> exception := BlockCannotReturn new.
> >>>>>>> exception
> >>>>>>> result: result;
> >>>>>>> deadHome: homeContext;
> >>>>>>> pc: self previousPc.
> >>>>>>> pc := nil.
> >>>>>>> ^exception signal
> >>>>>>>
> >>>>>>>
> >>>>>>>The VM crash is now avoided. The debugger displays the method,
> >>>>>>>but does not highlight the offending pc, which is no big deal. A
> >>>>>>>suitable defaultHandler for B lockCannotReturn may be able to get
> >>>>>>>the debugger to highlight correctly on opening. Try the
> >>>>>>>following examples:
> >>>>>>>
> >>>>>>>[[^1] on: BlockCannotReturn do: #resume] fork.
> >>>>>>>
> >>>>>>>[[^1] on: BlockCannotReturn do: [:ex| ex pc inspect. ex resume]]
> >>>>>>>fork
> >>>>>>>
> >>>>>>>[[^1] value] fork.
> >>>>>>>
> >>>>>>>They al; seem to behave perfectly acceptably to me. Does this
> >>>>>>>fix work for you?
> >>>>>>>
> >>>>>>>On Fri, Nov 17, 2023 at 3:14 PM Jaromir Matas <mail(a)jaromir.net>
> >>>>>>>wrote:
> >>>>>>>>Hi Eliot,
> >>>>>>>>
> >>>>>>>>How about to nil the pc just before making the return:
> >>>>>>>>```
> >>>>>>>>Context >> #cannotReturn: result
> >>>>>>>>
> >>>>>>>> self push: self pc. "backup the pc for the sake of
> >>>>>>>>debugging"
> >>>>>>>> closureOrNil ifNotNil: [^self cannotReturn: result to: self
> >>>>>>>>home sender; pc: nil].
> >>>>>>>> Processor debugWithTitle: 'Computation has been terminated!'
> >>>>>>>>translated full: false
> >>>>>>>>```
> >>>>>>>>The nilled pc should not even potentially interfere with the
> >>>>>>>>#isDead now.
> >>>>>>>>
> >>>>>>>>I hope this is at least a step in the right direction :)
> >>>>>>>>
> >>>>>>>>However, there's still a problem when debugging the resumption
> >>>>>>>>of #cannotReturn because the encoders expect a reasonable index.
> >>>>>>>>I haven't figured out yet where to place a nil check - #step,
> >>>>>>>>#stepToSendOrReturn... ?
> >>>>>>>>
> >>>>>>>>Thanks again,
> >>>>>>>>Jaromir
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>------ Original Message ------
> >>>>>>>>From "Eliot Miranda" <eliot.miranda(a)gmail.com>
> >>>>>>>>To "Jaromir Matas" <mail(a)jaromir.net>
> >>>>>>>>Date 11/17/2023 8:36:50 PM
> >>>>>>>>Subject Re: [squeak-dev] Re: Resuming on BlockCannotReturn
> >>>>>>>>exception
> >>>>>>>>
> >>>>>>>>>Hi Jaromir,
> >>>>>>>>>
> >>>>>>>>>>On Nov 17, 2023, at 7:05 AM, Jaromir Matas <mail(a)jaromir.net>
> >>>>>>>>>>wrote:
> >>>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>>>Eliot, hi again,
> >>>>>>>>>>
> >>>>>>>>>>Please disregard my previous comment about nilling the
> >>>>>>>>>>contexts that have returned. We are indeed talking about the
> >>>>>>>>>>context directly under the #cannotReturn context which is
> >>>>>>>>>>totally different from the home context in another thread
> >>>>>>>>>>that's gone.
> >>>>>>>>>>
> >>>>>>>>>>I may still be confused but would nilling the pc of the
> >>>>>>>>>>context directly under the cannotReturn context help? Here's
> >>>>>>>>>>what I mean:
> >>>>>>>>>>```
> >>>>>>>>>>Context >> #cannotReturn: result
> >>>>>>>>>>
> >>>>>>>>>> closureOrNil ifNotNil: [^self pc: nil; cannotReturn:
> >>>>>>>>>>result to: self home sender].
> >>>>>>>>>> Processor debugWithTitle: 'Computation has been
> >>>>>>>>>>terminated!' translated full: false.
> >>>>>>>>>>```
> >>>>>>>>>>Instead of crashing the VM invokes the debugger with the
> >>>>>>>>>>'Computation has been terminated!' message.
> >>>>>>>>>>
> >>>>>>>>>>Does this make sense?
> >>>>>>>>>
> >>>>>>>>>Nearly. But it loses the information on what the pc actually
> >>>>>>>>>is, and that’s potentially vital information. So IMO the ox
> >>>>>>>>>should only be nilled between the BlockCannotReturn exception
> >>>>>>>>>being created and raised.
> >>>>>>>>>
> >>>>>>>>>[But if you try this don’t be surprised if it causes a few
> >>>>>>>>>temporary problems. It looks to me that without a little
> >>>>>>>>>refactoring this could easily cause an infinite recursion
> >>>>>>>>>around the sending of isDead. I’m sure you’ll be able to fix
> >>>>>>>>>the code to work correctly]
> >>>>>>>>>
> >>>>>>>>>>Thanks,
> >>>>>>>>>>Jaromir
> >>>>>>>>>>
> >>>>>>>>>>
> >>>>>>>>>>------ Original Message ------
> >>>>>>>>>>From "Jaromir Matas" <mail(a)jaromir.net>
> >>>>>>>>>>To "Eliot Miranda" <eliot.miranda(a)gmail.com>; "The
> >>>>>>>>>>general-purpose Squeak developers list"
> >>>>>>>>>><squeak-dev(a)lists.squeakfoundation.org>
> >>>>>>>>>>Date 11/17/2023 10:15:17 AM
> >>>>>>>>>>Subject [squeak-dev] Re: Resuming on BlockCannotReturn
> >>>>>>>>>>exception
> >>>>>>>>>>
> >>>>>>>>>>>Hi Eliot,
> >>>>>>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>>------ Original Message ------
> >>>>>>>>>>>From "Eliot Miranda" <eliot.miranda(a)gmail.com>
> >>>>>>>>>>>To "Jaromir Matas" <mail(a)jaromir.net>
> >>>>>>>>>>>Cc "The general-purpose Squeak developers list"
> >>>>>>>>>>><squeak-dev(a)lists.squeakfoundation.org>
> >>>>>>>>>>>Date 11/16/2023 11:52:45 PM
> >>>>>>>>>>>Subject Re: Re[2]: [squeak-dev] Re: Resuming on
> >>>>>>>>>>>BlockCannotReturn exception
> >>>>>>>>>>>
> >>>>>>>>>>>>Hi Jaromir,
> >>>>>>>>>>>>
> >>>>>>>>>>>>On Thu, Nov 16, 2023 at 2:22 PM Jaromir Matas
> >>>>>>>>>>>><mail(a)jaromir.net> wrote:
> >>>>>>>>>>>>>Hi Nicolas, Eliot,
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>here's what I understand is happening (see the enclosed
> >>>>>>>>>>>>>screenshot):
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>1) we fork a new process to evaluate [^1]
> >>>>>>>>>>>>>2) the new process evaluates [^1] which means instruction
> >>>>>>>>>>>>>18 is being evaluated, hence pc points to instruction 19
> >>>>>>>>>>>>>now
> >>>>>>>>>>>>>3) however, the home context where ^1 should return to is
> >>>>>>>>>>>>>gone by this time (the process that executed the fork has
> >>>>>>>>>>>>>already returned - notice the two up arrows in the debugger
> >>>>>>>>>>>>>screenshot)
> >>>>>>>>>>>>>4) the VM can't finish the instruction and returns control
> >>>>>>>>>>>>>to the image via placing the #cannotReturn: context on top
> >>>>>>>>>>>>>of the [^1] context
> >>>>>>>>>>>>>5) #cannotReturn: evaluation results in signalling the BCR
> >>>>>>>>>>>>>exception which is then handled by the #resume handler
> >>>>>>>>>>>>> (in our debugged case the [:ex | self halt. ex resume]
> >>>>>>>>>>>>>handler)
> >>>>>>>>>>>>>6) ex resume is evaluated, however, this means requesting
> >>>>>>>>>>>>>the VM to evaluate instruction 19 of the [^1] context -
> >>>>>>>>>>>>>which is past the last instruction of the context and the
> >>>>>>>>>>>>>crash ensues
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>I wonder whether such situations could/should be prevented
> >>>>>>>>>>>>>inside the VM or whether such an expectation is wrong for
> >>>>>>>>>>>>>some reason.
> >>>>>>>>>>>>
> >>>>>>>>>>>>As Nicolas says, IMO this is best done at the image level.
> >>>>>>>>>>>>
> >>>>>>>>>>>>It could be prevented in the VM, but at great cost, and only
> >>>>>>>>>>>>partially. The performance issue is that the last bytecode
> >>>>>>>>>>>>in a method is not marked in any way, and that to determine
> >>>>>>>>>>>>the last bytecode the bytecodes must be symbolically
> >>>>>>>>>>>>evaluated from the start of the method. See implementors of
> >>>>>>>>>>>>endPC at the image level (which defer to the method trailer)
> >>>>>>>>>>>>and implementors of endPCOf: in the VMMaker code. Doing this
> >>>>>>>>>>>>every time execution commences is prohibitively expensive.
> >>>>>>>>>>>>The "only partially" issue is that following the return
> >>>>>>>>>>>>instruction may be other valid bytecodes, but these are not
> >>>>>>>>>>>>a continuation.
> >>>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>>Consider the following code in some block:
> >>>>>>>>>>>> [self expression ifTrue:
> >>>>>>>>>>>> [^1].
> >>>>>>>>>>>> ^2
> >>>>>>>>>>>>
> >>>>>>>>>>>>The bytecodes for this are
> >>>>>>>>>>>> pushReceiver
> >>>>>>>>>>>> send #expression
> >>>>>>>>>>>> jumpFalse L1
> >>>>>>>>>>>> push 1
> >>>>>>>>>>>> methodReturnTop
> >>>>>>>>>>>>L1
> >>>>>>>>>>>> push 2
> >>>>>>>>>>>> methodReturnTop
> >>>>>>>>>>>>
> >>>>>>>>>>>>Clearly if expression is true these should be *no*
> >>>>>>>>>>>>continuation in which ^2 is executed.
> >>>>>>>>>>>
> >>>>>>>>>>>Well, in that case there's a bug because the computation in
> >>>>>>>>>>>the following example shouldn't continue past the [^1] block
> >>>>>>>>>>>but it silently does:
> >>>>>>>>>>>`[[true ifTrue: [^ 1]] on: BlockCannotReturn do: #resume ]
> >>>>>>>>>>>fork`
> >>>>>>>>>>>
> >>>>>>>>>>>The bytecodes are
> >>>>>>>>>>> push true
> >>>>>>>>>>> jumpFalse L1
> >>>>>>>>>>> push 1
> >>>>>>>>>>> returnTop
> >>>>>>>>>>>L1
> >>>>>>>>>>> push nil
> >>>>>>>>>>> blockReturn
> >>>>>>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>>So even if the VM did try and detect whether the return was
> >>>>>>>>>>>>at the last block method, it would only work for special
> >>>>>>>>>>>>cases.
> >>>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>>It seems to me the issue is simply that the context that
> >>>>>>>>>>>>cannot be returned from should be marked as dead (see
> >>>>>>>>>>>>Context>>isDead) by setting its pc to nil at some point,
> >>>>>>>>>>>>presumably after copying the actual return pc into the
> >>>>>>>>>>>>BlockCannotReturn exception, to avoid ever trying to resume
> >>>>>>>>>>>>the context.
> >>>>>>>>>>>
> >>>>>>>>>>>Does this mean, in other words, that every context that
> >>>>>>>>>>>returns should nil its pc to avoid being "wrongly"
> >>>>>>>>>>>reused/executed in the future, which concerns primarily those
> >>>>>>>>>>>being referenced somewhere hence potentially executable in
> >>>>>>>>>>>the future, is that right?
> >>>>>>>>>>>Hypothetical question: would nilling the pc during returns
> >>>>>>>>>>>"fix" the example?
> >>>>>>>>>>>Thanks a lot for helping me understand this.
> >>>>>>>>>>>Best,
> >>>>>>>>>>>Jaromir
> >>>>>>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>Thanks,
> >>>>>>>>>>>>>Jaromir
> >>>>>>>>>>>>>
> >>>>>>>>>>>>><bdxuqalu.png>
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>------ Original Message ------
> >>>>>>>>>>>>>From "Eliot Miranda" <eliot.miranda(a)gmail.com>
> >>>>>>>>>>>>>To "Jaromir Matas" <mail(a)jaromir.net>; "The general-purpose
> >>>>>>>>>>>>>Squeak developers list"
> >>>>>>>>>>>>><squeak-dev(a)lists.squeakfoundation.org>
> >>>>>>>>>>>>>Date 11/16/2023 6:48:43 PM
> >>>>>>>>>>>>>Subject Re: [squeak-dev] Re: Resuming on BlockCannotReturn
> >>>>>>>>>>>>>exception
> >>>>>>>>>>>>>
> >>>>>>>>>>>>>>Hi Jaromir,
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>On Nov 16, 2023, at 3:23 AM, Jaromir Matas
> >>>>>>>>>>>>>>><mail(a)jaromir.net> wrote:
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>Hi Nicloas,
> >>>>>>>>>>>>>>>No no, I don't have any practical scenario in mind, I'm
> >>>>>>>>>>>>>>>just trying to understand why the VM is implemented like
> >>>>>>>>>>>>>>>this, whether there were a reason to leave this
> >>>>>>>>>>>>>>>possibility of a crash, e.g. it would slow down the VM to
> >>>>>>>>>>>>>>>try to prevent such a dumb situation (who would resume
> >>>>>>>>>>>>>>>from BCR in his right mind? :) ) - or perhaps I have
> >>>>>>>>>>>>>>>overlooked some good reason to even keep this behavior in
> >>>>>>>>>>>>>>>the VM. That's all.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>>Let’s first understand what’s really happening. Presumably
> >>>>>>>>>>>>>>at tone point a context is resumed those pc is already at
> >>>>>>>>>>>>>>the block return bytecode (effectively, because it crashes
> >>>>>>>>>>>>>>in JITted code, but I bet the stack vm will crash also,
> >>>>>>>>>>>>>>but not as cleanly - it will try and execute the bytes in
> >>>>>>>>>>>>>>the encoded method trailer). So which method actually
> >>>>>>>>>>>>>>sends resume, and to what, and what state is resume’s
> >>>>>>>>>>>>>>receiver when resume is sent?
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>Thanks for your reply.
> >>>>>>>>>>>>>>>Regards,
> >>>>>>>>>>>>>>>Jaromir
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>------ Original Message ------
> >>>>>>>>>>>>>>>From "Nicolas Cellier"
> >>>>>>>>>>>>>>><nicolas.cellier.aka.nice(a)gmail.com>
> >>>>>>>>>>>>>>>To "Jaromir Matas" <mail(a)jaromir.net>; "The
> >>>>>>>>>>>>>>>general-purpose Squeak developers list"
> >>>>>>>>>>>>>>><squeak-dev(a)lists.squeakfoundation.org>
> >>>>>>>>>>>>>>>Date 11/16/2023 7:20:20 AM
> >>>>>>>>>>>>>>>Subject Re: [squeak-dev] Resuming on BlockCannotReturn
> >>>>>>>>>>>>>>>exception
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>Hi Jaromir,
> >>>>>>>>>>>>>>>>Is there a scenario where it would make sense to resume
> >>>>>>>>>>>>>>>>a BlockCannotReturn?
> >>>>>>>>>>>>>>>>If not, I would suggest to protect at image side and
> >>>>>>>>>>>>>>>>override #resume.
> >>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>Le mer. 15 nov. 2023, 23:42, Jaromir Matas
> >>>>>>>>>>>>>>>><mail(a)jaromir.net> a écrit :
> >>>>>>>>>>>>>>>>>Hi Eliot, Christoph, All,
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>It's known the following example crashes the VM. Is
> >>>>>>>>>>>>>>>>>this an intended behavior or a "tolerated bug"?
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>`[[^ 1] on: BlockCannotReturn do: #resume] fork`
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>I understand why it crashes: the non-local return has
> >>>>>>>>>>>>>>>>>nowhere to return to and so resuming the computation
> >>>>>>>>>>>>>>>>>leads to a crash. But why not raise another BCR
> >>>>>>>>>>>>>>>>>exception to prevent the crash? Potential infinite
> >>>>>>>>>>>>>>>>>loop? Perhaps I'm just missing the purpose of this
> >>>>>>>>>>>>>>>>>behavior...
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>Thanks for an explanation.
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>Best,
> >>>>>>>>>>>>>>>>>Jaromir
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>--
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>Jaromir Matas
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>>
> >>>>>>>>>>>>--
> >>>>>>>>>>>>_,,,^..^,,,_
> >>>>>>>>>>>>best, Eliot
> >>>>>>>>>><Context-cannotReturn.st>
> >>>>>>>
> >>>>>>>
> >>>>>>>--
> >>>>>>>_,,,^..^,,,_
> >>>>>>>best, Eliot
> >>>>>><ProcessTest-testResumeAfterBCR.st>