1 /*
   2  * Copyright (c) 2011, 2012, 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  * @test
  26  * @summary smoke tests for CallSite
  27  *
  28  * @build indify.Indify
  29  * @compile CallSiteTest.java
  30  * @run main/othervm/timeout=3600 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies
  31  *      indify.Indify
  32  *      --expand-properties --classpath ${test.classes}
  33  *      --java test.java.lang.invoke.CallSiteTest
  34  */
  35 
  36 package test.java.lang.invoke;
  37 
  38 import java.io.*;
  39 
  40 import java.lang.invoke.*;
  41 import static java.lang.invoke.MethodHandles.*;
  42 import static java.lang.invoke.MethodType.*;
  43 
  44 public class CallSiteTest {
  45     private static final Class<?> CLASS = CallSiteTest.class;
  46 
  47     private static CallSite mcs;
  48     private static CallSite vcs;
  49     private static MethodHandle mh_foo;
  50     private static MethodHandle mh_bar;
  51 
  52     static {
  53         try {
  54             mh_foo = lookup().findStatic(CLASS, "foo", methodType(int.class, int.class, int.class));
  55             mh_bar = lookup().findStatic(CLASS, "bar", methodType(int.class, int.class, int.class));
  56             mcs = new MutableCallSite(mh_foo);
  57             vcs = new VolatileCallSite(mh_foo);
  58         } catch (Exception e) {
  59             e.printStackTrace();
  60         }
  61     }
  62 
  63     public static void main(String... av) throws Throwable {
  64         testMutableCallSite();
  65         testVolatileCallSite();
  66     }
  67 
  68     private static final int N = Integer.MAX_VALUE / 100;
  69     private static final int RESULT1 = 762786192;
  70     private static final int RESULT2 = -21474836;
  71 
  72     private static void assertEquals(int expected, int actual) {
  73         if (expected != actual)
  74             throw new AssertionError("expected: " + expected + ", actual: " + actual);
  75     }
  76 
  77     private static void testMutableCallSite() throws Throwable {
  78         // warm-up
  79         for (int i = 0; i < 20000; i++) {
  80             mcs.setTarget(mh_foo);
  81         }
  82         // run
  83         for (int n = 0; n < 2; n++) {
  84             mcs.setTarget(mh_foo);
  85             for (int i = 0; i < 5; i++) {
  86                 assertEquals(RESULT1, runMutableCallSite());
  87             }
  88             mcs.setTarget(mh_bar);
  89             for (int i = 0; i < 5; i++) {
  90                 assertEquals(RESULT2, runMutableCallSite());
  91             }
  92         }
  93     }
  94     private static void testVolatileCallSite() throws Throwable {
  95         // warm-up
  96         for (int i = 0; i < 20000; i++) {
  97             vcs.setTarget(mh_foo);
  98         }
  99         // run
 100         for (int n = 0; n < 2; n++) {
 101             vcs.setTarget(mh_foo);
 102             for (int i = 0; i < 5; i++) {
 103                 assertEquals(RESULT1, runVolatileCallSite());
 104             }
 105             vcs.setTarget(mh_bar);
 106             for (int i = 0; i < 5; i++) {
 107                 assertEquals(RESULT2, runVolatileCallSite());
 108             }
 109         }
 110     }
 111 
 112     private static int runMutableCallSite() throws Throwable {
 113         int sum = 0;
 114         for (int i = 0; i < N; i++) {
 115             sum += (int) INDY_mcs().invokeExact(i, i+1);
 116         }
 117         return sum;
 118     }
 119     private static int runVolatileCallSite() throws Throwable {
 120         int sum = 0;
 121         for (int i = 0; i < N; i++) {
 122             sum += (int) INDY_vcs().invokeExact(i, i+1);
 123         }
 124         return sum;
 125     }
 126 
 127     static int foo(int a, int b) { return a + b; }
 128     static int bar(int a, int b) { return a - b; }
 129 
 130     private static MethodType MT_bsm() {
 131         shouldNotCallThis();
 132         return methodType(CallSite.class, Lookup.class, String.class, MethodType.class);
 133     }
 134 
 135     private static CallSite bsm_mcs(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
 136         return mcs;
 137     }
 138     private static MethodHandle MH_bsm_mcs() throws ReflectiveOperationException {
 139         shouldNotCallThis();
 140         return lookup().findStatic(lookup().lookupClass(), "bsm_mcs", MT_bsm());
 141     }
 142     private static MethodHandle INDY_mcs() throws Throwable {
 143         shouldNotCallThis();
 144         return ((CallSite) MH_bsm_mcs().invoke(lookup(), "foo", methodType(int.class, int.class, int.class))).dynamicInvoker();
 145     }
 146 
 147     private static CallSite bsm_vcs(Lookup caller, String name, MethodType type) throws ReflectiveOperationException {
 148         return vcs;
 149     }
 150     private static MethodHandle MH_bsm_vcs() throws ReflectiveOperationException {
 151         shouldNotCallThis();
 152         return lookup().findStatic(lookup().lookupClass(), "bsm_vcs", MT_bsm());
 153     }
 154     private static MethodHandle INDY_vcs() throws Throwable {
 155         shouldNotCallThis();
 156         return ((CallSite) MH_bsm_vcs().invoke(lookup(), "foo", methodType(int.class, int.class, int.class))).dynamicInvoker();
 157     }
 158 
 159     private static void shouldNotCallThis() {
 160         // if this gets called, the transformation has not taken place
 161         throw new AssertionError("this code should be statically transformed away by Indify");
 162     }
 163 }