Recently, I read here about JVM optimizations , which are great,
but i have a problem with one optimization, namely Null Check Elimination (or Uncommon trap)
To sum up Null Check Elimination removes a if (obj == null) ...
and hopes for the best, while if encounters a Segmentation Fault it recompiles the code and this time includes the neglected if (obj == null) ...
.
My question is, Given:
bool foo(MyClass obj)
{
if(obj == null)
return false;
m_someVar++;
obj.doSomething(m_someVar);
}
because the Null-Check is eliminated, and required only after m_someVar++
.
will foo execute m_someVar++
an extra time when c will be null?
Edit:
Is there some source for deeper explanation on the implementation of this optimizations, which explain how does this optimization keeps the code semantically same?
Thanks
There are many possibilities ho to avoid the problem: Delaying or undoing the increment was already mentioned in a comment. The JVM has a big bag of tricks and some of them applies:
obj.doSomething(m_someVar)
is a non-virtual method call (aprivate
orfinal
method, or a never overridden method), then it probably requires an explicit null check(*) as there would be no SEGV, but the NPE must be thrown before the call. I'm assuming the method was not inlined, as otherwise this analysis should be applied after inlining.obj.doSomething(m_someVar)
is a virtual method call, then you have to do "method dispatch", i.e., something likeobj.getClass().getPointerToMethod("doSomething(int)")
in order to determine what concrete method to call. I wrote "something like" as doing this literally is very time-consuming and gets optimized away as much as possible. This dispatch can be moved above the increment and it itself will throw an NPE, ifobj
happens to benull
.if (obj.getClass() != MyClass.class) uncommon_trap();
, which is the simplest case (called "monomorphic call site"), but even this involves dereferencingobj
and you again get an NPE fornull
.(*) A null check may look like
obj.getClass()
which in assembler is a single instruction loading from a fixed offset relative to theobj
pointer. Whenobj == null
then an unmapped page ist hit.