[jmm-dev] The JSR-133 Cookbook and final fields
Petr Chalupa
email at pitr.ch
Sun Nov 20 21:37:20 UTC 2016
Thanks, I did not realise this is actually ill-advised. The read of b is
racy so it should be no surprise that the value based on it in the final
field can differ.
However I've remembered http://www.hboehm.info/c++mm/why_undef.html and got
a thought how to change the example to be maybe problematic again:
In the constructor with a body as follows
final T a;
T b;
X() {
T local = computeAValue();
b = local;
doMoreOtherThings();
// b never modified, it is equal to local
a = local; // line A
}
could a compiler decide to optimise line A to a read of the same value from
b (introducing the racy read) instead of local variable to save space? What
am I missing, what prevents compiler to do optimisation like that?
Best regards,
Petr Chalupa
On Fri, Nov 18, 2016 at 1:12 AM, Doug Lea <dl at cs.oswego.edu> wrote:
> On 11/17/2016 06:41 PM, Petr Chalupa wrote:
>
>> Hello,
>>
>> If there is only StoreStore barrier at the end of a constructor then
>> following code concerns me:
>>
>
> There are several ill-advised things people can do in constructors that
> cause the base final field guarantee to be useless. Most famously,
> publishing "this" before assigning the field.
>
> static C global;
> class C {
> final int a;
> C (int a) { global = this; this.a = a; }
> }
>
> And as your example shows, initializing a final with the result of
> a computation reading a non-final field is also a bad idea.
> There are probably others too, all of which one hopes any concurrent
> programmer can see are too crazy to do. (And which good tools would
> help point out.)
>
> -Doug
>
>
>> // Thread 1:
>>
>> class X {
>> static X instance;
>> final int a;
>> int b;
>>
>> X() {
>> a = 0;
>> a++;
>> b = 10
>> a += b; // could read 42?
>> }
>> }
>>
>> void publish() {
>> X.instance = new X();
>> }
>>
>> // Thread 2:
>> X.instance.b = 42;
>>
>> Could the read of b in constructor see 42? If it can, a StoreLoad might
>> be required as well.
>> Could you confirm or explain where my thought was wrong. Thanks.
>>
>> Best regards,
>> Petr Chalupa
>>
>> On Wed, Nov 16, 2016 at 1:56 PM, Doug Lea <dl at cs.oswego.edu
>> <mailto:dl at cs.oswego.edu>> wrote:
>>
>> On 11/15/2016 01:44 PM, Hans Boehm wrote:
>>
>> Generalizing final field memory ordering to non-final fields
>> also has
>> optimization consequences on the reader side that we're still
>> struggling
>> with for C++.
>>
>> For example, on any flavor of ARM or Power, in
>>
>> tmp = x;
>> ...
>> tmp2 = y;
>> if (tmp == tmp2) {
>> tmp3 = tmp2.a;
>> }
>>
>> the last assignment can no longer be replaced by tmp3 = tmp.a,
>> because that
>> wouldn't preserve ordering between the load of y and that of a.
>> (I suspect
>> that such a replacement can be beneficial if the branch can be
>> correctly
>> predicted, since tmp may be available earlier.)
>>
>> Presumably similar rules already apply to final field
>> optimization.
>>
>>
>> If Tmp.a is final, both the tmp and tmp2 reads are possible only
>> after tmp.a is (finally) set, so the optimization is OK.
>> (This requires that there be no address speculation for "new" objects.
>> Otherwise all sorts of Java security properties would be broken.)
>>
>> -Doug
>>
>>
>>
>>
>>
>>
>>
>
More information about the jmm-dev
mailing list