Rebel block

Alan Lovejoy sourcery at pacbell.net
Tue Jul 14 04:05:23 UTC 1998


sqrmax at cvtci.com.ar wrote:

> Hi.
>
> I've got a misbehaving block. I evaluate it, and because what's inside it
> is in beta, it crashes and burns. So I open the debugger and "of course, I
> forgot the caret" or so. So I close the debugger, fix it, and when I try to
> evaluate the block again an error pops up because the block is still evaluating
> itself?!?!... no debugger window is visible (and no debugger shows up in find
> window). If I recreate the block, I can evaluate it but when it crashes once,
> it renders itself into a rebel block again!!!
>
> All I can see is that the primitive that evaluates the block fails just
> after nil DoIt. What's going on?
>
> Andres.

BlockContexts in Squeak are not reentrant.  A block that is executing--or whose
execution is not properly terminated--cannot be evaluated.  The VM will refuse
to evaluate any BlockContext whose program counter is not at the beginning
of the block (its "pc" instance variable must be equal to the value of the instance
variable "startpc", otherwise the #value primitive will fail).

The primitive failure actually provides an opportunity to do something about
this problem.  Specifically, when the #value primitive fails, one can simply
make a copy of the block, set the copy's pc to startpc, and then reevaluate
the block.  It is also a good idea to send the message #fixTemps to the
copy, since it is very likely that reentrant use of a block will want closure
semantics for the block.

Here's the actual code to execute the strategy outlined above:

BlockContext>reset
    pc := startpc

BlockContext>copy
    ^self shallowCopy postCopy

BlockContext>postCopy
    "If you want a copy of the block, you will also want:
        the copy to bind to the current values of its outer references, and
        the program counter of the copy to be reset to the beginning"
    self reset.
    self fixTemps

BlockContext>basicValue
    <primitive: 81>
    ^self basicValueWithArguments: #()

BlockContext>basicValueWithArguments: anArray
    <primitive: 82>
    ^self valueError

BlockContext>valueWithArguments: anArray
    <primitive: 82>
    ^anArray size == 0
        ifTrue: [self copy basicValue "the primitive may have failed because the argArray was size 0"]
        ifFalse: [self copy basicValueWithArguments: anArray]


With the changes above, the following code can be executed successfully:

| block |
block := [:index | index > 0 ifTrue: [block value: index - 1]].
block value: 10.

--Alan





More information about the Squeak-dev mailing list