Here’s a scenario where I want constant folding, when types are known statically:
static final ClassValue<Foo> MYCV = ...;
static final Class<Bar> C_Bar = Bar.class;
static final Foo BAR_FOO = MYCV.get(C_Bar);
Foo getCV0() { return MYCV.get(C_Bar); }
// == BAR_FOO as a constant
Foo getCV1(Bar x) { return MYCV.get(x.getClass()); }
// == BAR_FOO as a constant if Bar is final, or x.getClass == Bar
Foo getCV2(Object x) { return MYCV.get(x.getClass()); }
// == BAR_FOO if x.getClass == Bar
Like MutableCallSite.getTarget, ClassValue.get is likely to be a constant
value for a long time, and it is profitable for the JIT to speculate that it
will be constant forever. This requires putting a dependency on n-methods
that incorporate a speculated constant, so that if MutableCallSite.setTarget
or ClassValue.remove is called, the code can be recompiled.
As part of a solution to this, I wonder if maybe we should refactor the existing dependency stuff to work on arbitrary values instead of MHs, so that there is some building block MostlyConstant which holds a speculatively-constant value, so that the JIT will aggressively fold through it with a dependency.
Or, we can just apply the special logic on CallSite.target to another
suitable field, of whatever internal ClassValue$Entry structure tracks
an individual class value binding. To generalize this logic, we could
mark such fields with an internal annotation. (H/T to Vladimir I.)
Like @Stable means that a field has an uninitialized past and a
permanent future, @MostlyConstant (name to be chosen) means that
the present state is reliable but not necessarily permanent. The two
annotations would work together, in which case a field would not
be speculated if it were in its default state.
For ClassValue::get, the other part of the solution is to be sure that the
JIT can execute the necessary table lookup performed by ClassValue::get
at compile time, when (as is often the case) the Class argument can be
inferred to be a constant.
static final ClassValue<Foo> MYCV = ...;
static final Class<Bar> C_Bar = Bar.class;
static final Foo BAR_FOO = MYCV.get(C_Bar);
Foo getCV0() { return MYCV.get(C_Bar); }
// == BAR_FOO as a constant
Foo getCV1(Bar x) { return MYCV.get(x.getClass()); }
// == BAR_FOO as a constant if Bar is final, or x.getClass == Bar
Foo getCV2(Object x) { return MYCV.get(x.getClass()); }
// == BAR_FOO if x.getClass == Bar
Like MutableCallSite.getTarget, ClassValue.get is likely to be a constant
value for a long time, and it is profitable for the JIT to speculate that it
will be constant forever. This requires putting a dependency on n-methods
that incorporate a speculated constant, so that if MutableCallSite.setTarget
or ClassValue.remove is called, the code can be recompiled.
As part of a solution to this, I wonder if maybe we should refactor the existing dependency stuff to work on arbitrary values instead of MHs, so that there is some building block MostlyConstant which holds a speculatively-constant value, so that the JIT will aggressively fold through it with a dependency.
Or, we can just apply the special logic on CallSite.target to another
suitable field, of whatever internal ClassValue$Entry structure tracks
an individual class value binding. To generalize this logic, we could
mark such fields with an internal annotation. (H/T to Vladimir I.)
Like @Stable means that a field has an uninitialized past and a
permanent future, @MostlyConstant (name to be chosen) means that
the present state is reliable but not necessarily permanent. The two
annotations would work together, in which case a field would not
be speculated if it were in its default state.
For ClassValue::get, the other part of the solution is to be sure that the
JIT can execute the necessary table lookup performed by ClassValue::get
at compile time, when (as is often the case) the Class argument can be
inferred to be a constant.
- relates to
-
JDK-8351215 ClassValue API improvements
-
- New
-