Immutability support

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

Re: Immutability support

philippeback
Tried it and it returns false for this Windows VM.

Phil

On Wed, Jan 25, 2017 at 2:14 PM, Clément Bera <[hidden email]> wrote:
I introduced the method #supportsWriteBarrier in Pharo 6.

You can backport it if you want:

VirtualMachine>>#supportsWriteBarrier
"Answer whether the VM observes the per-object read-only flag and consequently
aborts writes to inst vars of, and fails primitives that attempt to write, to read-only objects."

^(self parameterAt: 65)
ifNil: [false]
ifNotNil:
[:param| "In older VMs this is a boolean reflecting MULTIPLE_BYTECODE_SETS"
param isInteger "In newer VMs it is a set of integer flags, bit 1 of which is IMMUTABILITY"
ifTrue: [param anyMask: 2]
ifFalse: [false]]



On Wed, Jan 25, 2017 at 2:06 PM, [hidden email] <[hidden email]> wrote:
The "latest" Windows VM I do use has no such method.

Virtual Machine
---------------
C:\Users\Philippe\Dropbox\Sibelga\JiraAutomation\Pharo5.0\latestvm\pharo.exe
CoInterpreter * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
StackToRegisterMappingCogit * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
VM: 201701151442 https://github.com/pharo-project/pharo-vm.git $ Date: Sun Jan 15 15:42:39 2017 +0100 $ Plugins: 201701151442 https://github.com/pharo-project/pharo-vm.git $

Win32 built on Jan 15 2017 15:59:52 CUT Compiler: 5.4.0
VMMaker versionString VM: 201701151442 https://github.com/pharo-project/pharo-vm.git $ Date: Sun Jan 15 15:42:39 2017 +0100 $ Plugins: 201701151442 https://github.com/pharo-project/pharo-vm.git $
CoInterpreter * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
StackToRegisterMappingCogit * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017

Inline image 1


On Wed, Jan 25, 2017 at 1:54 PM, Clément Bera <[hidden email]> wrote:


On Wed, Jan 25, 2017 at 11:35 AM, Norbert Hartl <[hidden email]> wrote:
Does anyone know the state of immutability support in vm and image? The latest vm downloadable is compiled with

IMMUTABILITY=1

(Esteban said that). When I open a pharo6 image with this VM and do:

ASUser new
        setIsReadOnlyObject: true;
        name: 'foo'

with

ASUser>>#name: arg1
        name := arg1

I don't get an exception. Is there something missing or am I not understanding?

Hi Norbert,

Thank you very much for looking read-only objects.

When mutating an instance variable, the VM triggers a call-back that by default does nothing. In your case, running your code does not raise an exception but the object should not be modified either. If you want an exception, you need to change the call-back code, i.e., the method Object>>#attemptToAssign: value withIndex: index. For example, you could write:

Object>>#attemptToAssign: value withIndex: index 
| process |
self notify: 'object changed !'.
process := Processor activeProcess.
[ process suspendedContext: process suspendedContext sender ] forkAt: Processor activePriority + 1.
Processor yield.

Then, your code should open a notification window with 'object changed', and proceeding keeps running the code without mutating the object.

One needs to build a ModificationTracker framework on top of the VM support I introduced. Multiple things are required, like default behavior in this call-back and in primitive failure code. I am willing to support and help anyone willing to build such a framework, but I won't build it myself.

If you have any other questions or if you find bug don't hesitate to ask further questions

Best,

PS: Make sure "Smalltalk vm supportsWriteBarrier" answers true in your system, if this is not the case it means the VM does not support read-only objects.

Clement




 

Norbert




Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Denis Kudriashov
In reply to this post by Clément Béra

2017-01-25 13:59 GMT+01:00 Clément Bera <[hidden email]>:
It also raise another question: does these primitives support mirror approach? (when it can be called with receiver as first argument?)

Yes I made sure the mirror approach works. Even better, there are tests ensuring that it works. You can see in the class WriteBarrierTest that objects can become read-only through an instance of TTMirror, look for example into the users of TTMirror>>#setIsReadOnlyObjectOf: object to: boolean.

I think we need move it to MirrorPrimitives which was introduced in Pharo 6.
Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

NorbertHartl
In reply to this post by Clément Béra
Clément,

Am 25.01.2017 um 13:54 schrieb Clément Bera <[hidden email]>:



On Wed, Jan 25, 2017 at 11:35 AM, Norbert Hartl <[hidden email]> wrote:
Does anyone know the state of immutability support in vm and image? The latest vm downloadable is compiled with

