0. Background:
http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-January/003709.html
http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-January/003712.html
http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-February/003883.html
http://mail.openjdk.java.net/pipermail/valhalla-spec-experts/2018-February/000581.html
1. At the moment value instances cannot be created using new but are instantiated using __MakeDefault.
Alternatively new value instances can be carved out of existing ones using the __WithField operator.
The present ticket is to follow up on Brian's observation that we should "offer a syntax for declaring constructors that
looks more like a regular constructor or factory." This is motivated by "missed the point" comments from several people
who were distracted by __MakeDefault and __WithField."
2. Here are some notes from John Rose on a syntax for declaring value constructors that
looks more like a regular constructor or factory.
This is what I call "classic constructor notation" (CCN). Given that it works OK
out of the box for VBCs, it will also work OK for values. We will want to give it
a refresh (along the Project Amber lines) to work *better* for values (including
withers and other "reconstructors"!). And *better* for objects too, again along
Amber lines (notation improvement across the board, not just for new types).
So, for CCN, I am convinced the most direct translation strategy is the one
which translates 'this.x = y' to 'push L0; push y; withfield VT.x'. Brian would
like to suppress other uses of 'this', which I am fine with pending further discussion.
I think the less-buggy way to translate classic constructors is to set up a hidden
'this' in L0 with 'vdefault' and then piecemeal translate the field assignments (with
or without explicit 'this.' qualifier), adding 'areturn L0' at the end (and every 'return').
The existing DU/DA tracking for fields should be unchanged.
The other translation strategy which Brian suggested publicly, of creating a bunch
of temps for the fields and then assembling the value at the end, may be trickier
to implement in javac (as well as requiring a backtrack if I'm right about user model).
But my main point at this time is to please use the piecemeal withfield translation *if*
it is (as I think it may be) significantly simpler to program in javac.
3. Here is the sketch Brian and John converged on for how we could implement “codes like a class” constructors.
We accept the same compiler productions for constructors as for classes. We impose the following semantic restrictions:
- super() calls are illegal, as there is no superclass
- Forbid all uses of `this` in the constructor body, implicit and explicit, except for
- reads of fields (this.x)
- assignments to fields (this.x = …)
- delegation to this() constructors
This means no instance method calls, no this-bound method refs, etc.
- We use the usual DA/DU analysis on fields, since they’re final
What we change is the translation. We introduce a synthetic local variable, $this, that is initialized to vdefault. Every time we see an assignment to a field, we transform that into a withheld. When we write out the method, instead of writing out a ctor, we write out a synthetic static factory method instead.
So if the user writes:
<acc> Foo(ARGS) {
BODY
}
we translate into
<acc> synthetic static $make$(ARGS) {
$this = vdefault Foo
{ tranform(BODY) }
}
return $this;
}
where transform(BODY) incorporates the following transformations:
this.x = e —> $this = $this.withfield(x, e)
this.x —> getfield $this.x
this(args) —> $this = invokestatic $make$(args)
return —> return $this
any other use of `this`, implicit or not, is an error.
4. Here is some additional notes from John:
I was thinking about value type constructors, and it seems to me that a first
cut is fairly simple.
The first set of actions basically removes value-type specific checks:
* Allow trees of the form x=this.f and this.f=x (get and set value field).
* Allow trees of the form x=f and f=x, converting to this.f as needed.
* Do the DU/DA analysis for final fields, as usual.
Carry those trees through various phases of the compiler, until it's
time to emit code.
The tricky part is modifying code generation of constructors for
value types.
For a constructor, reserve a local (say Local[0]) and use it as a temp
to hold the value type instance under constructor. In a preamble,
initialize it to VT.default.
When generating x=this.f, use a getfield bytecode on the temp.
(This is the same as for object classes, so it's a no-op.)
When generating this.f=x, push the temp, execute withfield
(after a swap, I guess), and store the new value back to the temp.
Finally, emit an epilogue for the constructor which returns the temp.
The constructor must not be named <init>; pick a name (we'll
change it over time) that's conventional. I suggest "$make",
with ACC_STATIC and ACC_SYNTHETIC, and a signature
that returns the VT as its result. It's really an unnamed factory
method, hence the odd spelling and ACC_SYNTHETIC.
Other uses of 'this' should turn into errors, but a first cut can ignore
throwing diagnostics. Finding 'this', apart from a field reference,
in code generation can just throw an assert. But the best design
of all, IMO, would be to allow arbitrary use of 'this' when all fields
are DA. After all, that's the point at which the full instance is live.
I'm probably missing a couple of points but I think the above is
the substance of a solution for adapting object constructors to
values. Note that there doesn't have to be much tree transformation.
No lowering, for example. The raw field references this.f can flow
all the way to code generation. Or so I think…
http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-January/003709.html
http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-January/003712.html
http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-February/003883.html
http://mail.openjdk.java.net/pipermail/valhalla-spec-experts/2018-February/000581.html
1. At the moment value instances cannot be created using new but are instantiated using __MakeDefault.
Alternatively new value instances can be carved out of existing ones using the __WithField operator.
The present ticket is to follow up on Brian's observation that we should "offer a syntax for declaring constructors that
looks more like a regular constructor or factory." This is motivated by "missed the point" comments from several people
who were distracted by __MakeDefault and __WithField."
2. Here are some notes from John Rose on a syntax for declaring value constructors that
looks more like a regular constructor or factory.
This is what I call "classic constructor notation" (CCN). Given that it works OK
out of the box for VBCs, it will also work OK for values. We will want to give it
a refresh (along the Project Amber lines) to work *better* for values (including
withers and other "reconstructors"!). And *better* for objects too, again along
Amber lines (notation improvement across the board, not just for new types).
So, for CCN, I am convinced the most direct translation strategy is the one
which translates 'this.x = y' to 'push L0; push y; withfield VT.x'. Brian would
like to suppress other uses of 'this', which I am fine with pending further discussion.
I think the less-buggy way to translate classic constructors is to set up a hidden
'this' in L0 with 'vdefault' and then piecemeal translate the field assignments (with
or without explicit 'this.' qualifier), adding 'areturn L0' at the end (and every 'return').
The existing DU/DA tracking for fields should be unchanged.
The other translation strategy which Brian suggested publicly, of creating a bunch
of temps for the fields and then assembling the value at the end, may be trickier
to implement in javac (as well as requiring a backtrack if I'm right about user model).
But my main point at this time is to please use the piecemeal withfield translation *if*
it is (as I think it may be) significantly simpler to program in javac.
3. Here is the sketch Brian and John converged on for how we could implement “codes like a class” constructors.
We accept the same compiler productions for constructors as for classes. We impose the following semantic restrictions:
- super() calls are illegal, as there is no superclass
- Forbid all uses of `this` in the constructor body, implicit and explicit, except for
- reads of fields (this.x)
- assignments to fields (this.x = …)
- delegation to this() constructors
This means no instance method calls, no this-bound method refs, etc.
- We use the usual DA/DU analysis on fields, since they’re final
What we change is the translation. We introduce a synthetic local variable, $this, that is initialized to vdefault. Every time we see an assignment to a field, we transform that into a withheld. When we write out the method, instead of writing out a ctor, we write out a synthetic static factory method instead.
So if the user writes:
<acc> Foo(ARGS) {
BODY
}
we translate into
<acc> synthetic static $make$(ARGS) {
$this = vdefault Foo
{ tranform(BODY) }
}
return $this;
}
where transform(BODY) incorporates the following transformations:
this.x = e —> $this = $this.withfield(x, e)
this.x —> getfield $this.x
this(args) —> $this = invokestatic $make$(args)
return —> return $this
any other use of `this`, implicit or not, is an error.
4. Here is some additional notes from John:
I was thinking about value type constructors, and it seems to me that a first
cut is fairly simple.
The first set of actions basically removes value-type specific checks:
* Allow trees of the form x=this.f and this.f=x (get and set value field).
* Allow trees of the form x=f and f=x, converting to this.f as needed.
* Do the DU/DA analysis for final fields, as usual.
Carry those trees through various phases of the compiler, until it's
time to emit code.
The tricky part is modifying code generation of constructors for
value types.
For a constructor, reserve a local (say Local[0]) and use it as a temp
to hold the value type instance under constructor. In a preamble,
initialize it to VT.default.
When generating x=this.f, use a getfield bytecode on the temp.
(This is the same as for object classes, so it's a no-op.)
When generating this.f=x, push the temp, execute withfield
(after a swap, I guess), and store the new value back to the temp.
Finally, emit an epilogue for the constructor which returns the temp.
The constructor must not be named <init>; pick a name (we'll
change it over time) that's conventional. I suggest "$make",
with ACC_STATIC and ACC_SYNTHETIC, and a signature
that returns the VT as its result. It's really an unnamed factory
method, hence the odd spelling and ACC_SYNTHETIC.
Other uses of 'this' should turn into errors, but a first cut can ignore
throwing diagnostics. Finding 'this', apart from a field reference,
in code generation can just throw an assert. But the best design
of all, IMO, would be to allow arbitrary use of 'this' when all fields
are DA. After all, that's the point at which the full instance is live.
I'm probably missing a couple of points but I think the above is
the substance of a solution for adapting object constructors to
values. Note that there doesn't have to be much tree transformation.
No lowering, for example. The raw field references this.f can flow
all the way to code generation. Or so I think…
- relates to
-
JDK-8205910 diagnose use of 'this' with DU fields (for VTs and VBCs)
- Resolved