[Vm-dev] Why become should fail on readonly objects?

Eliot Miranda eliot.miranda at gmail.com
Thu Jan 11 01:57:14 UTC 2018


Hi Denis,

On Wed, Jan 10, 2018 at 2:46 AM, Denis Kudriashov <dionisiydk at gmail.com>
wrote:

>
> Hi.
>
> Look at following example:
>
> p1 := 10 at 20.
> p2 := 40 at 50.
> p1 becomeForward: p2.
> p1 == p2 "==> true"
>
>
> It shows that become operation do not modifies p1 instance. It just
> replaces value in all references.
> Now if p1 will be read only object then become will fail:
>
> p1 := 10 at 20.
> p2 := 40 at 50.
>
> p1 beReadOnlyObject.
>
> p1 becomeForward: p2. "==> fail by modification error"
>
> My question is why this logic is valid? As simple user I do not see how
> become modifies the state of receiver p1.
>

Well, the reason is to prevent changing literals.  Let's say you have a
method like

Object>>printOn: aStream
"Append to the argument, aStream, a sequence of characters that
identifies the receiver."

| title |
title := self class name.
aStream
nextPutAll: (title first isVowel ifTrue: ['an '] ifFalse: ['a ']);
nextPutAll: title

Without read-only literals there is nothing to stop the programmer from
making the mistake of doing something like
    ((Object>>#printOn:) literalAt: 4) at: 1 put: $A
which would cause Object new to print as 'An Object', not 'an Object'.
Once literals are read-only then this can't happen; the at:put: will fail.

But one can use becomeForward: or become: in exactly the same way.  Unless
become is illegal for read-only objects, there is nothing to stop the
programmer from making the mistake of doing
    ((Object>>#printOn:) literalAt: 4) becomeForward: 'An '
    ((Object>>#printOn:) literalAt: 4) become: 'An '

And what I expect is failing on another case which surprisingly do not fail:
>
> p1 := 10 at 20.
> p2 := 40 at 50.
> array := {  p1. p2}.
> array beReadOnlyObject.
> p1 becomeForward: p2.
>
> array = {40 at 50. 40 at 50} "==true"
>
> Here become operation modifies state of read only object. But it not fails.
>

The reason here is to do with instance migration on class definition.  We
want becomeForward: to update any and all instances of a class when we
shape change a class.  Further, the only way the VM can prevent this is by
scanning the entire heap looking for any reference to the receiver of
becomeForward: from a read-only object.  And we want becomeForward: to be
fast; the last thing we want is to introduce a full heap scan when we
introduce read-only objects.  So we're being pragmatic; the definitions
here, that two-way become fails if either is a read-only object, and that
one-way become fails if the receiver is read-only, work well with the way
the system implements instance migration, and allow us to implement become
in the presence of read-only objects without a full heap scan.

This matches the VW implementation which makes the same choices for the
same reasons.  It's not ideal, but neither is having the VM catch your last
case.  Instead it's a workable compromise.  HTH


Best regards,
> Denis
>

Likewise.  Happy New Year!

_,,,^..^,,,_
best, Eliot
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20180110/bf415510/attachment-0001.html>


More information about the Vm-dev mailing list