And it works! All become tests are green. See attached for VM and image side code.
Now most interesting thing. How much speed we gain?
Before:
| x y |
x := 'ab' copy. y := 'cd' copy.
[ 100 timesRepeat: [ x become: y ] ] timeToRun
1786
After:
| x y |
x := 'ab' copy. y := 'cd' copy.
[ 1000000 timesRepeat: [ x become: y ] ] timeToRun
82
So,
(1786 / 100) / (82 / 1000000 ) asFloat 217804.8780487805
217'804 times faster!!!!!! :)
But of course there are caveats if objects involved are compiled method(s) or symbols (selectors).
A check is required and invalidate cache in this case. For symbols it is harder, since symbols are not special objects. A cheapest way to workaround it is just override #become: for Symbol class to always use slow version. (oh.. btw, same could be done for CompiledMethod(s)).
So, instead of putting heavyweight logic into this new primitive, if may be better to just override #become: for critical classes. And since become is symmetric, we may need to use double-dispatch to check that none of pair is system-critical object, otherwise just fallback to slow version.