1 /* 2 * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.bench.java.lang.foreign; 24 25 import java.lang.foreign.*; 26 27 import org.openjdk.jmh.annotations.Benchmark; 28 import org.openjdk.jmh.annotations.BenchmarkMode; 29 import org.openjdk.jmh.annotations.Fork; 30 import org.openjdk.jmh.annotations.Measurement; 31 import org.openjdk.jmh.annotations.Mode; 32 import org.openjdk.jmh.annotations.OutputTimeUnit; 33 import org.openjdk.jmh.annotations.State; 34 import org.openjdk.jmh.annotations.Warmup; 35 36 import java.lang.foreign.Arena; 37 import java.lang.invoke.MethodHandle; 38 import java.lang.invoke.MethodType; 39 import java.util.concurrent.TimeUnit; 40 41 import static java.lang.invoke.MethodHandles.lookup; 42 43 @BenchmarkMode(Mode.AverageTime) 44 @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) 45 @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) 46 @State(org.openjdk.jmh.annotations.Scope.Thread) 47 @OutputTimeUnit(TimeUnit.NANOSECONDS) 48 @Fork(value = 3, jvmArgsAppend = { "--enable-native-access=ALL-UNNAMED" }) 49 public class Upcalls extends CLayouts { 50 51 static final Linker abi = Linker.nativeLinker(); 52 static final MethodHandle blank; 53 static final MethodHandle identity; 54 static final MethodHandle args5; 55 static final MethodHandle args10; 56 57 static final MemorySegment cb_blank; 58 static final MemorySegment cb_identity; 59 static final MemorySegment cb_args5; 60 static final MemorySegment cb_args10; 61 62 static final long cb_blank_jni; 63 static final long cb_identity_jni; 64 static final long cb_args5_jni; 65 static final long cb_args10_jni; 66 67 static { 68 System.loadLibrary("UpcallsJNI"); 69 70 String className = "org/openjdk/bench/java/lang/foreign/Upcalls"; 71 cb_blank_jni = JNICB.makeCB(className, "blank", "()V"); 72 cb_identity_jni = JNICB.makeCB(className, "identity", "(I)I"); 73 cb_args5_jni = JNICB.makeCB(className, "args5", "(JDJDJ)V"); 74 cb_args10_jni = JNICB.makeCB(className, "args10", "(JDJDJDJDJD)V"); 75 76 try { 77 System.loadLibrary("Upcalls"); 78 { 79 String name = "blank"; 80 MethodType mt = MethodType.methodType(void.class); 81 FunctionDescriptor fd = FunctionDescriptor.ofVoid(); 82 83 blank = linkFunc(name, fd); 84 cb_blank = makeCB(name, mt, fd); 85 } 86 { 87 String name = "identity"; 88 MethodType mt = MethodType.methodType(int.class, int.class); 89 FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_INT); 90 91 identity = linkFunc(name, fd); 92 cb_identity = makeCB(name, mt, fd); 93 } 94 { 95 String name = "args5"; 96 MethodType mt = MethodType.methodType(void.class, 97 long.class, double.class, long.class, double.class, long.class); 98 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 99 C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG); 100 101 args5 = linkFunc(name, fd); 102 cb_args5 = makeCB(name, mt, fd); 103 } 104 { 105 String name = "args10"; 106 MethodType mt = MethodType.methodType(void.class, 107 long.class, double.class, long.class, double.class, long.class, 108 double.class, long.class, double.class, long.class, double.class); 109 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 110 C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG, 111 C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE); 112 113 args10 = linkFunc(name, fd); 114 cb_args10 = makeCB(name, mt, fd); 115 } 116 } catch (ReflectiveOperationException e) { 117 throw new BootstrapMethodError(e); 118 } 119 } 120 121 static MethodHandle linkFunc(String name, FunctionDescriptor baseDesc) { 122 return abi.downcallHandle( 123 SymbolLookup.loaderLookup().find(name).orElseThrow(), 124 baseDesc.appendArgumentLayouts(C_POINTER) 125 ); 126 } 127 128 static MemorySegment makeCB(String name, MethodType mt, FunctionDescriptor fd) throws ReflectiveOperationException { 129 return abi.upcallStub( 130 lookup().findStatic(Upcalls.class, name, mt), 131 fd, Arena.global() 132 ); 133 } 134 135 static native void blank(long cb); 136 static native int identity(int x, long cb); 137 static native void args5(long a0, double a1, long a2, double a3, long a4, long cb); 138 static native void args10(long a0, double a1, long a2, double a3, long a4, 139 double a5, long a6, double a7, long a8, double a9, long cb); 140 141 @Benchmark 142 public void jni_blank() throws Throwable { 143 blank(cb_blank_jni); 144 } 145 146 @Benchmark 147 public void panama_blank() throws Throwable { 148 blank.invokeExact(cb_blank); 149 } 150 151 @Benchmark 152 public int jni_identity() throws Throwable { 153 return identity(10, cb_identity_jni); 154 } 155 156 @Benchmark 157 public void jni_args5() throws Throwable { 158 args5(1L, 2D, 3L, 4D, 5L, cb_args5_jni); 159 } 160 161 @Benchmark 162 public void jni_args10() throws Throwable { 163 args10(1L, 2D, 3L, 4D, 5L, 6D, 7L, 8D, 9L, 10D, cb_args10_jni); 164 } 165 166 @Benchmark 167 public int panama_identity() throws Throwable { 168 return (int) identity.invokeExact(10, cb_identity); 169 } 170 171 @Benchmark 172 public void panama_args5() throws Throwable { 173 args5.invokeExact(1L, 2D, 3L, 4D, 5L, cb_args5); 174 } 175 176 @Benchmark 177 public void panama_args10() throws Throwable { 178 args10.invokeExact(1L, 2D, 3L, 4D, 5L, 6D, 7L, 8D, 9L, 10D, cb_args10); 179 } 180 181 static void blank() {} 182 static int identity(int x) { return x; } 183 static void args5(long a0, double a1, long a2, double a3, long a4) { } 184 static void args10(long a0, double a1, long a2, double a3, long a4, 185 double a5, long a6, double a7, long a8, double a9) { } 186 }