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

Eliot Miranda eliot.miranda at gmail.com
Tue Jan 24 20:17:44 UTC 2012


On Tue, Jan 24, 2012 at 12:41 AM, Mariano Martinez Peck <
marianopeck at gmail.com> wrote:

>
>
>
> On Mon, Jan 23, 2012 at 10:22 PM, Eliot Miranda <eliot.miranda at gmail.com>wrote:
>
>>
>>
>>
>> On Mon, Jan 23, 2012 at 12:57 PM, Stéphane Ducasse <
>> stephane.ducasse at inria.fr> wrote:
>>
>>> Hi elliot
>>>
>>> What are these tryNamedPrimitive?
>>>
>>
>> The methods in ProtoObject implement invoking primitives in the context
>> of the debugger.
>>
>
> Ok, I was not that far :)
>
>
>>  The debugger used to use methods in Object, tryPrimitive0,
>> tryPrimitive1: tryPrimitive2:with: et al, to invoke normal primitives.  The
>> debugger would choose the tryPrimitive1: method with the right number of
>> arguments, modify its header to change its primitive number of the desired
>> primitive, and then call it to invoke the primitive.  This is not
>> reentrant.  If one is trying to debug the debugger then the tryPrimitive:
>> method can be modified by the debugger that is debugging the debugger that
>> is in the process of editing the tryPrimitive: method.  To fix this, and
>> eliminate the tryPrimitiveN methods, someone introduced the
>> tryPrimitive:withArgs: primitive.  (Note that in VisualWorks we solved this
>> by creating a method on the fly to invoke a given primitive and evaluating
>> it using a primitive that did the same thing as withArgs:executeMethod:).
>>
>
> Eliot, isn't that what I have suggested in my previous email? at least as
> I can understand, that was my idea. In fact, since even if we have this new
> primitive, we have to keep those methods because Pharo could be opened in
> older VMs, wouldn't it make sense such proposal? because that way we can
> remove those methods.
> So...if we are in latest cog, we use the primitive, otherwise, we generate
> the CM on the fly and we execute it. In both cases, we do not use these
> methods.
>

Sure.


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


>
>
>>
>> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20120124/5f13542b/attachment-0001.htm


More information about the Vm-dev mailing list