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

Mariano Martinez Peck marianopeck at gmail.com
Wed Jan 25 13:31:25 UTC 2012


On Wed, Jan 25, 2012 at 2:21 PM, 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?
>

With my second attempt (the one of reusing the same compiled method and
changing the number of arguments) I guess it is quite fast. I have to do
that, but for example, I avoid the lookup. So if I am not missing something
I should be more or less as fast as the original version. Am I missing
something?


> I.e., the code should work everywhere, right?
>
>
Yes, because in Cog it will use the primitive and in previous VM the
primitive will fail and "rc" will be in nil, and hence the smalltalk code
will be executed.


>  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 :-)
>
>
In my second attempt they are not called temporal. There is
#tryNamedPrimitiveTemplateMethod
Is it beter?

Thanks.


> 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
>
>
>


-- 
Mariano
http://marianopeck.wordpress.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20120125/1e00dcaf/attachment-0001.htm


More information about the Vm-dev mailing list