Object new becomeForward: #normal

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Object new becomeForward: #normal

marcel.taeumel
Hi, there.

Why are there guards to prevent forward-becoming to immediates (chars, ints) but not to symbols?

This will break your image: "Object new becomeForward: #normal"

... because Cursor class MNU #normal ... :-) Either this is a bug or forward-becoming to symbols is not intended at all.

Best,
Marcel
Reply | Threaded
Open this post in threaded view
|

Re: Object new becomeForward: #normal

Levente Uzonyi
On Tue, 18 Jul 2017, marcel.taeumel wrote:

> Hi, there.
>
> Why are there guards to prevent forward-becoming to immediates (chars, ints)
> but not to symbols?

The former is technically impossible due to different object
representations, the latter is possible and not restricted at all. For
example, true and false are not immediate objects, you can use #become*:
on them to blow your image up.
So, there's no restriction at all if it's technically possible to use
#become*:.
The responsibility model is the simplest here: use at your own risk.
Since this comes up every once in a while, I suggest a comment be added to
those methods stating the responsibility model explicitly.

I don't know how the VM handles immutability in this case, but it's
possible that it wouldn't let #become*: affect immutable objects. On the
other hand, I'm sure it would let you change fields of immutable objects
via #become*:, but that's not an issue in your case.

Levente

>
> This will break your image: "Object new becomeForward: #normal"
>
> ... because Cursor class MNU #normal ... :-) Either this is a bug or
> forward-becoming to symbols is not intended at all.
>
> Best,
> Marcel
>
>
>
> --
> View this message in context: http://forum.world.st/Object-new-becomeForward-normal-tp4955525.html
> Sent from the Squeak - Dev mailing list archive at Nabble.com.

Reply | Threaded
Open this post in threaded view
|

Re: Object new becomeForward: #normal

Bert Freudenberg
In reply to this post by marcel.taeumel
On Tue, Jul 18, 2017 at 1:33 PM, marcel.taeumel <[hidden email]> wrote:
Hi, there.

Why are there guards to prevent forward-becoming to immediates (chars, ints)
but not to symbols?

This will break your image: "Object new becomeForward: #normal"

... because Cursor class MNU #normal ... :-) Either this is a bug or
forward-becoming to symbols is not intended at all.

​The unexpected behavior is that #becomeForward: actually *modifies* the target object, because it tries to preserve the identity hash by copying it from the source to the target object. If you don't copy the hash it actually works:

x := Object new.
x becomeForward: 42 copyHash: false.
x​ 
"=> 42"

y := Object new.
y becomeForward: #normal copyHash: false.
"=> #normal"

​Arguably "copyHash: false" is a safer default, but then again, it would break identity-hashed collections that have the source object as key.

- Bert -


Reply | Threaded
Open this post in threaded view
|

Re: Object new becomeForward: #normal

Levente Uzonyi
In reply to this post by Levente Uzonyi
Nvm. What Bert wrote.

Levente

On Tue, 18 Jul 2017, Levente Uzonyi wrote:

> On Tue, 18 Jul 2017, marcel.taeumel wrote:
>
>> Hi, there.
>>
>> Why are there guards to prevent forward-becoming to immediates (chars,
> ints)
>> but not to symbols?
>
> The former is technically impossible due to different object
> representations, the latter is possible and not restricted at all. For
> example, true and false are not immediate objects, you can use #become*:
> on them to blow your image up.
> So, there's no restriction at all if it's technically possible to use
> #become*:.
> The responsibility model is the simplest here: use at your own risk.
> Since this comes up every once in a while, I suggest a comment be added to
> those methods stating the responsibility model explicitly.
>
> I don't know how the VM handles immutability in this case, but it's
> possible that it wouldn't let #become*: affect immutable objects. On the
> other hand, I'm sure it would let you change fields of immutable objects
> via #become*:, but that's not an issue in your case.
>
> Levente
>
>>
>> This will break your image: "Object new becomeForward: #normal"
>>
>> ... because Cursor class MNU #normal ... :-) Either this is a bug or
>> forward-becoming to symbols is not intended at all.
>>
>> Best,
>> Marcel
>>
>>
>>
>> --
>> View this message in context:
> http://forum.world.st/Object-new-becomeForward-normal-tp4955525.html
>> Sent from the Squeak - Dev mailing list archive at Nabble.com.
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Object new becomeForward: #normal

