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

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
36 messages Options
12
Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2
 


On Mon, Jan 23, 2012 at 8:52 AM, Mariano Martinez Peck <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2
 


On Mon, Jan 23, 2012 at 12:57 PM, Stéphane Ducasse <[hidden email]> 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:).

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.

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 <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

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

Mariano Martinez Peck
 


On Mon, Jan 23, 2012 at 10:22 PM, Eliot Miranda <[hidden email]> wrote:
 


On Mon, Jan 23, 2012 at 12:57 PM, Stéphane Ducasse <[hidden email]> 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.
 

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?
 

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 <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2
 


On Tue, Jan 24, 2012 at 12:41 AM, Mariano Martinez Peck <[hidden email]> wrote:
 


On Mon, Jan 23, 2012 at 10:22 PM, Eliot Miranda <[hidden email]> wrote:
 


On Mon, Jan 23, 2012 at 12:57 PM, Stéphane Ducasse <[hidden email]> 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 <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

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

Mariano Martinez Peck
 


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 <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

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

Mariano Martinez Peck
 
sorry...here is the attached.

On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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


TryNamedPrimitive.1.cs (3K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2
 


On Tue, Jan 24, 2012 at 2:02 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

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

Mariano Martinez Peck
 


On Wed, Jan 25, 2012 at 2:43 AM, Eliot Miranda <[hidden email]> wrote:
 


On Tue, Jan 24, 2012 at 2:02 PM, Mariano Martinez Peck <[hidden email]> 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.

True.
 
 I think either copying a template method (e.g. stored in a class variable) and  changing its argument count,

Let's see if I understand. I have attaached a new version that supposes to do this. I tested and seems to work.
Is it better?  If you agree, I can put a nice comment and commit.
 
or creating a method directly (look at the generate: method) would be much faster.  Speed can be important in the debugger.

I am not sure if I understood. Maybe you mean something along the lines of:

MethodNode new
selector: #tryNamedPrimitive:arg2:
arguments: (OrderedCollection with: (TempVariableNode new name: 'arg1' index: 0 type: 2 scope: 0; nowHasDef; nowHasRef; beMethodArg; yourself) with: (TempVariableNode new name: 'arg1' index: 0 type: 2 scope: 0; nowHasDef; nowHasRef; beMethodArg; yourself))
precedence: 3
temporaries: #()
block: BlockNode new
encoder: (EncoderForV3PlusClosures new
instVarNamed: 'class' put: UndefinedObject; yourself)
primitive: 117

and then send #generate:

but I get lost to get this working...the previous solution seems easier.

Thanks!


 

On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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


TryNamedPrimitiveSettingNumArgs.2.cs (3K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

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

Andreas.Raab
In reply to this post by Eliot Miranda-2
 
Hi Eliot -

On 1/25/2012 2:43, Eliot Miranda wrote:
On Tue, Jan 24, 2012 at 2:02 PM, Mariano Martinez Peck <[hidden email]> 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? I.e., the code should work everywhere, right?

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

Cheers,
  - Andreas



On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

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

Mariano Martinez Peck
 


On Wed, Jan 25, 2012 at 2:21 PM, Andreas Raab <[hidden email]> wrote:
 
Hi Eliot -

On 1/25/2012 2:43, Eliot Miranda wrote:
On Tue, Jan 24, 2012 at 2:02 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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

Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2
In reply to this post by Mariano Martinez Peck
 


On Wed, Jan 25, 2012 at 3:13 AM, Mariano Martinez Peck <[hidden email]> wrote:
 


On Wed, Jan 25, 2012 at 2:43 AM, Eliot Miranda <[hidden email]> wrote:
 


On Tue, Jan 24, 2012 at 2:02 PM, Mariano Martinez Peck <[hidden email]> 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.

True.
 
 I think either copying a template method (e.g. stored in a class variable) and  changing its argument count,

Let's see if I understand. I have attaached a new version that supposes to do this. I tested and seems to work.
Is it better?  If you agree, I can put a nice comment and commit.
 
or creating a method directly (look at the generate: method) would be much faster.  Speed can be important in the debugger.

I am not sure if I understood. Maybe you mean something along the lines of:

MethodNode new
selector: #tryNamedPrimitive:arg2:
arguments: (OrderedCollection with: (TempVariableNode new name: 'arg1' index: 0 type: 2 scope: 0; nowHasDef; nowHasRef; beMethodArg; yourself) with: (TempVariableNode new name: 'arg1' index: 0 type: 2 scope: 0; nowHasDef; nowHasRef; beMethodArg; yourself))
precedence: 3
temporaries: #()
block: BlockNode new
encoder: (EncoderForV3PlusClosures new
instVarNamed: 'class' put: UndefinedObject; yourself)
primitive: 117

and then send #generate:

No, I meant create the method directly as does the body of generate:using:.  e.g. if the method looks like
 
tryNamedPrimitiveWith: a with: b ... with: n
     <primitive: 'function to be filled in later' module: 'module to be filled in later'>
    ^ContextPart primitiveFailToken

then it looks something like

tempMethodForNamedPrimitive: functionName inModule: moduleName numArgs: nArgs

literals := { { moduleName. functionName. 0. 0. }.
 Smalltalk bindingOf: #ContextPart.
 #primitiveFailToken.
 self additionalMethodStateForNamedPrimitiveWithNArgs: nArgs.
 Smalltalk bindingOf: #Object }.
bytes := #( 17 "push lit var 1 (ContextPart)" 210 "send lit 2 with 0 args (primitiveFailToken)" 124 "return top" ).
method := aCompiledMethodClass
newBytes: bytes size
trailerBytes: CompiledMethodTrailer empty 
nArgs: nargs
nTemps: nargs
nStack: 0
nLits: literals size
primitive: 117.
1 to: literals size do: [:i | method literalAt: i put: (literals at: i)].
  0 to: bytes size - 1 do: [:i| method byteAt: method initialPC + i put: (bytes at: i + 1)].
  ^method

But since the bytecodes don't change with the argument count it is even faster to create the above, copy it and smash the selector and argument count into the copy.  MethodWrappers4.2 has an example of this kind of thing.

 
but I get lost to get this working...the previous solution seems easier.

Do you want to build Trabants or BMWs?  Documentation helps.
 

Thanks!


 

On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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





--
best,
Eliot

Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2
In reply to this post by Andreas.Raab
 


On Wed, Jan 25, 2012 at 5:21 AM, Andreas Raab <[hidden email]> wrote:
 
Hi Eliot -

On 1/25/2012 2:43, Eliot Miranda wrote:
On Tue, Jan 24, 2012 at 2:02 PM, Mariano Martinez Peck <[hidden email]> 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? I.e., the code should work everywhere, right?

Right.  The primitive I implemented at Qwaq/Teleplace (ContextPart>>#tryNamedPrimitiveIn:for:withArgs:) makes these methods obsolete but since this primitive isn't yet in the standard VM the body uses those old methods in case the primitive doesn't exist.  As soon as the primitive is in the standard VM as well there's neither no need for those methods in ProtoObject nor the need to synthesize a method on each use.  The synthesizing a method approach has a nice conceptual simplicity.  It doesn't need a special primitive, and uses machinery that already exists.  But IIRC we decided to go the primitive route because ContextPart>>#tryPrimitiveFor:receiver:args: already existed and provided a model.
 

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

Cheers,
  - Andreas



On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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





--
best,
Eliot

Reply | Threaded
Open this post in threaded view
|

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

Mariano Martinez Peck
In reply to this post by Eliot Miranda-2
 


On Wed, Jan 25, 2012 at 6:40 PM, Eliot Miranda <[hidden email]> wrote:
 


On Wed, Jan 25, 2012 at 3:13 AM, Mariano Martinez Peck <[hidden email]> wrote:
 


On Wed, Jan 25, 2012 at 2:43 AM, Eliot Miranda <[hidden email]> wrote:
 


On Tue, Jan 24, 2012 at 2:02 PM, Mariano Martinez Peck <[hidden email]> 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.

True.
 
 I think either copying a template method (e.g. stored in a class variable) and  changing its argument count,

Let's see if I understand. I have attaached a new version that supposes to do this. I tested and seems to work.
Is it better?  If you agree, I can put a nice comment and commit.
 
or creating a method directly (look at the generate: method) would be much faster.  Speed can be important in the debugger.

I am not sure if I understood. Maybe you mean something along the lines of:

MethodNode new
selector: #tryNamedPrimitive:arg2:
arguments: (OrderedCollection with: (TempVariableNode new name: 'arg1' index: 0 type: 2 scope: 0; nowHasDef; nowHasRef; beMethodArg; yourself) with: (TempVariableNode new name: 'arg1' index: 0 type: 2 scope: 0; nowHasDef; nowHasRef; beMethodArg; yourself))
precedence: 3
temporaries: #()
block: BlockNode new
encoder: (EncoderForV3PlusClosures new
instVarNamed: 'class' put: UndefinedObject; yourself)
primitive: 117

and then send #generate:

No, I meant create the method directly as does the body of generate:using:.  e.g. if the method looks like
 
tryNamedPrimitiveWith: a with: b ... with: n
     <primitive: 'function to be filled in later' module: 'module to be filled in later'>
    ^ContextPart primitiveFailToken

then it looks something like

tempMethodForNamedPrimitive: functionName inModule: moduleName numArgs: nArgs

literals := { { moduleName. functionName. 0. 0. }.
 Smalltalk bindingOf: #ContextPart.
 #primitiveFailToken.
 self additionalMethodStateForNamedPrimitiveWithNArgs: nArgs.
 Smalltalk bindingOf: #Object }.
bytes := #( 17 "push lit var 1 (ContextPart)" 210 "send lit 2 with 0 args (primitiveFailToken)" 124 "return top" ).
method := aCompiledMethodClass
newBytes: bytes size
trailerBytes: CompiledMethodTrailer empty 
nArgs: nargs
nTemps: nargs
nStack: 0
nLits: literals size
primitive: 117.
1 to: literals size do: [:i | method literalAt: i put: (literals at: i)].
  0 to: bytes size - 1 do: [:i| method byteAt: method initialPC + i put: (bytes at: i + 1)].
  ^method

But since the bytecodes don't change with the argument count it is even faster to create the above, copy it and smash the selector and argument count into the copy.  MethodWrappers4.2 has an example of this kind of thing.


Ok. I will try to give it a try to this approach as well.
But what happened with the version I attached in the previous email that uses a template method and just change the arguments number?
It looks quite fast since the only thing I have to do is to set the arguments number (which are bitAnd:, bitShift: and bitOr: only), and quite easy to understand at the same time.

 
 
but I get lost to get this working...the previous solution seems easier.

Do you want to build Trabants or BMWs?  

I didn't understand. Which solution which be each car?
 
Documentation helps.
 

I didn't understand either. If you refer to the fact I didn't put comments in the .cs I attached, I explicitly said in my previous email "If you agree, I can put a nice comment and commit.". It already took me the whole morning (yes, I am completly noob here) to do the version of changing the argument count, so I was waiting the confirmation in the solution before documenting it and make it better.
 
 

Thanks!


 

On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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





--
best,
Eliot





--
Mariano
http://marianopeck.wordpress.com

Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2
 


On Wed, Jan 25, 2012 at 9:57 AM, Mariano Martinez Peck <[hidden email]> wrote:
 


On Wed, Jan 25, 2012 at 6:40 PM, Eliot Miranda <[hidden email]> wrote:
 


On Wed, Jan 25, 2012 at 3:13 AM, Mariano Martinez Peck <[hidden email]> wrote:
 


On Wed, Jan 25, 2012 at 2:43 AM, Eliot Miranda <[hidden email]> wrote:
 


On Tue, Jan 24, 2012 at 2:02 PM, Mariano Martinez Peck <[hidden email]> 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.

True.
 
 I think either copying a template method (e.g. stored in a class variable) and  changing its argument count,

Let's see if I understand. I have attaached a new version that supposes to do this. I tested and seems to work.
Is it better?  If you agree, I can put a nice comment and commit.
 
or creating a method directly (look at the generate: method) would be much faster.  Speed can be important in the debugger.

I am not sure if I understood. Maybe you mean something along the lines of:

MethodNode new
selector: #tryNamedPrimitive:arg2:
arguments: (OrderedCollection with: (TempVariableNode new name: 'arg1' index: 0 type: 2 scope: 0; nowHasDef; nowHasRef; beMethodArg; yourself) with: (TempVariableNode new name: 'arg1' index: 0 type: 2 scope: 0; nowHasDef; nowHasRef; beMethodArg; yourself))
precedence: 3
temporaries: #()
block: BlockNode new
encoder: (EncoderForV3PlusClosures new
instVarNamed: 'class' put: UndefinedObject; yourself)
primitive: 117

and then send #generate:

No, I meant create the method directly as does the body of generate:using:.  e.g. if the method looks like
 
tryNamedPrimitiveWith: a with: b ... with: n
     <primitive: 'function to be filled in later' module: 'module to be filled in later'>
    ^ContextPart primitiveFailToken

then it looks something like

tempMethodForNamedPrimitive: functionName inModule: moduleName numArgs: nArgs

literals := { { moduleName. functionName. 0. 0. }.
 Smalltalk bindingOf: #ContextPart.
 #primitiveFailToken.
 self additionalMethodStateForNamedPrimitiveWithNArgs: nArgs.
 Smalltalk bindingOf: #Object }.
bytes := #( 17 "push lit var 1 (ContextPart)" 210 "send lit 2 with 0 args (primitiveFailToken)" 124 "return top" ).
method := aCompiledMethodClass
newBytes: bytes size
trailerBytes: CompiledMethodTrailer empty 
nArgs: nargs
nTemps: nargs
nStack: 0
nLits: literals size
primitive: 117.
1 to: literals size do: [:i | method literalAt: i put: (literals at: i)].
  0 to: bytes size - 1 do: [:i| method byteAt: method initialPC + i put: (bytes at: i + 1)].
  ^method

But since the bytecodes don't change with the argument count it is even faster to create the above, copy it and smash the selector and argument count into the copy.  MethodWrappers4.2 has an example of this kind of thing.


Ok. I will try to give it a try to this approach as well.
But what happened with the version I attached in the previous email that uses a template method and just change the arguments number?

That would be fine.  I didn't look.
 
It looks quite fast since the only thing I have to do is to set the arguments number (which are bitAnd:, bitShift: and bitOr: only), and quite easy to understand at the same time.

Agreed.
 

 
 
but I get lost to get this working...the previous solution seems easier.

Do you want to build Trabants or BMWs?  

I didn't understand. Which solution which be each car?

Compiling from source each time = trabant.  Synthesizing directly = vw.   Using a template method = bmw.  

(vw = VisualWorks ;) )
 
 
Documentation helps.
 

I didn't understand either. If you refer to the fact I didn't put comments in the .cs I attached, I explicitly said in my previous email "If you agree, I can put a nice comment and commit.". It already took me the whole morning (yes, I am completly noob here) to do the version of changing the argument count, so I was waiting the confirmation in the solution before documenting it and make it better.

I mean in general if one builds good quality code that is "clever" then that code needs to be documented.  Sometimes simple doesn't cut it (look at the complexity involved in making a VM fast).  So if simple doesn't cut it one must document.

 
 

Thanks!


 

On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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





--
best,
Eliot





--
Mariano
http://marianopeck.wordpress.com





--
best,
Eliot

Reply | Threaded
Open this post in threaded view
|

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

Mariano Martinez Peck
 


Ok. I will try to give it a try to this approach as well.
But what happened with the version I attached in the previous email that uses a template method and just change the arguments number?

That would be fine.  I didn't look.
 

Since I am quite newbie here and the change can be quite important, I would really appreciate if someone can take a look to the .cs so that I feel confident to commit it :)
 
 
but I get lost to get this working...the previous solution seems easier.

Do you want to build Trabants or BMWs?  

I didn't understand. Which solution which be each car?

Compiling from source each time = trabant.  Synthesizing directly = vw.   Using a template method = bmw.  

(vw = VisualWorks ;) )


:):):):)

