Mercurial > hg > truffle
diff graal/com.oracle.jvmci.service/src/com/oracle/jvmci/service/Services.java @ 21614:2f92172fa320
Truffle and NFI implementations are now accessed via JVMCI services instead of being hard coded in the VM (JBS:GRAAL-51)
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Sun, 31 May 2015 13:42:47 +0200 |
parents | 71b338926f2e |
children | 9966b358bc2b |
line wrap: on
line diff
--- a/graal/com.oracle.jvmci.service/src/com/oracle/jvmci/service/Services.java Sun May 31 12:32:15 2015 +0200 +++ b/graal/com.oracle.jvmci.service/src/com/oracle/jvmci/service/Services.java Sun May 31 13:42:47 2015 +0200 @@ -29,9 +29,10 @@ import sun.reflect.*; /** - * A mechanism on top of the standard {@link ServiceLoader} that enables a runtime to efficiently - * load services marked by {@link Service}. This may be important for services loaded early in the - * runtime initialization process. + * A mechanism on top of the standard {@link ServiceLoader} that enables JVMCI enabled runtime to + * efficiently load services marked by {@link Service}. This is important to avoid the performance + * overhead of the standard service loader mechanism for services loaded in the runtime + * initialization process. */ public class Services { @@ -54,6 +55,7 @@ @SuppressWarnings("unchecked") @CallerSensitive public static <S> Iterable<S> load(Class<S> service) { + // TODO(ds): add SecurityManager checks if (Service.class.isAssignableFrom(service)) { try { return (Iterable<S>) cache.get(service); @@ -67,5 +69,50 @@ return ServiceLoader.load(service, cl); } + /** + * Gets the implementation for a given service for which at most one implementation must be + * available. + * + * @param service the service whose implementation is being requested + * @param required specifies if an {@link InternalError} should be thrown if no implementation + * of {@code service} is available + */ + @SuppressWarnings("unchecked") + @CallerSensitive + public static <S> S loadSingle(Class<S> service, boolean required) { + // TODO(ds): add SecurityManager checks + Iterable<S> impls = null; + if (Service.class.isAssignableFrom(service)) { + try { + impls = (Iterable<S>) cache.get(service); + } catch (UnsatisfiedLinkError e) { + // Fall back to standard ServiceLoader + } + } + + if (impls == null) { + // Need to use the ClassLoader of the caller + ClassLoader cl = Reflection.getCallerClass().getClassLoader(); + impls = ServiceLoader.load(service, cl); + } + S singleImpl = null; + for (S impl : impls) { + if (singleImpl != null) { + throw new InternalError(String.format("Multiple %s implementations found: %s, %s", service.getName(), singleImpl.getClass().getName(), impl.getClass().getName())); + } + singleImpl = impl; + } + if (singleImpl == null && required) { + String javaHome = System.getProperty("java.home"); + String vmName = System.getProperty("java.vm.name"); + Formatter errorMessage = new Formatter(); + errorMessage.format("The VM does not expose required service %s.%n", service.getName()); + errorMessage.format("Currently used Java home directory is %s.%n", javaHome); + errorMessage.format("Currently used VM configuration is: %s", vmName); + throw new UnsupportedOperationException(errorMessage.toString()); + } + return singleImpl; + } + private static native <S> S[] getServiceImpls(Class<?> service); }