On Jan 23, 2012, at 10:22 PM, Eliot Miranda wrote:
>
>
> On Mon, Jan 23, 2012 at 12:57 PM, Stéphane Ducasse
> <[email protected]> wrote:
> Hi elliot
>
> What are these tryNamedPrimitive?
>
> The methods in ProtoObject implement invoking primitives in the context of
> the debugger. 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:).
Thanks for the explanation.
I have another question
is this for invoking primitive directly? Or my question is why we
cannot simply call the method that is flagged as a primitive?
I started to read the interpreter of camillo and I did not arrive yet at
primitives :)
> 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.
You lost me. You mean that you want to avoid to have a primitive to execute
primitives?
>
> 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:.
Yes I see.
Thanks for the explanation.
>
>
> HTH
> Eliot
>
>
> Stef
>
> > On Mon, Jan 23, 2012 at 8:52 AM, Mariano Martinez Peck
> > <[email protected]> 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
>