Bert Freudenberg
In reply to this post by Levente Uzonyi
On Tue, Jul 18, 2017 at 4:09 PM, Levente Uzonyi <[hidden email]> wrote:
On Tue, 18 Jul 2017, marcel.taeumel wrote:

Hi, there.

Why are there guards to prevent forward-becoming to immediates (chars, ints)
but not to symbols?

The former is technically impossible due to different object representations, the latter is possible and not restricted at all. For example, true and false are not immediate objects, you can use #become*: on them to blow your image up.
So, there's no restriction at all if it's technically possible to use #become*:.
The responsibility model is the simplest here: use at your own risk.
Since this comes up every once in a while, I suggest a comment be added to those methods stating the responsibility model explicitly.

​+1

*Especially* a warning that becomeForward: does modify the target's hash.
I don't know how the VM handles immutability in this case, but it's possible that it wouldn't let #become*: affect immutable objects.

​I think that would be fine, you should​ be able to become an immutable object and vice versa.
 
On the other hand, I'm sure it would let you change fields of immutable objects via #become*:, but that's not an issue in your case.

​This is debatable ...​ I would rather have the VM raise an error when trying to become a field of an immutable object. Immutable should mean immutable, no?

​- Bert -​

 


Levente



This will break your image: "Object new becomeForward: #normal"

... because Cursor class MNU #normal ... :-) Either this is a bug or
forward-becoming to symbols is not intended at all.

Best,
Marcel



Reply | Threaded
Open this post in threaded view
|

Re: Object new becomeForward: #normal

Levente Uzonyi
On Tue, 18 Jul 2017, Bert Freudenberg wrote:

> On Tue, Jul 18, 2017 at 4:09 PM, Levente Uzonyi <[hidden email]> wrote:
>       On Tue, 18 Jul 2017, marcel.taeumel wrote:
>
>             Hi, there.
>
>             Why are there guards to prevent forward-becoming to immediates (chars, ints)
>             but not to symbols?
>
>
>       The former is technically impossible due to different object representations, the latter is possible and not restricted at all. For
>       example, true and false are not immediate objects, you can use #become*: on them to blow your image up.
>       So, there's no restriction at all if it's technically possible to use #become*:.
>       The responsibility model is the simplest here: use at your own risk.
>       Since this comes up every once in a while, I suggest a comment be added to those methods stating the responsibility model explicitly.
>
>
> ​+1
>
> *Especially* a warning that becomeForward: does modify the target's hash.
>       ​I don't know how the VM handles immutability in this case, but it's possible that it wouldn't let #become*: affect immutable objects.
>
>
> ​I think that would be fine, you should​ be able to become an immutable object and vice versa.
>  
>       On the other hand, I'm sure it would let you change fields of immutable objects via #become*:, but that's not an issue in your case.
>
>
> ​This is debatable ...​ I would rather have the VM raise an error when trying to become a field of an immutable object. Immutable should mean
> immutable, no?
#become: would become slow again if we had to find all objects
referencing the one we're about to swap. Or, we'd have to make the whole
object graph immutable when we make an object immutable. In that
case #become: could just fail when the receiver or the argument is
immutable.

Levente

>
> ​- Bert -​
>
>  
>
>
>       Levente
>
>
>             This will break your image: "Object new becomeForward: #normal"
>
>             ... because Cursor class MNU #normal ... :-) Either this is a bug or
>             forward-becoming to symbols is not intended at all.
>
>             Best,
>             Marcel
>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Object new becomeForward: #normal

