RFR (S) 8073479: Replace obj.getClass hacks with Objects.requireNonNull
John Rose
john.r.rose at oracle.com
Sun Feb 22 00:58:02 UTC 2015
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 <vitalyd at 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.shipilev at 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
>>
>>
>>
More information about the core-libs-dev
mailing list