[Vm-dev] questions about a couple of primitives

Chris Muller asqueaker at gmail.com
Mon Aug 31 23:03:17 UTC 2020


> Spur has a lazy become scheme which means that become is implemented by morphing objects into forwarders to copies of objects.  So if a become: b, then the system allocated copies of a and b, say a' and b', and morphs a into a forwarder to b', and b into a forwarder to a'.  Forwarders are followed lazily, either when a message is sent to a forwarder or when a primitive encounters a forwarder somewhere within the objects it consumes.  When a primitive fails the VM scans the input arguments to a depth specific to the primitive and if it finds references to forwarders, fixes them up to point to the targets of the forwarders, and retries the primitive.  The old implementation of instVarAt:[put:] had primities that failed for indexes beyond the named instance variables, and handled indexed inst vars in primitive failure code:
> Object>>instVarAt: index
> "Primitive. Answer a fixed variable in an object. The numbering of the
> variables corresponds to the named instance variables. Fail if the index
> is not an Integer or is not the index of a fixed variable. Essential. See
> Object documentation whatIsAPrimitive."
> <primitive: 73>
> "Access beyond fixed variables."
> ^self basicAt: index - self class instSize
> Chris Muller uses instVarAt:[put:] on large arrays in his Magma database. He was noticing a severe slow down in Magma on Spur because instVarAt:[put:] was failing, the entire Array was being scanned for forwarders, and then the primitive actually failed and the basicAt:put: ran.
> The solution to this was to replace primitives 73 & 74 with the new slotAt:[put:] primitives 173 & 174. Now the primitive does not fail, and performance is restored (and much improved because Spur is faster).

I just checked, apparently I'm still using my own #slotAt:[put:] from
2014, which reads:

slotAt: anInteger
    "Flat slot access.  Answer the object referenced by the receiver
at its anInteger'th slot."
    | namedSize |
    ^ anInteger > (namedSize:=self class instSize)
        ifTrue: [ self basicAt: (anInteger-namedSize) ]
        ifFalse: [ self instVarAt: anInteger ]

The timestamp on #instVarAt: using primitve 173 is 2017, so it sounds
like I can go back to simply using #instVarAt: instead of my own
#slotAt:, do you agree?


 - Chris

More information about the Vm-dev mailing list