1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2016 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker import annotations.BootstrapMethod; 18*795d594fSAndroid Build Coastguard Worker import annotations.CalledByIndy; 19*795d594fSAndroid Build Coastguard Worker import java.lang.invoke.CallSite; 20*795d594fSAndroid Build Coastguard Worker import java.lang.invoke.ConstantCallSite; 21*795d594fSAndroid Build Coastguard Worker import java.lang.invoke.MethodHandle; 22*795d594fSAndroid Build Coastguard Worker import java.lang.invoke.MethodHandles; 23*795d594fSAndroid Build Coastguard Worker import java.lang.invoke.MethodType; 24*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.CyclicBarrier; 25*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.atomic.AtomicInteger; 26*795d594fSAndroid Build Coastguard Worker 27*795d594fSAndroid Build Coastguard Worker public class TestInvokeCustomWithConcurrentThreads extends TestBase implements Runnable { 28*795d594fSAndroid Build Coastguard Worker private static final int NUMBER_OF_THREADS = 16; 29*795d594fSAndroid Build Coastguard Worker 30*795d594fSAndroid Build Coastguard Worker private static final AtomicInteger nextIndex = new AtomicInteger(0); 31*795d594fSAndroid Build Coastguard Worker 32*795d594fSAndroid Build Coastguard Worker private static final ThreadLocal<Integer> threadIndex = 33*795d594fSAndroid Build Coastguard Worker new ThreadLocal<Integer>() { 34*795d594fSAndroid Build Coastguard Worker @Override 35*795d594fSAndroid Build Coastguard Worker protected Integer initialValue() { 36*795d594fSAndroid Build Coastguard Worker return nextIndex.getAndIncrement(); 37*795d594fSAndroid Build Coastguard Worker } 38*795d594fSAndroid Build Coastguard Worker }; 39*795d594fSAndroid Build Coastguard Worker 40*795d594fSAndroid Build Coastguard Worker // Array of call sites instantiated, one per thread 41*795d594fSAndroid Build Coastguard Worker private static final CallSite[] instantiated = new CallSite[NUMBER_OF_THREADS]; 42*795d594fSAndroid Build Coastguard Worker 43*795d594fSAndroid Build Coastguard Worker // Array of counters for how many times each instantiated call site is called 44*795d594fSAndroid Build Coastguard Worker private static final AtomicInteger[] called = new AtomicInteger[NUMBER_OF_THREADS]; 45*795d594fSAndroid Build Coastguard Worker 46*795d594fSAndroid Build Coastguard Worker // Array of call site indices of which call site a thread invoked 47*795d594fSAndroid Build Coastguard Worker private static final AtomicInteger[] targetted = new AtomicInteger[NUMBER_OF_THREADS]; 48*795d594fSAndroid Build Coastguard Worker 49*795d594fSAndroid Build Coastguard Worker // Synchronization barrier all threads will wait on in the bootstrap method. 50*795d594fSAndroid Build Coastguard Worker private static final CyclicBarrier barrier = new CyclicBarrier(NUMBER_OF_THREADS); 51*795d594fSAndroid Build Coastguard Worker TestInvokeCustomWithConcurrentThreads()52*795d594fSAndroid Build Coastguard Worker private TestInvokeCustomWithConcurrentThreads() {} 53*795d594fSAndroid Build Coastguard Worker getThreadIndex()54*795d594fSAndroid Build Coastguard Worker private static int getThreadIndex() { 55*795d594fSAndroid Build Coastguard Worker return threadIndex.get().intValue(); 56*795d594fSAndroid Build Coastguard Worker } 57*795d594fSAndroid Build Coastguard Worker notUsed(int x)58*795d594fSAndroid Build Coastguard Worker public static int notUsed(int x) { 59*795d594fSAndroid Build Coastguard Worker return x; 60*795d594fSAndroid Build Coastguard Worker } 61*795d594fSAndroid Build Coastguard Worker run()62*795d594fSAndroid Build Coastguard Worker public void run() { 63*795d594fSAndroid Build Coastguard Worker int x = setCalled(-1 /* argument dropped */); 64*795d594fSAndroid Build Coastguard Worker notUsed(x); 65*795d594fSAndroid Build Coastguard Worker } 66*795d594fSAndroid Build Coastguard Worker 67*795d594fSAndroid Build Coastguard Worker @CalledByIndy( 68*795d594fSAndroid Build Coastguard Worker bootstrapMethod = 69*795d594fSAndroid Build Coastguard Worker @BootstrapMethod( 70*795d594fSAndroid Build Coastguard Worker enclosingType = TestInvokeCustomWithConcurrentThreads.class, 71*795d594fSAndroid Build Coastguard Worker name = "linkerMethod", 72*795d594fSAndroid Build Coastguard Worker parameterTypes = {MethodHandles.Lookup.class, String.class, MethodType.class} 73*795d594fSAndroid Build Coastguard Worker ), 74*795d594fSAndroid Build Coastguard Worker fieldOrMethodName = "setCalled", 75*795d594fSAndroid Build Coastguard Worker returnType = int.class, 76*795d594fSAndroid Build Coastguard Worker parameterTypes = {int.class} 77*795d594fSAndroid Build Coastguard Worker ) setCalled(int index)78*795d594fSAndroid Build Coastguard Worker private static int setCalled(int index) { 79*795d594fSAndroid Build Coastguard Worker called[index].getAndIncrement(); 80*795d594fSAndroid Build Coastguard Worker targetted[getThreadIndex()].set(index); 81*795d594fSAndroid Build Coastguard Worker return 0; 82*795d594fSAndroid Build Coastguard Worker } 83*795d594fSAndroid Build Coastguard Worker 84*795d594fSAndroid Build Coastguard Worker @SuppressWarnings("unused") linkerMethod( MethodHandles.Lookup caller, String name, MethodType methodType)85*795d594fSAndroid Build Coastguard Worker private static CallSite linkerMethod( 86*795d594fSAndroid Build Coastguard Worker MethodHandles.Lookup caller, String name, MethodType methodType) throws Throwable { 87*795d594fSAndroid Build Coastguard Worker MethodHandle mh = 88*795d594fSAndroid Build Coastguard Worker caller.findStatic(TestInvokeCustomWithConcurrentThreads.class, name, methodType); 89*795d594fSAndroid Build Coastguard Worker assertEquals(methodType, mh.type()); 90*795d594fSAndroid Build Coastguard Worker assertEquals(mh.type().parameterCount(), 1); 91*795d594fSAndroid Build Coastguard Worker mh = MethodHandles.insertArguments(mh, 0, getThreadIndex()); 92*795d594fSAndroid Build Coastguard Worker mh = MethodHandles.dropArguments(mh, 0, int.class); 93*795d594fSAndroid Build Coastguard Worker assertEquals(mh.type().parameterCount(), 1); 94*795d594fSAndroid Build Coastguard Worker assertEquals(methodType, mh.type()); 95*795d594fSAndroid Build Coastguard Worker 96*795d594fSAndroid Build Coastguard Worker // Wait for all threads to be in this method. 97*795d594fSAndroid Build Coastguard Worker // Multiple call sites should be created, but only one 98*795d594fSAndroid Build Coastguard Worker // invoked. 99*795d594fSAndroid Build Coastguard Worker barrier.await(); 100*795d594fSAndroid Build Coastguard Worker 101*795d594fSAndroid Build Coastguard Worker instantiated[getThreadIndex()] = new ConstantCallSite(mh); 102*795d594fSAndroid Build Coastguard Worker return instantiated[getThreadIndex()]; 103*795d594fSAndroid Build Coastguard Worker } 104*795d594fSAndroid Build Coastguard Worker test()105*795d594fSAndroid Build Coastguard Worker public static void test() throws Throwable { 106*795d594fSAndroid Build Coastguard Worker // Initialize counters for which call site gets invoked 107*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < NUMBER_OF_THREADS; ++i) { 108*795d594fSAndroid Build Coastguard Worker called[i] = new AtomicInteger(0); 109*795d594fSAndroid Build Coastguard Worker targetted[i] = new AtomicInteger(0); 110*795d594fSAndroid Build Coastguard Worker } 111*795d594fSAndroid Build Coastguard Worker 112*795d594fSAndroid Build Coastguard Worker // Run threads that each invoke-custom the call site 113*795d594fSAndroid Build Coastguard Worker Thread[] threads = new Thread[NUMBER_OF_THREADS]; 114*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < NUMBER_OF_THREADS; ++i) { 115*795d594fSAndroid Build Coastguard Worker threads[i] = new Thread(new TestInvokeCustomWithConcurrentThreads()); 116*795d594fSAndroid Build Coastguard Worker threads[i].start(); 117*795d594fSAndroid Build Coastguard Worker } 118*795d594fSAndroid Build Coastguard Worker 119*795d594fSAndroid Build Coastguard Worker // Wait for all threads to complete 120*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < NUMBER_OF_THREADS; ++i) { 121*795d594fSAndroid Build Coastguard Worker threads[i].join(); 122*795d594fSAndroid Build Coastguard Worker } 123*795d594fSAndroid Build Coastguard Worker 124*795d594fSAndroid Build Coastguard Worker // Check one call site instance won 125*795d594fSAndroid Build Coastguard Worker int winners = 0; 126*795d594fSAndroid Build Coastguard Worker int votes = 0; 127*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < NUMBER_OF_THREADS; ++i) { 128*795d594fSAndroid Build Coastguard Worker assertNotEquals(instantiated[i], null); 129*795d594fSAndroid Build Coastguard Worker if (called[i].get() != 0) { 130*795d594fSAndroid Build Coastguard Worker winners++; 131*795d594fSAndroid Build Coastguard Worker votes += called[i].get(); 132*795d594fSAndroid Build Coastguard Worker } 133*795d594fSAndroid Build Coastguard Worker } 134*795d594fSAndroid Build Coastguard Worker 135*795d594fSAndroid Build Coastguard Worker System.out.println("Winners " + winners + " Votes " + votes); 136*795d594fSAndroid Build Coastguard Worker 137*795d594fSAndroid Build Coastguard Worker // We assert this below but output details when there's an error as 138*795d594fSAndroid Build Coastguard Worker // it's non-deterministic. 139*795d594fSAndroid Build Coastguard Worker if (winners != 1) { 140*795d594fSAndroid Build Coastguard Worker System.out.println("Threads did not the same call-sites:"); 141*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < NUMBER_OF_THREADS; ++i) { 142*795d594fSAndroid Build Coastguard Worker System.out.format( 143*795d594fSAndroid Build Coastguard Worker " Thread % 2d invoked call site instance #%02d\n", i, targetted[i].get()); 144*795d594fSAndroid Build Coastguard Worker } 145*795d594fSAndroid Build Coastguard Worker } 146*795d594fSAndroid Build Coastguard Worker 147*795d594fSAndroid Build Coastguard Worker // We assert this below but output details when there's an error as 148*795d594fSAndroid Build Coastguard Worker // it's non-deterministic. 149*795d594fSAndroid Build Coastguard Worker if (votes != NUMBER_OF_THREADS) { 150*795d594fSAndroid Build Coastguard Worker System.out.println("Call-sites invocations :"); 151*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < NUMBER_OF_THREADS; ++i) { 152*795d594fSAndroid Build Coastguard Worker System.out.format( 153*795d594fSAndroid Build Coastguard Worker " Call site instance #%02d was invoked % 2d times\n", i, called[i].get()); 154*795d594fSAndroid Build Coastguard Worker } 155*795d594fSAndroid Build Coastguard Worker } 156*795d594fSAndroid Build Coastguard Worker 157*795d594fSAndroid Build Coastguard Worker assertEquals(winners, 1); 158*795d594fSAndroid Build Coastguard Worker assertEquals(votes, NUMBER_OF_THREADS); 159*795d594fSAndroid Build Coastguard Worker } 160*795d594fSAndroid Build Coastguard Worker } 161