1 /*
  2  * Copyright (c) 2020, 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.jdk.incubator.foreign;
 24 
 25 import jdk.incubator.foreign.FunctionDescriptor;
 26 import jdk.incubator.foreign.MemoryAddress;
 27 import jdk.incubator.foreign.CLinker;
 28 import jdk.incubator.foreign.ResourceScope;
 29 import jdk.incubator.foreign.SymbolLookup;
 30 import org.openjdk.jmh.annotations.Benchmark;
 31 import org.openjdk.jmh.annotations.BenchmarkMode;
 32 import org.openjdk.jmh.annotations.Fork;
 33 import org.openjdk.jmh.annotations.Measurement;
 34 import org.openjdk.jmh.annotations.Mode;
 35 import org.openjdk.jmh.annotations.OutputTimeUnit;
 36 import org.openjdk.jmh.annotations.State;
 37 import org.openjdk.jmh.annotations.Warmup;
 38 
 39 import java.lang.invoke.MethodHandle;
 40 import java.lang.invoke.MethodType;
 41 import java.util.concurrent.TimeUnit;
 42 
 43 import static java.lang.invoke.MethodHandles.lookup;
 44 import static jdk.incubator.foreign.CLinker.C_DOUBLE;
 45 import static jdk.incubator.foreign.CLinker.C_INT;
 46 import static jdk.incubator.foreign.CLinker.C_LONG_LONG;
 47 import static jdk.incubator.foreign.CLinker.C_POINTER;
 48 
 49 @BenchmarkMode(Mode.AverageTime)
 50 @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
 51 @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
 52 @State(org.openjdk.jmh.annotations.Scope.Thread)
 53 @OutputTimeUnit(TimeUnit.NANOSECONDS)
 54 @Fork(value = 3, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED" })
 55 public class Upcalls {
 56 
 57     static final CLinker abi = CLinker.getInstance();
 58     static final MethodHandle blank;
 59     static final MethodHandle identity;
 60     static final MethodHandle args5;
 61     static final MethodHandle args10;
 62 
 63     static final MemoryAddress cb_blank;
 64     static final MemoryAddress cb_identity;
 65     static final MemoryAddress cb_args5;
 66     static final MemoryAddress cb_args10;
 67 
 68     static final long cb_blank_jni;
 69     static final long cb_identity_jni;
 70     static final long cb_args5_jni;
 71     static final long cb_args10_jni;
 72 
 73     static {
 74         System.loadLibrary("UpcallsJNI");
 75 
 76         String className = "org/openjdk/bench/jdk/incubator/foreign/Upcalls";
 77         cb_blank_jni = makeCB(className, "blank", "()V");
 78         cb_identity_jni = makeCB(className, "identity", "(I)I");
 79         cb_args5_jni = makeCB(className, "args5", "(JDJDJ)V");
 80         cb_args10_jni = makeCB(className, "args10", "(JDJDJDJDJD)V");
 81 
 82         try {
 83             System.loadLibrary("Upcalls");
 84             {
 85                 String name = "blank";
 86                 MethodType mt = MethodType.methodType(void.class);
 87                 FunctionDescriptor fd = FunctionDescriptor.ofVoid();
 88 
 89                 blank = linkFunc(name, mt, fd);
 90                 cb_blank = makeCB(name, mt, fd);
 91             }
 92             {
 93                 String name = "identity";
 94                 MethodType mt = MethodType.methodType(int.class, int.class);
 95                 FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_INT);
 96 
 97                 identity = linkFunc(name, mt, fd);
 98                 cb_identity = makeCB(name, mt, fd);
 99             }
100             {
101                 String name = "args5";
102                 MethodType mt = MethodType.methodType(void.class,
103                         long.class, double.class, long.class, double.class, long.class);
104                 FunctionDescriptor fd = FunctionDescriptor.ofVoid(
105                         C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG);
106 
107                 args5 = linkFunc(name, mt, fd);
108                 cb_args5 = makeCB(name, mt, fd);
109             }
110             {
111                 String name = "args10";
112                 MethodType mt = MethodType.methodType(void.class,
113                         long.class, double.class, long.class, double.class, long.class,
114                         double.class, long.class, double.class, long.class, double.class);
115                 FunctionDescriptor fd = FunctionDescriptor.ofVoid(
116                         C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG,
117                         C_DOUBLE, C_LONG_LONG, C_DOUBLE, C_LONG_LONG, C_DOUBLE);
118 
119                 args10 = linkFunc(name, mt, fd);
120                 cb_args10 = makeCB(name, mt, fd);
121             }
122         } catch (ReflectiveOperationException e) {
123             throw new BootstrapMethodError(e);
124         }
125     }
126 
127     static MethodHandle linkFunc(String name, MethodType baseType, FunctionDescriptor baseDesc) {
128         return abi.downcallHandle(
129             SymbolLookup.loaderLookup().lookup(name).orElseThrow(),
130             baseType.insertParameterTypes(baseType.parameterCount(), MemoryAddress.class),
131             baseDesc.withAppendedArgumentLayouts(C_POINTER)
132         );
133     }
134 
135     static MemoryAddress makeCB(String name, MethodType mt, FunctionDescriptor fd) throws ReflectiveOperationException {
136         return abi.upcallStub(
137             lookup().findStatic(Upcalls.class, name, mt),
138             fd, ResourceScope.globalScope()
139         ).address();
140     }
141 
142     static native void blank(long cb);
143     static native int identity(int x, long cb);
144     static native void args5(long a0, double a1, long a2, double a3, long a4, long cb);
145     static native void args10(long a0, double a1, long a2, double a3, long a4,
146                               double a5, long a6, double a7, long a8, double a9, long cb);
147     static native long makeCB(String holder, String name, String signature);
148 
149     @Benchmark
150     public void jni_blank() throws Throwable {
151         blank(cb_blank_jni);
152     }
153 
154     @Benchmark
155     public void panama_blank() throws Throwable {
156         blank.invokeExact(cb_blank);
157     }
158 
159     @Benchmark
160     public int jni_identity() throws Throwable {
161         return identity(10, cb_identity_jni);
162     }
163 
164     @Benchmark
165     public void jni_args5() throws Throwable {
166         args5(1L, 2D, 3L, 4D, 5L, cb_args5_jni);
167     }
168 
169     @Benchmark
170     public void jni_args10() throws Throwable {
171         args10(1L, 2D, 3L, 4D, 5L, 6D, 7L, 8D, 9L, 10D, cb_args10_jni);
172     }
173 
174     @Benchmark
175     public int panama_identity() throws Throwable {
176         return (int) identity.invokeExact(10, cb_identity);
177     }
178 
179     @Benchmark
180     public void panama_args5() throws Throwable {
181         args5.invokeExact(1L, 2D, 3L, 4D, 5L, cb_args5);
182     }
183 
184     @Benchmark
185     public void panama_args10() throws Throwable {
186         args10.invokeExact(1L, 2D, 3L, 4D, 5L, 6D, 7L, 8D, 9L, 10D, cb_args10);
187     }
188 
189     static void blank() {}
190     static int identity(int x) { return x; }
191     static void args5(long a0, double a1, long a2, double a3, long a4) { }
192     static void args10(long a0, double a1, long a2, double a3, long a4,
193                        double a5, long a6, double a7, long a8, double a9) { }
194 }