1 /*
  2  * Copyright (c) 2022, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 import com.sun.javatest.regtest.agent.CustomMainWrapper;
 27 
 28 import java.lang.invoke.MethodHandle;
 29 import java.lang.invoke.MethodHandles;
 30 import java.lang.invoke.MethodType;
 31 import java.util.ArrayList;
 32 import java.util.List;
 33 import java.util.concurrent.ThreadFactory;
 34 
 35 public class Virtual implements CustomMainWrapper {
 36 
 37     private static List<String> vmOpts = new ArrayList<>();
 38     static {
 39         vmOpts.add("--enable-preview");
 40 
 41         // This property is used by ProcessTools
 42         vmOpts.add("-Dmain.wrapper=Virtual");
 43     }
 44 
 45     public Virtual() {
 46     }
 47 
 48     @Override
 49     public Thread createThread(ThreadGroup tg, Runnable task) {
 50         ThreadFactory factory;
 51         try {
 52             factory = VirtualAPI.instance().factory(true);
 53         } catch (Throwable e) {
 54             // we are in driver mode, the --enable-preview is not propagated
 55             // should we distinct driver vs main?
 56             factory = null;
 57         }
 58 
 59         return factory == null ? new Thread(tg, task) : factory.newThread(task);
 60     }
 61 
 62     @Override
 63     public List<String> getAdditionalVMOpts() {
 64         return vmOpts;
 65     }
 66 }
 67 
 68 class VirtualAPI {
 69 
 70     private MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
 71 
 72     private ThreadFactory virtualThreadFactory;
 73     private ThreadFactory platformThreadFactory;
 74 
 75 
 76     VirtualAPI() {
 77         try {
 78 
 79             Class<?> vbuilderClass =Class.forName("java.lang.Thread$Builder$OfVirtual");
 80             Class<?> pbuilderClass =Class.forName("java.lang.Thread$Builder$OfPlatform");
 81 
 82 
 83             MethodType vofMT = MethodType.methodType(vbuilderClass);
 84             MethodType pofMT = MethodType.methodType(pbuilderClass);
 85 
 86             MethodHandle ofVirtualMH =  publicLookup.findStatic(Thread.class, "ofVirtual", vofMT);
 87             MethodHandle ofPlatformMH =  publicLookup.findStatic(Thread.class, "ofPlatform", pofMT);
 88 
 89             Object virtualBuilder = ofVirtualMH.invoke();
 90             Object platformBuilder = ofPlatformMH.invoke();
 91 
 92             MethodType factoryMT = MethodType.methodType(ThreadFactory.class);
 93             MethodHandle vfactoryMH =  publicLookup.findVirtual(vbuilderClass, "factory", factoryMT);
 94             MethodHandle pfactoryMH =  publicLookup.findVirtual(pbuilderClass, "factory", factoryMT);
 95 
 96             virtualThreadFactory = (ThreadFactory) vfactoryMH.invoke(virtualBuilder);
 97             platformThreadFactory = (ThreadFactory) pfactoryMH.invoke(platformBuilder);
 98 
 99         } catch (Throwable t) {
100             throw new RuntimeException(t);
101         }
102     }
103 
104     private static VirtualAPI instance = new VirtualAPI();
105 
106     public static VirtualAPI instance() {
107         return instance;
108     }
109 
110     public ThreadFactory factory(boolean isVirtual) {
111         return isVirtual ? virtualThreadFactory : platformThreadFactory;
112     }
113 }