RFR: 8251462: No native wrappers generated anymore with -XX:-TieredCompilation after JDK-8251462

Volker Simonis simonis at openjdk.org
Tue Mar 26 19:19:43 UTC 2024


Since [JDK-8251462: Simplify compilation policy](https://bugs.openjdk.org/browse/JDK-8251462), introduced in JDK 17, no native wrappers are generated any more if running with `-XX:-TieredCompilation` (i.e. native methods are not compiled any more).

The attached JMH benchmark demonstrate that native method calls became twice as expensive with JDK 17:

  public static native void emptyStaticNativeMethod();

  @Benchmark
  public static void baseline() {
  }

  @Benchmark
  public static void staticMethodCallingStatic() {
    emptyStaticMethod();
  }

  @Benchmark
  public static void staticMethodCallingStaticNative() {
    emptyStaticNativeMethod();
  }

  @Benchmark
  @Fork(jvmArgsAppend = "-XX:-TieredCompilation")
  public static void staticMethodCallingStaticNativeNoTiered() {
    emptyStaticNativeMethod();
  }

  @Benchmark
  @Fork(jvmArgsAppend = "-XX:+PreferInterpreterNativeStubs")
  public static void staticMethodCallingStaticNativeIntStub() {
    emptyStaticNativeMethod();
  }


JDK 11
======

Benchmark                                           Mode  Cnt   Score   Error  Units
NativeCall.baseline                                 avgt    5   0.390 ± 0.016  ns/op
NativeCall.staticMethodCallingStatic                avgt    5   1.693 ± 0.053  ns/op
NativeCall.staticMethodCallingStaticNative          avgt    5  10.287 ± 0.754  ns/op
NativeCall.staticMethodCallingStaticNativeNoTiered  avgt    5   9.966 ± 0.248  ns/op
NativeCall.staticMethodCallingStaticNativeIntStub   avgt    5  20.384 ± 0.444  ns/op


JDK 17 & 21
===========

Benchmark                                           Mode  Cnt   Score   Error  Units
NativeCall.baseline                                 avgt    5   0.390 ± 0.017  ns/op
NativeCall.staticMethodCallingStatic                avgt    5   1.852 ± 0.272  ns/op
NativeCall.staticMethodCallingStaticNative          avgt    5  10.648 ± 0.661  ns/op
NativeCall.staticMethodCallingStaticNativeNoTiered  avgt    5  20.657 ± 1.084  ns/op
NativeCall.staticMethodCallingStaticNativeIntStub   avgt    5  22.429 ± 0.991  ns/op


The issue can bee seen if we run with `-XX:+PrintCompilation -XX:+PrintInlining`. With JDK 11 we get the following output for `-XX:+TieredCompilation`:

    172  111    b  3       io.simonis.NativeCall::staticMethodCallingStaticNative (4 bytes)
                              @ 0   io.simonis.NativeCall::emptyStaticNativeMethod (0 bytes)   native method
    172  112     n 0       io.simonis.NativeCall::emptyStaticNativeMethod (native)   (static)
    173  113    b  4       io.simonis.NativeCall::staticMethodCallingStaticNative (4 bytes)
                              @ 0   io.simonis.NativeCall::emptyStaticNativeMethod (0 bytes)   native method
    173  111       3       io.simonis.NativeCall::staticMethodCallingStaticNative (4 bytes)   made not entrant

As you can see, the native wrapper for `NativeCall::emptyStaticNativeMethod()` gets compiled with compiled id 112. If we run with `-XX:-TieredCompilation`:

    117    5    b        io.simonis.NativeCall::staticMethodCallingStaticNative (4 bytes)
                            @ 0   io.simonis.NativeCall::emptyStaticNativeMethod (0 bytes)   native method
    117    6     n       io.simonis.NativeCall::emptyStaticNativeMethod (native)   (static)

There's still a native wrapper created with compile id 6.

With JDK 17 and later, the `-XX:+PrintCompilation` output looks similar for the default `-XX:+TieredCompilation` case:

     56   26    b  3       io.simonis.NativeCall::staticMethodCallingStaticNative (4 bytes)
                              @ 0   io.simonis.NativeCall::emptyStaticNativeMethod (0 bytes)   native method
     56   27     n 0       io.simonis.NativeCall::emptyStaticNativeMethod (native)   (static)
     56   28    b  4       io.simonis.NativeCall::staticMethodCallingStaticNative (4 bytes)
                              @ 0   io.simonis.NativeCall::emptyStaticNativeMethod (0 bytes)   native method
     56   26       3       io.simonis.NativeCall::staticMethodCallingStaticNative (4 bytes)   made not entrant

But with `-XX:-TieredCompilation`, we don't generate the native wrapper any more:

     58    5    b        io.simonis.NativeCall::staticMethodCallingStaticNative (4 bytes)
                            @ 0   io.simonis.NativeCall::emptyStaticNativeMethod (0 bytes)   native method


Which basically means that we're always invoking the native method through the interpreter stub.

There are certainly different ways to fix this issue. The one proposed in this PR seemed simple and non-intrusive to me but I'm open for better alternatives. I'd especially appreciate if @veresov could take a look and advice.

Once we agree on the problem and a solution for it, I can also add a test and potentially the JMH benchmark from the JBS issue to this PR.

-------------

Commit messages:
 - 8251462: No native wrappers generated anymore with -XX:-TieredCompilation after JDK-8251462

Changes: https://git.openjdk.org/jdk/pull/18496/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=18496&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8251462
  Stats: 4 lines in 1 file changed: 4 ins; 0 del; 0 mod
  Patch: https://git.openjdk.org/jdk/pull/18496.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/18496/head:pull/18496

PR: https://git.openjdk.org/jdk/pull/18496


More information about the hotspot-compiler-dev mailing list