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