Nice because it means that we found a fast solution yet quite understandable :)
 
 
 
Documentation helps.
 

I didn't understand either. If you refer to the fact I didn't put comments in the .cs I attached, I explicitly said in my previous email "If you agree, I can put a nice comment and commit.". It already took me the whole morning (yes, I am completly noob here) to do the version of changing the argument count, so I was waiting the confirmation in the solution before documenting it and make it better.

I mean in general if one builds good quality code that is "clever" then that code needs to be documented.  Sometimes simple doesn't cut it (look at the complexity involved in making a VM fast).  So if simple doesn't cut it one must document.

Agree. Once someone gives me the OK for my .cs, I will add comments and commit.

Thanks Eliot.
 

 
 

Thanks!


 

On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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





--
best,
Eliot





--
Mariano
http://marianopeck.wordpress.com





--
best,
Eliot





--
Mariano
http://marianopeck.wordpress.com

Reply | Threaded
Open this post in threaded view
|

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

stephane ducasse-2

for the record mariano, VW implementation of method wrapper had a template of method one for each number of possible args
and they reserved space in the compiled method to be able to binding the class name (from memory) so installing one was copy of the right template + homeClass + selector (not sure anymore) so it was quite fast and simple to read.

Stef

On Jan 25, 2012, at 7:36 PM, Mariano Martinez Peck wrote:

