src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java
changeset 59262 06970ab040d4
parent 58851 f1e6442241ca
equal deleted inserted replaced
59261:4cf1246fbb9c 59262:06970ab040d4
    35 import java.util.Map;
    35 import java.util.Map;
    36 import java.util.ServiceLoader;
    36 import java.util.ServiceLoader;
    37 import java.util.Set;
    37 import java.util.Set;
    38 
    38 
    39 import jdk.internal.misc.VM;
    39 import jdk.internal.misc.VM;
    40 import jdk.internal.reflect.Reflection;
       
    41 
    40 
    42 /**
    41 /**
    43  * Provides utilities needed by JVMCI clients.
    42  * Provides utilities needed by JVMCI clients.
    44  */
    43  */
    45 public final class Services {
    44 public final class Services {
   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      */