[Vm-dev] Primitive 60 vs methods with more than one argument

David T. Lewis lewis at mail.msen.com
Sun Oct 20 00:58:07 UTC 2013


On Sat, Oct 19, 2013 at 10:53:40PM +0200, Levente Uzonyi wrote:
> 
> Hi,
> 
> the code of primitive 60 seems to be assuming that the method has exactly 
> one argument, ignoring the actual number of arguments. This seems to be an 
> unnecessary restriction, which makes it cumbersome/impossible to use it in 
> methods which have more arguments, like #at:ifAbsent:.
> 
> Since the primitive uses two objects from the top of the stack, it's 
> possible to write a hackish method to see the potential benefits:
> 
> ifAbsent: aBlock receiver: receiver at: index
> 
> 	<primitive: 60>
> 	^aBlock value
> 
> The primitive will treat the variable receiver as the receiver, and index 
> as the index. The real receiver is not used at all.
> 
> This method performs 37% better than #at:ifAbsent for the case where 
> the index is valid.
> 
> Does it have any benefits not taking the actual number of arguments into 
> account in this primitive?
> 
> Cheers,
> Levente

I tried a rather casual benchmark. In the VM, I changed from this:

commonAt: stringy
	"This code is called if the receiver responds primitively to at:.
	If this is so, it will be installed in the atCache so that subsequent calls of at:
	or next may be handled immediately in bytecode primitive routines."
	| index rcvr atIx result |
	index := self positive32BitValueOf: (self stackTop).  "Sets primFailCode"
	rcvr := self stackValue: 1.

To this:

commonAt: stringy
	"This code is called if the receiver responds primitively to at:.
	If this is so, it will be installed in the atCache so that subsequent calls of at:
	or next may be handled immediately in bytecode primitive routines."
	| index rcvr atIx result |
	index := self positive32BitValueOf: (self stackValue: argumentCount - 1).  "Sets primFailCode"
	rcvr := self stackValue: argumentCount.


Then I ran the following test with each VM:

(1 to: 25) collect: [:foo |
size := 100000000.
bigArray := Array new: size.
1 to: size do: [:i | bigArray at: i put: i].
Smalltalk garbageCollect.
Time millisecondsToRun: [1 to: size do: [:i | bigArray at: i]]].

I ended up with less than 1% performance difference between the two VMs
for the common case of #at: access to an array.

This was not a very careful test, but it suggests that your idea could
be used to improve at:ifAbsent: performance without causing significant
performance problems elsewhere.

Dave



More information about the Vm-dev mailing list