>
>
> Ok. I will try to give it a try to this approach as well.
> But what happened with the version I attached in the previous email that uses a template method and just change the arguments number?
>
> That would be fine.  I didn't look.
>  
>
> Since I am quite newbie here and the change can be quite important, I would really appreciate if someone can take a look to the .cs so that I feel confident to commit it :)
>  
>  
> but I get lost to get this working...the previous solution seems easier.
>
> Do you want to build Trabants or BMWs?  
>
> I didn't understand. Which solution which be each car?
>
> Compiling from source each time = trabant.  Synthesizing directly = vw.   Using a template method = bmw.  
>
> (vw = VisualWorks ;) )
>
>
> :):):):)
>
> Nice because it means that we found a fast solution yet quite understandable :)
>  
>  
>  
> Documentation helps.
>  
>
> I didn't understand either. If you refer to the fact I didn't put comments in the .cs I attached, I explicitly said in my previous email "If you agree, I can put a nice comment and commit.". It already took me the whole morning (yes, I am completly noob here) to do the version of changing the argument count, so I was waiting the confirmation in the solution before documenting it and make it better.
>
> I mean in general if one builds good quality code that is "clever" then that code needs to be documented.  Sometimes simple doesn't cut it (look at the complexity involved in making a VM fast).  So if simple doesn't cut it one must document.
>
> Agree. Once someone gives me the OK for my .cs, I will add comments and commit.
>
> Thanks Eliot.
>  
>
>  
>  
>
> Thanks!
>
>
>  
>
> On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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
>
>
>
>
>
> --
> best,
> Eliot
>
>
>
>
>
> --
> Mariano
> http://marianopeck.wordpress.com
>
>
>
>
>
> --
> best,
> Eliot
>
>
>
>
>
> --
> Mariano
> http://marianopeck.wordpress.com
>

