1 /*
2  * Copyright (c) 2015, 2019, 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 jdk.vm.ci.hotspot;
24 
25 import java.util.List;
26 import java.util.Set;
27 
28 import jdk.vm.ci.code.CompilationRequest;
29 import jdk.vm.ci.common.JVMCIError;
30 import jdk.vm.ci.common.NativeImageReinitialize;
31 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
32 import jdk.vm.ci.runtime.JVMCICompiler;
33 import jdk.vm.ci.runtime.JVMCICompilerFactory;
34 import jdk.vm.ci.runtime.JVMCIRuntime;
35 import jdk.vm.ci.services.JVMCIPermission;
36 import jdk.vm.ci.services.JVMCIServiceLocator;
37 import jdk.vm.ci.services.Services;
38 
39 import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
40 
41 final class HotSpotJVMCICompilerConfig {
42 
43     /**
44      * This factory allows JVMCI initialization to succeed but raises an error if the VM asks JVMCI
45      * to perform a compilation. This allows the reflective parts of the JVMCI API to be used
46      * without requiring a compiler implementation to be available.
47      */
48     private static class DummyCompilerFactory implements JVMCICompilerFactory, JVMCICompiler {
49 
50         private final String reason;
51 
DummyCompilerFactory(String reason)52         DummyCompilerFactory(String reason) {
53             this.reason = reason;
54         }
55 
56         @Override
compileMethod(CompilationRequest request)57         public HotSpotCompilationRequestResult compileMethod(CompilationRequest request) {
58             throw new JVMCIError("no JVMCI compiler selected: " + reason);
59         }
60 
61         @Override
getCompilerName()62         public String getCompilerName() {
63             return "null";
64         }
65 
66         @Override
createCompiler(JVMCIRuntime runtime)67         public JVMCICompiler createCompiler(JVMCIRuntime runtime) {
68             return this;
69         }
70     }
71 
72     /**
73      * Factory of the selected system compiler.
74      */
75     @NativeImageReinitialize private static JVMCICompilerFactory compilerFactory;
76 
77     /**
78      * Gets the selected system compiler factory.
79      *
80      * @return the selected system compiler factory
81      * @throws SecurityException if a security manager is present and it denies
82      *             {@link JVMCIPermission} for any {@link JVMCIServiceLocator} loaded by this method
83      */
getCompilerFactory()84     static JVMCICompilerFactory getCompilerFactory() {
85         if (compilerFactory == null) {
86             JVMCICompilerFactory factory = null;
87             String compilerName = Option.Compiler.getString();
88             if (compilerName != null) {
89                 if (compilerName.isEmpty()) {
90                     factory = new DummyCompilerFactory(" empty \"\" is specified");
91                 } else if (compilerName.equals("null")) {
92                     factory = new DummyCompilerFactory("\"null\" is specified");
93                 } else {
94                     for (JVMCICompilerFactory f : getJVMCICompilerFactories()) {
95                         if (f.getCompilerName().equals(compilerName)) {
96                             factory = f;
97                         }
98                     }
99                     if (factory == null) {
100                         if (Services.IS_IN_NATIVE_IMAGE) {
101                             throw new JVMCIError("JVMCI compiler '%s' not found in JVMCI native library.%n" +
102                                             "Use -XX:-UseJVMCINativeLibrary when specifying a JVMCI compiler available on a class path with %s.",
103                                             compilerName, Option.Compiler.getPropertyName());
104                         }
105                         throw new JVMCIError("JVMCI compiler '%s' not found", compilerName);
106                     }
107                 }
108             } else {
109                 // Auto select a single available compiler
110                 String reason = "default compiler is not found";
111                 for (JVMCICompilerFactory f : getJVMCICompilerFactories()) {
112                     if (factory == null) {
113                         openJVMCITo(f.getClass().getModule());
114                         factory = f;
115                     } else {
116                         // Multiple factories seen - cancel auto selection
117                         reason = "multiple factories seen: \"" + factory.getCompilerName() + "\" and \"" + f.getCompilerName() + "\"";
118                         factory = null;
119                         break;
120                     }
121                 }
122                 if (factory == null) {
123                     factory = new DummyCompilerFactory(reason);
124                 }
125             }
126             factory.onSelection();
127             compilerFactory = factory;
128         }
129         return compilerFactory;
130     }
131 
132     /**
133      * Opens all JVMCI packages to {@code otherModule}.
134      */
openJVMCITo(Module otherModule)135     private static void openJVMCITo(Module otherModule) {
136         if (!IS_IN_NATIVE_IMAGE) {
137             Module jvmci = HotSpotJVMCICompilerConfig.class.getModule();
138             if (jvmci != otherModule) {
139                 Set<String> packages = jvmci.getPackages();
140                 for (String pkg : packages) {
141                     boolean opened = jvmci.isOpen(pkg, otherModule);
142                     if (!opened) {
143                         jvmci.addOpens(pkg, otherModule);
144                     }
145                 }
146             }
147         }
148     }
149 
getJVMCICompilerFactories()150     private static List<JVMCICompilerFactory> getJVMCICompilerFactories() {
151         return JVMCIServiceLocator.getProviders(JVMCICompilerFactory.class);
152     }
153 }
154