When Will Jvm Use Intrinsics

When will JVM use intrinsics

The answer is simple: an intrinsic function is defined in this way because a faster, native way to obtain the result of the function exists and it is applied in case thanks to a specified mapping.

That's not something related to compilation at all. Integer.bitCount is special in the sense that implementation is marked to be replaceable with a native asm instruction POPCNT. Basically this native instruction is used when using the Integer.bitCount function (if the CPU supports that instruction), when you declare your own copy of the function the normal implementation is used.

Why JVM is able to recognize that the function can be optimized? Because it's hardcoded somewhere in the JDK, that has nothing to do with similarity to the code.

What is the difference between Java intrinsic and native methods?

The JIT knows about intrinsics, so it can inline the relevant machine instruction into the code it's JITing, and optimize around it as part of a hot loop.

A JNI function is a 100% black box for the compiler, with significant call/return overhead (especially if you use it for just a scalar).

But even if it were just a call to a function like int bitcount(unsigned x){ return __builtin_popcount(x); } that compiled to x86-64 popcnt eax, edi ; ret (x86-64 System V calling convention) the caller (which the JIT compiler is emitting) would still have to assume that all the call-clobbered registers were clobbered. On x86-64, that's most of the integer registers and all the FP/vector registers. (Just like the cost for an ahead-of-time C++ compiler for calling a black-box function vs. an intrinsic). But I suspect the cost for calling a JNI function includes some extra overhead on top of that.

And of course a call to any unknown function means that variables which were in registers might need to be synced to memory if the JIT compiler can't prove that nothing else has a reference to them. (Escape analysis.)

Plus, intrinsics mean the JVM understands what the function does, and can optimize through it. e.g. with constant propagation, it knows that popcount(5) = 2 set bits. But with an actual JNI function, it would still have to call it. And every call is a visible side-effect unless there's some way to declare the function as "pure" so it can CSE.

With heavy inlining, compile time constants are not rare.

Why do java intrinsic functions still have code?

As per wiki, the definition of Intrinsic Function is as follows:

In compiler theory, an intrinsic function is a function available for
use in a given programming language whose implementation is handled
specially by the compiler. Typically, it substitutes a sequence of
automatically generated instructions for the original function call,
similar to an inline function. Unlike an inline function though, the
compiler has an intimate knowledge of the intrinsic function and can
therefore better integrate it and optimize it for the situation. This
is also called builtin function in many languages.

Further it says, important and relevant to your question:

Compilers that implement intrinsic functions generally enable them
only when the user has requested optimization, falling back to a
default implementation provided by the language runtime environment
otherwise.

So, it means a default implementation is used most of the time until optimization is not requested or possible (this depends on which machine/configuration JVM is running on). JVM can replace the whole Integer.bitCount() code to an optimized machine code instruction.

Further, check this discussion which explains the point nicely with an example code.

Where is the assembly implementation code of the intrinsic method in Java HotSpot?

but how to find the actually implementation(assembly code I think) of
the method _getByte

By looking for vmIntrinsics::_getByte in your IDE or simply by grepping HotSpot sources.

However, you won't find the assembly code. Calls to intrinsic methods in HotSpot are typically translated to JIT compiler's intermediate representation (IR). Corresponding IR nodes are manually added to the node graph at the parsing stage of compilation.

Since different JIT compilers have different IRs, intrinsics need to be implemented separately for C1 and C2.

For example, as to _getByte,

  • C1 implementation of the intrinsic is in GraphBuilder::append_unsafe_get_obj;
  • C2 implementation of the intrinsic is in LibraryCallKit::inline_unsafe_access.

What does 'intrinsify' mean in the JVM source code?

JVM intrinsics are methods in the JDK for which the JITs emit specialized sequences of machine instructions which can be directly inlined into the caller. For example on x86 Integer.bitCount(int) can be replaced with the POPCNT instruction.

The pure java implementation is likely too complex to be recognized by peephole optimizations - unlike emulate-rotation-with-shifts for example - and JNI overhead would kill any performance gains from using hand-crafted assembly for a single operation.

Many unsafe methods are also intrinsified so that those method calls are not black boxes for the optimizer (as JNI methods would be), which, yes, allows it to be less conservative. But that's just a sub-property of intrinsification.

  • Wikipedia article
  • Some slides on hotspot intrinsics

(those are basically the top google results for "hotspot intrinsics")

Does Java JIT cheat when running JDK code?

Yes, HotSpot JVM is kind of "cheating", because it has a special version of some BigInteger methods that you won't find in Java code. These methods are called JVM intrinsics.

In particular, BigInteger.multiplyToLen is an intrinsic method in HotSpot. There is a special hand-coded assembly implementation in JVM source base, but only for x86-64 architecture.

You may disable this intrinsic with -XX:-UseMultiplyToLenIntrinsic option to force JVM to use pure Java implementation. In this case the performance will be similar to the performance of your copied code.

P.S. Here is a list of other HotSpot intrinsic methods.

How to disable intrinsics usage for the JIT compiler?

Use

java -XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_<method_name>[,...]

For example

java -XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_equals,_hashCode

As @apangin noticed, you may use -XX:+PrintIntrinsics first to see which methods are actually intrinsified in your test and disable them.



Related Topics



Leave a reply



Submit