1 /* 2 * Copyright (c) 2014 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.vm.compiler; 24 25 import org.openjdk.jmh.annotations.Benchmark; 26 import org.openjdk.jmh.annotations.BenchmarkMode; 27 import org.openjdk.jmh.annotations.Mode; 28 import org.openjdk.jmh.annotations.OutputTimeUnit; 29 import org.openjdk.jmh.annotations.Scope; 30 import org.openjdk.jmh.annotations.Setup; 31 import org.openjdk.jmh.annotations.State; 32 import org.openjdk.jmh.infra.Blackhole; 33 34 import java.util.concurrent.TimeUnit; 35 36 @BenchmarkMode(Mode.AverageTime) 37 @OutputTimeUnit(TimeUnit.NANOSECONDS) 38 @State(Scope.Thread) 39 public class InterfaceCalls { 40 41 interface AnInterface { 42 public int getInt(); 43 } 44 45 interface SecondInterface { 46 public int get1(); 47 } 48 49 interface OnlyHasOneImplInterface { 50 public int getLong(); 51 } 52 53 interface AloneInterface { 54 public int getNumber(); 55 } 56 57 class SingleImplementor implements OnlyHasOneImplInterface { 58 public int getLong() { 59 return 1; 60 } 61 } 62 63 class Extender1 extends SingleImplementor { 64 } 65 66 class FirstClass implements AnInterface { 67 public int getInt() { 68 return 1; 69 } 70 } 71 72 class SecondClass implements AnInterface { 73 public int getInt() { 74 return 2; 75 } 76 } 77 78 class ThirdClass implements AnInterface { 79 public int getInt() { 80 return -3; 81 } 82 } 83 84 class FourthClass implements AnInterface { 85 public int getInt() { 86 return -4; 87 } 88 } 89 90 class FifthClass implements AnInterface { 91 public int getInt() { 92 return -5; 93 } 94 } 95 96 class MultiClass1 implements AnInterface, SecondInterface { 97 public int get1() { 98 return 1; 99 } 100 101 public int getInt() { 102 return 2; 103 } 104 } 105 106 class MultiClass2 implements AnInterface, SecondInterface { 107 public int get1() { 108 return -1; 109 } 110 111 public int getInt() { 112 return -2; 113 } 114 } 115 116 class Aloner implements AloneInterface { 117 public int getNumber() { 118 return 7; 119 } 120 } 121 122 public Object dummy1; 123 124 public Object dummy2; 125 126 public Object dummy3; 127 128 public AnInterface multi1a, multi2a; 129 130 public SecondInterface multi1b, multi2b; 131 132 public Object multic, multic2; 133 134 public AnInterface[] as = new AnInterface[5]; 135 136 public AnInterface multi; 137 138 public OnlyHasOneImplInterface single1; 139 140 public OnlyHasOneImplInterface single2; 141 142 public AloneInterface alone; 143 144 int count; 145 146 @Setup 147 public void setupSubclass() { 148 dummy1 = new FirstClass(); 149 dummy2 = new SecondClass(); 150 dummy3 = new ThirdClass(); 151 as[0] = new FirstClass(); 152 as[1] = new SecondClass(); 153 as[2] = new ThirdClass(); 154 as[3] = new FourthClass(); 155 as[4] = new FifthClass(); 156 MultiClass1 mc1 = new MultiClass1(); 157 multi1a = mc1; 158 multi1b = mc1; 159 multic = mc1; 160 MultiClass2 mc2 = new MultiClass2(); 161 multi2a = mc2; 162 multi2b = mc2; 163 multic2 = mc2; 164 single1 = new SingleImplementor(); 165 single2 = new Extender1(); 166 alone = new Aloner(); 167 } 168 169 private void swapMultiParts() { 170 AnInterface tmpa = multi1a; 171 SecondInterface tmpb = multi1b; 172 multi1a = multi2a; 173 multi2a = tmpa; 174 multi1b = multi2b; 175 multi2b = tmpb; 176 } 177 178 @SuppressWarnings("unused") 179 private void swapMulti() { 180 Object tmp = multic; 181 multic = multic2; 182 multic2 = tmp; 183 } 184 185 /** 186 * Tests a call where there are multiple implementors but only one of the implementors is every used here so the 187 * call-site is monomorphic 188 */ 189 @Benchmark 190 public int testMonomorphic() { 191 return as[0].getInt(); 192 } 193 194 /** Tests a interface call that only has one single implementation */ 195 @Benchmark 196 public int testSingle() { 197 return alone.getNumber(); 198 } 199 200 /** 201 * Tests a call where there is a single implementation but multiple classes that inherit that implementation and both 202 * these implementors are used. 203 */ 204 @Benchmark 205 public int testSingle2() { 206 OnlyHasOneImplInterface oi; 207 if ((count & 1) == 0) { 208 oi = single1; 209 } else { 210 oi = single2; 211 } 212 count++; 213 return oi.getLong(); 214 } 215 216 /** 217 * Tests calling two different interface methods in two different interfaces on the same receiver. Make sure to switch 218 * between two different types of receivers to achieve polymorhpism 219 */ 220 @Benchmark 221 public void testCall2Poly2(Blackhole bh) { 222 bh.consume(multi1a.getInt()); 223 bh.consume(multi1b.get1()); 224 swapMultiParts(); 225 } 226 227 @Benchmark 228 public int testCallMulti1Poly2NoSwap() { 229 return multi1a.getInt(); 230 } 231 232 /** 233 * This test goes together with Multi2 below It tests if a class implements multiple interfaces if the different 234 * interfaces take different amounts of time (They do for hotspot) 235 */ 236 @Benchmark 237 public int testCallMulti1Poly2() { 238 swapMultiParts(); 239 return multi1a.getInt(); 240 } 241 242 /** 243 * This test goes together with Multi2 below It tests if a class implements multiple interfaces if the different 244 * interfaces take different amounts of time (They do for hotspot) 245 */ 246 @Benchmark 247 public int testCallMulti2Poly2() { 248 swapMultiParts(); 249 return multi1b.get1(); 250 } 251 252 /** Interface call with three different receivers */ 253 @Benchmark 254 public void testCallPoly3(Blackhole bh) { 255 for (int kk = 0; kk < 3; kk++) { 256 bh.consume(as[kk].getInt()); 257 } 258 } 259 260 /** Interface call with five different receivers. */ 261 @Benchmark 262 public void testCallPoly5(Blackhole bh) { 263 for (int kk = 0; kk < 3; kk++) { 264 bh.consume(as[kk].getInt()); 265 } 266 } 267 268 int l; 269 270 /** 271 * Interface call address computation within loop but the receiver preexists the loop and the ac can be moved outside 272 * of the loop 273 */ 274 @Benchmark 275 public int testAC1() { 276 AnInterface ai = as[l]; 277 l = 1 - l; 278 return ai.getInt(); 279 } 280 281 /** Tests an interface cast followed by an interface call. */ 282 @Benchmark 283 public int testInterfaceCastAndCall() throws Exception { 284 return ((AnInterface) dummy1).getInt() + ((AnInterface) dummy2).getInt() 285 + ((AnInterface) dummy3).getInt(); 286 } 287 }