Skip to content

Commit 9d0f7bc

Browse files
committed
svm: migrate ServiceLoaderFeature to JVMCI reflection
1 parent 796ce92 commit 9d0f7bc

File tree

1 file changed

+65
-40
lines changed

1 file changed

+65
-40
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ServiceLoaderFeature.java

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
*/
2525
package com.oracle.svm.hosted;
2626

27-
import java.lang.reflect.Constructor;
28-
import java.lang.reflect.Method;
2927
import java.lang.reflect.Modifier;
3028
import java.nio.charset.StandardCharsets;
3129
import java.util.Collection;
@@ -41,6 +39,7 @@
4139
import org.graalvm.nativeimage.hosted.RuntimeReflection;
4240
import org.graalvm.nativeimage.hosted.RuntimeResourceAccess;
4341

42+
import com.oracle.graal.pointsto.constraints.UnsupportedPlatformException;
4443
import com.oracle.svm.core.FutureDefaultsOptions;
4544
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
4645
import com.oracle.svm.core.feature.InternalFeature;
@@ -50,6 +49,9 @@
5049
import com.oracle.svm.core.option.HostedOptionKey;
5150
import com.oracle.svm.core.util.BasedOnJDKFile;
5251
import com.oracle.svm.hosted.analysis.Inflation;
52+
import com.oracle.svm.hosted.substitute.DeletedElementException;
53+
import com.oracle.svm.util.JVMCIReflectionUtil;
54+
import com.oracle.svm.util.dynamicaccess.JVMCIRuntimeReflection;
5355

5456
import jdk.graal.compiler.hotspot.CompilerConfigurationFactory;
5557
import jdk.graal.compiler.hotspot.HotSpotBackendFactory;
@@ -59,6 +61,8 @@
5961
import jdk.graal.compiler.options.OptionType;
6062
import jdk.graal.compiler.truffle.hotspot.TruffleCallBoundaryInstrumentationFactory;
6163
import jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory;
64+
import jdk.vm.ci.meta.ResolvedJavaMethod;
65+
import jdk.vm.ci.meta.ResolvedJavaType;
6266
import sun.util.locale.provider.LocaleDataMetaInfo;
6367

6468
/**
@@ -160,54 +164,75 @@ public void afterRegistration(AfterRegistrationAccess access) {
160164
public void beforeAnalysis(BeforeAnalysisAccess access) {
161165
FeatureImpl.BeforeAnalysisAccessImpl accessImpl = (FeatureImpl.BeforeAnalysisAccessImpl) access;
162166
accessImpl.imageClassLoader.classLoaderSupport.serviceProvidersForEach((serviceName, providers) -> {
163-
Class<?> serviceClass = access.findClassByName(serviceName);
164-
boolean skipService = false;
165-
/* If the service should not end up in the image, we remove all the providers with it */
166167
Collection<String> providersToSkip = providers;
167-
if (servicesToSkip.contains(serviceName)) {
168-
skipService = true;
169-
} else if (serviceClass == null || serviceClass.isArray() || serviceClass.isPrimitive()) {
170-
skipService = true;
171-
} else if (!accessImpl.getHostVM().platformSupported(serviceClass)) {
172-
skipService = true;
173-
} else {
174-
providersToSkip = providers.stream().filter(serviceProvidersToSkip::contains).collect(Collectors.toList());
175-
if (!providersToSkip.isEmpty()) {
168+
try {
169+
/*
170+
* The following will throw an `UnsupportedPlatformException` if the service is not
171+
* supported.
172+
*/
173+
ResolvedJavaType serviceClass = accessImpl.findTypeByName(serviceName);
174+
boolean skipService = false;
175+
/*
176+
* If the service should not end up in the image, we remove all the providers with
177+
* it.
178+
*/
179+
if (servicesToSkip.contains(serviceName)) {
176180
skipService = true;
181+
} else if (serviceClass == null || serviceClass.isArray() || serviceClass.isPrimitive()) {
182+
skipService = true;
183+
} else if (!accessImpl.getHostVM().platformSupported(serviceClass)) {
184+
skipService = true;
185+
} else {
186+
providersToSkip = providers.stream().filter(serviceProvidersToSkip::contains).collect(Collectors.toList());
187+
if (!providersToSkip.isEmpty()) {
188+
skipService = true;
189+
}
177190
}
191+
if (!skipService) {
192+
access.registerReachabilityHandler(a -> handleServiceClassIsReachable(a, serviceClass, providers), serviceClass);
193+
return;
194+
}
195+
} catch (UnsupportedPlatformException e) {
196+
// Service class is not supported - skipping
178197
}
179-
if (skipService) {
180-
ServiceCatalogSupport.singleton().removeServicesFromServicesCatalog(serviceName, new HashSet<>(providersToSkip));
181-
return;
182-
}
183-
access.registerReachabilityHandler(a -> handleServiceClassIsReachable(a, serviceClass, providers), serviceClass);
198+
// skip service
199+
ServiceCatalogSupport.singleton().removeServicesFromServicesCatalog(serviceName, new HashSet<>(providersToSkip));
184200
});
185201
}
186202