Reply | Threaded
Open this post in threaded view
|

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

Eliot Miranda-2
 


On Wed, Jan 25, 2012 at 1:32 PM, stephane ducasse <[hidden email]> wrote:

for the record mariano, VW implementation of method wrapper had a template of method one for each number of possible args
and they reserved space in the compiled method to be able to binding the class name (from memory) so installing one was copy of the right template + homeClass + selector (not sure anymore) so it was quite fast and simple to read.

and the same thing is in my port to 4.2, MethodWrappers4.2 on squeaksource.  See MwMethodWrapper's class instance variable protoMethods.
 

Stef

On Jan 25, 2012, at 7:36 PM, Mariano Martinez Peck wrote:

>
>
> Ok. I will try to give it a try to this approach as well.
> But what happened with the version I attached in the previous email that uses a template method and just change the arguments number?
>
> That would be fine.  I didn't look.
>
>
> Since I am quite newbie here and the change can be quite important, I would really appreciate if someone can take a look to the .cs so that I feel confident to commit it :)
>
>
> but I get lost to get this working...the previous solution seems easier.
>
> Do you want to build Trabants or BMWs?
>
> I didn't understand. Which solution which be each car?
>
> Compiling from source each time = trabant.  Synthesizing directly = vw.   Using a template method = bmw.
>
> (vw = VisualWorks ;) )
>
>
> :):):):)
>
> Nice because it means that we found a fast solution yet quite understandable :)
>
>
>
> Documentation helps.
>
>
> I didn't understand either. If you refer to the fact I didn't put comments in the .cs I attached, I explicitly said in my previous email "If you agree, I can put a nice comment and commit.". It already took me the whole morning (yes, I am completly noob here) to do the version of changing the argument count, so I was waiting the confirmation in the solution before documenting it and make it better.
>
> I mean in general if one builds good quality code that is "clever" then that code needs to be documented.  Sometimes simple doesn't cut it (look at the complexity involved in making a VM fast).  So if simple doesn't cut it one must document.
>
> Agree. Once someone gives me the OK for my .cs, I will add comments and commit.
>
> Thanks Eliot.
>
>
>
>
>
> Thanks!
>
>
>
>
> On Tue, Jan 24, 2012 at 11:01 PM, Mariano Martinez Peck <[hidden email]> 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 <[hidden email]> 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
>
>
>
>
>
> --
> best,
> Eliot
>
>
>
>
>
> --
> Mariano
> http://marianopeck.wordpress.com
>
>
>
>
>
> --
> best,
> Eliot
>
>
>
>
>
> --
> Mariano
> http://marianopeck.wordpress.com
>




--
best,
Eliot

Reply | Threaded
Open this post in threaded view
|

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

Igor Stasenko
 
phew... done reading through overquoting :)

+1000 to removing tryXYZprimitive:

I was always wondering what those methods for, until i met a need to
support debugging when invoking nativeboost-prim methods,
because it needs special handing when invoking methods with native
code via debugger.

Then i understood that this mechanism is necessary.. yet a bit awkward..

So, improving it is wellcome! :)

--
Best regards,
Igor Stasenko.
Reply | Threaded
Open this post in threaded view
|

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

Mariano Martinez Peck
 


On Thu, Jan 26, 2012 at 11:18 AM, Igor Stasenko <[hidden email]> wrote:

phew... done reading through overquoting :)

+1000 to removing tryXYZprimitive:

I was always wondering what those methods for, until i met a need to
support debugging when invoking nativeboost-prim methods,
because it needs special handing when invoking methods with native
code via debugger.

Then i understood that this mechanism is necessary.. yet a bit awkward..

Funny. Even after implementing the fix, I still do not understand why all these is needed. Can someone explain to a newbie why invoking primitives (whether they are normal primitives, named primitives or NB primitives) from the debugger is different than invoking them normally (as when they are invoked by normal code)

Thanks
 

So, improving it is wellcome! :)

--
Best regards,
Igor Stasenko.



--
Mariano
http://marianopeck.wordpress.com

Reply | Threaded
Open this post in threaded view
|

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

stephane ducasse-2

> phew... done reading through overquoting :)
>
> +1000 to removing tryXYZprimitive:
>
> I was always wondering what those methods for, until i met a need to
> support debugging when invoking nativeboost-prim methods,
> because it needs special handing when invoking methods with native
> code via debugger.
>
> Then i understood that this mechanism is necessary.. yet a bit awkward..
>
> Funny. Even after implementing the fix, I still do not understand why all these is needed. Can someone explain to a newbie why invoking primitives (whether they are normal primitives, named primitives or NB primitives) from the debugger is different than invoking them normally (as when they are invoked by normal code)

Yes I want to understand too.

>
> Thanks
>  
>
> So, improving it is wellcome! :)
>
> --
> Best regards,
> Igor Stasenko.
>
>
>
> --
> Mariano
> http://marianopeck.wordpress.com
>

12