[Vm-dev] Fwd: Mirror primitives [Was The better debugger support by extending an Object protocol]

Eliot Miranda eliot.miranda at gmail.com
Mon Sep 7 19:13:07 UTC 2009

---------- Forwarded message ----------
From: Eliot Miranda <eliot.miranda at gmail.com>
Date: Mon, Sep 7, 2009 at 11:56 AM
Subject: Mirror primitives [Was The better debugger support by
extending an Object protocol]
To: The general-purpose Squeak developers list
<squeak-dev at lists.squeakfoundation.org>

Hi Igor,

On Mon, Sep 7, 2009 at 10:29 AM, Igor Stasenko <siguctua at gmail.com> wrote:
> 2009/9/7 Bert Freudenberg <bert at freudenbergs.de>:
> >
> > On 07.09.2009, at 18:40, Randal L. Schwartz wrote:
> >
> >>>>>>> "Igor" == Igor Stasenko <siguctua at gmail.com> writes:
> >>
> >> Igor> Here is the default implementation of
> >>
> >> Object> debugPrintOn: aStream
> >> Igor>   ^ self printOn: aStream
> >>
> >> I like it, but I don't like the name.  It conjurs up the idea of debugging
> >> the #printOn: method itself.
> >>
> >> maybe #printForDebuggerOn: ?
> >
> >
> > It matches the other methods like #longPrintOn: though.
> >
> > Also that would imply only the debugger invokes it, when it's clearly
> > appropriate for any purpose.
> >
> > However, apart from this bike shedding ;) do others think it's a good idea
> > in general? IMHO #printOn: is primarily used for debugging anyway so I
> > wouldn't really expect a separate debug print method to be needed. Debugging
> > transparent proxies isn't for the faint-of-heart anyway, so these developers
> > can adapt their tools and proxies I would guess. OTOH there is precedence in
> > e.g. #asExplorerString, which exists solely to get rid of the quotes
> > enclosing strings for aesthetic reasons ...
> >
> I agree with you Bert, that we should consider if its really necessary.
> While #printOn: is used by most code for debugging, some of the code
> using it to serialize object to textual stream, so the #printOn: usage
> is much more generic than just debugging.
> As for debugging the transparent proxies - yes you can make own
> tools.. but this means reimplementing/hacking
> other tools , like debugger, inspector and so on, which will probably
> end up with similar solution to what i proposing.
> For example, there was a point of discrepancy with debugging the code
> which uses Magma.
> The magma forwarding proxy reifying the object once the first real
> message is sent to it.
> And the problem with such a proxy, that you can't use them in certain
> situations, like:
> self perform: aSelectorProxied with: #foo
> because #perform doesn't sends the messages to aSelectorProxied and
> primitive fails. But then, when you entering the debugger and trying
> to figure out why its not working - a proxy becomes a real object when
> it printed out.. and so you can't debug the error using debugger.
> Which leaves you to wonder, why code works in debugger, but not
> working at run time :)

I have fixes for this integrated in Qwaq.  This is work I did for
VisualWorks a while back.  The idea is to add a set of mirror
primitives, so called because they do reflection, to ContextPart.
These primitives implement the basic operations of the object model
needed for execution simulation, fetching an object's class, accessing
its named and indexed instance variables, and the number of indexed
instance variables, sending a message, but they take the object
operated on as a parameter and so do function without sending messages
to that object.  These primitives are then used by the execution
simulation machinery to correctly simulate the execution of the
virtual machine irrespective of the class and/or messages implemented
by the receiver.

