this is why we need a solid proxy. Stef On Oct 23, 2011, at 12:13 PM, Mariano Martinez Peck wrote:
Um, I'm not upto optimization tricks yet, so no. :)
This has nothing to do with *your* optimization tricks. These are optimization tricks that the VM and the compiler play on you. Below a list of potentially dangerous selectors that might not cause the GOODS proxy objects to load the object. You need to be aware of these details to be able to write code that works with proxy objects:
ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue: and: or: whileFalse: whileTrue: whileFalse whileTrue to:do: to:by:do: caseOf: caseOf:otherwise: ifNil: ifNotNil: ifNil:ifNotNil: ifNotNil:ifNil: repeat + - < > <= >= = ~= * / \\ @ bitShift: // bitAnd: bitOr: at: at:put: size next nextPut: atEnd == class blockCopy: value value: do: new new: x y yourself
Just a small comment: not ALL those methods will be *never* executed.
All those that are optimized by the compiler: MessageNode >> #initialize (instVar MacroSelectors) ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue: and: or: whileFalse: whileTrue: whileFalse whileTrue to:do: to:by:do: caseOf: caseOf:otherwise: ifNil: ifNotNil: ifNil:ifNotNil: ifNotNil:ifNil: repeat
Those are never executed, hence you cannot intercept them.
Now, those special selectors that have associated bytecodes: Smalltalk specialSelectors -> #(#+ 1 #- 1 #< 1 #> 1 #'<=' 1 #'>=' 1 #= 1 #'~=' 1 #* 1 #/ 1 #'\\' 1 #@ 1 #bitShift: 1 #'//' 1 #bitAnd: 1 #bitOr: 1 #at: 1 #at:put: 2 #size 0 #next 0 #nextPut: 1 #atEnd 0 #'==' 1 #class 0 #blockCopy: 1 #value 0 #value: 1 #do: 1 #new 0 #new: 1 #x 0 #y 0)
SOME of them are not executed.
1) Some are ALWAYS executed For example, the bytecode for #atEnd does nothing more than a small optimization, but it is always executed at the end: StackInterpreter >> bytecodePrimAtEnd messageSelector := self specialSelector: 21. argumentCount := 0. self normalSend.
2) Some are SOMETIMES executed. Example, #+, #>=, etc. All those math bytecode usually work if the receiver and argument are numbers. But if they are not, like in the case of a proxy, then the bytecode fails and hence, the method is executed. Example: StackInterpreter >> bytecodePrimAdd | rcvr arg result | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. (self areIntegers: rcvr and: arg) ifTrue: [result := (objectMemory integerValueOf: rcvr) + (objectMemory integerValueOf: arg). (objectMemory isIntegerValue: result) ifTrue: [self internalPop: 2 thenPush: (objectMemory integerObjectOf: result). ^ self fetchNextBytecode "success"]] ifFalse: [self initPrimCall. self externalizeIPandSP. self primitiveFloatAdd: rcvr toArg: arg. self internalizeIPandSP. self successful ifTrue: [^ self fetchNextBytecode "success"]].
messageSelector := self specialSelector: 0. argumentCount := 1. self normalSend
3) Some are NEVER executed. For example, #class and #==. StackInterpreter >> bytecodePrimEquivalent
| rcvr arg | rcvr := self internalStackValue: 1. arg := self internalStackValue: 0. self booleanCheat: rcvr = arg.
So, for a proxy I think the only problem is (apart from the already mentioned compiler inlining) point 3), that is #== and #class
Anyway, I have wirtten a paper about writting proxies in Smalltalk which you may find interesting. http://rmod.lille.inria.fr/web/pier/software/Marea/GhostProxies You can get the paper from there.
Cheers
Lukas
-- Lukas Renggli www.lukas-renggli.ch
-- Mariano http://marianopeck.wordpress.com