IMMUTABILITY=1

(Esteban said that). When I open a pharo6 image with this VM and do:

ASUser new
        setIsReadOnlyObject: true;
        name: 'foo'

with

ASUser>>#name: arg1
        name := arg1

I don't get an exception. Is there something missing or am I not understanding?

Hi Norbert,

Thank you very much for looking read-only objects.

When mutating an instance variable, the VM triggers a call-back that by default does nothing. In your case, running your code does not raise an exception but the object should not be modified either. If you want an exception, you need to change the call-back code, i.e., the method Object>>#attemptToAssign: value withIndex: index. For example, you could write:

Object>>#attemptToAssign: value withIndex: index 
| process |
self notify: 'object changed !'.
process := Processor activeProcess.
[ process suspendedContext: process suspendedContext sender ] forkAt: Processor activePriority + 1.
Processor yield.

Then, your code should open a notification window with 'object changed', and proceeding keeps running the code without mutating the object.

thank you very much for the explanation. What was the rationale behind doing nothing as default? I can see there is two interpretations of read-only. One being just don't modify the object the other being throwing an exception when an attempt to modify is made. I think that having an exception thrown would make it easier to write code using it. I don't want to monkey patch Object but still make this general applicable.

One needs to build a ModificationTracker framework on top of the VM support I introduced. Multiple things are required, like default behavior in this call-back and in primitive failure code. I am willing to support and help anyone willing to build such a framework, but I won't build it myself.

Modification tracking is exactly the reason why I look into it. I have two other approaches doing modification tracking. But both are inferior to an approach using read-only objects.

Norbert 

If you have any other questions or if you find bug don't hesitate to ask further questions

Best,

PS: Make sure "Smalltalk vm supportsWriteBarrier" answers true in your system, if this is not the case it means the VM does not support read-only objects.

Clement




 

Norbert

Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Clément Béra
In reply to this post by Denis Kudriashov
@Phil, then the VM does not support it. I believe the latest VM from files.pharo.org should support it, but not the stable one.

@Denis Sure move it to MirrorPrimitive and update the WriteBarrier tests.

On Wed, Jan 25, 2017 at 3:09 PM, Denis Kudriashov <[hidden email]> wrote:

2017-01-25 13:59 GMT+01:00 Clément Bera <[hidden email]>:
It also raise another question: does these primitives support mirror approach? (when it can be called with receiver as first argument?)

Yes I made sure the mirror approach works. Even better, there are tests ensuring that it works. You can see in the class WriteBarrierTest that objects can become read-only through an instance of TTMirror, look for example into the users of TTMirror>>#setIsReadOnlyObjectOf: object to: boolean.

I think we need move it to MirrorPrimitives which was introduced in Pharo 6.

Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Clément Béra
In reply to this post by NorbertHartl
Norbert,

On Wed, Jan 25, 2017 at 3:36 PM, Norbert Hartl <[hidden email]> wrote:
Clément,

Am 25.01.2017 um 13:54 schrieb Clément Bera <[hidden email]>:



On Wed, Jan 25, 2017 at 11:35 AM, Norbert Hartl <[hidden email]> wrote:
Does anyone know the state of immutability support in vm and image? The latest vm downloadable is compiled with

IMMUTABILITY=1

(Esteban said that). When I open a pharo6 image with this VM and do:

ASUser new
        setIsReadOnlyObject: true;
        name: 'foo'

with

ASUser>>#name: arg1
        name := arg1

I don't get an exception. Is there something missing or am I not understanding?

Hi Norbert,

Thank you very much for looking read-only objects.

When mutating an instance variable, the VM triggers a call-back that by default does nothing. In your case, running your code does not raise an exception but the object should not be modified either. If you want an exception, you need to change the call-back code, i.e., the method Object>>#attemptToAssign: value withIndex: index. For example, you could write:

Object>>#attemptToAssign: value withIndex: index 
| process |
self notify: 'object changed !'.
process := Processor activeProcess.
[ process suspendedContext: process suspendedContext sender ] forkAt: Processor activePriority + 1.
Processor yield.

Then, your code should open a notification window with 'object changed', and proceeding keeps running the code without mutating the object.

thank you very much for the explanation. What was the rationale behind doing nothing as default? I can see there is two interpretations of read-only. One being just don't modify the object the other being throwing an exception when an attempt to modify is made. I think that having an exception thrown would make it easier to write code using it. I don't want to monkey patch Object but still make this general applicable.

