Safe final immutable objects
pitr-ch opened this issue · 8 comments
this is followup to #102 discussion.
In Java if you create an object where all its fields as declared as final than the visibility of those fields is guaranteed (assuming proper construction (which means that references to it do not escape during construction)).
I am looking for a way to properly construct an object in JRuby having similar guaranty assuming any ivar won't be changed after the construction. So it would not need synchronization for every subsequent method call.
From my limited knowledge of Java and JMM I am thinking that the following should work
module GuaranteedVisibility
require 'jruby'
java_import 'sun.misc.Unsafe'
constructor = Unsafe.java_class.declared_constructor
constructor.accessible = true
UNSAFE = constructor.new_instance
def new(*args, &block)
super *args, &block
# only Java8
# http://openjdk.java.net/jeps/171
# http://stackoverflow.com/questions/23603304/java-8-unsafe-xxxfence-instructions
UNSAFE.store_fence
end
end
class ACLass
extend GuaranteedVisibility
def initialize
@a = 'a'
end
end
AClass.new # guarantees visibility
The store_fence
method will ensure that the store_cache on the processor core will be flushed to memory so all other cores will see the latest values. (Same can be done by writing to a volatile field on Java7.)
@pitr-ch I had completely forgotten about this thread but recently started experimenting with a similar idea. In that implementation I dynamically define new methods on an object's singleton class when a field is set. The newly defined methods don't need to include locking since they are read-only. I haven't done any performance testing or deep research into the inner workings of MRI or JRuby, so I don't know if my approach is as sound as I hope it is (I assume that all Ruby implementations must include some form of locking when dynamically defining new methods). I'd be curious to hear your thoughts on the direction I've taken.
Although this works it will cause trouble since on MRI any method definition drops whole method look-up cache. There will be similar problems on JRuby. Any meta-programming involving changing shape of a type will be costly. Usual assumption for language optimization is that type keeps the shape most of the time. You may find this interesting: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that-clear-rubys-method-cache.md I guess Truffle will be the best in optimizing these but even there a proper memory fence will be way faster. cc @chrisseaton.
I agree I'm afraid this isn't likely to achieve good performance on any implementation of Ruby - including Truffle.
But I was little bit wrong see http://tmm1.net/ruby21-method-cache/, MRI does not drop whole cache any more.
Well that's unfortunate, but I'm certainly glad I asked. Thank you both for the info.
@jdantonio the idea/question I've proposed/asked is still not confirmed so I would like to keep it open until somebody with enough knowledge confirms it or I have time to study and confirm it myself.
It's being resolved in the Synchronization Layer.