[Vm-dev] Re: [Pharo-project] is there a way to avoid all the #tryNamedPrimitive:with: * in ProtoObject

Eliot Miranda eliot.miranda at gmail.com
Wed Jan 25 17:48:39 UTC 2012


On Wed, Jan 25, 2012 at 5:21 AM, Andreas Raab <andreas.raab at gmx.de> wrote:

>
>  Hi Eliot -
>
> On 1/25/2012 2:43, Eliot Miranda wrote:
>
> On Tue, Jan 24, 2012 at 2:02 PM, Mariano Martinez Peck <
> marianopeck at gmail.com> wrote:
>
>>
>> sorry...here is the attached.
>>
>
>  OK. What you've done will work.
>
>
> I actually quite like it. Getting rid of all those methods in class
> ProtoObject is definitely a good thing. Is there any downside other than
> some possible performance issues? I.e., the code should work everywhere,
> right?
>

Right.  The primitive I implemented at Qwaq/Teleplace
(ContextPart>>#tryNamedPrimitiveIn:for:withArgs:) makes these methods
obsolete but since this primitive isn't yet in the standard VM the body
uses those old methods in case the primitive doesn't exist.  As soon as the
primitive is in the standard VM as well there's neither no need for those
methods in ProtoObject nor the need to synthesize a method on each use.
 The synthesizing a method approach has a nice conceptual simplicity.  It
doesn't need a special primitive, and uses machinery that already exists.
 But IIRC we decided to go the primitive route because
ContextPart>>#tryPrimitiveFor:receiver:args: already existed and provided a
model.


>
>  Some criticism: Since the method is new the flushCache should be
> unneeded.  I think either copying a template method (e.g. stored in a class
> variable) and  changing its argument count, or creating a method directly
> (look at the generate: method) would be much faster.  Speed can be
> important in the debugger.
>
>
> More important in my view is the misuse of the term "temporal" in the
> method names. I find it quite confusing to read about "temporal" compiled
> methods :-)
>
> Cheers,
>   - Andreas
>
>
>
>> On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <
>> marianopeck at gmail.com> wrote:
>>
>>>
>>>
>>>>>>  Analogously, one needs a way of invoking named primitives in the
>>>>>> debugger, and using tryNamedPrimitive[:with:with:...] et al has exactly the
>>>>>> same weaknesses as tryPrimitiveN above.  So introducing a primitive to run
>>>>>> named primitives is in keeping with tryPrimitive:withArgs:.  Using the
>>>>>> VisualWorks approach is feasible but violates Occam's razor.
>>>>>>
>>>>>
>>>>> What what about temporally (to be removed in the future) just when we
>>>>> are using older VMs?
>>>>>
>>>>
>>>>  If temporary, then fine.  But its all work :)
>>>>
>>>
>>>
>>> Well...writing papers can be boring ;)
>>> Please, could you take a look to the attached .cs?  I tried to do what I
>>> had in mind. Since this part of the system is new for me, I have not sure
>>> it is correct, nor how to test it. So far what I did for testing it is to
>>> take the  #tryNamedPrimitiveIn: aCompiledMethod for: aReceiver withArgs:
>>> arguments
>>> and (temporally) remove the <primitive: 218 error: ec> and define 'ec'
>>> as a temporal variable. Since it will be nil, the following code will be
>>> executed.
>>> Then I put a halt in #open: fileName forWrite: writeMode   from
>>> StandardFileStream and then I do it:
>>> FileDirectory default forceNewFileNamed: 'xxxxx'.
>>> Once in the debugger, I went to:
>>>
>>> StandardFileStream retryWithGC:[self primOpen: f writable: writeMode]
>>>                     until:[:id| id notNil]
>>>                     forFileNamed: fileName.
>>>
>>> did a "through" in the close, and be sure I could do "into" and "step"
>>> for #self primOpen: f writable: writeMode  (which is a named primitive).
>>>
>>> is this ok?
>>>
>>> Thanks Eliot!
>>>
>>>
>>>
>>>>
>>>>
>>>>>
>>>>>
>>>>>>
>>>>>>  Why do we need them in ProtoObject?
>>>>>>>
>>>>>>
>>>>>>  Once tryNamedPrimitiveIn:for:withArgs: is implemented in all
>>>>>> relevant virtual machines we don't need them.  You'll notice that there is
>>>>>> no trace of the tryPrimitiveN methods anymore, even though they're in
>>>>>> Smalltalk-80.
>>>>>>
>>>>>>
>>>>>>> Because I'm not sure that adding primitive to VM is always a good
>>>>>>> solution.
>>>>>>>
>>>>>>
>>>>>>  Agreed.  But it is in keeping with the primitive for invoking
>>>>>> numbered primitives,  tryPrimitive:withArgs:.
>>>>>>
>>>>>>
>>>>>>  HTH
>>>>>> Eliot
>>>>>>
>>>>>>
>>>>>>> Stef
>>>>>>>
>>>>>>> > On Mon, Jan 23, 2012 at 8:52 AM, Mariano Martinez Peck <
>>>>>>> marianopeck at gmail.com> wrote:
>>>>>>> > Hi guys. I usually like to take a look to ProtoObject and see what
>>>>>>> is really needed for the minimal object. But having 30% of the methods
>>>>>>> being  #tryNamedPrimitive:with: *  is not fun.
>>>>>>> > So...I wonder, do you think there could be another way so that to
>>>>>>> avoid having all those methods in ProtoObject ?
>>>>>>> >
>>>>>>> > Yes there is.  I implemented primitive 218 in Cog,
>>>>>>> primitiveDoNamedPrimitiveWithArgs, which is accessed via
>>>>>>> >
>>>>>>> >
>>>>>>> >               tryNamedPrimitiveIn: aCompiledMethod for: aReceiver
>>>>>>> withArgs: arguments
>>>>>>> >                       | selector theMethod spec receiverClass |
>>>>>>> >                       <primitive: 218 error: ec>
>>>>>>> >                       ec ifNotNil:
>>>>>>> >                               ["If ec is an integer other than -1
>>>>>>> there was a problem with primitive 218,
>>>>>>> >                                 not with the external primitive
>>>>>>> itself.  -1 indicates a generic failure (where
>>>>>>> >                                 ec should be nil) but ec = nil
>>>>>>> means primitive 218 is not implemented.  So
>>>>>>> >                                 interpret -1 to mean the external
>>>>>>> primitive failed with a nil error code."
>>>>>>> >                                ec isInteger ifTrue:
>>>>>>> >                                       [ec = -1
>>>>>>> >                                               ifTrue: [ec := nil]
>>>>>>> >                                               ifFalse: [self
>>>>>>> primitiveFailed]].
>>>>>>> >                               ^{PrimitiveFailToken. ec}].
>>>>>>> >                       "Assume a nil error code implies the
>>>>>>> primitive is not implemented and fall back on the old code."
>>>>>>> >                       "Hack. Attempt to execute the named
>>>>>>> primitive from the given compiled method"
>>>>>>> >                       arguments size > 8 ifTrue:
>>>>>>> >                               [^{PrimitiveFailToken. nil}].
>>>>>>> >                       selector := #(
>>>>>>> >                               tryNamedPrimitive
>>>>>>> >                               tryNamedPrimitive:
>>>>>>> >                               tryNamedPrimitive:with:
>>>>>>> >                               tryNamedPrimitive:with:with:
>>>>>>> >                               tryNamedPrimitive:with:with:with:
>>>>>>> >
>>>>>>> tryNamedPrimitive:with:with:with:with:
>>>>>>> >
>>>>>>> tryNamedPrimitive:with:with:with:with:with:
>>>>>>> >
>>>>>>> tryNamedPrimitive:with:with:with:with:with:with:
>>>>>>> >
>>>>>>> tryNamedPrimitive:with:with:with:with:with:with:with:) at: arguments size+1.
>>>>>>> >                       receiverClass := self objectClass: aReceiver.
>>>>>>> >                       theMethod := receiverClass lookupSelector:
>>>>>>> selector.
>>>>>>> >                       theMethod == nil ifTrue:
>>>>>>> >                               [^{PrimitiveFailToken. nil}].
>>>>>>> >                       spec := theMethod literalAt: 1.
>>>>>>> >                       spec replaceFrom: 1 to: spec size with:
>>>>>>> (aCompiledMethod literalAt: 1) startingAt: 1.
>>>>>>> >                       Smalltalk unbindExternalPrimitives.
>>>>>>> >                       ^self object: aReceiver perform: selector
>>>>>>> withArguments: arguments inClass: receiverClass
>>>>>>> >
>>>>>>> > (cf tryPrimitive: withArgs:) and used in
>>>>>>> >
>>>>>>> >
>>>>>>> >               doPrimitive: primitiveIndex method: meth receiver:
>>>>>>> receiver args: arguments
>>>>>>> >                       "Simulate a primitive method whose index is
>>>>>>> primitiveIndex.  The simulated receiver
>>>>>>> >                        and arguments are given as arguments to
>>>>>>> this message. Any primitive which provokes
>>>>>>> >                        execution needs to be intercepted and
>>>>>>> simulated to avoid execution running away."
>>>>>>> >
>>>>>>> >                       | value |
>>>>>>> >                       "If successful, push result and return
>>>>>>> resuming context, else ^ { PrimitiveFailToken. errorCode }"
>>>>>>> >                       (primitiveIndex = 19) ifTrue:
>>>>>>> >                               [ToolSet
>>>>>>> >                                       debugContext: self
>>>>>>> >                                       label:'Code simulation error'
>>>>>>> >                                       contents: nil].
>>>>>>> >
>>>>>>> >                       "ContextPart>>blockCopy:; simulated to get
>>>>>>> startpc right"
>>>>>>> >                       (primitiveIndex = 80 and: [(self
>>>>>>> objectClass: receiver) includesBehavior: ContextPart])
>>>>>>> >                               ifTrue: [^self push: ((BlockContext
>>>>>>> newForMethod: receiver method)
>>>>>>> >
>>>>>>> home: receiver home
>>>>>>> >
>>>>>>> startpc: pc + 2
>>>>>>> >
>>>>>>> nargs: (arguments at: 1))].
>>>>>>> >                       (primitiveIndex = 81 and: [(self
>>>>>>> objectClass: receiver) == BlockContext]) "BlockContext>>value[:value:...]"
>>>>>>> >                               ifTrue: [^receiver pushArgs:
>>>>>>> arguments from: self].
>>>>>>> >                       (primitiveIndex = 82 and: [(self
>>>>>>> objectClass: receiver) == BlockContext]) "BlockContext>>valueWithArguments:"
>>>>>>> >                               ifTrue: [^receiver pushArgs:
>>>>>>> arguments first from: self].
>>>>>>> >                       primitiveIndex = 83 "afr 9/11/1998 19:50"
>>>>>>> "Object>>perform:[with:...]"
>>>>>>> >                               ifTrue: [^self send: arguments first
>>>>>>> >                                                       to: receiver
>>>>>>> >                                                       with:
>>>>>>> arguments allButFirst
>>>>>>> >                                                       super:
>>>>>>> false].
>>>>>>> >                       primitiveIndex = 84 "afr 9/11/1998 19:50 &
>>>>>>> eem 8/18/2009 17:04" "Object>>perform:withArguments:"
>>>>>>> >                               ifTrue: [^self send: arguments first
>>>>>>> >                                                       to: receiver
>>>>>>> >                                                       with:
>>>>>>> (arguments at: 2)
>>>>>>> >                                                       startClass:
>>>>>>> nil].
>>>>>>> >                       primitiveIndex = 100 "eem 8/18/2009 16:57"
>>>>>>> "Object>>perform:withArguments:inSuperclass:"
>>>>>>> >                               ifTrue: [^self send: arguments first
>>>>>>> >                                                       to: receiver
>>>>>>> >                                                       with:
>>>>>>> (arguments at: 2)
>>>>>>> >                                                       startClass:
>>>>>>> (arguments at: 3)].
>>>>>>> >
>>>>>>> >                       "Mutex>>primitiveEnterCriticalSection
>>>>>>> >
>>>>>>>  Mutex>>primitiveTestAndSetOwnershipOfCriticalSection"
>>>>>>> >                       (primitiveIndex = 186 or: [primitiveIndex =
>>>>>>> 187]) ifTrue:
>>>>>>> >                               [| active effective |
>>>>>>> >                                active := Processor activeProcess.
>>>>>>> >                                effective := active
>>>>>>> effectiveProcess.
>>>>>>> >                                "active == effective"
>>>>>>> >                                value := primitiveIndex = 186
>>>>>>> >                                                       ifTrue:
>>>>>>> [receiver primitiveEnterCriticalSectionOnBehalfOf: effective]
>>>>>>> >                                                       ifFalse:
>>>>>>> [receiver primitiveTestAndSetOwnershipOfCriticalSectionOnBehalfOf:
>>>>>>> effective].
>>>>>>> >                                ^(value isArray
>>>>>>> >                                   and: [value size = 2
>>>>>>> >                                   and: [value first ==
>>>>>>> PrimitiveFailToken]])
>>>>>>> >                                       ifTrue: [value]
>>>>>>> >                                       ifFalse: [self push: value]].
>>>>>>> >
>>>>>>> >                       primitiveIndex = 188 ifTrue: "eem 5/27/2008
>>>>>>> 11:10 Object>>withArgs:executeMethod:"
>>>>>>> >                               [^MethodContext
>>>>>>> >                                       sender: self
>>>>>>> >                                       receiver: receiver
>>>>>>> >                                       method: (arguments at: 2)
>>>>>>> >                                       arguments: (arguments at:
>>>>>>> 1)].
>>>>>>> >
>>>>>>> >                       "Closure primitives"
>>>>>>> >                       (primitiveIndex = 200 and: [self ==
>>>>>>> receiver]) ifTrue:
>>>>>>> >
>>>>>>> "ContextPart>>closureCopy:copiedValues:; simulated to get startpc right"
>>>>>>> >                               [^self push: (BlockClosure
>>>>>>> >
>>>>>>> outerContext: receiver
>>>>>>> >
>>>>>>> startpc: pc + 2
>>>>>>> >
>>>>>>> numArgs: arguments first
>>>>>>> >
>>>>>>> copiedValues: arguments last)].
>>>>>>> >                       ((primitiveIndex between: 201 and: 205)
>>>>>>>              "BlockClosure>>value[:value:...]"
>>>>>>> >                       or: [primitiveIndex between: 221 and: 222])
>>>>>>> ifTrue: "BlockClosure>>valueNoContextSwitch[:]"
>>>>>>> >                               [^receiver
>>>>>>> simulateValueWithArguments: arguments caller: self].
>>>>>>> >                       primitiveIndex = 206 ifTrue:
>>>>>>>                            "BlockClosure>>valueWithArguments:"
>>>>>>> >                               [^receiver
>>>>>>> simulateValueWithArguments: arguments first caller: self].
>>>>>>> >
>>>>>>> >                       primitiveIndex = 118 ifTrue:
>>>>>>> "tryPrimitive:withArgs:; avoid recursing in the VM"
>>>>>>> >                               [(arguments size = 2
>>>>>>> >                                and: [arguments first isInteger
>>>>>>> >                                and: [arguments last class ==
>>>>>>> Array]]) ifFalse:
>>>>>>> >                                       [^ContextPart
>>>>>>> primitiveFailTokenFor: nil].
>>>>>>> >                                ^self doPrimitive: arguments first
>>>>>>> method: meth receiver: receiver args: arguments last].
>>>>>>> >
>>>>>>> >                       value := primitiveIndex = 120 "FFI method"
>>>>>>> >                                               ifTrue: [(meth
>>>>>>> literalAt: 1) tryInvokeWithArguments: arguments]
>>>>>>> >                                               ifFalse:
>>>>>>> >
>>>>>>> [primitiveIndex = 117 "named primitives"
>>>>>>> >
>>>>>>> ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments]
>>>>>>> >
>>>>>>> ifFalse:
>>>>>>> >
>>>>>>>     [receiver tryPrimitive: primitiveIndex withArgs: arguments]].
>>>>>>> >                       ^(value isArray
>>>>>>> >                           and: [value size = 2
>>>>>>> >                           and: [value first ==
>>>>>>> PrimitiveFailToken]])
>>>>>>> >                               ifTrue: [value]
>>>>>>> >                               ifFalse: [self push: value]
>>>>>>> >
>>>>>>> > (find attached).  But these need implementing in the standard VM
>>>>>>> before they can be used in Pharo, Squeak, etc.
>>>>>>> >
>>>>>>> >
>>>>>>> > Thanks
>>>>>>> >
>>>>>>> > --
>>>>>>> > Mariano
>>>>>>> > http://marianopeck.wordpress.com
>>>>>>> >
>>>>>>> >
>>>>>>> >
>>>>>>> >
>>>>>>> > --
>>>>>>> > best,
>>>>>>> > Eliot
>>>>>>> >
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>>  --
>>>>>> best,
>>>>>> Eliot
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Mariano
>>>>> http://marianopeck.wordpress.com
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>>  --
>>>> best,
>>>> Eliot
>>>>
>>>>
>>>>
>>>
>>>
>>> --
>>> Mariano
>>> http://marianopeck.wordpress.com
>>>
>>>
>>
>>
>> --
>> Mariano
>> http://marianopeck.wordpress.com
>>
>>
>>
>
>
>  --
> best,
> Eliot
>
>
>


-- 
best,
Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20120125/5a4c9176/attachment-0001.htm


More information about the Vm-dev mailing list