--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java 2016-12-09 00:49:13.699624681 -0800 @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot; + +import static jdk.vm.ci.common.InitTimer.timer; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.stream.Collectors; + +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionType; +import org.graalvm.compiler.options.OptionValue; +import org.graalvm.compiler.phases.tiers.CompilerConfiguration; +import org.graalvm.compiler.serviceprovider.GraalServices; + +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.common.InitTimer; + +/** + * A factory that creates the {@link CompilerConfiguration} the Graal compiler will use. Each + * factory must have a unique {@link #name} and {@link #autoSelectionPriority}. The latter imposes a + * total ordering between factories for the purpose of auto-selecting the factory to use. + */ +public abstract class CompilerConfigurationFactory implements Comparable { + + static class Options { + // @formatter:off + @Option(help = "Names the Graal compiler configuration to use. If ommitted, the compiler configuration " + + "with the highest auto-selection priority is used. To see the set of available configurations, " + + "supply the value 'help' to this option.", type = OptionType.Expert) + public static final OptionValue CompilerConfiguration = new OptionValue<>(null); + // @formatter:on + } + + /** + * The name of this factory. This must be unique across all factory instances and is used when + * selecting a factory based on the value of {@link Options#CompilerConfiguration}. + */ + private final String name; + + /** + * The priority of this factory. This must be unique across all factory instances and is used + * when selecting a factory when {@link Options#CompilerConfiguration} is omitted + */ + private final int autoSelectionPriority; + + protected CompilerConfigurationFactory(String name, int autoSelectionPriority) { + this.name = name; + this.autoSelectionPriority = autoSelectionPriority; + assert checkAndAddNewFactory(this); + } + + public abstract CompilerConfiguration createCompilerConfiguration(); + + /** + * Collect the set of available {@linkplain HotSpotBackendFactory backends} for this compiler + * configuration. + */ + public BackendMap createBackendMap() { + // default to backend with the same name as the compiler configuration + return new DefaultBackendMap(name); + } + + public interface BackendMap { + HotSpotBackendFactory getBackendFactory(Architecture arch); + } + + public static class DefaultBackendMap implements BackendMap { + + private final IdentityHashMap, HotSpotBackendFactory> backends = new IdentityHashMap<>(); + + @SuppressWarnings("try") + public DefaultBackendMap(String backendName) { + try (InitTimer t = timer("HotSpotBackendFactory.register")) { + for (HotSpotBackendFactory backend : GraalServices.load(HotSpotBackendFactory.class)) { + if (backend.getName().equals(backendName)) { + Class arch = backend.getArchitecture(); + HotSpotBackendFactory oldEntry = backends.put(arch, backend); + assert oldEntry == null || oldEntry == backend : "duplicate Graal backend"; + } + } + } + } + + @Override + public final HotSpotBackendFactory getBackendFactory(Architecture arch) { + return backends.get(arch.getClass()); + } + } + + @Override + public int compareTo(CompilerConfigurationFactory o) { + if (autoSelectionPriority > o.autoSelectionPriority) { + return -1; + } + if (autoSelectionPriority < o.autoSelectionPriority) { + return 1; + } + assert this == o : "distinct compiler configurations cannot have the same auto selection priority"; + return 0; + } + + @SuppressWarnings("all") + private static boolean assertionsEnabled() { + boolean assertionsEnabled = false; + assert assertionsEnabled = true; + return assertionsEnabled; + } + + /** + * List used to assert uniqueness of {@link #name} and {@link #autoSelectionPriority} across all + * {@link CompilerConfigurationFactory} instances. + */ + private static final List factories = assertionsEnabled() ? new ArrayList<>() : null; + + private static boolean checkAndAddNewFactory(CompilerConfigurationFactory factory) { + for (CompilerConfigurationFactory other : factories) { + assert !other.name.equals(factory.name) : factory.getClass().getName() + " cannot have the same selector as " + other.getClass().getName() + ": " + factory.name; + assert other.autoSelectionPriority != factory.autoSelectionPriority : factory.getClass().getName() + " cannot have the same auto-selection priority as " + other.getClass().getName() + + ": " + factory.autoSelectionPriority; + } + factories.add(factory); + return true; + } + + /** + * @return sorted list of {@link CompilerConfigurationFactory}s + */ + private static List getAllCandidates() { + List candidates = new ArrayList<>(); + for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) { + candidates.add(candidate); + } + Collections.sort(candidates); + return candidates; + } + + /** + * Selects and instantiates a {@link CompilerConfigurationFactory}. The selection algorithm is + * as follows: if {@code name} is non-null, then select the factory with the same name else if + * {@link Options#CompilerConfiguration}{@code .getValue()} is non-null then select the factory + * whose name matches the value else select the factory with the highest + * {@link #autoSelectionPriority} value. + * + * @param name the name of the compiler configuration to select (optional) + */ + @SuppressWarnings("try") + public static CompilerConfigurationFactory selectFactory(String name) { + CompilerConfigurationFactory factory = null; + try (InitTimer t = timer("CompilerConfigurationFactory.selectFactory")) { + String value = name == null ? Options.CompilerConfiguration.getValue() : name; + if ("help".equals(value)) { + System.out.println("The available Graal compiler configurations are:"); + for (CompilerConfigurationFactory candidate : getAllCandidates()) { + System.out.println(" " + candidate.name); + } + System.exit(0); + } else if (value != null) { + for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) { + if (candidate.name.equals(value)) { + factory = candidate; + break; + } + } + if (factory == null) { + throw new GraalError("Graal compiler configuration '%s' not found. Available configurations are: %s", value, + getAllCandidates().stream().map(c -> c.name).collect(Collectors.joining(", "))); + } + } else { + List candidates = getAllCandidates(); + if (candidates.isEmpty()) { + throw new GraalError("No %s providers found", CompilerConfigurationFactory.class.getName()); + } + factory = candidates.get(0); + } + } + return factory; + } +}