1 /* 2 * Copyright (c) 2021, 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 test.java.lang.constant; 24 25 import java.lang.constant.ClassDesc; 26 import java.lang.constant.ConstantDesc; 27 import java.lang.constant.DirectMethodHandleDesc; 28 import java.lang.constant.DynamicConstantDesc; 29 import java.lang.constant.MethodHandleDesc; 30 import java.lang.constant.MethodTypeDesc; 31 import java.lang.invoke.MethodHandles; 32 import java.util.ArrayList; 33 import java.util.List; 34 import java.util.concurrent.Callable; 35 import java.util.concurrent.CountDownLatch; 36 import java.util.concurrent.ExecutorService; 37 import java.util.concurrent.Executors; 38 import java.util.concurrent.Future; 39 40 /** 41 * @test 42 * @bug 8263108 43 * @summary Verify that concurrent classloading of java.lang.constant.DynamicConstantDesc and 44 * java.lang.constant.ConstantDescs doesn't lead to a deadlock 45 * @run main/othervm DynamicConstantDescTest 46 * @run main/othervm DynamicConstantDescTest 47 * @run main/othervm DynamicConstantDescTest 48 * @run main/othervm DynamicConstantDescTest 49 * @run main/othervm DynamicConstantDescTest 50 */ 51 // Implementation note: This test cannot use testng, since by the time this test gets a chance 52 // to trigger a concurrent classloading of the classes it's interested in, the testng infrastructure 53 // would already have loaded those classes in a single main thread. 54 public class DynamicConstantDescTest { 55 56 /** 57 * Loads {@code java.lang.constant.DynamicConstantDesc} and {@code java.lang.constant.ConstantDescs} 58 * and invokes {@code java.lang.constant.DynamicConstantDesc#ofCanonical()} concurrently in a thread 59 * of their own and expects the classloading of both those classes 60 * to succeed. 61 */ main(final String[] args)62 public static void main(final String[] args) throws Exception { 63 final CountDownLatch taskTriggerLatch = new CountDownLatch(4); 64 final List<Callable<?>> tasks = new ArrayList<>(); 65 // a bunch of tasks - some doing just Class.forName and some 66 // invoking DynamicConstantDesc.ofCanonical 67 tasks.add(new Task("java.lang.constant.DynamicConstantDesc", taskTriggerLatch)); 68 tasks.add(new InvokeOfCanonical(taskTriggerLatch)); 69 tasks.add(new Task("java.lang.constant.ConstantDescs", taskTriggerLatch)); 70 tasks.add(new InvokeOfCanonical(taskTriggerLatch)); 71 final ExecutorService executor = Executors.newFixedThreadPool(tasks.size()); 72 try { 73 final Future<?>[] results = new Future[tasks.size()]; 74 // submit 75 int i = 0; 76 for (final Callable<?> task : tasks) { 77 results[i++] = executor.submit(task); 78 } 79 // wait for completion 80 for (i = 0; i < tasks.size(); i++) { 81 results[i].get(); 82 } 83 } finally { 84 executor.shutdownNow(); 85 } 86 } 87 88 private static class Task implements Callable<Class<?>> { 89 private final String className; 90 private final CountDownLatch latch; 91 Task(final String className, final CountDownLatch latch)92 private Task(final String className, final CountDownLatch latch) { 93 this.className = className; 94 this.latch = latch; 95 } 96 97 @Override call()98 public Class<?> call() { 99 System.out.println(Thread.currentThread().getName() + " loading " + this.className); 100 try { 101 // let the other tasks know we are ready to trigger our work 102 latch.countDown(); 103 // wait for the other task to let us know they are ready to trigger their work too 104 latch.await(); 105 return Class.forName(this.className); 106 } catch (Exception e) { 107 throw new RuntimeException(e); 108 } 109 } 110 } 111 112 enum MyEnum {A, B} 113 114 private static class InvokeOfCanonical implements Callable<Object> { 115 private final CountDownLatch latch; 116 InvokeOfCanonical(final CountDownLatch latch)117 private InvokeOfCanonical(final CountDownLatch latch) { 118 this.latch = latch; 119 } 120 121 @Override call()122 public Object call() { 123 System.out.println(Thread.currentThread().getName() 124 + " calling DynamicConstantDesc.ofCanonical()"); 125 try { 126 // let the other tasks know we are ready to trigger our work 127 latch.countDown(); 128 // wait for the other task to let us know they are ready to trigger their work too 129 latch.await(); 130 ConstantDesc desc = DynamicConstantDesc.ofCanonical(boostrapMethodForEnumConstant(), 131 "A", ClassDesc.of("test.java.lang.constant.DynamicConstantDescTest").nested("MyEnum"), 132 new ConstantDesc[0]); 133 if (desc == null) { 134 throw new Exception("DynamicConstantDesc.ofCanonical unexpectedly returned null"); 135 } 136 if (!MyEnum.A.equals(desc.resolveConstantDesc(MethodHandles.lookup()))) { 137 throw new Exception("DynamicConstantDesc.ofCanonical returned unexpected result " + desc); 138 } 139 return desc; 140 } catch (Exception e) { 141 throw new RuntimeException(e); 142 } 143 } 144 boostrapMethodForEnumConstant()145 private static DirectMethodHandleDesc boostrapMethodForEnumConstant() { 146 ClassDesc[] args = {ClassDesc.of("java.lang.invoke.MethodHandles").nested("Lookup"), 147 ClassDesc.of("java.lang.String"), 148 ClassDesc.of("java.lang.Class")}; 149 return MethodHandleDesc.ofMethod(java.lang.constant.DirectMethodHandleDesc.Kind.STATIC, 150 ClassDesc.of("java.lang.invoke.ConstantBootstraps"), 151 "enumConstant", MethodTypeDesc.of(ClassDesc.of("java.lang.Enum"), new ClassDesc[0]) 152 .insertParameterTypes(0, args)); 153 } 154 155 } 156 157 }