1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.hotspot;
  24 
  25 import static jdk.vm.ci.common.InitTimer.timer;
  26 import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX;
  27 
  28 import java.io.PrintStream;
  29 
  30 import org.graalvm.compiler.debug.MethodFilter;
  31 import org.graalvm.compiler.options.Option;
  32 import org.graalvm.compiler.options.OptionKey;
  33 import org.graalvm.compiler.options.OptionType;
  34 import org.graalvm.compiler.options.OptionValues;
  35 import org.graalvm.compiler.options.OptionsParser;
  36 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
  37 
  38 import jdk.vm.ci.common.InitTimer;
  39 import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory;
  40 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
  41 import jdk.vm.ci.hotspot.HotSpotSignature;
  42 import jdk.vm.ci.runtime.JVMCIRuntime;
  43 import jdk.vm.ci.services.Services;
  44 
  45 public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFactory {
  46 
  47     private static MethodFilter[] graalCompileOnlyFilter;
  48 
  49     private final HotSpotGraalJVMCIServiceLocator locator;
  50 
  51     HotSpotGraalCompilerFactory(HotSpotGraalJVMCIServiceLocator locator) {
  52         this.locator = locator;
  53     }
  54 
  55     @Override
  56     public String getCompilerName() {
  57         return "graal";
  58     }
  59 
  60     /**
  61      * Initialized when this factory is {@linkplain #onSelection() selected}.
  62      */
  63     private OptionValues options;
  64 
  65     @Override
  66     public void onSelection() {
  67         JVMCIVersionCheck.check(false);
  68         assert options == null : "cannot select " + getClass() + " service more than once";
  69         options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
  70         initializeGraalCompileOnlyFilter(options);
  71         if (graalCompileOnlyFilter != null || !Options.UseTrivialPrefixes.getValue(options)) {
  72             /*
  73              * Exercise this code path early to encourage loading now. This doesn't solve problem of
  74              * deadlock during class loading but seems to eliminate it in practice.
  75              */
  76             adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.FullOptimization);
  77             adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.Simple);
  78         }
  79     }
  80 
  81     private static void initializeGraalCompileOnlyFilter(OptionValues options) {
  82         String optionValue = Options.GraalCompileOnly.getValue(options);
  83         if (optionValue != null) {
  84             MethodFilter[] filter = MethodFilter.parse(optionValue);
  85             if (filter.length == 0) {
  86                 filter = null;
  87             }
  88             graalCompileOnlyFilter = filter;
  89         }
  90     }
  91 
  92     @Override
  93     public void printProperties(PrintStream out) {
  94         out.println("[Graal properties]");
  95         options.printHelp(OptionsParser.getOptionsLoader(), out, GRAAL_OPTION_PROPERTY_PREFIX);
  96     }
  97 
  98     static class Options {
  99 
 100         // @formatter:off
 101         @Option(help = "In tiered mode compile Graal and JVMCI using optimized first tier code.", type = OptionType.Expert)
 102         public static final OptionKey<Boolean> CompileGraalWithC1Only = new OptionKey<>(true);
 103 
 104         @Option(help = "Hook into VM-level mechanism for denoting compilations to be performed in first tier.", type = OptionType.Expert)
 105         public static final OptionKey<Boolean> UseTrivialPrefixes = new OptionKey<>(false);
 106 
 107         @Option(help = "A method filter selecting what should be compiled by Graal.  All other requests will be reduced to CompilationLevel.Simple.", type = OptionType.Expert)
 108         public static final OptionKey<String> GraalCompileOnly = new OptionKey<>(null);
 109         // @formatter:on
 110 
 111     }
 112 
 113     @Override
 114     public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) {
 115         HotSpotGraalCompiler compiler = createCompiler(runtime, options, CompilerConfigurationFactory.selectFactory(null, options));
 116         // Only the HotSpotGraalRuntime associated with the compiler created via
 117         // jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving
 118         // VM events.
 119         locator.onCompilerCreation(compiler);
 120         return compiler;
 121     }
 122 
 123     /**
 124      * Creates a new {@link HotSpotGraalRuntime} object and a new {@link HotSpotGraalCompiler} and
 125      * returns the latter.
 126      *
 127      * @param runtime the JVMCI runtime on which the {@link HotSpotGraalRuntime} is built
 128      * @param compilerConfigurationFactory factory for the {@link CompilerConfiguration}
 129      */
 130     @SuppressWarnings("try")
 131     public static HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime, OptionValues options, CompilerConfigurationFactory compilerConfigurationFactory) {
 132         HotSpotJVMCIRuntime jvmciRuntime = (HotSpotJVMCIRuntime) runtime;
 133         try (InitTimer t = timer("HotSpotGraalRuntime.<init>")) {
 134             HotSpotGraalRuntime graalRuntime = new HotSpotGraalRuntime(jvmciRuntime, compilerConfigurationFactory, options);
 135             return new HotSpotGraalCompiler(jvmciRuntime, graalRuntime);
 136         }
 137     }
 138 
 139     @Override
 140     public String[] getTrivialPrefixes() {
 141         if (Options.UseTrivialPrefixes.getValue(options)) {
 142             if (Options.CompileGraalWithC1Only.getValue(options)) {
 143                 return new String[]{"jdk/vm/ci", "org/graalvm/compiler", "com/oracle/graal"};
 144             }
 145         }
 146         return null;
 147     }
 148 
 149     @Override
 150     public CompilationLevelAdjustment getCompilationLevelAdjustment() {
 151         if (graalCompileOnlyFilter != null) {
 152             return CompilationLevelAdjustment.ByFullSignature;
 153         }
 154         if (!Options.UseTrivialPrefixes.getValue(options)) {
 155             if (Options.CompileGraalWithC1Only.getValue(options)) {
 156                 // We only decide using the class declaring the method
 157                 // so no need to have the method name and signature
 158                 // symbols converted to a String.
 159                 return CompilationLevelAdjustment.ByHolder;
 160             }
 161         }
 162         return CompilationLevelAdjustment.None;
 163     }
 164 
 165     @Override
 166     public CompilationLevel adjustCompilationLevel(Class<?> declaringClass, String name, String signature, boolean isOsr, CompilationLevel level) {
 167         return adjustCompilationLevelInternal(declaringClass, name, signature, level);
 168     }
 169 
 170     static {
 171         // Fail-fast detection for package renaming to guard use of package
 172         // prefixes in adjustCompilationLevelInternal.
 173         assert Services.class.getName().equals("jdk.vm.ci.services.Services");
 174         assert HotSpotGraalCompilerFactory.class.getName().equals("org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory");
 175     }
 176 
 177     /*
 178      * This method is static so it can be exercised during initialization.
 179      */
 180     private static CompilationLevel adjustCompilationLevelInternal(Class<?> declaringClass, String name, String signature, CompilationLevel level) {
 181         if (graalCompileOnlyFilter != null) {
 182             if (level == CompilationLevel.FullOptimization) {
 183                 String declaringClassName = declaringClass.getName();
 184                 HotSpotSignature sig = null;
 185                 for (MethodFilter filter : graalCompileOnlyFilter) {
 186                     if (filter.hasSignature() && sig == null) {
 187                         sig = new HotSpotSignature(HotSpotJVMCIRuntime.runtime(), signature);
 188                     }
 189                     if (filter.matches(declaringClassName, name, sig)) {
 190                         return level;
 191                     }
 192                 }
 193                 return CompilationLevel.Simple;
 194             }
 195         }
 196         if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
 197             String declaringClassName = declaringClass.getName();
 198             if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm.compiler") || declaringClassName.startsWith("com.oracle.graal")) {
 199                 return CompilationLevel.Simple;
 200             }
 201         }
 202         return level;
 203     }
 204 }