Just because their layout is the same doesn't mean you can use the wrong one when declaring a data-structure. They still have a very nearly 1-to-1 correspondence with C in that respect too.
Someone else has to answer this. I suppose it's not that bad. The immutables are getting copied into the heap allocated memory from the array, which should be fairly okay to mutate?!But I seriously don't know the details on this. From a semantic viewpoint it's definitely not okay!
On Tuesday, February 10, 2015 at 1:25:15 AM UTC+11, Simon Danisch wrote:Someone else has to answer this. I suppose it's not that bad. The immutables are getting copied into the heap allocated memory from the array, which should be fairly okay to mutate?!But I seriously don't know the details on this. From a semantic viewpoint it's definitely not okay!WARNING: if you use unsafe practices to mutate an immutable object you enter the realms of undefined behaviour where the compiler/runtime can do anything it likes from sending your details to Scammers-R-Us to eating your shorts. Seriously if anything in the compiler optimisations, the runtime or garbage collector is changed to depend on immutables being, well, immutable, then it will cause unknown issues. And there is no guarantee that this hasn't happened already, just your specific code hasn't hit it ... yet.
Things that may be an issue include:1. Julia now has a generational GC, does it assume immutable intergenerational pointers cannot change and doesn't rescan for them?
2. Does the compiler generate the correct GC write barriers for unsafe operations and does it ignore immutables since they can't change?
3. Do optimisations use copies of immutables as implied in the manual, so you don't mutate what you think you mutate?
4. Does the generated code *not* use copies where it normally might, since it doesn't matter if the object is immutable, so again you don't mutate what you expected to?
1. and 2. require the GC to run during the lifetime of the mutated immutable, maybe you have been lucky and that hasn't happened ... yet.3. and 4. the behaviour depends on what other use is made of the immutable, again maybe you have been lucky.As for passing immutables to C, well was always going to be risky, C just doesn't understand immutable. If as suggested by Jameson mutables are layout compatible with C then the faster the habit of using immutables for that dies the better.
On Mon Feb 09 2015 at 7:59:20 PM <ele...@gmail.com> wrote:
On Tuesday, February 10, 2015 at 1:25:15 AM UTC+11, Simon Danisch wrote:Someone else has to answer this. I suppose it's not that bad. The immutables are getting copied into the heap allocated memory from the array, which should be fairly okay to mutate?!But I seriously don't know the details on this. From a semantic viewpoint it's definitely not okay!WARNING: if you use unsafe practices to mutate an immutable object you enter the realms of undefined behaviour where the compiler/runtime can do anything it likes from sending your details to Scammers-R-Us to eating your shorts. Seriously if anything in the compiler optimisations, the runtime or garbage collector is changed to depend on immutables being, well, immutable, then it will cause unknown issues. And there is no guarantee that this hasn't happened already, just your specific code hasn't hit it ... yet.Semantically, modifying a field of the immutable in the array is the same as reading the whole thing, creating a new immutable with one field modified, and writing it back to the array. The only thing you are likely missing by hacking unsafe_store in this manner is a missing TBAA annotation. That's fairly unlikely to matter here though (more about this below).
Things that may be an issue include:1. Julia now has a generational GC, does it assume immutable intergenerational pointers cannot change and doesn't rescan for them?If your type contains pointers to other non-isbits types, you are probably just as well off using a type. They are stored the same. Only `isbits` types get the special inline-storage behavior.
2. Does the compiler generate the correct GC write barriers for unsafe operations and does it ignore immutables since they can't change?No, it doesn't generate write barriers during calls to unsafe_store. Although if you are writing bits data inside the immutable, it hardly matters, since it doesn't need a write barrier to do that.
3. Do optimisations use copies of immutables as implied in the manual, so you don't mutate what you think you mutate?Quite frequently. But if you mutate the array data, you mutate the array data, no questions asked. What you definitely shouldn't do is grab a pointer to your immutable (via pointer_from_objref) and try to mutate that (but trying to grab a pointer to an immutable should become an error in a future version of Julia anyways).
4. Does the generated code *not* use copies where it normally might, since it doesn't matter if the object is immutable, so again you don't mutate what you expected to?This is possible. But it would require LLVM to decide that the array slot itself couldn't have been re-assigned. Any intervening function call is typically enough to block optimization on assuming the array data hasn't changed. But TBAA (type-based alias analysis) is probably more likely to bite you here, since LLVM won't consider the offset store to affect the immutable type it lives inside.
1. and 2. require the GC to run during the lifetime of the mutated immutable, maybe you have been lucky and that hasn't happened ... yet.3. and 4. the behaviour depends on what other use is made of the immutable, again maybe you have been lucky.As for passing immutables to C, well was always going to be risky, C just doesn't understand immutable. If as suggested by Jameson mutables are layout compatible with C then the faster the habit of using immutables for that dies the better.There's nothing risky about it. Types have the same layout and the same behavior when getting passed to C regardless of whether they are declared mutable or immutable. The ccall code hardly even checks the `.mutable` field of the type (and that code hopefully will be deprecated soon, since it doesn't really benefit the user).
Often, however, `immutable` provides a better representation of a C-struct and is therefore necessary for compatibility (unless the only usages of the type are by-pointer).
The updated documentation I mentioned above is part of my ccall-enhancement pull request (which makes calling c functions that require or return by-value structs actually work correctly). It can be read at:
On Tuesday, February 10, 2015 at 1:10:33 PM UTC+11, Jameson wrote:On Mon Feb 09 2015 at 7:59:20 PM <ele...@gmail.com> wrote:
On Tuesday, February 10, 2015 at 1:25:15 AM UTC+11, Simon Danisch wrote:Someone else has to answer this. I suppose it's not that bad. The immutables are getting copied into the heap allocated memory from the array, which should be fairly okay to mutate?!But I seriously don't know the details on this. From a semantic viewpoint it's definitely not okay!WARNING: if you use unsafe practices to mutate an immutable object you enter the realms of undefined behaviour where the compiler/runtime can do anything it likes from sending your details to Scammers-R-Us to eating your shorts. Seriously if anything in the compiler optimisations, the runtime or garbage collector is changed to depend on immutables being, well, immutable, then it will cause unknown issues. And there is no guarantee that this hasn't happened already, just your specific code hasn't hit it ... yet.Semantically, modifying a field of the immutable in the array is the same as reading the whole thing, creating a new immutable with one field modified, and writing it back to the array. The only thing you are likely missing by hacking unsafe_store in this manner is a missing TBAA annotation. That's fairly unlikely to matter here though (more about this below).This depends on what is the immutable object. I am assuming that its the memory inside the array, not some heap object pointed to by the array. If its the latter ignore most of my rant, but I understand (from your excellent documentation referenced below) its the former for at least some immutable structs. If its the memory inside the array then copying another immutable with different field values over it changes the immutable, its only existence is in the array slot, so effectively arrays of immutables are immutable, except for push pop etc.So a user who makes a local copy of a field of an immutable is stuffed (well, its immutable so the field can't change right?), so is the compiler which hoists x = immutable.field out of a loop, as is LLVM if it understands immutable and keeps field values in registers. As you note AA is supposed to fix this, but if its missing then the problem remains, and the user copy isn't subject to AA correction anyway.
Things that may be an issue include:1. Julia now has a generational GC, does it assume immutable intergenerational pointers cannot change and doesn't rescan for them?If your type contains pointers to other non-isbits types, you are probably just as well off using a type. They are stored the same. Only `isbits` types get the special inline-storage behavior.And then you don't mutate an immutable, but it would be good to document this restriction.
2. Does the compiler generate the correct GC write barriers for unsafe operations and does it ignore immutables since they can't change?No, it doesn't generate write barriers during calls to unsafe_store. Although if you are writing bits data inside the immutable, it hardly matters, since it doesn't need a write barrier to do that.Yes, I was thinking of pointers, but your exclusion above cures that.3. Do optimisations use copies of immutables as implied in the manual, so you don't mutate what you think you mutate?Quite frequently. But if you mutate the array data, you mutate the array data, no questions asked. What you definitely shouldn't do is grab a pointer to your immutable (via pointer_from_objref) and try to mutate that (but trying to grab a pointer to an immutable should become an error in a future version of Julia anyways).Again cached copies should be invalidated somehow.
4. Does the generated code *not* use copies where it normally might, since it doesn't matter if the object is immutable, so again you don't mutate what you expected to?This is possible. But it would require LLVM to decide that the array slot itself couldn't have been re-assigned. Any intervening function call is typically enough to block optimization on assuming the array data hasn't changed. But TBAA (type-based alias analysis) is probably more likely to bite you here, since LLVM won't consider the offset store to affect the immutable type it lives inside.Yes, which leads to the above problems.1. and 2. require the GC to run during the lifetime of the mutated immutable, maybe you have been lucky and that hasn't happened ... yet.3. and 4. the behaviour depends on what other use is made of the immutable, again maybe you have been lucky.As for passing immutables to C, well was always going to be risky, C just doesn't understand immutable. If as suggested by Jameson mutables are layout compatible with C then the faster the habit of using immutables for that dies the better.There's nothing risky about it. Types have the same layout and the same behavior when getting passed to C regardless of whether they are declared mutable or immutable. The ccall code hardly even checks the `.mutable` field of the type (and that code hopefully will be deprecated soon, since it doesn't really benefit the user).Its risky in that a mutation inside the C library won't be detected by AA either.
Often, however, `immutable` provides a better representation of a C-struct and is therefore necessary for compatibility (unless the only usages of the type are by-pointer).Thats probably the problematic design decision. Hindsight (that wonderful thing) might suggest a C compatible definition for types that are passed to C (somewhat like the nebulous "standard layout" structs in C++11).
On Mon Feb 09 2015 at 7:59:20 PM <ele...@gmail.com> wrote:
On Tuesday, February 10, 2015 at 1:25:15 AM UTC+11, Simon Danisch wrote:Someone else has to answer this. I suppose it's not that bad. The immutables are getting copied into the heap allocated memory from the array, which should be fairly okay to mutate?!But I seriously don't know the details on this. From a semantic viewpoint it's definitely not okay!WARNING: if you use unsafe practices to mutate an immutable object you enter the realms of undefined behaviour where the compiler/runtime can do anything it likes from sending your details to Scammers-R-Us to eating your shorts. Seriously if anything in the compiler optimisations, the runtime or garbage collector is changed to depend on immutables being, well, immutable, then it will cause unknown issues. And there is no guarantee that this hasn't happened already, just your specific code hasn't hit it ... yet.Semantically, modifying a field of the immutable in the array is the same as reading the whole thing, creating a new immutable with one field modified, and writing it back to the array. The only thing you are likely missing by hacking unsafe_store in this manner is a missing TBAA annotation. That's fairly unlikely to matter here though (more about this below).Things that may be an issue include:1. Julia now has a generational GC, does it assume immutable intergenerational pointers cannot change and doesn't rescan for them?If your type contains pointers to other non-isbits types, you are probably just as well off using a type. They are stored the same. Only `isbits` types get the special inline-storage behavior.2. Does the compiler generate the correct GC write barriers for unsafe operations and does it ignore immutables since they can't change?No, it doesn't generate write barriers during calls to unsafe_store. Although if you are writing bits data inside the immutable, it hardly matters, since it doesn't need a write barrier to do that.3. Do optimisations use copies of immutables as implied in the manual, so you don't mutate what you think you mutate?Quite frequently. But if you mutate the array data, you mutate the array data, no questions asked. What you definitely shouldn't do is grab a pointer to your immutable (via pointer_from_objref) and try to mutate that (but trying to grab a pointer to an immutable should become an error in a future version of Julia anyways).4. Does the generated code *not* use copies where it normally might, since it doesn't matter if the object is immutable, so again you don't mutate what you expected to?This is possible. But it would require LLVM to decide that the array slot itself couldn't have been re-assigned. Any intervening function call is typically enough to block optimization on assuming the array data hasn't changed. But TBAA (type-based alias analysis) is probably more likely to bite you here, since LLVM won't consider the offset store to affect the immutable type it lives inside.1. and 2. require the GC to run during the lifetime of the mutated immutable, maybe you have been lucky and that hasn't happened ... yet.3. and 4. the behaviour depends on what other use is made of the immutable, again maybe you have been lucky.As for passing immutables to C, well was always going to be risky, C just doesn't understand immutable. If as suggested by Jameson mutables are layout compatible with C then the faster the habit of using immutables for that dies the better.There's nothing risky about it. Types have the same layout and the same behavior when getting passed to C regardless of whether they are declared mutable or immutable. The ccall code hardly even checks the `.mutable` field of the type (and that code hopefully will be deprecated soon, since it doesn't really benefit the user).Often, however, `immutable` provides a better representation of a C-struct and is therefore necessary for compatibility (unless the only usages of the type are by-pointer).The updated documentation I mentioned above is part of my ccall-enhancement pull request (which makes calling c functions that require or return by-value structs actually work correctly). It can be read at:
Alignment (or at least, rounding up the size of a structure to a multiple of the requested alignment)
I got a 404 error for that... can you please update the link?