[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 01:43:01 UTC 2012


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


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


More information about the Vm-dev mailing list