JDK-8076112 : Add @HotSpotIntrinsicCandidate annotation to indicate methods for which Java Runtime has intrinsics
  • Type: Enhancement
  • Component: core-libs
  • Affected Version: 9
  • Priority: P1
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2015-03-26
  • Updated: 2022-05-17
  • Resolved: 2015-07-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
9 b74Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Intrinsics are high optimized (mostly hand written assembler) code which are used instead of normal JIT compiled code.

There is need to indicate java methods which are intrinsified by JVM:
 - If such methods are modified corresponding code in JVM should also be modified if needed (we had cases in the past when intrinsics stop working and we get performance regression because signature of java method was modified without notifying Hotspot group).
 - Intrinsics assume that all validation checks are done by java code. We want all calls to intrinsified methods precede by clearly related parameter validation function.
 - Intrinsified java method preferably should be 'private' (which is effectively 'final').
 - Intrinsified java method preferably should be 'static' (to discourage coupling of JVM to JDK-defined object layouts).
 - JVM can add restriction to intrinsify only annotated methods to enforce annotation and presence of validation checks in java code.

For future maintainers, the above rules should be explained clearly in the javadoc for @HotSpotIntrinsicCandidate.

Here are suggested changes:


The example of usage:

diff -r dd8d2a336f90 src/java.base/share/classes/java/math/BigInteger.java
--- a/src/java.base/share/classes/java/math/BigInteger.java	Fri Mar 20 11:42:31 2015 -0700
+++ b/src/java.base/share/classes/java/math/BigInteger.java	Thu Mar 26 12:23:06 2015 -0700
@@ -2857,6 +2857,33 @@
      * Multiply an array by one word k and add to result, return the carry
     static int mulAdd(int[] out, int[] in, int offset, int len, int k) {
+    	implMulAddCheck(out, in, offset, len, k);
+    	return implMulAdd(out, in, offset, len, k);
+    }
+    /**
+     * Parameters validation.
+     */
+    private static void implMulAddCheck(int[] out, int[] in, int offset, int len, int k) {
+    	if (len > in.length) {
+    	    throw newIllegalArgumentException("input length is out of bound: " + len + " > " + in.length);
+    	}
+        if (offset < 0) {
+            throw newIllegalArgumentException("input offset is invalid: " + offset);
+        }
+    	if (offset > (out.length - 1)) {
+    	    throw newIllegalArgumentException("input offset is out of bound: " + offset + " > " + (out.length - 1));
+    	}
+    	if (len > (out.length - offset)) {
+    	    throw newIllegalArgumentException("input len is out of bound: " + len + " > " + (out.length - offset));
+    	}
+    }
+    /**
+     * Java Runtime may use intrinsic for this method.
+     */
+    @HotSpotIntrinsicCandidate
+    private static int implMulAdd(int[] out, int[] in, int offset, int len, int k) {
         long kLong = k & LONG_MASK;
         long carry = 0;
URL: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/96e2b032b26f User: lana Date: 2015-07-22 21:33:50 +0000

URL: http://hg.openjdk.java.net/jdk9/jdk9/hotspot/rev/90922865a9d6 User: lana Date: 2015-07-22 21:33:30 +0000

URL: http://hg.openjdk.java.net/jdk9/jdk9/rev/e73e50a98134 User: lana Date: 2015-07-22 21:33:13 +0000

URL: http://hg.openjdk.java.net/jdk9/hs-comp/jdk/rev/96e2b032b26f User: zmajo Date: 2015-07-03 07:14:52 +0000

URL: http://hg.openjdk.java.net/jdk9/hs-comp/hotspot/rev/90922865a9d6 User: zmajo Date: 2015-07-03 07:14:51 +0000

URL: http://hg.openjdk.java.net/jdk9/hs-comp/rev/e73e50a98134 User: zmajo Date: 2015-07-03 07:14:49 +0000

I filed JDK-8129882 to keep track of the issue mentioned in my previous comment.

Hi Rémi, Hi Florian, I investigated a bit more and decided to go for keeping the retention policy RUNTIME. Here are my reasons. Currently, the HotSpotVM looks for a set of per-method annotations so that it can treat these methods specially later on. These annotations are: sun_reflect_CallerSensitive_signature java_lang_invoke_ForceInline_signature java_lang_invoke_DontInline_signature java_lang_invoke_InjectedProfile_signature java_lang_invoke_LambdaForm_Compiled_signature java_lang_invoke_LambdaForm_Hidden_signature java_lang_invoke_Stable_signature sun_misc_Contended_signature I'm not sure which of these annotations is useful for anyone except the VM, but all annotations have a RetentionPolicy.Runtime. (I doubt that, e.g., java_lang_invoke_LambdaForm_Hidden has uses outside of the VM or that sun_misc_Contended_signature has a meaning if the code using it is not running on top of HotSpot.) The reason for retention policy Runtime for these classes is the way the HotSpot VM currently processes annotations. Annotations not visible at runtime are already "gone" by the time the above-listed special annotations are processed and their presence is noted by the VM (in ClassFileParser::AnnotationCollector::annotation_index). So, as the current state is, for HotSpotIntrinsicCandidate we must have RetentionPolicy.RUNTIME, just as for all other VM-relevant annotations. Changing the VM to retain class annotations until a later moment is not in the scope of the current work. The current state can (and maybe should) be improved. We might want to change the RetentionPolicy for all these annotations and and it would also make sense to move these annotations from the three different classes (four with HotSpotIntrinsicCandidate) they are declared in to a single VM-specific class (as John R. already made the observation in a private message). I'll file an issue for that and link it to the current issue. Thank you and best regards, Zoltan

Hi Rémi, then I misunderstood the difference between the different annotation types, thank you for pointing them out to me. I've already sent out the RFR for this work (to hotspot-dev, core-libs-dev, and jdk9-dev). Could you maybe send your comments as a reply to the RFR as well so that other people can see them as well (and they understand why I update the webrev). Thank you and best regards, Zoltan

Zoltan, RetentionPolicy.RUNTIME means accessible by the the Java side (by reflection), RetentionPolicy.CLASS is enough if the annotation is useful for the VM. Having private Hotspot specific annotation visible from the Java side seems a wrong idea for me.

Hi Florian, it is appropriate to use the RUNTIME retention policy because the VM checks at runtime if a method has been marked as intrinsics. See the modifications to library_call.cpp in the RFR that I'll send out soon (hopefully today). Best regards, Zoltan

Is RetentionPolicy.RUNTIME really appropriate here? Wouldn't it be sufficient for analysis purposes if the annotations remained in the class file?

It's probably best to check for two kinds of mismatch. 1. Method marked @HotSpotIntrinsicCandidate, but no intrinsic has been registered in the JVM. It's OK if the intrinsic was explicitly disabled. It's OK if the intrinsic is not present on this platform. Not OK if there is an intrinsic for a *different* method type descriptor. 2. Method not marked @HotSpotIntrinsicCandidate, and intrinsic is registered. In cases where mismatch #1 is possible in the future, we want to encourage programmers to explicitly mark their code where they expect an acceleration of performance. Normally, mismatches should be ignored. But the debug version of the JVM should probably reject them, something like assertion failures. In this way, nightly testing can (probably) detect mismatches before they propagated further. Some intrinsics, like trig functions, are not very interesting to mark in the source, because nothing is likely to go wrong with them. Some intrinsics, like vectorized array processing, should probably be marked to draw attention from maintainers, because the JVM makes an especially aggressive transformation on them.