[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