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

Eliot Miranda eliot.miranda at gmail.com
Mon Sep 7 19:25:53 UTC 2009


On Mon, Sep 7, 2009 at 11:56 AM, Eliot Miranda<eliot.miranda at gmail.com> wrote:
> 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
> correctly.
>
>
> 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
> affected.
>
> 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
>    ^activeProcess effectiveProcess ifNil: [activeProcess]
>
> I'll try and get round to this soon.

That appeared to be very easy, because the debugger is well-factored,
deferring to its interruptedProcess for all execution.  care to bang
on the attached?  The definition of process is probably wrong for your
image so integrate that carefully.


>
>
> 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.
>
> best
> Eliot
>
>>
>> >
>> > - Bert -
>> >
>>
>>
>> --
>> Best regards,
>> Igor Stasenko AKA sig.
>>
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: effectiveProcess.st
Type: application/octet-stream
Size: 2441 bytes
Desc: not available
Url : http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20090907/5af7eb7e/effectiveProcess.obj


More information about the Squeak-dev mailing list