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

Eliot Miranda eliot.miranda at gmail.com
Mon Jan 23 13:56:56 EST 2012

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
  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
arguments size > 8 ifTrue:
[^{PrimitiveFailToken. nil}].
selector := #(
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:

(cf tryPrimitive: withArgs:) and used in

doPrimitive: primitiveIndex method: meth receiver: receiver args: arguments
"Simulate a primitive method whose index is primitiveIndex.  The simulated
 and arguments are given as arguments to this message. Any primitive which
 execution needs to be intercepted and simulated to avoid execution running
 | value |
"If successful, push result and return resuming context, else ^ {
PrimitiveFailToken. errorCode }"
(primitiveIndex = 19) ifTrue:
debugContext: self
label:'Code simulation error'
contents: nil].
 "ContextPart>>blockCopy:; simulated to get startpc right"
(primitiveIndex = 80 and: [(self objectClass: receiver) includesBehavior:
ifTrue: [^self push: ((BlockContext newForMethod: receiver method)
home: receiver home
startpc: pc + 2
nargs: (arguments at: 1))].
(primitiveIndex = 81 and: [(self objectClass: receiver) == BlockContext])
ifTrue: [^receiver pushArgs: arguments from: self].
(primitiveIndex = 82 and: [(self objectClass: receiver) == BlockContext])
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"
ifTrue: [^self send: arguments first
to: receiver
with: (arguments at: 2)
startClass: nil].
primitiveIndex = 100 "eem 8/18/2009 16:57"
ifTrue: [^self send: arguments first
to: receiver
with: (arguments at: 2)
startClass: (arguments at: 3)].
(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:
 ^(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
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:
[^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]
[primitiveIndex = 117 "named primitives"
ifTrue: [self tryNamedPrimitiveIn: meth for: receiver withArgs: arguments]
[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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.pharo.org/pipermail/pharo-dev_lists.pharo.org/attachments/20120123/52faf157/attachment-0001.html>

More information about the Pharo-dev mailing list