Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8231285

consolidate signature fingerprinting code in HotSpot sources

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Won't Fix
    • Icon: P3 P3
    • tbd
    • 14
    • hotspot

      If JDK-8230199 is adopted, there will be a further opportunity to reduce complexity, footprint, and startup time, by consolidating overlapping and redundant "signature fingerprint" mechanisms.

      The `Method::fingerprint` feature is a 64-bit fixed-size bit mask that summarizes the return type and up to 14 parameter types (as `T_INT`, etc.). For methods with more than 14 parameters, the fingerprint has a singular `overflow_fingerprint` value (currently all-one-bits), which forces clients to inspect and parse the character string of the `Method::signature`. Since most methods have less than 15 parameters, this suffices to improve argument and return type classification in nearly all cases.

      (The bit mask also has a status bit the encodes `Method::is_static`, which tells clients whether an extra receiver parameter is present.)

      This fingerprint is used by the `SignatureIterator` class to speed up things like `JavaCalls` and JNI method processing.

      Building this fingerprint is currently the job of the Fingerprinter class, which is designed as a lazily computed accelerator for specific signature-processing tasks. But since the class file parser needs to make *at least one* pass over every signature, it’s reasonable to (a) combine those those passes into one pass, and (b) *also* compute the 64-bit fingerprint.

      Meanwhile, shortly after a method is loaded, when it is linked, the JVM computes adapters for it to help with various special transitions (compiled and interpreted modes). This assignment of adapters is done eagerly for each method, but each distinct "shape" of adapter is built at most once (and lazily, in fact). The distinct "shape" of a required adapter is encoded in a second fingerprint structure, `clas AdapterFingerPrint` (`sharedRuntime.cpp`). These fingerprints are also computed eagerly, once per method (at method link time, which is long before the first call).

      There is clearly an opportunity to consolidate this logic, so that the first fingerprint (computed during class loading) is used to look up the adapters that are installed later (during method linking).

      The contents of an `AdapterFingerPrint` instance for a given method are currently derived by making a scan along the method's signature string. This is a longer way around, and an iteration over the method's pre-computed fingerprint would be faster.

      Better yet, there would be less wasted motion if the actual method fingerprint could be used directly as a key into the registry of adapters (the AdapterHandlerTable).

      There are two tricky issues with making such a change. First, methods with too many arguments don't encode in 64 bits, but are marked with the above-mentioned `overflow_fingerprint` state. Such methods would have to do something more complicated with variable-length registry keys, like the present scheme. Alternatively, such methods would have to get their own non-shared adapters, which might work OK also. The native call adapters use a two-tier scheme like this.

      Second, the data used as a key to the AdapterHandlerTable is different (in minor details) from the fingerprint stored in `Method::fingerprint`. Subword types (like `T_CHAR`) are erased to `T_INT`. More oddly, reference types (`T_OBJECT`, `T_ARRAY`) are erased to an integral type (`T_INT` or `T_LONG`, depending on word size). Also, `T_VOID` markers are present to represent "skipped" words for long and double arguments. There's also a hidden "appendix" argument which shows up in adapters but not in the classfile, for certain methods.

      These differences can be overcome by a number of means. The erasure to int and long can be modeled by a shallow bitwise mapping of the original 64-bit mask, which produces a new mask with "erased" fields, and the appendix can be introduced by adding a field (and dealing with overflow if it happens). The extra `T_VOID` markers can be removed from the key. The modified mask can be used directly as a key in the adapter library.

      A somewhat deeper change would be to change the structure of the `Method::fingerprint` field to cover all the needs of the adapter library. For example:

      1. The current fingerprint mask has 3 unused bits. Use them to remember stuff.
      2. Store at least one more bit which signals "special circumstances".
      2a. Overflow is a special circumstance.
      2b. Overflow is a special circumstance.
      3. Consider narrowing the 4-bit type fields of fingerprints to 2-3 bits, by encoding subword type distinctions elsewhere. The essential parameter types are `T_INT`, `T_LONG`, `T_OBJECT`, `T_FLOAT`, and `T_DOUBLE`, with `T_VOID` also useful in return types. This requires 3 bits, unless non-integral types were similarly collapsed (also a possibility).
      3a. Store subword sizes in additional 2-bit fields shifted higher in the bitmask.
      3b. Locate this bitmask by using a `parameter_size` field in the mask (always present, or else optionally enabled using another slack bit).
      3c. Note that normalizing subwords to int involves removing those extra bits, and perhaps the `parameter_size` field, which would be a simple operation.
      4. Use one slack bit as the "overflow" bit to encode the overflow state.
      4b. Put this slack bit at the lowest bit position, and let `0` be the overflow state.
      4c. When the 64-bit value is even (LSB of `0`), interpret it as a pointer to a structure like today's `AdapterFingerPrint`.
      4d. This expanded structure can have as many 4-bit `BasicType` fields as necessary, and as many extra bits also (such as `is_static`, `has_appendix`, etc.).

            Unassigned Unassigned
            jrose John Rose
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: