[jmm-dev] The JSR-133 Cookbook and final fields
Hans Boehm
boehm at acm.org
Sun Nov 20 23:40:21 UTC 2016
Java optimizers are not generally allowed to reread a globally visible
field when the original code didn't. This is yet another reason for that
restriction.
This is different from C and C++.
On Sun, Nov 20, 2016 at 1:37 PM, Petr Chalupa <email at pitr.ch> wrote:
> 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