/* * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.openjdk.bench.vm.compiler; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) @Warmup(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) @Fork(value = 3) public class InterfaceCalls { interface AnInterface { public int getInt(); } interface SecondInterface { public int get1(); } interface OnlyHasOneImplInterface { public int getLong(); } interface AloneInterface { public int getNumber(); } class SingleImplementor implements OnlyHasOneImplInterface { public int getLong() { return 1; } } class Extender1 extends SingleImplementor { } class FirstClass implements AnInterface { public int getInt() { return 1; } } class SecondClass implements AnInterface { public int getInt() { return 2; } } class ThirdClass implements AnInterface { public int getInt() { return -3; } } class FourthClass implements AnInterface { public int getInt() { return -4; } } class FifthClass implements AnInterface { public int getInt() { return -5; } } class MultiClass1 implements AnInterface, SecondInterface { public int get1() { return 1; } public int getInt() { return 2; } } class MultiClass2 implements AnInterface, SecondInterface { public int get1() { return -1; } public int getInt() { return -2; } } class Aloner implements AloneInterface { public int getNumber() { return 7; } } public Object dummy1; public Object dummy2; public Object dummy3; public AnInterface multi1a, multi2a; public SecondInterface multi1b, multi2b; public Object multic, multic2; public AnInterface[] as = new AnInterface[5]; public AnInterface multi; public OnlyHasOneImplInterface single1; public OnlyHasOneImplInterface single2; public AloneInterface alone; int count; @Setup public void setupSubclass() { dummy1 = new FirstClass(); dummy2 = new SecondClass(); dummy3 = new ThirdClass(); as[0] = new FirstClass(); as[1] = new SecondClass(); as[2] = new ThirdClass(); as[3] = new FourthClass(); as[4] = new FifthClass(); MultiClass1 mc1 = new MultiClass1(); multi1a = mc1; multi1b = mc1; multic = mc1; MultiClass2 mc2 = new MultiClass2(); multi2a = mc2; multi2b = mc2; multic2 = mc2; single1 = new SingleImplementor(); single2 = new Extender1(); alone = new Aloner(); } private void swapMultiParts() { AnInterface tmpa = multi1a; SecondInterface tmpb = multi1b; multi1a = multi2a; multi2a = tmpa; multi1b = multi2b; multi2b = tmpb; } @SuppressWarnings("unused") private void swapMulti() { Object tmp = multic; multic = multic2; multic2 = tmp; } /** * Tests a call where there are multiple implementors but only one of the implementors is every used here so the * call-site is monomorphic */ @Benchmark public int testMonomorphic() { return as[0].getInt(); } /** Tests a interface call that only has one single implementation */ @Benchmark public int testSingle() { return alone.getNumber(); } /** * Tests a call where there is a single implementation but multiple classes that inherit that implementation and both * these implementors are used. */ @Benchmark public int testSingle2() { OnlyHasOneImplInterface oi; if ((count & 1) == 0) { oi = single1; } else { oi = single2; } count++; return oi.getLong(); } /** * Tests calling two different interface methods in two different interfaces on the same receiver. Make sure to switch * between two different types of receivers to achieve polymorhpism */ @Benchmark public void testCall2Poly2(Blackhole bh) { bh.consume(multi1a.getInt()); bh.consume(multi1b.get1()); swapMultiParts(); } @Benchmark public int testCallMulti1Poly2NoSwap() { return multi1a.getInt(); } /** * This test goes together with Multi2 below It tests if a class implements multiple interfaces if the different * interfaces take different amounts of time (They do for hotspot) */ @Benchmark public int testCallMulti1Poly2() { swapMultiParts(); return multi1a.getInt(); } /** * This test goes together with Multi2 below It tests if a class implements multiple interfaces if the different * interfaces take different amounts of time (They do for hotspot) */ @Benchmark public int testCallMulti2Poly2() { swapMultiParts(); return multi1b.get1(); } /** Interface call with three different receivers */ @Benchmark public void testCallPoly3(Blackhole bh) { for (int kk = 0; kk < 3; kk++) { bh.consume(as[kk].getInt()); } } /** Interface call with five different receivers. */ @Benchmark public void testCallPoly5(Blackhole bh) { for (int kk = 0; kk < 5; kk++) { bh.consume(as[kk].getInt()); } } int l; /** * Interface call address computation within loop but the receiver preexists the loop and the ac can be moved outside * of the loop */ @Benchmark public int testAC1() { AnInterface ai = as[l]; l = 1 - l; return ai.getInt(); } /** Tests an interface cast followed by an interface call. */ @Benchmark public int testInterfaceCastAndCall() throws Exception { return ((AnInterface) dummy1).getInt() + ((AnInterface) dummy2).getInt() + ((AnInterface) dummy3).getInt(); } }