--- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java 2017-04-28 11:49:04.000000000 +0200 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java 2017-04-28 11:49:04.000000000 +0200 @@ -22,9 +22,17 @@ */ package org.graalvm.compiler.serviceprovider; +import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; +import static org.graalvm.compiler.serviceprovider.JDK9Method.addOpens; +import static org.graalvm.compiler.serviceprovider.JDK9Method.getModule; +import static org.graalvm.compiler.serviceprovider.JDK9Method.getPackages; +import static org.graalvm.compiler.serviceprovider.JDK9Method.isOpenTo; + +import java.lang.reflect.Method; import java.util.Iterator; import java.util.ServiceConfigurationError; import java.util.ServiceLoader; +import java.util.Set; import jdk.vm.ci.services.JVMCIPermission; import jdk.vm.ci.services.Services; @@ -32,14 +40,32 @@ /** * A mechanism for accessing service providers that abstracts over whether Graal is running on * JVMCI-8 or JVMCI-9. In JVMCI-8, a JVMCI specific mechanism is used to lookup services via the - * hidden JVMCI class loader. in JVMCI-9, the standard {@link ServiceLoader} mechanism is used. + * hidden JVMCI class loader. In JVMCI-9, the standard {@link ServiceLoader} mechanism is used. */ public final class GraalServices { private GraalServices() { } - public static final boolean Java8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0; + /** + * Opens all JVMCI packages to the module of a given class. This relies on JVMCI already having + * opened all its packages to the module defining {@link GraalServices}. + * + * @param other all JVMCI packages will be opened to the module defining this class + */ + public static void openJVMCITo(Class other) { + Object jvmci = getModule.invoke(Services.class); + Object otherModule = getModule.invoke(other); + if (jvmci != otherModule) { + Set packages = getPackages.invoke(jvmci); + for (String pkg : packages) { + boolean opened = isOpenTo.invoke(jvmci, pkg, otherModule); + if (!opened) { + addOpens.invoke(jvmci, pkg, otherModule); + } + } + } + } /** * Gets an {@link Iterable} of the providers available for a given service. @@ -50,9 +76,9 @@ public static Iterable load(Class service) { assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName(); if (Java8OrEarlier) { - return Services.load(service); + return load8(service); } - ServiceLoader iterable = ServiceLoader.load(service); + Iterable iterable = ServiceLoader.load(service); return new Iterable() { @Override public Iterator iterator() { @@ -66,8 +92,8 @@ @Override public S next() { S provider = iterator.next(); - // Allow Graal extensions to access JVMCI assuming they have JVMCIPermission - Services.exportJVMCITo(provider.getClass()); + // Allow Graal extensions to access JVMCI + openJVMCITo(provider.getClass()); return provider; } @@ -81,6 +107,23 @@ } /** + * {@code Services.load(Class)} is only defined in JVMCI-8. + */ + private static volatile Method loadMethod; + + @SuppressWarnings("unchecked") + private static Iterable load8(Class service) throws InternalError { + try { + if (loadMethod == null) { + loadMethod = Services.class.getMethod("load", Class.class); + } + return (Iterable) loadMethod.invoke(null, service); + } catch (Exception e) { + throw new InternalError(e); + } + } + + /** * Gets the provider for a given service for which at most one provider must be available. * * @param service the service whose provider is being requested @@ -92,16 +135,14 @@ */ public static S loadSingle(Class service, boolean required) { assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName(); - if (Java8OrEarlier) { - return Services.loadSingle(service, required); - } - Iterable providers = ServiceLoader.load(service); + Iterable providers = load(service); S singleProvider = null; try { for (Iterator it = providers.iterator(); it.hasNext();) { singleProvider = it.next(); if (it.hasNext()) { - throw new InternalError(String.format("Multiple %s providers found", service.getName())); + S other = it.next(); + throw new InternalError(String.format("Multiple %s providers found: %s, %s", service.getName(), singleProvider.getClass().getName(), other.getClass().getName())); } } } catch (ServiceConfigurationError e) { @@ -111,9 +152,6 @@ if (required) { throw new InternalError(String.format("No provider for %s found", service.getName())); } - } else { - // Allow Graal extensions to access JVMCI assuming they have JVMCIPermission - Services.exportJVMCITo(singleProvider.getClass()); } return singleProvider; }