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         private final HotSpotJVMCIRuntime runtime;
52 
DummyCompilerFactory(String reason, HotSpotJVMCIRuntime runtime)53         DummyCompilerFactory(String reason, HotSpotJVMCIRuntime runtime) {
54             this.reason = reason;
55             this.runtime = runtime;
56         }
57 
58         @Override
compileMethod(CompilationRequest request)59         public HotSpotCompilationRequestResult compileMethod(CompilationRequest request) {
60             throw runtime.exitHotSpotWithMessage(1, "Cannot use JVMCI compiler: %s%n", reason);
61         }
62 
63         @Override
getCompilerName()64         public String getCompilerName() {
65             return "null";
66         }
67 
68         @Override
createCompiler(JVMCIRuntime rt)69         public JVMCICompiler createCompiler(JVMCIRuntime rt) {
70             return this;
71         }
72 
73         @Override
isGCSupported(int gcIdentifier)74         public boolean isGCSupported(int gcIdentifier) {
75             return false;
76         }
77     }
78 
79     /**
80      * Factory of the selected system compiler.
81      */
82     @NativeImageReinitialize private static JVMCICompilerFactory compilerFactory;
83 
84     /**
85      * Gets the selected system compiler factory.
86      *
87      * @return the selected system compiler factory
88      * @throws SecurityException if a security manager is present and it denies
89      *             {@link JVMCIPermission} for any {@link JVMCIServiceLocator} loaded by this method
90      */
getCompilerFactory(HotSpotJVMCIRuntime runtime)91     static JVMCICompilerFactory getCompilerFactory(HotSpotJVMCIRuntime runtime) {
92         if (compilerFactory == null) {
93             JVMCICompilerFactory factory = null;
94             String compilerName = Option.Compiler.getString();
95             if (compilerName != null) {
96                 String compPropertyName = Option.Compiler.getPropertyName();
97                 if (compilerName.isEmpty()) {
98                     factory = new DummyCompilerFactory("Value of " + compPropertyName + " is empty", runtime);
99                 } else if (compilerName.equals("null")) {
100                     factory = new DummyCompilerFactory("Value of " + compPropertyName + " is \"null\"", runtime);
101                 } else {
102                     for (JVMCICompilerFactory f : getJVMCICompilerFactories()) {
103                         if (f.getCompilerName().equals(compilerName)) {
104                             factory = f;
105                         }
106                     }
107                     if (factory == null) {
108                         if (Services.IS_IN_NATIVE_IMAGE) {
109                             throw runtime.exitHotSpotWithMessage(1, "JVMCI compiler '%s' not found in JVMCI native library.%n" +
110                                             "Use -XX:-UseJVMCINativeLibrary when specifying a JVMCI compiler available on a class path with %s.%n",
111                                             compilerName, compPropertyName);
112                         }
113                         throw runtime.exitHotSpotWithMessage(1, "JVMCI compiler '%s' specified by %s not found%n", compilerName, compPropertyName);
114                     }
115                 }
116             } else {
117                 // Auto select a single available compiler
118                 String reason = "No JVMCI compiler found";
119                 for (JVMCICompilerFactory f : getJVMCICompilerFactories()) {
120                     if (factory == null) {
121                         openJVMCITo(f.getClass().getModule());
122                         factory = f;
123                     } else {
124                         // Multiple factories seen - cancel auto selection
125                         reason = "Multiple JVMCI compilers found: \"" + factory.getCompilerName() + "\" and \"" + f.getCompilerName() + "\"";
126                         factory = null;
127                         break;
128                     }
129                 }
130                 if (factory == null) {
131                     factory = new DummyCompilerFactory(reason, runtime);
132                 }
133             }
134             factory.onSelection();
135             compilerFactory = factory;
136         }
137         return compilerFactory;
138     }
139 
140     /**
141      * Opens all JVMCI packages to {@code otherModule}.
142      */
openJVMCITo(Module otherModule)143     private static void openJVMCITo(Module otherModule) {
144         if (!IS_IN_NATIVE_IMAGE) {
145             Module jvmci = HotSpotJVMCICompilerConfig.class.getModule();
146             if (jvmci != otherModule) {
147                 Set<String> packages = jvmci.getPackages();
148                 for (String pkg : packages) {
149                     boolean opened = jvmci.isOpen(pkg, otherModule);
150                     if (!opened) {
151                         jvmci.addOpens(pkg, otherModule);
152                     }
153                 }
154             }
155         }
156     }
157 
getJVMCICompilerFactories()158     private static List<JVMCICompilerFactory> getJVMCICompilerFactories() {
159         return JVMCIServiceLocator.getProviders(JVMCICompilerFactory.class);
160     }
161 }
162