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 
  44 public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFactory {
  45 
  46     private static MethodFilter[] graalCompileOnlyFilter;
  47     private static boolean compileGraalWithC1Only;
  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         initializeGraalCompilePolicyFields(options);
  71         /*
  72          * Exercise this code path early to encourage loading now. This doesn't solve problem of
  73          * deadlock during class loading but seems to eliminate it in practice.
  74          */
  75         adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.FullOptimization);
  76         adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.Simple);
  77     }
  78 
  79     private static void initializeGraalCompilePolicyFields(OptionValues options) {
  80         compileGraalWithC1Only = Options.CompileGraalWithC1Only.getValue(options);
  81         String optionValue = Options.GraalCompileOnly.getValue(options);
  82         if (optionValue != null) {
  83             MethodFilter[] filter = MethodFilter.parse(optionValue);
  84             if (filter.length == 0) {
  85                 filter = null;
  86             }
  87             graalCompileOnlyFilter = filter;
  88         }
  89     }
  90 
  91     @Override
  92     public void printProperties(PrintStream out) {
  93         out.println("[Graal properties]");
  94         options.printHelp(OptionsParser.getOptionsLoader(), out, GRAAL_OPTION_PROPERTY_PREFIX);
  95     }
  96 
  97     static class Options {
  98 
  99         // @formatter:off
 100         @Option(help = "In tiered mode compile Graal and JVMCI using optimized first tier code.", type = OptionType.Expert)
 101         public static final OptionKey<Boolean> CompileGraalWithC1Only = new OptionKey<>(true);
 102 
 103         @Option(help = "A method filter selecting what should be compiled by Graal.  All other requests will be reduced to CompilationLevel.Simple.", type = OptionType.Expert)
 104         public static final OptionKey<String> GraalCompileOnly = new OptionKey<>(null);
 105         // @formatter:on
 106 
 107     }
 108 
 109     @Override
 110     public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) {
 111         HotSpotGraalCompiler compiler = createCompiler(runtime, options, CompilerConfigurationFactory.selectFactory(null, options));
 112         // Only the HotSpotGraalRuntime associated with the compiler created via
 113         // jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving
 114         // VM events.
 115         locator.onCompilerCreation(compiler);
 116         return compiler;
 117     }
 118 
 119     /**
 120      * Creates a new {@link HotSpotGraalRuntime} object and a new {@link HotSpotGraalCompiler} and
 121      * returns the latter.
 122      *
 123      * @param runtime the JVMCI runtime on which the {@link HotSpotGraalRuntime} is built
 124      * @param compilerConfigurationFactory factory for the {@link CompilerConfiguration}
 125      */
 126     @SuppressWarnings("try")
 127     public static HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime, OptionValues options, CompilerConfigurationFactory compilerConfigurationFactory) {
 128         HotSpotJVMCIRuntime jvmciRuntime = (HotSpotJVMCIRuntime) runtime;
 129         try (InitTimer t = timer("HotSpotGraalRuntime.<init>")) {
 130             HotSpotGraalRuntime graalRuntime = new HotSpotGraalRuntime(jvmciRuntime, compilerConfigurationFactory, options);
 131             return new HotSpotGraalCompiler(jvmciRuntime, graalRuntime, graalRuntime.getOptions());
 132         }
 133     }
 134 
 135     @Override
 136     public CompilationLevelAdjustment getCompilationLevelAdjustment() {
 137         if (graalCompileOnlyFilter != null) {
 138             return CompilationLevelAdjustment.ByFullSignature;
 139         }
 140         if (compileGraalWithC1Only) {
 141             // We only decide using the class declaring the method
 142             // so no need to have the method name and signature
 143             // symbols converted to a String.
 144             return CompilationLevelAdjustment.ByHolder;
 145         }
 146         return CompilationLevelAdjustment.None;
 147     }
 148 
 149     @Override
 150     public CompilationLevel adjustCompilationLevel(Class<?> declaringClass, String name, String signature, boolean isOsr, CompilationLevel level) {
 151         return adjustCompilationLevelInternal(declaringClass, name, signature, level);
 152     }
 153 
 154     static {
 155         // Fail-fast detection for package renaming to guard use of package
 156         // prefixes in adjustCompilationLevelInternal.
 157         assert jdk.vm.ci.services.Services.class.getName().equals("jdk.vm.ci.services.Services");
 158         assert HotSpotGraalCompilerFactory.class.getName().equals("org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory");
 159     }
 160 
 161     /*
 162      * This method is static so it can be exercised during initialization.
 163      */
 164     private static CompilationLevel adjustCompilationLevelInternal(Class<?> declaringClass, String name, String signature, CompilationLevel level) {
 165         if (compileGraalWithC1Only) {
 166             if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
 167                 String declaringClassName = declaringClass.getName();
 168                 if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm") || declaringClassName.startsWith("com.oracle.graal")) {
 169                     return CompilationLevel.Simple;
 170                 }
 171             }
 172         }
 173         return checkGraalCompileOnlyFilter(declaringClass.getName(), name, signature, level);
 174     }
 175 
 176     public static CompilationLevel checkGraalCompileOnlyFilter(String declaringClassName, String name, String signature, CompilationLevel level) {
 177         if (graalCompileOnlyFilter != null) {
 178             if (level == CompilationLevel.FullOptimization) {
 179                 HotSpotSignature sig = null;
 180                 for (MethodFilter filter : graalCompileOnlyFilter) {
 181                     if (filter.hasSignature() && sig == null) {
 182                         sig = new HotSpotSignature(HotSpotJVMCIRuntime.runtime(), signature);
 183                     }
 184                     if (filter.matches(declaringClassName, name, sig)) {
 185                         return level;
 186                     }
 187                 }
 188                 return CompilationLevel.Simple;
 189             }
 190         }
 191         return level;
 192     }
 193 }