some JDK methods should have ad hoc argument profiling

XMLWordPrintable

    • Type: Enhancement
    • Resolution: Unresolved
    • Priority: P4
    • tbd
    • Affects Version/s: 27
    • Component/s: hotspot
    • None

      Some utility methods (such as Objects.equals, Objects.requireNonNull, Objects.checkIndex), can be viewed as "honorary bytecode instructions", in that they perform very low-level services. If the JVM had been designed slightly differently, they might have been given their own bytecodes (virtual instructions).

      It is perfectly reasonable to implement them as methods, where users used to write out error-prone expressions in their absence.

      x == y || x != null && x.equals(y) ⇒ Objects.equals(x, y)
      if (x == null) throw ... ⇒ Objects.requireNonNull
      if (i<0 || i>=n) throw ... ⇒ Objects.checkIndex

      Refactoring (error-prone) expressions like these into (reliable) methods like thiese is a good practice. But there is one risk. The original hand-written expression was always directly folded into the JIT's IR and optimized in context. But as a method call, the JIT needs to make an inlining decision to get the same effect. This is why such methods are often marked ForceInline in the JDK code (this annotation only works in the JDK).

      There is another optimization risk even after inlining is solved for. The profiling information inside the method is shared by all callers, where (before the refactoring) the profiling information for each hand-written expression was separate. Sadly, hand-written repetitive code is better profiled than refactored code.

      This should be solved for, specifically for low-level JDK methods like these, by profiling their arguments, at every call site (and then inlining). Note that many bytecodes (like aastore and invokevirtual) automatically include profiling of their key arguments. Methods which inline low-level operations, like Objects.equals, should also have their inputs profiled. Since profiling records both nullity and object classes, this would restore important missing optimizations to the comparisons, and to method invocations (like x.equals(y) inside Objects.equals(x,y)).

      Specific proposal:

      1. Build a new annotation @ForceProfile alongside @ForceInline; both annotations valid only in the JDK, and significant to the VM. When a method is marked FP, add argument profile records for all calls to it. (Follow MethodData::profile_unsafe as a template for implementing this.)

      2. If the method is virtual, consider looking for the same descriptor in subclasses as well. Object.equals is a likely candidate.

      3. In the JIT inlining policy, favor inlining of a method marked FP, if the profile data looks valuable. Otherwise apply standard inlining policy. This logic is independent of the older FI marking.

      4. In the JDK, mark appropriate methods as FI, starting with Objects.equals.

      When potentially adding @ForceProfile markings, the thing to look for is:

      A. The method body should be simple, obviously a good profiling candidate.
      B. The method should take at least one reference argument (other than "this").
      C. The method should test reference type or nullity, and/or perform a further method call on a reference.
      D. There is evidence or reasoning that profiles within this method get polluted, harming the optimization of the method, relative to a hand-written expansion of its body.

            Assignee:
            Unassigned
            Reporter:
            John Rose
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: