Login  Register

Re: stepping over non local return in a protected block

Posted by Jaromir Matas on May 25, 2021; 7:51pm
URL: https://forum.world.st/stepping-over-non-local-return-in-a-protected-block-tp5128777p5130004.html

Hi Nicolas, Christoph,


Nicolas Cellier wrote

> Simulating #aboutToReturn:through: did jump to first unwind context. But
> this first unwind context was determined BEFORE the simulation #ensure:
> has been inserted. This had the effect of skipping the simulation
> machinery protection, and did result in a BlockCannotReturn
> (cannotReturn:) error...
>
> This did prevent the debugger to correctly debug a protected block with
> non local return like this:
>  
> [^2] ensure: [Transcript cr; show: 'done'].

What would you think about this approach: because #return:from: supplies the
first unwind context for #aboutToReturn:through: prematurely, how about to
supply nil instead of the first unwind context and let #resume:through: find
the first unwind context at precisely the right time? I.e.:

resume: value through: firstUnwindCtxt
        "Unwind thisContext to self and resume with value as result of last send.
         Execute any unwind blocks while unwinding.
         ASSUMES self is a sender of thisContext."

        | ctxt unwindBlock |
        self isDead ifTrue: [self cannotReturn: value to: self].
----> ctxt := firstUnwindCtxt ifNil: [thisContext findNextUnwindContextUpTo:
self].
        [ctxt isNil] whileFalse:
                [(ctxt tempAt: 2) ifNil:
                        [ctxt tempAt: 2 put: true.
                         unwindBlock := ctxt tempAt: 1.
                         thisContext terminateTo: ctxt.
                         unwindBlock value].
                 ctxt := ctxt findNextUnwindContextUpTo: self].
        thisContext terminateTo: self.
        ^value

The change is without any adverse effects and deals with all similar
simulated non-local returns.


Here's the modified #return:from:

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 |
        aSender isDead ifTrue:
                [^self send: #cannotReturn: to: self with: {value}].
        newTop := aSender sender.
        (self findNextUnwindContextUpTo: newTop) ifNotNil:
-----> [^self send: #aboutToReturn:through: to: self with: {value. nil}].
        self releaseTo: newTop.
        newTop ifNotNil: [newTop push: value].
        ^newTop

What do you think? Would this be clean?



-----
^[^ Jaromir
--
Sent from: http://forum.world.st/Squeak-Dev-f45488.html

^[^ Jaromir