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

JSR 292: invokeExact (invokehandle) operations should profile method handle behavior forms

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • hs25, 8, 9, 10
    • hotspot

      Method handles, like inner classes, are encapsulated behavior and values, and can be type-profiled for optimistic compilation. The required profiling is different, however, since it needs to look at the MethodHandle.form.vmentry field, rather than the Object._klass field. Since method handle invocation is done with a special hidden bytecode "invokehandle", the profiling machinery should be modified to capture that extra data when executing "invokehandle" instructions.

      Background:

      A method handle's meaning or behavior breaks into three parts:
      1. the compiled bytecode of its LambdaForm (MethodHandle.form.vmentry)
      2. the constants embedded in the LambdaForm expressions
      3. bound values stored in the method handle itself (as a BoundMethodHandle subclass)

      Parts 1 and 2 correspond to the (often anonymous) class of an inner class object which adapts some functional interface. Part 3 corresponds to the instance variables of that object. Normal class-based type profiling in the JVM allows the JIT to produce good code for inner class objects in many cases.

      Currently, part 2 is merged into part 1, because bytecodes are customized to contain all LF constants. JDK-8001106 aims share bytecodes (part 1) among many similar LFs, where the only differences are constant arguments stored in the LF expressions.

      The profiling of method handles therefore has three possible levels:
      A. (Coarse) Detect call sites with one or two distinct bytecode (vmentry values) and optimistically compile code that loads parts 2 and 3 as non-constants.
      B. (Medium) Detect call sites with one or two distinct lambda forms (form values) and optimistically compile code that loads part 3 as non-constants. (Most similar to inner classes.)
      C. (Fine) Detect call sites with one or two distinct method handles (receiver values) and optimistically compile code that inlines the whole method handle.

      Case C. would be a subsumed by instance profiling, as in JDK-8016580.


      Addendum, some additional notes on a possible implementation of Case A or case B...

      We could consider adding profiling to the “linker methods” (bytecode callsite adapters) the VM installs at MH invoke and/or indy bytecode sites. (Some or all of them; we can choose.) Those guys are responsible for appendix argument. The JDK code in invokeHandleForm and callSiteForm spins these linker methods.

      Linker methods are defined by JDK code, but are responsible for the fine semantic details of any user-visible MH or indy call site. For example, the logic of invokeExact that throws an exception if the MH type does not match, and the more complex logic for generic invoke that attempts to adjust argument types (and varargs) on a mismatch, is all inside the JDK-spun code of the linker method. Thus, linker methods can be a potent tool for optimizing (or even enhancing) MH invocation.

      With a little thought, it should be possible to incorporate extra profiling logic into these linker methods. The VM does some profiling at the bytecode level (using interpreter assembly code). By changing the JDK code that spins linker methods, we can add more profiling to complement the existing profiling. We can add MH-specific profiling of the MH shape, such as its LF identity. If by means of such profiling, we could capture an effectively-constant LF, we would be able to inline that LF, even for an invoke of a non-constant MH value.

      The appendix argument associated with the linker method is normally a MemberName (or indy CallSite). If we were to add profiling to the linker method logic, it would have to accumulate the data somewhere. That’s easy; just add an indirection to the appendix argument. Let’s call that a “profiling appendix”. It contains a blank (at first) profile, plus a constant pointer to the MemberName (or CallSite, if we are doing this trick to indy).

      The linker method logic is adjusted to reach through the extra indirection, and also update the profile (so it is no longer blank).

      What’s harder, but perhaps doable without C2 changes, is to coax the C2 optimizer to take action based on the profile data accumulated in the appendix argument. One idea for this: Use stable fields to hold the profile bits, so C2 already knows how to constant fold them (when they are not blank). Add logic like this to the invoker:

      ```
      LambdaForm lfexp = appendix.lfprofile; //stable
      LambdaForm lfact = mh.form;
      if (lfexp != null && lfact == lfexp)
        //do what invokeBasic would do with this LF:
        return linkToStatic(mh … , lfexp.vmentry);
      else return mh.invokeBasic(…);
      ```

      What I’m proposing here is not just an optional profiling “widget” to wrap around a MH. Those are subject to profile pollution if the (wrapped) MH is shared, called from several places with disparate profiled activities. Instead, adding logic to the invoker methods is a systematic play to inject profiling around MH calls (not just free-floating MHs), by hacking into the VM infrastructure that binds them to specific bytecode call sites.

            roland Roland Westrelin
            jrose John Rose
            Votes:
            1 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated: