I cannot believe it but it seems to work. I would really
appreaciate if someone can take a look, and consider to integrate
it.
Having no way to execute a method on a receveir WITHOUT sending a
message to the object, is really a problem. I am implementing
proxies, which understand NOTHING (their class has method
dictionary in nil and I use the cannotInterpret trick) and so I
CANNOT send a message because I will be in loop. I have a similar
problem with primitiveChangeClassTo: but fortunately, Eliot did
#adoptInstance: which receiver is the class and not the object.
Anyway, this is the method
CompiledMethod >> executeWithReceiver: aReceiver arguments:
anArray
"Execute the compiledMethod against the aReceiver and args in
argArray."
<primitive: 190>
self primitiveFailed
And this is the primitive.
StackInterpreterPrimitives >>
primitiveExecuteWithReceiverArguments
"method, recevier, and the array of arguments are on top of
stack. Execute method against receiver and args.
Set primitiveFunctionPointer because no cache lookup has been
done for the method, and
hence primitiveFunctionPointer is stale."
| receiverMethod argCnt argumentArray primitiveIndex
receiverObject |
receiverMethod := self stackValue: 2.
receiverObject := self stackValue: 1.
argumentArray := self stackTop.
((objectMemory isOopCompiledMethod: receiverMethod)
and: [objectMemory isArray: argumentArray]) ifFalse:
[^self primitiveFailFor: PrimErrBadArgument].
argCnt := self argumentCountOf: receiverMethod.
argCnt = (objectMemory fetchWordLengthOf: argumentArray)
ifFalse:
[^self primitiveFailFor: PrimErrBadNumArgs].
self pop: 3.
self push: receiverObject.
0 to: argCnt - 1 do:
[:i|
self push: (objectMemory fetchPointer: i ofObject:
argumentArray)].
newMethod := receiverMethod.
primitiveIndex := self primitiveIndexOf: newMethod.
primitiveFunctionPointer := self functionPointerFor:
primitiveIndex inClass: nil.
argumentCount := argCnt.
"We set the messageSelector for executeMethod below since
things
like the at cache read messageSelector and so it cannot be
left stale."
messageSelector := objectMemory nilObject.
self executeNewMethod.
"Recursive xeq affects primErrorCode"
self initPrimCall
Thanks for taking a look and hopefully integrate this or something
better,
Mariano
Wouldn't you want to do a class check on the object vs installed
class of the CompiledMethod as part of PrimErrBadArgument checks?
Otherwise you'd probably end up insilly situations with
CompiledMethods which accesses/stores to instvars :)
Sorry Henry, I couldn't follow you :( I based such implementation in this one: primitiveExecuteMethodArgsArray
primitiveExecuteMethodArgsArray "receiver, argsArray, then method are on top of stack. Execute method against receiver and args.
Set primitiveFunctionPointer because no cache lookup has been done for the method, and hence primitiveFunctionPointer is stale." | methodArgument argCnt argumentArray primitiveIndex | methodArgument := self stackTop.
argumentArray := self stackValue: 1. ((objectMemory isOopCompiledMethod: methodArgument) and: [objectMemory isArray: argumentArray]) ifFalse: [^self primitiveFailFor: PrimErrBadArgument].
argCnt := self argumentCountOf: methodArgument. argCnt = (objectMemory fetchWordLengthOf: argumentArray) ifFalse: [^self primitiveFailFor: PrimErrBadNumArgs]. self pop: 2. 0 to: argCnt - 1 do:
[:i| self push: (objectMemory fetchPointer: i ofObject: argumentArray)]. newMethod := methodArgument. primitiveIndex := self primitiveIndexOf: newMethod. primitiveFunctionPointer := self functionPointerFor: primitiveIndex inClass: nil.
argumentCount := argCnt. "We set the messageSelector for executeMethod below since things like the at cache read messageSelector and so it cannot be left stale." messageSelector := objectMemory nilObject.
self executeNewMethod. "Recursive xeq affects primErrorCode" self initPrimCall