JDK-8194743 : Compiler implementation for Statements before super()
  • Type: Sub-task
  • Component: tools
  • Sub-Component: javac
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2018-01-08
  • Updated: 2024-03-21
  • Resolved: 2023-11-27
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 22 Other
22 b26Fixed repo-valhallaFixed
Related Reports
CSR :  
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Currently it is not permitted to precede the `this()` or `super()` call in a constructor invocation with statements.  This often causes distorted control flow and challenges in refactoring.  

We would amend JLS 8.8.7 as follows: 

- Production is amended to:

    ConstructorBody:
        { [ BlockStatements ] [ ExplicitConstructorInvocation ] [ BlockStatements ] }
 
- Restriction about first statement is relaxed to apply to the explicit ctor invocation, wherever it resides.

- s/begin with/include/

- Add note (somewhere) that in the first BlockStatement, `this` is DU, and in the second, `this` is DA.

- Clarify that a return statement may only be used in the second BlockStatements.



Comments
A pull request was submitted for review. URL: https://git.openjdk.org/valhalla/pull/981 Date: 2024-01-29 19:12:52 +0000
29-01-2024

Changeset: 12e983a7 Author: Archie Cobbs <acobbs@openjdk.org> Committer: Vicente Romero <vromero@openjdk.org> Date: 2023-11-27 17:26:52 +0000 URL: https://git.openjdk.org/jdk/commit/12e983a72e72ed56741ddc45e47d337716a8da65
27-11-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/13656 Date: 2023-04-25 20:40:18 +0000
25-04-2023

After discussion on amber-dev it was decided to simplify the changes, at least for now. The new change can be stated simply as "Allow zero or more static context statements prior to `this()`/`super()`". Compared to before what has been removed is: * The DA/DU analysis that would have allowed e.g. invoking `this()` in one branch of the code and `super()` in another. * Ability to assign local instance fields JEP has been updated. Original more extensive changes are preserved on branch https://github.com/archiecobbs/jdk/tree/SuperInit1 New simpler changes will for now live on branch https://github.com/archiecobbs/jdk/tree/SuperInit
01-02-2023

* Compiler changes prototyped here: https://github.com/archiecobbs/jdk/tree/JDK-8194743 * Draft JEP created here: https://bugs.openjdk.org/browse/JDK-8300786 > I don't think the present RFE is completely formulated without dealing with this dark corner of the language and JVM specification Agreed, though for practical reasons the JEP proposes only language changes at first, so as to not unnecessarily couple the JLS and JVM changes together, at least in this first round. In addition to what you suggest, it would be nice to allow `super()` within `try { }` blocks, as long as any exceptions thrown therein result in the constructor (re)throwing an exception. This would not only give developers more freedom, but also enable certain bytecode analysis techniques that are now impossible, e.g., time tracking constructors by wrapping them in synthetic `try { } finally { }` statements.
20-01-2023

As clarified in JDK-8159747, the JVM allows a class to assign its own fields, in a constructor, before the super call, even though the receiver state is "uninitializedThis". The relevant spec is https://docs.oracle.com/javase/specs/jvms/se19/html/jvms-4.html#jvms-4.10.1.9.putfield-100.P.1 Setting a local field at this time is reasonable. It supports translation strategies that create up-level links to enclosing classes ("this$0"). See JDK-4030374. I don't think the present RFE is completely formulated without dealing with this dark corner of the language and JVM specification. Specifically, it is reasonable for a class instance to set up its own local state even before a superclass has done so for its local state, because those two sets of state are disjoint and cannot interact, until some kind of subclass code begins to run that can access both sets of state. And that is impossible before the super call. Thus we allow writes to local fields before the super call. (A minor point: The JVM could safely allow reads at this point as well but does not.) To reflect this corner of the JVM's capability, the language should allow a class to access its own fields, even before the super call in a constructor. One general reason is completeness. Another is that users might wish to set up external links before the super call, for reasons similar to those of the translation strategy ("this$0" links). It would be reasonably simple to specify this in the JLS. Direct references to local (non-inherited) fields, either as unqualified names or as names qualified by "this", are already special-cased (in constructors) as aliases for DA/DU variables, if they are final. Extend this special-casing for non-finals as well, except for fields with initializers. (Fields with initializers must continue to be initialized just after the super call, for compatibility, and early access to them should not be allowed.) Then, if early access (either read or write) occurs to such a field, allow the same operations that would be allowed on a regular local variable (perhaps marked final, if the field is final). The earliest point that the field value can be accessed (by the JVM) as an actual stored instance field is either after the super call, or during the super call in a local method (overriding an API point in the super, and called in the super constructor). In order to make such accesses work correctly, it is sufficent to issue a "putfield" instruction immediately before the "invokespecial" instruction to the super constructor, one such "putfield" instruction for each local field that has been accessed, in that constructor, before that point (i.e., the super call). The translation strategy is simple, and reminiscent of the translation of record constructors. Create a synthetic local variable for each local field accessed before the super call. If the field is non-final, initialize it to the field's default value (recall there is no initializer). Translate all reads and writes of the field (as either "f" or "this.f") to use the synthetic local. Then, just before the super call, commit all such locals to the instance, by issuing a series of "putfield" instructions. (This is the only place where a "putfield" stores to "uninitializedThis".) At that point, the synthetic locals are no longer alive (and their slots can be recycled). After the super call, references to the same fields use the older translation strategy, issuing either "getfield" or "putfield" instructions.
21-12-2022

[~dholmes] Yes. That's what is meant by "in the first BlockStatements, `this` is DU" (DU=definitely unassigned.)
08-01-2018

Surely the first set of statements must be precluded from referring to "this" as well ?
08-01-2018