Non-local returns with promises (was: Re: Thoughts on a
concurrent Squeak VM)
siguctua at gmail.com
Sun Nov 4 22:07:42 UTC 2007
On 04/11/2007, Rob Withers <reefedjib at yahoo.com> wrote:
> ----- Original Message -----
> From: "Igor Stasenko" <siguctua at gmail.com>
> > I'm personally much more worrying about non-local returns.
> As an example of the problem of non-local return, let's look at this simple
> foo: bar
> bar ifTrue: [^ 1].
> self snafu.
> ^ 0
> If bar is eventual, we don't know at the time of invocation whether the
> method will exit through the non-local
> return or through the return at the end of the method.
> How to best deal with this?
> My thought is that the context needs to become eventual, be sent as a lambda
> to the bar promise, and the context return a promise. The return will check
> to see if there is a resolver on the context and #resolve: it with the
> appropriate return value. The lambda needs to be all sequential code from
> the point where a message is sent to the promise that includes a block as an
> argument to the end of the context. So the lambda would be:
> f := [:barVow |
> barVow ifTrue: [^1].
> self snafu.
> ^ 0]
> and we would send:
> ^ bar whenResolved: f.
> So the challenge here would be in capturing the lambda and in effect
> rewriting the code for this method, on the fly. The lambda is just a one
> arg blockContext, where the ip points to the pushTemp: 0.
> 17 <10> pushTemp: 0
> 18 <99> jumpFalse: 21
> 19 <76> pushConstant: 1
> 20 <7C> returnTop
> 21 <70> self
> 22 <D0> send: snafu
> 23 <87> pop
> 24 <75> pushConstant: 0
> 25 <7C> returnTop
> and the two return bytecodes, would each need to resolve the promise
> returned. This needs to become something like the following, where lines
> 28-36 is the original block with three rewrites:
> first, pushTemp: 1 instead of pushTemp: 0, since the block arg is a
> separate temp.
> second, the two returnTops needs to become a jumpTo: and a blockReturn,
> so we can resolve the promise.
> 21 <10> pushTemp: 0
> 22 <89> pushThisContext:
> 23 <76> pushConstant: 1
> 24 <C8> send: blockCopy:
> 25 <A4 0A> jumpTo: 37
> 27 <69> popIntoTemp: 1
> 28 <11> pushTemp: 1
> 29 <99> jumpFalse: 32
> 30 <76> pushConstant: 1
> 31 <93> jumpTo: 36
> 32 <70> self
> 33 <D1> send: snafu
> 34 <87> pop
> 35 <75> pushConstant: 0
> 36 <7D> blockReturn
> 37 <E0> send: whenResolved:
> 38 <7C> returnTop
> Of course, we don't want to modify the original method, since another call
> to it may not involve a promise. So we are looking at creating a new
> MethodContext, which we rewrite to create a new BlockContext defined from
> lines 22-25 through 36 above. For every non-local return method when called
> with a promise.
> What do you think?
Hmm.. i think, you given a bad example. It depends on 'knowledge' that
#ifTrue: is optimized by compiler as an execution branch, but not a
regular message send.
For general case we should consider passing a block as a argument, like:
bar someMethod: [^1].
But this again, not includes cases, when blocks are assigned to
temps/ivars within context and never passed as arguments to
I thought a bit about marking a method context containing blocks with
non-local returns with special flag, which will force context to not
activate until all free variables in method are resolved
(agruments/temps). This means that before any activation (entering
method and each send in method it will wait for resolving all promises
But i'm still doubt if this gives us anything.
There is many methods which operate with blocks by sending #value.. to
them. And these methods actually don't care if those blocks contain
non-local returns or not. They simply do their job.
Igor Stasenko AKA sig.
More information about the Squeak-dev