JEP 303 and ConstantDynamic
Hontvári Attila
attila at hontvari.net
Thu Aug 3 12:57:10 UTC 2017
(I wrote this idea to valhalla-spec-comments some months ago, but that
list doesn't seems to handle e-mails, so I'm trying now valhalla-dev as
the JEP states that it is the discussion list. )
The JEP proposes the many new intrinsic types (XYConstant,
BootstrapSpecifier, etc.), but I don't see any advantages over the
standard (Class/MethodHandle/etc. ) classes, instead they have many
disadvantages: not very readable, these new classes will be here
forever, and the compiler needs to be aware of them and evaluate the
Constable factory methods at compile-time. So I assume the JEP only
proposes intrinsic types because we can't use the standard existing
classes, because they hold the lookup information that is not available
at compile-time.
But as I understand this, the data of the instances of the intrinsic
types don't have to be known at compile-time; they only have to be known
and constant at run-time. So the evaluation of the constant expressions
can be delayed until the first use, using CONSTANT_Dynamic. In my
proposal, the user can define explicit constant expressions, which the
javac extracts to a condy BSM. In addition, any class could be used in
the expressions, not only the predefined Constables.
My proposal:
1. The user should be able to mark an expression with some keyword like
__CONDY.
Example: MethodHandle mh = __CONDY
MethodHandles.lookup().findVirtual(X.class, etc.);
2. Javac would extract the marked expression into an ad-hoc condy BSM.
3. In the original place of the that expression, javac puts an LDC.
4. For an Instrinsics.* method, the user must use a __CONDY expression.
5. The programmer can use such __CONDY expressions for any other
purposes too (see my example at the end of the email).
6. An alternative proposal for the first point is to pass a lambda
expression to __CONDY:
Example: MethodHandle mh = __CONDY((lookup) ->
lookup.findVirtual(Y.class, etc.));
For example, here is a thread-safe counter using the JEP 303 compiler
intrinsics:
public class Counter303 {
private int i;
public void increment() {
VarHandle VH = Intrinsics.ldc(VarHandleConstant.ofField(
ClassConstant.of("LCounter303;"), "i",
ClassConstant.of("I")));
VH.getAndAdd(this, i);
}
}
In this class, the compiler behaves specially with Intrinsics::ldc,
VarHandleConstant, ClassConstant: that is many complications in the
language for such a small feature. Also, a programmer needs to check for
@TrackableConstant for all methods that he wants to use as an argument
for an Intrinsics.* method.
According to my proposal, this class would be written as:
public class CounterCondy {
private int i;
public void increment() {
VarHandle VH = __CONDY
MethodHandles.lookup().findVarHandle(CounterCondy.class, "i", int.class);
VH.getAndAdd(this, i);
}
}
And the compiler would translate it to:
public class CounterCondy {
private int i;
public void increment() {
[ldc CONSTANT_Dynamic CounterCondy.$bsm1].getAndAdd(this, i);
}
private static VarHandle $bsm1(Lookup lookup, String name, Class
type) {
return MethodHandles.lookup().findVarHandle(CounterCondy.class,
"i", int.class)
}
}
Another negative about the 'Constable' approach is that the list of the
javac-supported Constable subclasses is not extensible. But with my
proposal, this feature can be applied to any type.
For example, compiling a regex pattern is slow. So sometimes people
cache the Pattern objects using static final fields:
private static final Pattern DIGITS = Pattern.compile("[0-9]");
public String[] m(String in) {
return DIGITS.split(in);
}
But this could be expressible using an __CONDY expression according to
my proposal, which is shorter, lazy, and makes the intention more clear:
public String[] m(String in) {
return (__CONDY Pattern.compile("[0-9]")).split(in);
}
Regards,
Attila
More information about the valhalla-dev
mailing list