On Jul 8, 2014, at 9:09 PM, John Rose <[email protected]> wrote:
> Regarding the extra cast in accessor logic that Paul picked up on: That may
> be a left-over from obsolete versions of the code, or it may cover for some
> corner cases, or it could possibly be a re-assurance to the JIT.
>
> Generally speaking, we lean heavily on MH types to guarantee a priori
> correctness of argument types. Paul is right that the stored value type is
> already validated and (except for corner cases we may be neglecting) does not
> need re-validation via a cast.
>
> It might be an interesting experiment to replace the cast with an assert.
>
I did briefly look at that a few months ago, i would need to systematically
revisit. My memory is hazy, I seem to recall removing casts perturbed the
compilation process more than i expected.
> Sometimes corner cases bite you. For example, an array store check is
> necessary, if the type is an interface, because interfaces are weakly checked
> all the way up to aastore or invokeinterface.
>
> Sometimes the JIT cannot see the type assurances implicit in a MH type, and
> so (when choosing internal MH code shapes) we must choose between handing the
> JIT code that is not locally verifiable, or adding "reassurance" casts to
> repair the local verifiability of the code. If the JIT thinks it sees
> badly-typed code, it might bail out.Note that "locality" of verifiability is
> a fluid concept, depending sometime on vagaries of inlining decisions. This
> is the reason for some awkward looking "belt and suspenders" MH internals,
> such as the free use of casts in LF bytecode rendering.
>
> Usually, redundant type verifications (including casts and signatures of
> incoming arguments) are eliminated, but they can cause (as noted) an extra
> null check. In theory, that should fold up also, if the null value is
> replaced by "another" null, as (p == null ? null : identityFunction(p)).
>
I quickly verified the fold up does as you expect. Also, if i do the following
the null check goes away:
public class A {
volatile String a = "A";
volatile String snull = null;
public volatile String b;
static final MethodHandle b_setter;
static {
try {
b_setter = MethodHandles.lookup().findSetter(A.class, "b",
String.class);
}
catch (Exception e) {
throw new Error(e);
}
}
public static void main(String[] args) {
A a = new A();
a.testLoop();
}
void testLoop() {
for (int i = 0; i < 1000000; i++) {
testLoopOne(a);
testLoopOne(snull);
}
}
void testLoopOne(String s) {
try {
b_setter.invokeExact(this, s);
} catch (Throwable t) {
throw new Error(t);
}
}
}
I am probably obsessing too much over some micro/nano-benchmarks, but i am
wondering if this could cause some unwanted de-opt/recompilation effects when
all is good with no null values then suddenly a null triggers de-optimization.
Paul.