Loosening requirements for super() invocation

Archie Cobbs archie.cobbs at gmail.com
Tue Nov 1 22:46:23 UTC 2022


On Tue, Nov 1, 2022 at 4:30 PM Brian Goetz <brian.goetz at oracle.com> wrote:

> First of all, when should this rule apply?
>
> At any point in a constructor (one that successfully compiles), the new
> object is always definitively in one of three states:
>
> State 0: neither super() nor this() has been invoked; neither the
> superclass nor this class are initialized
> State 1: super() has been invoked, so the superclass is initialized, but
> at least one final field in this class has not been initialized
> State 2: super() has been invoked and all final fields in this class have
> been initialized
>
> BTW, the current state is easily tracked within the existing DA/DU
> analysis of the prototype patch.
>
> The possible state transitions are:
>
> - super() takes you from:
>   - State 0 → State 1 if there remain any uninitialized final fields
>   - State 0 → State 2 if there are no remaining uninitialized final fields
> - this() takes you from State 0 → State 2
> - Initializing the last final field takes you from:
>   - State 0 → State 0
>   - State 1 → State 2
>
> Presumably the 'this' escape analysis should only apply in State 1. This
> is when the object is vulnerable because it's half initialized.
>
>
> In actuality, `this` can escape in any of the states; escaping means that
> `this` is exposed before the return from the constructor.  (Even the very
> last line of the constructor is suspect.  A class could have subclasses,
> which means we're still in "the middle" of the subclass constructor, and
> even for a final class, the write barrier does not get emitted until after
> the constructor completes.)
>

It can't escape in State 0, because the JVM itself prevents that, right?

But of course you're right about State 2 - the subclass constructor is
still happening at that point, and so you could invoke a method that is
overridden in the subclass, but the subclass won't be ready for it yet.

In any case, let's start with the strictest view and work backwards to
> relaxation.  The receiver may escape if:
>
>  - a non-final instance method is invoked (*)
>  - an instance method declared in a superclass is invoked
>  - the variable `this` is used for anything other than field access
>
> We should analyze not only constructor code, but instance initializer
> blocks and instance field initializers as well.
>

Yes... they are just blobs of code that get executed immediately after any
super() calls (as I've learned) and the patch includes a similar change to
that effect for DA/DU already.


> We can exclude final instance methods declared in the same class if the
> same analysis of the method (recursively) shows no escape of `this` (this
> is the * in the first bullet above.)
>

Neat.

You could also analyze static methods in the class to verify non-escape if
they were invoked with 'this' as a parameter... it's more or less the same
situation.

Any code in the compilation unit that is directly invoked by the
constructor and that can't possibly be overridden could in theory be fair
game for this non-escape analysis.

Inner class creation is a similar story as calling final methods in the
> same class; we can do a similar analysis of the inner class constructor to
> verify non-escape.
>

But the inner class Outer.Inner's constructor is going to say this.$0 =
Outer.this, which is an escape for Outer.this, right?

That would permit sneaky situations like this (choose either lambda or
inner class variant):

    public class MyClass  {

        public MyClass() {
            new Runnable() {
                public void run() {
                    MyClass.this.foo();
                }
            }.run();
        }

        public void foo() {
            // ...
        }
    }


> For the meaning of "known to be equal to 'this'", we would be limited in
> our ability to infer it in the usual ways (Turing complete, blah blah), so
> you'd still be able to evade the warning e.g.:
>
>
> For this to happen, `this` must have already escaped or have been assigned
> to another variable.  The above already detects this.
>

Right - in other words, the "anything other than field access" clause would
disallow casting (Object)this like in the example.

-Archie

-- 
Archie L. Cobbs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20221101/3248954a/attachment-0001.htm>


More information about the amber-dev mailing list