Hi Clément, IMO literals should be immutable all the time, and IMO the best way is via a per-object isImmutable bit. We implemented this for VW in 7.0 and it was a positive experience. I've implemented the "create an immutable subclass for each literal class" and it has lots of problems (thing printString or storeString having to produce something like 'an immutable string' asMutableString for a normal string). The per-object bit has other uses too. Object databases such as GemStone can use it to make write-through scheme efficient. The only problem we had was dealing with broken user code that was depending on mutable literals. This is of course a bug, but folks thought we shouldn't just break user code so Alan Knight provided a system setting that write a warning to the transcript and updated the literal instead if raising an error. That's easy to do, if IMO dubious. Fixing the code is as easy as sending copy to the literal in question, the copy being mutable. Now I implemented the per-object bit for the Newspeak interpreter WM so you'll find lots of the necessary work is there waiting to be ported to the Stack and Cog VMs. I've not had the time to implement the JIT support to catch inst var and at:put: writes to immutables. But it shouldn't be too much work. Volunteers? Eliot (phone)
|
On Mon, Oct 27, 2014 at 9:19 AM, Levente Uzonyi <[hidden email]> wrote:
See my message earlier in the thread. Via a per-object isImmutable bit. I mean, how would you prevent something like this? best, Eliot
|
On Mon, 27 Oct 2014, Eliot Miranda wrote:
> See my message earlier in the thread. Via a per-object isImmutable bit. So you would set the bit for the CompiledMethod and all literals (including sub-arrays, floats, integers, booleans etc)? Does the set immutability bit also mean that the object can't be swapped with #become:? Levente |
On Mon, Oct 27, 2014 at 9:55 AM, Levente Uzonyi <[hidden email]> wrote: --
The literals, definitely. Whether the bit is set for compiled methods or not depends on things like how easy you want to be able to update the source pointer or add/delete properties.
That's debatable, but in VW we disallowed two-way become: and allowed one-way become: for immutables. I think that's right. one-way become is about references to objects, two-way become is about changing objects themselves. best, Eliot
|
On Mon, 27 Oct 2014, Eliot Miranda wrote:
>> So you would set the bit for the CompiledMethod and all literals (including sub-arrays, floats, integers, booleans etc)? > > The literals, definitely. Whether the bit is set for compiled methods or not depends on things like how easy you want to be able to update the source pointer or add/delete properties. If the CompiledMethod itself is not immutable, then one can replace its top level literals easily. If it's immutable, then the system will face all kind of problems, like adding the correct trailer during method installation. You could say "no problem, I'll use #becomeForward: to do it, it's fast in Spur", but that's what my other question is about. > >> Does the set immutability bit also mean that the object can't be swapped with #become:? > > That's debatable, but in VW we disallowed two-way become: and allowed one-way become: for immutables. I think that's right. one-way become is about references to objects, two-way become is about changing objects themselves. It's not about #become: vs #becomeForward:. If objects with the immutable bit set can be replaced with #becomeForward:, then the literals are not really immutable, because they can be changed. If you also want to check if there are immutable objects pointing to the object which is about to be replaced, then the performance of #becomeForward: would become as slow as in the non-Spur VMs. Levente |
On Mon, Oct 27, 2014 at 12:12 PM, Levente Uzonyi <[hidden email]> wrote: --
I disagree. It's about an incremental improvement. A per-object immutability bit used to protect against direct alteration of literals works. Right now there's nothing to stop one recompiling a method, and per-object immutability doesn't change that. So mutable compiled methods are tolerable (at least in VW we kept methods mutable). But having the bit stop direct modification of literals is goodness, not to be avoided because it doesn't prevent more exotic modification via become. best, Eliot
|
On Mon, 27 Oct 2014, Eliot Miranda wrote:
> I disagree. It's about an incremental improvement. A per-object immutability bit used to protect against direct alteration of literals works. Right now there's nothing to stop one recompiling a method, and per-object immutability doesn't change that. So mutable compiled methods are tolerable (at least in VW we kept methods mutable). But having the bit stop direct modification of literals is goodness, not to be avoided because it doesn't prevent more exotic modification via become. But if you allow mutable CompiledMethods, then Clement's example can be rewritten as: MyClass >> #foo ^#(false) first ifFalse: [ 'first call since compilation' logCr. thisContext method in: [ :method | (method literalAt: (method literals indexOf: #(false)) put: { true }) ] ] ifTrue: [ 'other calls' logCr ] (#becomeForward: could also be used on the literal). How will you avoid implementing the deoptimization of the method (the slow path) when this is possible? Levente |
Free forum by Nabble | Edit this page |