Eliot Miranda-2
In reply to this post by Bert Freudenberg
Hi Bert,

   [please see the "however" later on]

On Tue, Jul 18, 2017 at 7:30 AM, Bert Freudenberg <[hidden email]> wrote:
On Tue, Jul 18, 2017 at 4:09 PM, Levente Uzonyi <[hidden email]> wrote:
On Tue, 18 Jul 2017, marcel.taeumel wrote:

Hi, there.

Why are there guards to prevent forward-becoming to immediates (chars, ints)
but not to symbols?

The former is technically impossible due to different object representations, the latter is possible and not restricted at all. For example, true and false are not immediate objects, you can use #become*: on them to blow your image up.
So, there's no restriction at all if it's technically possible to use #become*:.
The responsibility model is the simplest here: use at your own risk.
Since this comes up every once in a while, I suggest a comment be added to those methods stating the responsibility model explicitly.

​+1

*Especially* a warning that becomeForward: does modify the target's hash.
I don't know how the VM handles immutability in this case, but it's possible that it wouldn't let #become*: affect immutable objects.

​I think that would be fine, you should​ be able to become an immutable object and vice versa.
 
On the other hand, I'm sure it would let you change fields of immutable objects via #become*:, but that's not an issue in your case.

​This is debatable ...​ I would rather have the VM raise an error when trying to become a field of an immutable object. Immutable should mean immutable, no?

Agreed.  I'm modifying the Spur VM to fail becomeForward: when copyHash is true and the target object is immutable.  So when we have immutable literals, #normal would be immutable and the become would fail.  The operative code was

containsOnlyValidBecomeObjects: array1 and: array2 twoWay: isTwoWay copyHash: copyHash
...
[fieldOffset >= self baseHeaderSize] whileTrue:
[...
isTwoWay
ifTrue:
[...]
ifFalse:
>> [(copyHash and: [self isImmediate: oop2]) ifTrue:
>> [^PrimErrInappropriate]].
fieldOffset := fieldOffset - self bytesPerOop].
...
^0

and is now

containsOnlyValidBecomeObjects: array1 and: array2 twoWay: isTwoWay copyHash: copyHash
...
[fieldOffset >= self baseHeaderSize] whileTrue:
[...
 isTwoWay
ifTrue:
[...]
ifFalse:
>> [(copyHash and: [(self isImmediate: oop2) or: [self isImmutable: oop2]]) ifTrue:
>> [^PrimErrInappropriate]].
 fieldOffset := fieldOffset - self bytesPerOop].
...
^0

This was a slip on mine and Clément's part when we added read-only object support.

However, it seems to me that becomerForward: doing a copyHash is itself a bug.  What's the rationale for copying the receiver's hash to the target object?  I've seen various frameworks use become to clean-up objects by doing aNoLongerWantedObject becomeFor4ward: nil, and with our current default implementation for becomeForward: that will cause havoc.

​- Bert -​

Levente

This will break your image: "Object new becomeForward: #normal"

... because Cursor class MNU #normal ... :-) Either this is a bug or
forward-becoming to symbols is not intended at all.

Best,
Marcel
 
_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: Object new becomeForward: #normal

Clément Béra


On Tue, Jul 18, 2017 at 10:03 PM, Eliot Miranda <[hidden email]> wrote:
Hi Bert,

   [please see the "however" later on]

On Tue, Jul 18, 2017 at 7:30 AM, Bert Freudenberg <[hidden email]> wrote:
On Tue, Jul 18, 2017 at 4:09 PM, Levente Uzonyi <[hidden email]> wrote:
On Tue, 18 Jul 2017, marcel.taeumel wrote:

Hi, there.

Why are there guards to prevent forward-becoming to immediates (chars, ints)
but not to symbols?

