134 } catch (ClassNotFoundException e) { |
133 } catch (ClassNotFoundException e) { |
135 throw new InternalError(e); |
134 throw new InternalError(e); |
136 } |
135 } |
137 } |
136 } |
138 |
137 |
139 private static boolean jvmciEnabled = true; |
|
140 |
|
141 /** |
|
142 * When {@code -XX:-UseJVMCIClassLoader} is in use, JVMCI classes are loaded via the boot class |
|
143 * loader. When {@code null} is the second argument to |
|
144 * {@link ServiceLoader#load(Class, ClassLoader)}, service lookup will use the system class |
|
145 * loader and thus find application classes which violates the API of {@link #load} and |
|
146 * {@link #loadSingle}. To avoid this, a class loader that simply delegates to the boot class |
|
147 * loader is used. |
|
148 */ |
|
149 static class LazyBootClassPath { |
|
150 static final ClassLoader bootClassPath = new ClassLoader(null) { |
|
151 }; |
|
152 } |
|
153 |
|
154 private static ClassLoader findBootClassLoaderChild(ClassLoader start) { |
|
155 ClassLoader cl = start; |
|
156 while (cl.getParent() != null) { |
|
157 cl = cl.getParent(); |
|
158 } |
|
159 return cl; |
|
160 } |
|
161 |
|
162 private static final Map<Class<?>, List<?>> servicesCache = IS_BUILDING_NATIVE_IMAGE ? new HashMap<>() : null; |
138 private static final Map<Class<?>, List<?>> servicesCache = IS_BUILDING_NATIVE_IMAGE ? new HashMap<>() : null; |
163 |
139 |
164 @SuppressWarnings("unchecked") |
140 @SuppressWarnings("unchecked") |
165 private static <S> Iterable<S> load0(Class<S> service) { |
141 private static <S> Iterable<S> load0(Class<S> service) { |
166 if (IS_IN_NATIVE_IMAGE || IS_BUILDING_NATIVE_IMAGE) { |
142 if (IS_IN_NATIVE_IMAGE || IS_BUILDING_NATIVE_IMAGE) { |
171 if (IS_IN_NATIVE_IMAGE) { |
147 if (IS_IN_NATIVE_IMAGE) { |
172 throw new InternalError(String.format("No %s providers found when building native image", service.getName())); |
148 throw new InternalError(String.format("No %s providers found when building native image", service.getName())); |
173 } |
149 } |
174 } |
150 } |
175 |
151 |
176 Iterable<S> providers = Collections.emptyList(); |
152 Iterable<S> providers = ServiceLoader.load(service, ClassLoader.getSystemClassLoader()); |
177 if (jvmciEnabled) { |
|
178 ClassLoader cl = null; |
|
179 try { |
|
180 cl = getJVMCIClassLoader(); |
|
181 if (cl == null) { |
|
182 cl = LazyBootClassPath.bootClassPath; |
|
183 // JVMCI classes are loaded via the boot class loader. |
|
184 // If we use null as the second argument to ServiceLoader.load, |
|
185 // service loading will use the system class loader |
|
186 // and find classes on the application class path. Since we |
|
187 // don't want this, we use a loader that is as close to the |
|
188 // boot class loader as possible (since it is impossible |
|
189 // to force service loading to use only the boot class loader). |
|
190 cl = findBootClassLoaderChild(ClassLoader.getSystemClassLoader()); |
|
191 } |
|
192 providers = ServiceLoader.load(service, cl); |
|
193 } catch (UnsatisfiedLinkError e) { |
|
194 jvmciEnabled = false; |
|
195 } catch (InternalError e) { |
|
196 if (e.getMessage().equals("JVMCI is not enabled")) { |
|
197 jvmciEnabled = false; |
|
198 } else { |
|
199 throw e; |
|
200 } |
|
201 } |
|
202 } |
|
203 if (IS_BUILDING_NATIVE_IMAGE) { |
153 if (IS_BUILDING_NATIVE_IMAGE) { |
204 synchronized (servicesCache) { |
154 synchronized (servicesCache) { |
205 ArrayList<S> providersList = new ArrayList<>(); |
155 ArrayList<S> providersList = new ArrayList<>(); |
206 for (S provider : providers) { |
156 for (S provider : providers) { |
207 providersList.add(provider); |
157 providersList.add(provider); |
274 errorMessage.format("Currently used Java home directory is %s.%n", javaHome); |
224 errorMessage.format("Currently used Java home directory is %s.%n", javaHome); |
275 errorMessage.format("Currently used VM configuration is: %s", vmName); |
225 errorMessage.format("Currently used VM configuration is: %s", vmName); |
276 throw new UnsupportedOperationException(errorMessage.toString()); |
226 throw new UnsupportedOperationException(errorMessage.toString()); |
277 } |
227 } |
278 return singleProvider; |
228 return singleProvider; |
279 } |
|
280 |
|
281 static { |
|
282 Reflection.registerMethodsToFilter(Services.class, Set.of("getJVMCIClassLoader")); |
|
283 } |
|
284 |
|
285 /** |
|
286 * Gets the JVMCI class loader. |
|
287 * |
|
288 * @throws InternalError with the {@linkplain Throwable#getMessage() message} |
|
289 * {@code "JVMCI is not enabled"} iff JVMCI is not enabled |
|
290 */ |
|
291 private static ClassLoader getJVMCIClassLoader() { |
|
292 if (IS_IN_NATIVE_IMAGE) { |
|
293 return null; |
|
294 } |
|
295 return ClassLoader.getSystemClassLoader(); |
|
296 } |
229 } |
297 |
230 |
298 /** |
231 /** |
299 * A Java {@code char} has a maximal UTF8 length of 3. |
232 * A Java {@code char} has a maximal UTF8 length of 3. |
300 */ |
233 */ |