1+ import org .openjdk .jmh .annotations .*;
2+
3+ import java .lang .foreign .*;
4+ import java .lang .invoke .*;
5+ import java .util .*;
6+
7+ @ State (Scope .Benchmark )
8+ @ Fork (jvmArgsAppend = {"-XX:MaxInlineLevel=15" }) // default is 15 anyway, but override to make sure
9+ public class FFMVarHandleInlineTest {
10+
11+ /**
12+ * Implements the following:
13+ * <pre>{@code
14+ * int JAVA_INT_UNALIGNED(long offset) {
15+ * return MemorySegment
16+ * .ofAddress(offset)
17+ * .reinterpret(8L)
18+ * .get(ValueLayout.JAVA_INT_UNALIGNED, 0L)
19+ * }
20+ * }</pre>
21+ */
22+ private static final VarHandle JAVA_INT_UNALIGNED ;
23+
24+ static {
25+ try {
26+ var ofAddress = MethodHandles .lookup ()
27+ .findStatic (MemorySegment .class , "ofAddress" , MethodType .methodType (MemorySegment .class , long .class ));
28+
29+ var reinterpret = MethodHandles .lookup ()
30+ .findVirtual (MemorySegment .class , "reinterpret" , MethodType .methodType (MemorySegment .class , long .class ));
31+
32+ var vh = ValueLayout .JAVA_INT_UNALIGNED .varHandle ();
33+
34+ vh = MethodHandles .insertCoordinates (vh , 1 , 0L );
35+ vh = MethodHandles .filterCoordinates (vh , 0 , MethodHandles .filterReturnValue (
36+ ofAddress ,
37+ MethodHandles .insertArguments (reinterpret , 1 , 8L )
38+ ));
39+
40+ JAVA_INT_UNALIGNED = vh .withInvokeExactBehavior ();
41+ } catch (NoSuchMethodException | IllegalAccessException e ) {
42+ throw new RuntimeException (e );
43+ }
44+ }
45+
46+ // segment + offsets should comfortably fit in L1 cache
47+
48+ private MemorySegment segment ;
49+
50+ private long [] offsets ;
51+
52+ @ Param (value = {
53+ "1024" , // 1kb
54+ })
55+ private int segmentSize ;
56+
57+ @ Param (value = {
58+ //"8", // 64b
59+ //"512", // 4kb
60+ "2048" , // 16kb
61+ })
62+ private int offsetCount ;
63+
64+ @ Setup
65+ public void init () {
66+ var rand = new Random (7 );
67+
68+ // initialize segment with random values
69+ segment = Arena .ofAuto ().allocate (segmentSize );
70+ for (int i = 0 ; i < segment .byteSize () / 8 ; i ++) {
71+ segment .set (ValueLayout .JAVA_LONG , i * 8 , rand .nextLong ());
72+ }
73+
74+ var ints = (int )(segment .byteSize () >> 2 );
75+
76+ // initialize offset array
77+ offsets = new long [offsetCount ];
78+ for (int i = 0 ; i < offsets .length ; i ++) {
79+ offsets [i ] = segment .address () + (rand .nextInt (ints ) << 2 ); // random
80+ //offsets[i] = segment.address() + ((i % ints) << 2); // sequential
81+ }
82+
83+ // validate that all loops are implemented correctly
84+ var ref = t0_reference ();
85+ if (
86+ ref != t1_level8 () ||
87+ ref != t2_level9 () ||
88+ ref != t3_level10 () ||
89+ ref != t4_level11 ()
90+ ) {
91+ throw new IllegalStateException ();
92+ }
93+ }
94+
95+ @ Benchmark
96+ public int t0_reference () {
97+ var s = 0 ;
98+ for (long offset : offsets ) {
99+ s += (int )JAVA_INT_UNALIGNED .get (offset );
100+ }
101+ return s ;
102+ }
103+
104+ @ CompilerControl (CompilerControl .Mode .DONT_INLINE )
105+ @ Benchmark
106+ public int t1_level8 () {
107+ var s = 0 ;
108+ for (long offset : offsets ) {
109+ s += level8 (offset );
110+ }
111+ return s ;
112+ }
113+
114+ @ CompilerControl (CompilerControl .Mode .DONT_INLINE )
115+ @ Benchmark
116+ public int t2_level9 () {
117+ var s = 0 ;
118+ for (long offset : offsets ) {
119+ s += level9 (offset );
120+ }
121+ return s ;
122+ }
123+
124+ @ CompilerControl (CompilerControl .Mode .DONT_INLINE )
125+ @ Benchmark
126+ public int t3_level10 () {
127+ var s = 0 ;
128+ for (long offset : offsets ) {
129+ s += level10 (offset );
130+ }
131+ return s ;
132+ }
133+
134+ @ CompilerControl (CompilerControl .Mode .DONT_INLINE )
135+ @ Benchmark
136+ public int t4_level11 () {
137+ var s = 0 ;
138+ for (long offset : offsets ) {
139+ s += level11 (offset );
140+ }
141+ return s ;
142+ }
143+
144+ private static int level11 (long offset ) { return level10 (offset ); }
145+ private static int level10 (long offset ) { return level9 (offset ); }
146+ private static int level9 (long offset ) { return level8 (offset ); }
147+ private static int level8 (long offset ) { return level7 (offset ); }
148+ private static int level7 (long offset ) { return level6 (offset ); }
149+ private static int level6 (long offset ) { return level5 (offset ); }
150+ private static int level5 (long offset ) { return level4 (offset ); }
151+ private static int level4 (long offset ) { return level3 (offset ); }
152+ private static int level3 (long offset ) { return level2 (offset ); }
153+ private static int level2 (long offset ) { return level1 (offset ); }
154+ private static int level1 (long offset ) { return level0 (offset ); }
155+ private static int level0 (long offset ) { return (int )JAVA_INT_UNALIGNED .get (offset ); }
156+ //private static int level0(long offset) { return MemorySegment.ofAddress(offset).reinterpret(8L).get(ValueLayout.JAVA_INT_UNALIGNED, 0L); }
157+
158+ }
0 commit comments