The former is technically impossible due to different object representations, the latter is possible and not restricted at all. For example, true and false are not immediate objects, you can use #become*: on them to blow your image up.
So, there's no restriction at all if it's technically possible to use #become*:.
The responsibility model is the simplest here: use at your own risk.
Since this comes up every once in a while, I suggest a comment be added to those methods stating the responsibility model explicitly.

​+1

*Especially* a warning that becomeForward: does modify the target's hash.
I don't know how the VM handles immutability in this case, but it's possible that it wouldn't let #become*: affect immutable objects.

​I think that would be fine, you should​ be able to become an immutable object and vice versa.
 
On the other hand, I'm sure it would let you change fields of immutable objects via #become*:, but that's not an issue in your case.

​This is debatable ...​ I would rather have the VM raise an error when trying to become a field of an immutable object. Immutable should mean immutable, no?

Agreed.  I'm modifying the Spur VM to fail becomeForward: when copyHash is true and the target object is immutable.  So when we have immutable literals, #normal would be immutable and the become would fail.  The operative code was

containsOnlyValidBecomeObjects: array1 and: array2 twoWay: isTwoWay copyHash: copyHash
...
[fieldOffset >= self baseHeaderSize] whileTrue:
[...
isTwoWay
ifTrue:
[...]
ifFalse:
>> [(copyHash and: [self isImmediate: oop2]) ifTrue:
>> [^PrimErrInappropriate]].
fieldOffset := fieldOffset - self bytesPerOop].
...
^0

and is now

containsOnlyValidBecomeObjects: array1 and: array2 twoWay: isTwoWay copyHash: copyHash
...
[fieldOffset >= self baseHeaderSize] whileTrue:
[...
 isTwoWay
ifTrue:
[...]
ifFalse:
>> [(copyHash and: [(self isImmediate: oop2) or: [self isImmutable: oop2]]) ifTrue:
>> [^PrimErrInappropriate]].
 fieldOffset := fieldOffset - self bytesPerOop].
...
^0

This was a slip on mine and Clément's part when we added read-only object support.

Arguably we should fail too with copyHash true and the target is a pinned object. see #ifOopInvalidForBecome:errorCodeInto:
 

However, it seems to me that becomerForward: doing a copyHash is itself a bug.  What's the rationale for copying the receiver's hash to the target object?  I've seen various frameworks use become to clean-up objects by doing aNoLongerWantedObject becomeFor4ward: nil, and with our current default implementation for becomeForward: that will cause havoc.

​- Bert -​

Levente

This will break your image: "Object new becomeForward: #normal"

... because Cursor class MNU #normal ... :-) Either this is a bug or
forward-becoming to symbols is not intended at all.

Best,
Marcel
 
_,,,^..^,,,_
best, Eliot






Reply | Threaded
Open this post in threaded view
|

Re: Object new becomeForward: #normal

Bert Freudenberg
In reply to this post by Eliot Miranda-2
On Tue, Jul 18, 2017 at 10:03 PM, Eliot Miranda <[hidden email]> wrote:

I'm modifying the Spur VM to fail becomeForward: when copyHash is true and the target object is immutable.  So when we have immutable literals, #normal would be immutable and the become would fail. 

​+1​
 
However, it seems to me that becomerForward: doing a copyHash is itself a bug.  What's the rationale for copying the receiver's hash to the target object?  I've seen various frameworks use become to clean-up objects by doing aNoLongerWantedObject becomeFor4ward: nil, and with our current default implementation for becomeForward: that will cause havoc.

​Well, it would mean nil's identityHash changes. But since nil isn't typically used as key in hashed collections, that use may be fine?

I agree that the becomeForward: default should be to not copy the hash. This could be done in the image though, no need to change the primitive.

​- Bert -​


Reply | Threaded
Open this post in threaded view
|

Re: Object new becomeForward: #normal

Eliot Miranda-2