Well, when I introduced the code I thought someone would build a ModificationTracker framework... I think there should be a modification tracker framework that throws an exception only if no program is registered to handle the modification failure. No exception should be thrown in the generic case.

 

One needs to build a ModificationTracker framework on top of the VM support I introduced. Multiple things are required, like default behavior in this call-back and in primitive failure code. I am willing to support and help anyone willing to build such a framework, but I won't build it myself.

Modification tracking is exactly the reason why I look into it. I have two other approaches doing modification tracking. But both are inferior to an approach using read-only objects.

Overall, you need to:
- change the code of all numbered primitives mutating objects (such as at:put:) so that when they fail because of a read-only object they call the modification tracker framework.
- add the call to the modification tracker framework from the #attemptToAssign:withIndex: call-back.
- build a Modification tracker framework where external programs can easily register themselves to catch modification on specific objects or all instances of a specific class. Programs tracking modifications should be able to temporarily make the object writable, perform the modification and make it read-only again. 

You can check the VisualWork implementation (check for example the fall-back code of #at:put: and what it calls) and the comment I wrote in #attemptToAssign:withIndex: to get inspired.

If you do something like that, please, *please*, please contribute it back to the base Pharo image.

Thank you for experimenting with read-only objects. Don't hesitate to contact me if you have issues or questions.


Norbert 

If you have any other questions or if you find bug don't hesitate to ask further questions

Best,

PS: Make sure "Smalltalk vm supportsWriteBarrier" answers true in your system, if this is not the case it means the VM does not support read-only objects.

Clement




 

Norbert


Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

EstebanLM
In reply to this post by philippeback
nevertheless it should be there in latests vms.
which version are you using?

Esteban 

On 25 Jan 2017, at 15:04, [hidden email] wrote:

Tried it and it returns false for this Windows VM.

Phil

On Wed, Jan 25, 2017 at 2:14 PM, Clément Bera <[hidden email]> wrote:
I introduced the method #supportsWriteBarrier in Pharo 6.

You can backport it if you want:

VirtualMachine>>#supportsWriteBarrier
"Answer whether the VM observes the per-object read-only flag and consequently
aborts writes to inst vars of, and fails primitives that attempt to write, to read-only objects."

^(self parameterAt: 65)
ifNil: [false]
ifNotNil:
[:param| "In older VMs this is a boolean reflecting MULTIPLE_BYTECODE_SETS"
param isInteger "In newer VMs it is a set of integer flags, bit 1 of which is IMMUTABILITY"
ifTrue: [param anyMask: 2]
ifFalse: [false]]



On Wed, Jan 25, 2017 at 2:06 PM, [hidden email] <[hidden email]> wrote:
The "latest" Windows VM I do use has no such method.

Virtual Machine
---------------
C:\Users\Philippe\Dropbox\Sibelga\JiraAutomation\Pharo5.0\latestvm\pharo.exe
CoInterpreter * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
StackToRegisterMappingCogit * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
VM: 201701151442 https://github.com/pharo-project/pharo-vm.git $ Date: Sun Jan 15 15:42:39 2017 +0100 $ Plugins: 201701151442 https://github.com/pharo-project/pharo-vm.git $

Win32 built on Jan 15 2017 15:59:52 CUT Compiler: 5.4.0
VMMaker versionString VM: 201701151442 https://github.com/pharo-project/pharo-vm.git $ Date: Sun Jan 15 15:42:39 2017 +0100 $ Plugins: 201701151442 https://github.com/pharo-project/pharo-vm.git $
CoInterpreter * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
StackToRegisterMappingCogit * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017

<image.png>


On Wed, Jan 25, 2017 at 1:54 PM, Clément Bera <[hidden email]> wrote:


On Wed, Jan 25, 2017 at 11:35 AM, Norbert Hartl <[hidden email]> wrote:
Does anyone know the state of immutability support in vm and image? The latest vm downloadable is compiled with

IMMUTABILITY=1

(Esteban said that). When I open a pharo6 image with this VM and do:

ASUser new
        setIsReadOnlyObject: true;
        name: 'foo'

with

ASUser>>#name: arg1
        name := arg1

I don't get an exception. Is there something missing or am I not understanding?

Hi Norbert,

Thank you very much for looking read-only objects.

When mutating an instance variable, the VM triggers a call-back that by default does nothing. In your case, running your code does not raise an exception but the object should not be modified either. If you want an exception, you need to change the call-back code, i.e., the method Object>>#attemptToAssign: value withIndex: index. For example, you could write:

Object>>#attemptToAssign: value withIndex: index 
| process |
self notify: 'object changed !'.
process := Processor activeProcess.
[ process suspendedContext: process suspendedContext sender ] forkAt: Processor activePriority + 1.
Processor yield.

Then, your code should open a notification window with 'object changed', and proceeding keeps running the code without mutating the object.

One needs to build a ModificationTracker framework on top of the VM support I introduced. Multiple things are required, like default behavior in this call-back and in primitive failure code. I am willing to support and help anyone willing to build such a framework, but I won't build it myself.

If you have any other questions or if you find bug don't hesitate to ask further questions

Best,

PS: Make sure "Smalltalk vm supportsWriteBarrier" answers true in your system, if this is not the case it means the VM does not support read-only objects.

Clement




 

Norbert





Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

philippeback
In reply to this post by Clément Béra
I am using a quite recent VM that Esteban provides on the JFrog bintray (debug version with symbols).  So this is a bit surprising.

Phil

On Wed, Jan 25, 2017 at 3:41 PM, Clément Bera <[hidden email]> wrote:
@Phil, then the VM does not support it. I believe the latest VM from files.pharo.org should support it, but not the stable one.

@Denis Sure move it to MirrorPrimitive and update the WriteBarrier tests.

On Wed, Jan 25, 2017 at 3:09 PM, Denis Kudriashov <[hidden email]> wrote:

2017-01-25 13:59 GMT+01:00 Clément Bera <[hidden email]>:
It also raise another question: does these primitives support mirror approach? (when it can be called with receiver as first argument?)

Yes I made sure the mirror approach works. Even better, there are tests ensuring that it works. You can see in the class WriteBarrierTest that objects can become read-only through an instance of TTMirror, look for example into the users of TTMirror>>#setIsReadOnlyObjectOf: object to: boolean.

I think we need move it to MirrorPrimitives which was introduced in Pharo 6.


Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Denis Kudriashov
In reply to this post by Clément Béra

2017-01-25 15:52 GMT+01:00 Clément Bera <[hidden email]>:
Overall, you need to:
- change the code of all numbered primitives mutating objects (such as at:put:) so that when they fail because of a read-only object they call the modification tracker framework.

I think it is for future.

But now behaviour is just inconsistent because making object readonly breaks any app using it silently
Also I see that instVarAt:put: will raise error instead of skipping it. So two ways to modify object lead to different behavior. It's not good.

My conclusion: it must be error by default. Something like this:
Object>>#attemptToAssign: value withIndex: index 
      (ModificationForbidden for: self at: index with: value) signal
It is not fix completely inconsistence with #instVarAt:put: but at least they both will fail.

By the way I was supprized that failed #instVarAt:put: shows "bad receiver" in primitive er variable (<primitive: 174 error: ec>). Is "bad receiver" is always about mutability? And if not then how we will distinguish different cases?
Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Denis Kudriashov
Another question Clement.

I found that current method doing something strange:

attemptToAssign: value withIndex: index 
process := Processor activeProcess.
[ process suspendedContext: process suspendedContext sender ] forkAt: Processor activePriority + 1.
Processor yield.
"CAN'T REACH"

Could you comment why new process needed here? 
I just check simple version with error and it works:

attemptToAssign: value withIndex: index 
^self error: 'modification failed'.

Also if I will modify #contents: as "^contents:=newValue" then following code is working well:

o := ValueHolder new.
o beReadOnlyObject.
[o contents: #test] on: Error do: [:err | err resumeUnchecked: #done]. "=> #done"

So I not understand the problem described in method comment.

2017-01-25 16:21 GMT+01:00 Denis Kudriashov <[hidden email]>:

2017-01-25 15:52 GMT+01:00 Clément Bera <[hidden email]>:
Overall, you need to:
- change the code of all numbered primitives mutating objects (such as at:put:) so that when they fail because of a read-only object they call the modification tracker framework.

I think it is for future.

But now behaviour is just inconsistent because making object readonly breaks any app using it silently
Also I see that instVarAt:put: will raise error instead of skipping it. So two ways to modify object lead to different behavior. It's not good.

My conclusion: it must be error by default. Something like this:
Object>>#attemptToAssign: value withIndex: index 
      (ModificationForbidden for: self at: index with: value) signal
It is not fix completely inconsistence with #instVarAt:put: but at least they both will fail.

By the way I was supprized that failed #instVarAt:put: shows "bad receiver" in primitive er variable (<primitive: 174 error: ec>). Is "bad receiver" is always about mutability? And if not then how we will distinguish different cases?

Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Clément Béra


On Wed, Jan 25, 2017 at 4:42 PM, Denis Kudriashov <[hidden email]> wrote:
Another question Clement.

I found that current method doing something strange:

attemptToAssign: value withIndex: index 
process := Processor activeProcess.
[ process suspendedContext: process suspendedContext sender ] forkAt: Processor activePriority + 1.
Processor yield.
"CAN'T REACH"

Could you comment why new process needed here? 
I just check simple version with error and it works:

attemptToAssign: value withIndex: index 
^self error: 'modification failed'.

Also if I will modify #contents: as "^contents:=newValue" then following code is working well:

o := ValueHolder new.
o beReadOnlyObject.
[o contents: #test] on: Error do: [:err | err resumeUnchecked: #done]. "=> #done"

So I not understand the problem described in method comment.

Hi Denis,

I will look into this case tomorrow, it looks like a bug. Thanks for reporting.

For the Process hack, it's because the call-back was designed to return no value. It may look like it works when returning a value but you will have uncommon crashes.


2017-01-25 16:21 GMT+01:00 Denis Kudriashov <[hidden email]>:

2017-01-25 15:52 GMT+01:00 Clément Bera <[hidden email]>:
Overall, you need to:
- change the code of all numbered primitives mutating objects (such as at:put:) so that when they fail because of a read-only object they call the modification tracker framework.

I think it is for future.

But now behaviour is just inconsistent because making object readonly breaks any app using it silently
Also I see that instVarAt:put: will raise error instead of skipping it. So two ways to modify object lead to different behavior. It's not good.

My conclusion: it must be error by default. Something like this:
Object>>#attemptToAssign: value withIndex: index 
      (ModificationForbidden for: self at: index with: value) signal
It is not fix completely inconsistence with #instVarAt:put: but at least they both will fail.

By the way I was supprized that failed #instVarAt:put: shows "bad receiver" in primitive er variable (<primitive: 174 error: ec>). Is "bad receiver" is always about mutability? And if not then how we will distinguish different cases?


Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

philippeback
In reply to this post by EstebanLM
pharo-win-i386-201701151442-c50dec0.zip

On Wed, Jan 25, 2017 at 3:57 PM, Esteban Lorenzano <[hidden email]> wrote:
nevertheless it should be there in latests vms.
which version are you using?

Esteban 

On 25 Jan 2017, at 15:04, [hidden email] wrote:

Tried it and it returns false for this Windows VM.

Phil

On Wed, Jan 25, 2017 at 2:14 PM, Clément Bera <[hidden email]> wrote:
I introduced the method #supportsWriteBarrier in Pharo 6.

You can backport it if you want:

VirtualMachine>>#supportsWriteBarrier
"Answer whether the VM observes the per-object read-only flag and consequently
aborts writes to inst vars of, and fails primitives that attempt to write, to read-only objects."

^(self parameterAt: 65)
ifNil: [false]
ifNotNil:
[:param| "In older VMs this is a boolean reflecting MULTIPLE_BYTECODE_SETS"
param isInteger "In newer VMs it is a set of integer flags, bit 1 of which is IMMUTABILITY"
ifTrue: [param anyMask: 2]
ifFalse: [false]]



On Wed, Jan 25, 2017 at 2:06 PM, [hidden email] <[hidden email]> wrote:
The "latest" Windows VM I do use has no such method.

Virtual Machine
---------------
C:\Users\Philippe\Dropbox\Sibelga\JiraAutomation\Pharo5.0\latestvm\pharo.exe
CoInterpreter * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
StackToRegisterMappingCogit * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
VM: 201701151442 https://github.com/pharo-project/pharo-vm.git $ Date: Sun Jan 15 15:42:39 2017 +0100 $ Plugins: 201701151442 https://github.com/pharo-project/pharo-vm.git $

Win32 built on Jan 15 2017 15:59:52 CUT Compiler: 5.4.0
VMMaker versionString VM: 201701151442 https://github.com/pharo-project/pharo-vm.git $ Date: Sun Jan 15 15:42:39 2017 +0100 $ Plugins: 201701151442 https://github.com/pharo-project/pharo-vm.git $
CoInterpreter * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
StackToRegisterMappingCogit * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017

<image.png>


On Wed, Jan 25, 2017 at 1:54 PM, Clément Bera <[hidden email]> wrote:


On Wed, Jan 25, 2017 at 11:35 AM, Norbert Hartl <[hidden email]> wrote:
Does anyone know the state of immutability support in vm and image? The latest vm downloadable is compiled with

IMMUTABILITY=1

(Esteban said that). When I open a pharo6 image with this VM and do:

ASUser new
        setIsReadOnlyObject: true;
        name: 'foo'

with

ASUser>>#name: arg1
        name := arg1

I don't get an exception. Is there something missing or am I not understanding?

Hi Norbert,

Thank you very much for looking read-only objects.

When mutating an instance variable, the VM triggers a call-back that by default does nothing. In your case, running your code does not raise an exception but the object should not be modified either. If you want an exception, you need to change the call-back code, i.e., the method Object>>#attemptToAssign: value withIndex: index. For example, you could write:

Object>>#attemptToAssign: value withIndex: index 
| process |
self notify: 'object changed !'.
process := Processor activeProcess.
[ process suspendedContext: process suspendedContext sender ] forkAt: Processor activePriority + 1.
Processor yield.

Then, your code should open a notification window with 'object changed', and proceeding keeps running the code without mutating the object.

One needs to build a ModificationTracker framework on top of the VM support I introduced. Multiple things are required, like default behavior in this call-back and in primitive failure code. I am willing to support and help anyone willing to build such a framework, but I won't build it myself.

If you have any other questions or if you find bug don't hesitate to ask further questions

Best,

PS: Make sure "Smalltalk vm supportsWriteBarrier" answers true in your system, if this is not the case it means the VM does not support read-only objects.

Clement




 

Norbert






Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Martin McClure-2
In reply to this post by EstebanLM
On 01/25/2017 03:59 AM, Esteban Lorenzano wrote:
> but this is not real immutability, is like a write barrier, that’s why
> those method names were not chosen.

Thank you for choosing names based on "write barrier," not the incorrect
"read-only" or "immutable" (which are just things that can be done with
a write barrier, but not the only useful things).

Regards,

-Martin

Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

EstebanLM
In reply to this post by philippeback
yeah, something fishy is happening there. I will take a look.

On 25 Jan 2017, at 18:31, [hidden email] wrote:

pharo-win-i386-201701151442-c50dec0.zip

On Wed, Jan 25, 2017 at 3:57 PM, Esteban Lorenzano <[hidden email]> wrote:
nevertheless it should be there in latests vms.
which version are you using?

Esteban 

On 25 Jan 2017, at 15:04, [hidden email] wrote:

Tried it and it returns false for this Windows VM.

Phil

On Wed, Jan 25, 2017 at 2:14 PM, Clément Bera <[hidden email]> wrote:
I introduced the method #supportsWriteBarrier in Pharo 6.

You can backport it if you want:

VirtualMachine>>#supportsWriteBarrier
"Answer whether the VM observes the per-object read-only flag and consequently
aborts writes to inst vars of, and fails primitives that attempt to write, to read-only objects."

^(self parameterAt: 65)
ifNil: [false]
ifNotNil:
[:param| "In older VMs this is a boolean reflecting MULTIPLE_BYTECODE_SETS"
param isInteger "In newer VMs it is a set of integer flags, bit 1 of which is IMMUTABILITY"
ifTrue: [param anyMask: 2]
ifFalse: [false]]



On Wed, Jan 25, 2017 at 2:06 PM, [hidden email] <[hidden email]> wrote:
The "latest" Windows VM I do use has no such method.

Virtual Machine
---------------
C:\Users\Philippe\Dropbox\Sibelga\JiraAutomation\Pharo5.0\latestvm\pharo.exe
CoInterpreter * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
StackToRegisterMappingCogit * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
VM: 201701151442 https://github.com/pharo-project/pharo-vm.git $ Date: Sun Jan 15 15:42:39 2017 +0100 $ Plugins: 201701151442 https://github.com/pharo-project/pharo-vm.git $

Win32 built on Jan 15 2017 15:59:52 CUT Compiler: 5.4.0
VMMaker versionString VM: 201701151442 https://github.com/pharo-project/pharo-vm.git $ Date: Sun Jan 15 15:42:39 2017 +0100 $ Plugins: 201701151442 https://github.com/pharo-project/pharo-vm.git $
CoInterpreter * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017
StackToRegisterMappingCogit * VMMaker.oscog-eem.2090 uuid: 63a161b9-17e1-4911-a89a-1687d9ba9a1a Jan 15 2017

<image.png>


On Wed, Jan 25, 2017 at 1:54 PM, Clément Bera <[hidden email]> wrote:


On Wed, Jan 25, 2017 at 11:35 AM, Norbert Hartl <[hidden email]> wrote:
Does anyone know the state of immutability support in vm and image? The latest vm downloadable is compiled with

IMMUTABILITY=1

(Esteban said that). When I open a pharo6 image with this VM and do:

ASUser new
        setIsReadOnlyObject: true;
        name: 'foo'

with

ASUser>>#name: arg1
        name := arg1

I don't get an exception. Is there something missing or am I not understanding?

Hi Norbert,

Thank you very much for looking read-only objects.

When mutating an instance variable, the VM triggers a call-back that by default does nothing. In your case, running your code does not raise an exception but the object should not be modified either. If you want an exception, you need to change the call-back code, i.e., the method Object>>#attemptToAssign: value withIndex: index. For example, you could write:

Object>>#attemptToAssign: value withIndex: index 
| process |
self notify: 'object changed !'.
process := Processor activeProcess.
[ process suspendedContext: process suspendedContext sender ] forkAt: Processor activePriority + 1.
Processor yield.

Then, your code should open a notification window with 'object changed', and proceeding keeps running the code without mutating the object.

One needs to build a ModificationTracker framework on top of the VM support I introduced. Multiple things are required, like default behavior in this call-back and in primitive failure code. I am willing to support and help anyone willing to build such a framework, but I won't build it myself.

If you have any other questions or if you find bug don't hesitate to ask further questions

Best,

PS: Make sure "Smalltalk vm supportsWriteBarrier" answers true in your system, if this is not the case it means the VM does not support read-only objects.

Clement




 

Norbert







Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Denis Kudriashov
In reply to this post by Clément Béra

2017-01-25 18:23 GMT+01:00 Clément Bera <[hidden email]>:
For the Process hack, it's because the call-back was designed to return no value.

Now I am confused. 
Why anybody needs to return value from this method? 
And why there is  "CAN'T REACH" comment at the end of method?
Do you mean that method should never return? 
 
It may look like it works when returning a value but you will have uncommon crashes.

That's fun :)
Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Denis Kudriashov

2017-01-25 22:24 GMT+01:00 Denis Kudriashov <[hidden email]>:
For the Process hack, it's because the call-back was designed to return no value.

Now I am confused. 
Why anybody needs to return value from this method? 
And why there is  "CAN'T REACH" comment at the end of method?
Do you mean that method should never return? 
 
It may look like it works when returning a value but you will have uncommon crashes.

And is it safe to just signal error? 
Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Clément Béra
The "CAN'T REACH" comment is there because execution never reach that part of the code. If you write code there, it will never be executed. The process code performs a return without pushing any value on stack.

Signalling an error is safe if the error is never resumed. But you'll need the returnNoValue for performance intensive modification tracking.



On Wed, Jan 25, 2017 at 10:26 PM, Denis Kudriashov <[hidden email]> wrote:

2017-01-25 22:24 GMT+01:00 Denis Kudriashov <[hidden email]>:
For the Process hack, it's because the call-back was designed to return no value.

Now I am confused. 
Why anybody needs to return value from this method? 
And why there is  "CAN'T REACH" comment at the end of method?
Do you mean that method should never return? 
 
It may look like it works when returning a value but you will have uncommon crashes.

And is it safe to just signal error? 

Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

NorbertHartl

Am 26.01.2017 um 08:11 schrieb Clément Bera <[hidden email]>:

The "CAN'T REACH" comment is there because execution never reach that part of the code. If you write code there, it will never be executed. The process code performs a return without pushing any value on stack.

Because you return from the sender, right?

Signalling an error is safe if the error is never resumed. But you'll need the returnNoValue for performance intensive modification tracking.


Ok, while you are popping of the stack there is no way to return, right? I cannot see what it has to be that way but I can see that my approach cannot work this way. In my case the error is resumed because not resuming would defeat the purpose of having transparent modification tracking.

I'll use announcements for it because it is a better fit for that anyway.

Norbert


On Wed, Jan 25, 2017 at 10:26 PM, Denis Kudriashov <[hidden email]> wrote:

2017-01-25 22:24 GMT+01:00 Denis Kudriashov <[hidden email]>:
For the Process hack, it's because the call-back was designed to return no value.

Now I am confused. 
Why anybody needs to return value from this method? 
And why there is  "CAN'T REACH" comment at the end of method?
Do you mean that method should never return? 
 
It may look like it works when returning a value but you will have uncommon crashes.

And is it safe to just signal error? 


Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Denis Kudriashov
In reply to this post by Clément Béra

2017-01-26 8:11 GMT+01:00 Clément Bera <[hidden email]>:
The "CAN'T REACH" comment is there because execution never reach that part of the code. If you write code there, it will never be executed. The process code performs a return without pushing any value on stack.

Sorry Clement, maybe I am stupid but it is not clear for me.
If I put halt after "CAN'T REACH" I got debugger which means that it "can reach".
Maybe by "CAN'T REACH" you mean that any return value will not be used? But it is not true: if I return something it will be result of original assignment expression. But as you said it could crash VM.
 

Signalling an error is safe if the error is never resumed. But you'll need the returnNoValue for performance intensive modification tracking.

Do you have reproducible test case to crash VM when #attemptToAssign is badly implemented? It will help for framework implementation and would be nice description for method. In comment we can point to it. Because this magic with forking process is very confusing. 
Also I not get your "returnNoValue" sentence.
Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Clément Béra
In reply to this post by NorbertHartl


On Thu, Jan 26, 2017 at 9:54 AM, Norbert Hartl <[hidden email]> wrote:

Am 26.01.2017 um 08:11 schrieb Clément Bera <[hidden email]>:

The "CAN'T REACH" comment is there because execution never reach that part of the code. If you write code there, it will never be executed. The process code performs a return without pushing any value on stack.

Because you return from the sender, right?

Yes because the process code returns to the sender. 

In Smalltalk a send returns necessarily a value to be pushed on the stack of the context performing the send. In the write barrier call-back, the context is not performing a send, but an instance variable store. Unlike sends, instance variable stores are not expected to push a value on stack. If the call-back returns a value, it's pushed on stack while nothing is expected, and if further code use values on stack it will use the returned value instead of the correct one, furthermore, stack depth computation is messed up, overflowing the context stack somewhere in the runtime memory leading to data corruption.
Signalling an error is safe if the error is never resumed. But you'll need the returnNoValue for performance intensive modification tracking.


Ok, while you are popping of the stack there is no way to return, right? I cannot see what it has to be that way but I can see that my approach cannot work this way. In my case the error is resumed because not resuming would defeat the purpose of having transparent modification tracking.

I'll use announcements for it because it is a better fit for that anyway.

You can signal an error, but then keep the process code. For example:

Object>>#attemptToAssign: value withIndex: index 
| process |
NoModification signal.
process := Processor activeProcess.
[ process suspendedContext: process suspendedContext sender ] forkAt: Processor activePriority + 1.
Processor yield.

this method just works fine.

However, 

Object>>#attemptToAssign: value withIndex: index 
NoModification signal.

this method does not work because it returns a value.


Norbert


On Wed, Jan 25, 2017 at 10:26 PM, Denis Kudriashov <[hidden email]> wrote:

2017-01-25 22:24 GMT+01:00 Denis Kudriashov <[hidden email]>:
For the Process hack, it's because the call-back was designed to return no value.

Now I am confused. 
Why anybody needs to return value from this method? 
And why there is  "CAN'T REACH" comment at the end of method?
Do you mean that method should never return? 
 
It may look like it works when returning a value but you will have uncommon crashes.

And is it safe to just signal error? 



Reply | Threaded
Open this post in threaded view
|

Re: Immutability support

Clément Béra
In reply to this post by Denis Kudriashov

Sorry Clement, maybe I am stupid but it is not clear for me.
If I put halt after "CAN'T REACH" I got debugger which means that it "can reach".
Maybe by "CAN'T REACH" you mean that any return value will not be used? But it is not true: if I return something it will be result of original assignment expression. But as you said it could crash VM.

Ok I tried and I can see that. This is why I have bugs. Well "CAN'T REACH" was supposed to mean it cannot be reached, I don't understand how it could be reached.
 

On Thu, Jan 26, 2017 at 10:18 AM, Denis Kudriashov <[hidden email]> wrote:

2017-01-26 8:11 GMT+01:00 Clément Bera <[hidden email]>:
The "CAN'T REACH" comment is there because execution never reach that part of the code. If you write code there, it will never be executed. The process code performs a return without pushing any value on stack.

Sorry Clement, maybe I am stupid but it is not clear for me.
If I put halt after "CAN'T REACH" I got debugger which means that it "can reach".
Maybe by "CAN'T REACH" you mean that any return value will not be used? But it is not true: if I return something it will be result of original assignment expression. But as you said it could crash VM.
 

Signalling an error is safe if the error is never resumed. But you'll need the returnNoValue for performance intensive modification tracking.

Do you have reproducible test case to crash VM when #attemptToAssign is badly implemented? It will help for framework implementation and would be nice description for method. In comment we can point to it. Because this magic with forking process is very confusing. 
Also I not get your "returnNoValue" sentence.

123