[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 21:09:14 UTC 2009


Oops.  I left out popTo: et al and so Processor activeProcess would be
wrong inside unwind blocks evaluated in the debugger.  So find v2
attached...


On Mon, Sep 7, 2009 at 12:25 PM, Eliot Miranda<eliot.miranda at gmail.com> wrote:
> 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: 4228 bytes
Desc: not available
Url : http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20090907/6460e3b7/effectiveProcess.obj


More information about the Squeak-dev mailing list