All of the proposed tweaks to null checks fall down for somebody, some time.

The reason Object.getClass was being used in that twisty way is to get early 
placement of the null check.  Receiver null checks are performed at the call 
site, instead of inside the shared callee method.  So the trick of getClass is 
that you get to use the per-call-site profiling (of the receiver null check).

There are several possible ways to "fix" Objects.requireNonNull so that it 
resists profile pollution.

1. Special pleading:  Assume if the internal profile for O.rNN says "nulls have 
appeared here", that's uniquely ignorable.  A dirty hack, perhaps justifiable.  
This could be done a couple of ways:

1.1 Compiler intrinsic:  Make O.rNN into a compiler intrinsic.  Then we have 
our way with it.

1.2 Profile injection:  Modify the JDK code of O.rNN to declare that the 
profile should be special-cased.  It would be something like a "NOTREACHED" 
pragma.  We used this technique in JDK-8063137.  A simpler form could apply 
here also.  This technique is better, since it leaves a clear "footprint" in 
the Java code that something is happening.

2. Adopt ignorance:  Keep the implicit null check optimization (using OS traps, 
as Remi described).  But, stop using nullness profiles to disable this 
optimization, for some general class of methods which includes O.rNN.  The 
problem with this there are 0.001% places where null check exceptions are on 
warm paths, and those customers will get trap storms.

3. Stop optimizing:  Ditch the implicit null check optimization; use explicitly 
coded null checks.  This is a straw man, since the code density and path length 
would degrade for no particular benefit.  (Some null checks are elidable based 
on local type inference, but a stubborn percentage are not.  
PrintOptoStatistics tracks these numbers.)

4. Stop optimizing when the profile is polluted, which is the status quo.  
Aleksey has some evidence we lose a mere 1/3 of a machine cycle on some 
machines, with a polluted O.rNN.  I assume this requires good branch prediction 
and prefetch.  The HotSpot project includes optimizations to assist machines 
with poor branch prediction or prefetch, for various reasons I won't go into.  
The implicit null checks are such optimizations.  If O.rNN is going to be a 
full replacement for explicit null checks, we need to make sure it can't 
suddenly change its performance characteristics, because one client has fed it 
nulls.

5. Refine profiling:  Somehow gather profile information (at least nullness) on 
the operand to O.rNN, before it leaves user code and arrives in the shared 
(profile-pollutable) code of O.rNN.  There are several ways to do this, 
including:

5.1 Perform profiling in Tier One code, including inlined copies of O.rNN and 
any other trivial-enough function.  Use the context-specific profiles in Tier 
Two.  We have not developed this very far.

5.2 Perform argument profiling.  Set TypeProfileLevel=2 by default, or use some 
other logic that enhances argument profiling of calls to O.rNN.  This probably 
also needs more work.

I think 1.2 and 5.2 are worth working on.

— John

On Feb 20, 2015, at 6:20 AM, Vitaly Davidovich <vita...@gmail.com> wrote:
> 
> I really hope this doesn't require intrinsifying requireNonNull since, as
> mentioned before, this is a general issue.  I'm almost tempted to say that
> JIT should always treat a null check followed by an explicit NPE as being
> an uncommon path, despite what profile may say.
> 
> sent from my phone
> On Feb 20, 2015 8:18 AM, "Aleksey Shipilev" <aleksey.shipi...@oracle.com>
> wrote:
> 
>> Hi Peter,
>> 
>> Thanks for additional testing!
>> 
>> On 02/20/2015 03:48 PM, Peter Levart wrote:
>>> So we hope for Objects.requireNonNull to be inlined most of the times.
>> 
>> Yes, I think so, otherwise it is a platform bug :) And, as I said in
>> reply to Vitaly, the ultimate answer would be to intrinsify
>> Objects.requireNonNull to unconditionally bias it towards the non-null
>> case and implicit NP checks.
>> 
>> The test is actually specifically crafted to amplify the costs of the
>> pollution. The side effect of that method is excessive method calls.
>> It's not a surprise CPUs can execute the dense code oblivious of minor
>> code differences. (Speculation: CPUs need to re-adjust their pipelines
>> after the real call, so non-inlined version would pay some extra)
>> 
>> Thanks,
>> -Aleksey
>> 
>> 
>> 

Reply via email to