Skip to content

Instantly share code, notes, and snippets.

@rose00
Created April 22, 2025 21:28
Show Gist options
  • Save rose00/b6f7b2d18bae20b9cd277672c05075b5 to your computer and use it in GitHub Desktop.
Save rose00/b6f7b2d18bae20b9cd277672c05075b5 to your computer and use it in GitHub Desktop.

The @IntrinsicCandidate indicates that an annotated method is recognized by vmIntrinsics.hpp and may be subject to intrinsification by the HotSpot VM (see LibraryCallKit::try_to_inline in library_call.cpp) if an intrinsic is available. Intrinsification replaces a candidate method's body, bytecode or native, with handwritten platform assembly and/or compiler IR. Many Java library methods have properties that cannot be deduced by the compiler for optimization, or can utilize specific hardware instructions not modeled by the compiler IR, making intrinsics necessary.

Intrinsification may never happen, or happen at any moment during execution. For example, the bytecodes of a candidate method may be executed by lower compilation tiers of VM execution, while higher compilation tiers may replace the bytecodes with specialized assembly code and/or compiler IR. Therefore, intrinsic implementors must ensure that non-bytecode execution has the same results as execution of the actual Java code in all application contexts (given the assumptions on the arguments hold).

A candidate method should contain a minimal piece of Java code that should be replaced by an intrinsic wholesale. The backing intrinsic is (in the common case) unsafe - they do not perform checks, but have assumptions on their arguments that can ensure type safety. These assumptions must be clearly documented on the candidate methods, and the callers are fully responsible for preventing any kind of type safety violation. As long as these assumptions hold, readers can simply refer to the candidate method's Java code body for program behaviors.

Examples of type safety violations include: dereferencing a null pointer; accessing a field or method on an object which does not possess that field or method; accessing an element of an array not actually present in the array; and manipulating managed references in a way that prevents the GC from managing them.

To ensure type safety, candidate methods are typically private, and access to them are encapsulated by more accessible methods that perform argument validations. Any validation must be done on values that are exclusively accessed by the current thread: shared fields must be read into local variables, and shared arrays must be copied to an exclusive copy, to ensure each shared location (a field or an array component) is accessed exactly once. If a shared location is read multiple times for check and for use, race conditions may cause two reads to produce distinct values, known as TOCTOU (time of check and time of use), and the read for use may produce an illegal value. Finally, the thread-exclusive validated values are passed to the candidate method.

For some highly optimized algorithms, it may be impractical to ensure that array data is read or written only once by the intrinsic. If the caller of the intrinsic cannot guarantee that such array data is unshared, then the caller must also document the effects of any race condition. (Such a race occurs when another thread writes the array data during the execution of the intrinsic.) For example, the documentation can simply say that the result is undefined if a race happens. However, race conditions must not lead to program failures or type safety breaches, as listed above.

The HotSpot VM checks, when loading a class, the consistency of recognized methods and `@IntrinsicCandidate` annotations, unless the `CheckIntrinsics` VM flag is disabled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment