[squeak-dev] Implementing control operators

Eliot Miranda eliot.miranda at gmail.com
Wed Apr 13 22:59:46 UTC 2011


On Wed, Apr 13, 2011 at 3:42 PM, Frank Shearar <frank.shearar at angband.za.org
> wrote:

> On 2011/04/13 23:19, Eliot Miranda wrote:
>
>> Hi Frank,
>>
>>     you're committing a category error.  The space of bytecodes is
>> disjoint from the space of numbered primitives and they are entirely
>> unrelated.  The implementation of primitive 199 is given in e.g.
>> Interpreter class>>initializePrimitiveTable and is
>> primitiveMarkHandlerMethod, which itself is implemented as
>> primitiveFail, since (as the comment says) primitive 199 is only used to
>> mark a method as being an unwind-protect, not to change its invocation
>> semantics.  Bytecode 199 is indeed bytecodePrimClass and causes the VM
>> to fetch the class of the receiver (i.e. it is short-hand for sending
>> #class to the receiver, except that the message isn't looked up, and so
>> can't be overridden).  The sace of bytecodes is defined by e.g.
>> Interpreter class>>intiializeBytecodeTable.  Compare e.g. primitive 60
>> to bytecode 60 and the distinction should become clearer.
>>
>
> Ah! That was a silly mistake. I found initializeBytecodeTable by searching
> for methods containing '199', and leapt to my great confusion.
>
>
>  BTW, you should focus your understanding on how contexts work
>> (ContextPart & MethodContext). That's the fundamental, and above
>> contexts exceptions are implemented.  Anyone have a pointer to Peter
>> Deutsch's article on contexts ion the 1981 Byte issue?  That's a good
>> place to start.  Another place is the Blue Book's implementation chapter.
>>
>
> I have a fair idea on how contexts work, although I still need to figure
> out/find out how (and when) contexts are actually created. (More reading of
> VMMaker source is required.)
>

Effectively contexts are created when messages are activated.   Method
evaluation (see internalExecuteNewMethod and executeNewMethod) is a two step
process, primitive evaluation followed optionally by method activation.
 First the new method is examined to find out if it has a primitive, and if
it has then that primitive is executed.  If the primitive succeeds then its
result is returned to the sender and execution continues, without activating
the method.  If the primitive fails then the method is activated as if it
had no primitive.  A method is activated by creating a new context,
initialized with the new method, and the sender as the new context's sender,
moving the receiver and arguments of the message send from the sender
context to the new context and then continuing execution in the new context.
 See the section Contexts in the Blue
Book<http://www.mirandabanda.org/bluebook/bluebook_chapter27.html#Contexts27>.


Note, however that an efficient Smalltalk VM will /not/ create contexts on
activation, but defer creation until a context is referenced by the running
program, e.g. when creating a BlockClosure (the context being the closure's
home context), or when the programmer uses the thisContext pseudo-variable
explicitly.  That's one reason why Cog (and indeed the VisualWorks VM) is
much faster than the Interpreter.  And
this<http://www.mirandabanda.org/cogblog/2009/01/14/under-cover-contexts-and-the-big-frame-up/>goes
into the gory details.

HTH,
Eliot


> (At any rate, I know enough to have implemented a rough working
> implementation of shift/reset.)
>
> Randal mentions
> https://gforge.inria.fr/frs/download.php/26600/PBE2-Exceptions-2010-03-02.pdfand indeed, on page 24 I see what I _should_ have been looking at, namely
> _primitive_ 199, not _bytecode_ 199.
>
> I see that, for instance, using primitives to search for the handler
> context won't create more contexts in the call stack. When you're
> manipulating the current call stack that can be quite important, I would
> imagine?
>
> But I suppose I'm really asking this: is it _necessary_ to use primitive
> 199, or could one in _principle_ implement exception handling solely by
> in-image stack manipulation?
>

The VM needs to implement unwind-protect; one can't do that using in-image
manipulation, and unwind-protect is indicated by marking with primitive 198.
 But other than that, the use of the exception tag primitive 199 is just an
optimization, allowing the VM to perform relatively efficient search for
handlers.

best,
Eliot


> frank
>
>  On Wed, Apr 13, 2011 at 3:07 PM, Frank Shearar
>> <frank.shearar at angband.za.org <mailto:frank.shearar at angband.za.org>>
>> wrote:
>>
>>    I'm playing around with Danvy and Filinski's shift/reset operators,
>>    which allow a nice (lexically scoped) syntax for capturing partial
>>    continuations.
>>
>>    In particular, reset marks the stack in some way, and a later shift
>>    reifies the call stack between itself and reset as a function.
>>
>>    To that end, I'm delving into the guts of how exceptions work. I've
>>    a few questions:
>>
>>    First, I know that VMMaker (especially Interpreter
>>    class>>initializeBytecodeTable) lists all the known numbered
>>    primitives. In particular, BlockClosure>>on:do: uses <primitive: 199>.
>>
>>    on: exception do: handlerAction
>>    "Evaluate the receiver in the scope of an exception handler."
>>
>>            | handlerActive |
>>    <primitive: 199> "just a marker, fail and execute the following"
>>            handlerActive := true.
>>            ^ self value
>>
>>    and
>>
>>    bytecodePrimClass
>>            | rcvr |
>>            rcvr := self internalStackTop.
>>            self internalPop: 1 thenPush: (self fetchClassOf: rcvr).
>>            self fetchNextBytecode.
>>
>>    is the implementation of that bytecode.
>>
>>    But what's this really doing? Or, rather, how is what it's doing
>>    connected with marking a context so as to find an exception handler?
>>
>>    If it's purely a marker, could one use another primitive? (Other
>>    than "that's how we do it, and Things Will Break if something
>>    changes the primitive number". I can only find
>>    MethodContext>>isHandlerContext caring about the particular
>>    primitive number)
>>
>>    Could one, in principle at least, lose the primitive invocation and
>>    have an instvar isHandlerContext on ContextPart (MethodContext, more
>>    likely), and just repeatedly walk down the stack to find the handler
>>    rather than using another primitive to find the handler?
>>
>>    Secondly, what's handlerActive for in #on:do:? It's a local variable
>>    set and then never referenced. (No other method has 'handlerActive'
>>    in its source, in the base image.)
>>
>>    Thanks!
>>
>>    frank
>>
>>
>>
>>
>>
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20110413/3782ee5f/attachment.htm


More information about the Squeak-dev mailing list