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 }