[Vm-dev] questions about a couple of primitives
florin.mateoc at gmail.com
Mon Aug 31 20:34:54 UTC 2020
Thank you for your reply and for the extra details about #instVarAt:.
To answer your question, I would have expected the primitive to fail for
non-pointers objects, as I associate in my mind instvars with named
instvars, but I am not invested in this (mis)association, so thank you for
But regarding #ifCurtailed, I know that primitives198 1nd 199 are not
"real", I was referring to something else. The primitive failure code in
the method #ifCurtailed never touches the argument, regardless of the path
taken. I think that is incorrect, even if only for documentation purposes.
All the best,
On Mon, Aug 31, 2020 at 3:42 PM Eliot Miranda <eliot.miranda at gmail.com>
> Hi Florin,
> On Mon, Aug 31, 2020 at 7:30 AM Florin Mateoc <florin.mateoc at gmail.com>
>> I had some unexpected results while looking at some primitives in the
>> system, and I wanted to ask if they are expected/intentional:
>> 1. 'ab' instVarAt: 1 => 97 (and 'ab' instVarAt: 2 => 98)
>> I would have thought that #instVarAt: has pointer granularity, so I
>> am curious if the observed behavior is an accident or intentional (and
>> maybe even used somewhere)
> Since a ByteString's indexed inst vars are bytes this is as expected.
> What would you have expected? Smalltalk-80 has always behaved this way.
> There is a little more to this story. In Spur, instVarAt:[put:] is
> actually implemented by a new primitive slotAt:[put:]. Why?
> 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).
>> 2. | o | o := Object new. (WeakArray with: o) pointsTo: o => true
>> I thought the main use case for #pointsTo: was to find hard
>> references (e.g. for chasing memory leaks). The current behavior actually
>> makes that use case a little more difficult to implement, since you have to
>> special case weak references. When would one be interested in finding weak
> I can't answer this. The design decision was made a whole ago. It would
> be easy to add pointsStronglyTo: and implement that correctly. Remember
> that references from named inst vars of weak objects are strong references.
> Only references from indexed inst vars of weak objects are weak.
>> 3. The comment and the primitive used in #ensure: and #ifCurtailed: are
>> the same, but the primitive failure code is different - the one for
>> #ifCurtailed seems buggy, it never evaluates the argument
> Ah, this is a neat hack. The primitive numbers are not actually
> primitives, These primitives always fail, and the blocks are evaluated
> with the valueNoContextSwitch send in the method body. Instead the
> primitive numbers are used by the VM to mark the activations of ensure: and
> ifCurtailed: as unwind-protect frames. This was one of Andreas' neatest
> hacks (am I right in thinking this was Andreas Raab's scheme?), in that he
> added unwind-protect without needing e.g. another status bit in the
> CompiledMethod header. He could just use the primitive number that was
> already there.
> As far as ifCurtailed: not evaluating its argument, that is its semantics.
> ensure: always evaluates its argument, after evaluating its body.
> ifCurtailed: only evaluates its argument if a non-local return or
> exception return is taken and the normal return path is not taken. See
> Context>>#resume:through: which runs the ensure: & ifCurtailed: blocks.
> None of the above are critical, but I am curious about them.
>> Thank you in advance for any clarifications,
> best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Vm-dev