---------- Forwarded message ---------- From: Eliot Miranda <[hidden email]> 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 <[hidden email]> Hi Igor, On Mon, Sep 7, 2009 at 10:29 AM, Igor Stasenko <[hidden email]> wrote: > > 2009/9/7 Bert Freudenberg <[hidden email]>: > > > > On 07.09.2009, at 18:40, Randal L. Schwartz wrote: > > > >>>>>>> "Igor" == Igor Stasenko <[hidden email]> 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 :) 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. 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. > |
On Mon, Sep 07, 2009 at 12:13:07PM -0700, Eliot Miranda wrote: > > 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. <snip> > 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 I opened a Mantis issue to track this, and uploaded Eliot's fileouts: Mantis 7429: Add Mirror Primitives to the VM http://bugs.squeak.org/view.php?id=7429 A bit of work will be required to integrate the mirror primitives in MirrorPrimitivesVM.st into the base Squeak VM (this has not yet been done). Note that unit tests for the mirror primitives are present in the Squeak trunk image, which of course fail without VM support, so there is some interest in getting this integrated into the VM to support the tests in the image. Dave |
Free forum by Nabble | Edit this page |