187-
void handleServiceClassIsReachable(DuringAnalysisAccess access, Class<?> serviceProvider, Collection<String> providers) {
203+
void handleServiceClassIsReachable(DuringAnalysisAccess access, ResolvedJavaType serviceProvider, Collection<String> providers) {
204+
FeatureImpl.DuringAnalysisAccessImpl accessImpl = (FeatureImpl.DuringAnalysisAccessImpl) access;
188205
LinkedHashSet<String> registeredProviders = new LinkedHashSet<>();
189206
for (String provider : providers) {
190207
if (serviceProvidersToSkip.contains(provider)) {
191208
continue;
192209
}
193-
if (serviceProvider.equals(java.security.Provider.class) && !SecurityProvidersSupport.singleton().isUserRequestedSecurityProvider(provider)) {
210+
if (serviceProvider.equals(accessImpl.getMetaAccess().lookupJavaType(java.security.Provider.class)) && !SecurityProvidersSupport.singleton().isUserRequestedSecurityProvider(provider)) {
194211
SecurityProvidersSupport.singleton().markSecurityProviderAsNotLoaded(provider);
195212
} else {
196213
registerProviderForRuntimeReflectionAccess(access, provider, registeredProviders);
197214
}
198215
}
199-
registerProviderForRuntimeResourceAccess(access.getApplicationClassLoader().getUnnamedModule(), serviceProvider.getName(), registeredProviders);
216+
registerProviderForRuntimeResourceAccess(access.getApplicationClassLoader().getUnnamedModule(), serviceProvider.toClassName(), registeredProviders);
200217
}
201218

202219
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+21/src/java.base/share/classes/java/util/ServiceLoader.java#L745-L793")
203220
public static void registerProviderForRuntimeReflectionAccess(DuringAnalysisAccess access, String provider, Set<String> registeredProviders) {
221+
FeatureImpl.DuringAnalysisAccessImpl accessImpl = (FeatureImpl.DuringAnalysisAccessImpl) access;
204222
/* Make provider reflectively instantiable */
205-
Class<?> providerClass = access.findClassByName(provider);
223+
ResolvedJavaType providerClass;
224+
try {
225+
providerClass = accessImpl.findTypeByName(provider);
226+
} catch (UnsupportedPlatformException e) {
227+
return;
228+
} catch (DeletedElementException e) {
229+
/* Disallow services with implementation classes that are marked as @Deleted */
230+
return;
231+
}
206232

207233
if (providerClass == null || providerClass.isArray() || providerClass.isPrimitive()) {
208234
return;
209235
}
210-
FeatureImpl.DuringAnalysisAccessImpl accessImpl = (FeatureImpl.DuringAnalysisAccessImpl) access;
211236
if (!accessImpl.getHostVM().platformSupported(providerClass)) {
212237
return;
213238
}
@@ -222,10 +247,10 @@ public static void registerProviderForRuntimeReflectionAccess(DuringAnalysisAcce
222247
*
223248
* See ServiceLoader#loadProvider and ServiceLoader#findStaticProviderMethod.
224249
*/
225-
Method nullaryProviderMethod = findProviderMethod(providerClass);
226-
Constructor<?> nullaryConstructor = findNullaryConstructor(providerClass);
250+
ResolvedJavaMethod nullaryProviderMethod = findProviderMethod(providerClass);
251+
ResolvedJavaMethod nullaryConstructor = findNullaryConstructor(providerClass);
227252
if (nullaryConstructor != null || nullaryProviderMethod != null) {
228-
RuntimeReflection.register(providerClass);
253+
JVMCIRuntimeReflection.register(providerClass);
229254
if (nullaryConstructor != null) {
230255
/*
231256
* Registering a constructor with
@@ -235,22 +260,22 @@ public static void registerProviderForRuntimeReflectionAccess(DuringAnalysisAcce
235260
* if-statement cannot be eliminated.
236261
*
237262
*/
238-
RuntimeReflection.register(nullaryConstructor);
263+
JVMCIRuntimeReflection.register(nullaryConstructor);
239264
} else {
240265
/*
241266
* If there's no nullary constructor, register it as negative lookup to avoid
242267
* throwing a MissingReflectionRegistrationError at run time.
243268
*/
244-
RuntimeReflection.registerConstructorLookup(providerClass);
269+
JVMCIRuntimeReflection.registerConstructorLookup(providerClass);
245270
}
246271
if (nullaryProviderMethod != null) {
247-
RuntimeReflection.register(nullaryProviderMethod);
272+
JVMCIRuntimeReflection.register(nullaryProviderMethod);
248273
} else {
249274
/*
250275
* If there's no declared public provider() method, register it as negative lookup
251276
* to avoid throwing a MissingReflectionRegistrationError at run time.
252277
*/
253-
RuntimeReflection.registerMethodLookup(providerClass, "provider");
278+
JVMCIRuntimeReflection.registerMethodLookup(providerClass, "provider");
254279
}
255280
}
256281
/*
@@ -270,28 +295,28 @@ public static void registerProviderForRuntimeResourceAccess(Module module, Strin
270295
}
271296

272297
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+21/src/java.base/share/classes/java/util/ServiceLoader.java#L620-L631")
273-
private static Constructor<?> findNullaryConstructor(Class<?> providerClass) {
274-
Constructor<?> nullaryConstructor = null;
298+
private static ResolvedJavaMethod findNullaryConstructor(ResolvedJavaType providerClass) {
299+
ResolvedJavaMethod nullaryConstructor = null;
275300
try {
276-
Constructor<?> constructor = providerClass.getDeclaredConstructor();
301+
ResolvedJavaMethod constructor = JVMCIReflectionUtil.getDeclaredConstructor(false, providerClass);
277302
if (Modifier.isPublic(constructor.getModifiers())) {
278303
nullaryConstructor = constructor;
279304
}
280-
} catch (NoSuchMethodException | SecurityException | LinkageError e) {
305+
} catch (SecurityException | LinkageError e) {
281306
// ignore
282307
}
283308
return nullaryConstructor;
284309
}
285310

286311
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+21/src/java.base/share/classes/java/util/ServiceLoader.java#L583-L612")
287-
private static Method findProviderMethod(Class<?> providerClass) {
288-
Method nullaryProviderMethod = null;
312+
private static ResolvedJavaMethod findProviderMethod(ResolvedJavaType providerClass) {
313+
ResolvedJavaMethod nullaryProviderMethod = null;
289314
try {
290315
/* Only look for a provider() method if provider class is in an explicit module. */
291-
if (providerClass.getModule().isNamed() && !providerClass.getModule().getDescriptor().isAutomatic()) {
292-
for (Method method : providerClass.getDeclaredMethods()) {
316+
if (JVMCIReflectionUtil.getModule(providerClass).isNamed() && !JVMCIReflectionUtil.getModule(providerClass).getDescriptor().isAutomatic()) {
317+
for (ResolvedJavaMethod method : providerClass.getDeclaredMethods(false)) {
293318
if (Modifier.isPublic(method.getModifiers()) && Modifier.isStatic(method.getModifiers()) &&
294-
method.getParameterCount() == 0 && method.getName().equals("provider")) {
319+
method.getSignature().getParameterCount(false) == 0 && method.getName().equals("provider")) {
295320
if (nullaryProviderMethod == null) {
296321
nullaryProviderMethod = method;
297322
} else {

0 commit comments

Comments
 (0)