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  */
24 
25 package org.openjdk.bench.jdk.incubator.foreign;
26 
27 import jdk.incubator.foreign.MemoryAddress;
28 import jdk.incubator.foreign.MemoryHandles;
29 import jdk.incubator.foreign.MemoryLayout;
30 import jdk.incubator.foreign.MemoryLayouts;
31 import jdk.incubator.foreign.MemorySegment;
32 import org.openjdk.jmh.annotations.Benchmark;
33 import org.openjdk.jmh.annotations.BenchmarkMode;
34 import org.openjdk.jmh.annotations.Fork;
35 import org.openjdk.jmh.annotations.Measurement;
36 import org.openjdk.jmh.annotations.Mode;
37 import org.openjdk.jmh.annotations.OutputTimeUnit;
38 import org.openjdk.jmh.annotations.Setup;
39 import org.openjdk.jmh.annotations.State;
40 import org.openjdk.jmh.annotations.Warmup;
41 
42 import java.lang.invoke.MethodHandle;
43 import java.lang.invoke.MethodHandles;
44 import java.lang.invoke.MethodType;
45 import java.lang.invoke.VarHandle;
46 import java.util.concurrent.TimeUnit;
47 
48 @BenchmarkMode(Mode.AverageTime)
49 @Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
50 @Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
51 @State(org.openjdk.jmh.annotations.Scope.Thread)
52 @OutputTimeUnit(TimeUnit.MILLISECONDS)
53 @Fork(value = 3, jvmArgsAppend = { "--add-modules=jdk.incubator.foreign" })
54 public class TestAdaptVarHandles {
55 
56     static class IntBox {
57 
58         private final int value;
59 
IntBox(int value)60         IntBox(int value) {
61             this.value = value;
62         }
63 
intValue()64         int intValue() {
65             return value;
66         }
67     }
68 
69     static final int ELEM_SIZE = 1_000_000;
70 
71     static final MethodHandle INT_TO_INTBOX;
72     static final MethodHandle INTBOX_TO_INT;
73 
74     static {
75         try {
76             INT_TO_INTBOX = MethodHandles.lookup()
77                     .findConstructor(IntBox.class, MethodType.methodType(void.class, int.class));
78             INTBOX_TO_INT = MethodHandles.lookup()
79                     .findVirtual(IntBox.class, "intValue", MethodType.methodType(int.class));
80         } catch (Throwable ex) {
81             throw new ExceptionInInitializerError(ex);
82         }
83     }
84 
85     static final VarHandle VH_int = MethodHandles.arrayElementVarHandle(int[].class);
86 
87     static final VarHandle VH_box_int = MemoryHandles.filterValue(VH_int, INTBOX_TO_INT, INT_TO_INTBOX);
88 
89     static final VarHandle VH_addr_int = MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT)
90             .varHandle(int.class, MemoryLayout.PathElement.sequenceElement());
91 
92     static final VarHandle VH_addr_box_int = MemoryHandles.filterValue(VH_addr_int, INTBOX_TO_INT, INT_TO_INTBOX);
93 
94     static final MethodHandle MH_int = VH_int.toMethodHandle(VarHandle.AccessMode.GET);
95 
96     static final MethodHandle MH_box_int = MethodHandles.filterReturnValue(MH_int, INT_TO_INTBOX);
97 
98     int[] base = new int[ELEM_SIZE];
99     MemorySegment segment = MemorySegment.ofArray(base);
100 
101     @Setup
setup()102     public void setup() {
103         for (int i = 0; i < ELEM_SIZE; i++) {
104             base[i] = i;
105         }
106     }
107 
108     @Benchmark
vh_loop()109     public int vh_loop() throws Throwable {
110         int sum = 0;
111         for (int i = 0; i < ELEM_SIZE; i++) {
112             sum += (int)VH_int.get(base, i);
113         }
114         return sum;
115     }
116 
117     @Benchmark
vh_box_loop()118     public int vh_box_loop() throws Throwable {
119         int sum = 0;
120         for (int i = 0; i < ELEM_SIZE; i++) {
121             sum += ((IntBox)VH_box_int.get(base, i)).intValue();
122         }
123         return sum;
124     }
125 
126     @Benchmark
mh_loop()127     public int mh_loop() throws Throwable {
128         int sum = 0;
129         for (int i = 0; i < ELEM_SIZE; i++) {
130             sum += (int)MH_int.invokeExact(base, i);
131         }
132         return sum;
133     }
134 
135     @Benchmark
mh_box_loop()136     public int mh_box_loop() throws Throwable {
137         int sum = 0;
138         for (int i = 0; i < ELEM_SIZE; i++) {
139             sum += ((IntBox)MH_box_int.invokeExact(base, i)).intValue();
140         }
141         return sum;
142     }
143 
144     @Benchmark
segment_loop()145     public int segment_loop() throws Throwable {
146         int sum = 0;
147         for (int i = 0; i < ELEM_SIZE; i++) {
148             sum += (int)VH_addr_int.get(segment, (long)i);
149         }
150         return sum;
151     }
152 
153     @Benchmark
segment_box_loop()154     public int segment_box_loop() throws Throwable {
155         int sum = 0;
156         for (int i = 0; i < ELEM_SIZE; i++) {
157             sum += ((IntBox)VH_addr_box_int.get(segment, (long)i)).intValue();
158         }
159         return sum;
160     }
161 }
162