For example, (eschewing HTML for Bert's contentment)

ContextPart methods for mirror primitives
object: anObject instVarAt: anIndex
       "Primitive. Answer a fixed variable in an object. The numbering of the
        variables corresponds to the named instance variables. Fail if the index
        is not an Integer or is not the index of a fixed variable.
Essential for the
        debugger. See  Object documentation whatIsAPrimitive."

       <primitive: 73>
       "Access beyond fixed variables."
       ^self object: anObject basicAt: anIndex - (self objectClass:
anObject) instSize

object: anObject instVarAt: anIndex put: aValue
       "Primitive. Store a value into a fixed variable in the argument anObject.
        The numbering of the variables corresponds to the named instance
        variables.  Fail if the index is not an Integer or is not the index of a
        fixed variable.  Answer the value stored as the result. Using this
        message violates the  principle that each object has sovereign control
        over the storing of values into its instance variables.
Essential for the
        debugger. See Object documentation whatIsAPrimitive."

       <primitive: 74>
       "Access beyond fixed fields"
       ^self object: anObject basicAt: anIndex - (self objectClass:
anObject) instSize put: aValue

ContextPart methods for instruction decoding
pushReceiverVariable: offset
       "Simulate the action of bytecode that pushes the contents of
the receiver's
       instance variable whose index is the argument, index, on the
top of the stack."

       self push: (self object: self receiver instVarAt: offset + 1)

popIntoReceiverVariable: offset
       "Simulate the action of bytecode that removes the top of the stack and
       stores it into an instance variable of my receiver."

       self object: self receiver instVarAt: offset + 1 put: self pop

storeIntoReceiverVariable: offset
       "Simulate the action of bytecode that stores the top of the stack into an
       instance variable of my receiver."

       self object: self receiver instVarAt: offset + 1 put: self top

The attached change set for the image level code is also conflated
with changes that allow the debugger to set the primitive error code

The VM also needs to implement the primitives.  If the order of the
arguments are the same as those of the corresponding non-reflective
primitive (e.g. aContext object: theReceiver instVarAt: index put:
value has the same order as theReceiver instVarAt: index put: value)
and the primitive pops back the stack using self pop: argumentCount +
1, one can use the same VM primitive implementations as the
non-reflective ones and so avoid needing extra primitives.

However, not all primitives are correctly implemented; e.g. at: and
at:put: are, but size is not.  So before we can use this there is some
work to do in the standard VMs.  I'm attaching here the implementation
in the Stack VM which will require some back porting to the standard
VM.  None of these changes has performance implications because the
special selector impelmentations of at: at:put: size and #== are not

With the above changes one can safely step through code that uses
proxies that do not inherit from Object, or even ProtoObject.  I still
need to implement a PrimitiveObjectInspector, or use the mirror
primitives in implementing the Inspector.  However, there is one more
important thing needed in the debugger which these changes do not
address and that is the value of Processor activeProcess within  the
debugger.  e.g. "print it" the following:

| thisProcessOutsideTheDebugger thisProcessInsideTheDebugger |
thisProcessOutsideTheDebugger := Processor activeProcess.
self halt.
thisProcessInsideTheDebugger := Processor activeProcess.
'Send to here (Into) then proceed'.
thisProcessOutsideTheDebugger == thisProcessInsideTheDebugger

This will potentially break debugging of servers that maintain process
pools.  Andreas has proposed a very simple fix for this.  Add an
instance variable to Process called, e.g. effectiveProcess, which is
nil in normal processes.  When the debugger runs it sets
effectiveProcess to that of the process which it is debugging and
Processor activeProcess is implemented as something like

ProcessorScheduler methods for accessing
   ^activeProcess effectiveProcess ifNil: [activeProcess]

I'll try and get round to this soon.

I'm posting this rather than integrating because a) the VMs need to
get updated before we can use the image level code and, b) the VM
folks need code to test their VMs with.  I'm happy to integrate the
image-level changes once the VMs have been upgraded.


> >
> > - Bert -
> >
> --
> Best regards,
> Igor Stasenko AKA sig.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: MirrorPrimitives.st
Type: application/octet-stream
Size: 24501 bytes
Desc: not available
Url : http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20090907/6bff7d97/MirrorPrimitives-0001.obj
-------------- next part --------------
A non-text attachment was scrubbed...
Name: MirrorPrimitivesVM.st
Type: application/octet-stream
Size: 11208 bytes
Desc: not available
Url : http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20090907/6bff7d97/MirrorPrimitivesVM-0001.obj

More information about the Vm-dev mailing list