On Tue, Jul 18, 2017 at 2:10 PM, Bert Freudenberg <[hidden email]> wrote:
On Tue, Jul 18, 2017 at 10:03 PM, Eliot Miranda <[hidden email]> wrote:

I'm modifying the Spur VM to fail becomeForward: when copyHash is true and the target object is immutable.  So when we have immutable literals, #normal would be immutable and the become would fail. 

​+1​
 
However, it seems to me that becomerForward: doing a copyHash is itself a bug.  What's the rationale for copying the receiver's hash to the target object?  I've seen various frameworks use become to clean-up objects by doing aNoLongerWantedObject becomeFor4ward: nil, and with our current default implementation for becomeForward: that will cause havoc.

​Well, it would mean nil's identityHash changes. But since nil isn't typically used as key in hashed collections, that use may be fine?

Maybe but in Spur I doubt it :-)

#(nil false true) collect: [:ea| ea identityHash]  #(1 2 3)
 
I agree that the becomeForward: default should be to not copy the hash. This could be done in the image though, no need to change the primitive.

Changing the primitive is not an option as it breaks VM backward compatibility.  But adding another primitive that implements the desired default is quite straight-forward and then the image can use whichever it chooses without having to add another indirection.

_,,,^..^,,,_
best, Eliot


Reply | Threaded
Open this post in threaded view
|

Re: [Vm-dev] Object new becomeForward: #normal

Chris Muller-3
In reply to this post by Eliot Miranda-2
>> >> This is debatable ... I would rather have the VM raise an error when
>> >> trying to become a field of an immutable object. Immutable should mean
>> >> immutable, no?
>>
>> So for bulkBecome:, will the error mean it becomed some of them (the
>> ones that that could), but not all?   It's getting complex!
>
>
> None of them.  The semantics of primitives should be they either succeed and answer their result, or they fail without side-effects.  Alas the ImageSegment loading primitive is an exception, but I believe it's the only one.  So in the become primitives, validation is done before any becomes, including computing an estimate of any memory needed, and the entire bulk become will fail if any single object fails validation and/or if there is not enough memory to complete the operation (two-way become may involve creating copies of objects).

Okay, that sounds like a good principle.

>> > However, it seems to me that becomerForward: doing a copyHash is itself a
>> > bug.  What's the rationale for copying the receiver's hash to the target
>> > object?
>>
>> For when you become a Proxy object to a Symbol selector to perform,
>> which are keys in MethodDictionary's.  It's absolutely essential.
>
>
> This doesn't make sense to me.  Are you saying one has a proxy for a Symbol that is not present, this gets entered as a key into MethodDictionaries, and later is becalmed into the Symbol it represents?  If not, can you take me through the use-case?
>
> It seems to me that what one wants is the ability to determine an Object's identityHash.  I've long thought that Symbols should set their identityHash on creation so that Symbols identityHashes are constant across all systems.  This would men for example, that binary code loaders would not need to rehash method dictionaries because they would already be correctly hashed.  In these cases one definitely doesn't want to overwrite the target's identityHash; instead, taking your example, one would want to create the proxy with the identityHash of its target.

Woops, I misread this sentence:

>> > However, it seems to me that becomerForward: doing a copyHash is itself a

I thought you meant NOT copying the hash was a bug.  In fact, we agree
that copying (changing) the identityHash of the target object is not
very safe or useful.  Sorry for the confusion.

So, yeah, the scenario is the Magma app materialized an object which
references a Proxy.  Then that proxy was agitated (sent a message -->
DNU), whereupon the Symbol string is read from the DB and the Proxy
becomeFoward'ed to it.  But it was a Symbol that already existed in
MethodDictionary's, so its identityHash shouldn't change just because
of that.

Best.

PS -- Here is the first message of the first thread which was the
birth of the #becomeForward:copyHash: addition to the VM.   :)

     http://lists.squeakfoundation.org/pipermail/squeak-dev/2002-May/039735.html