1 /*
   2  * Copyright (c) 2015, 2015, 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.lir.phases;
  24 
  25 import java.util.regex.Pattern;
  26 
  27 import org.graalvm.compiler.debug.DebugCloseable;
  28 import org.graalvm.compiler.debug.DebugContext;
  29 import org.graalvm.compiler.debug.MemUseTrackerKey;
  30 import org.graalvm.compiler.debug.TimerKey;
  31 import org.graalvm.compiler.lir.LIR;
  32 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  33 import org.graalvm.compiler.options.Option;
  34 import org.graalvm.compiler.options.OptionKey;
  35 import org.graalvm.compiler.options.OptionType;
  36 
  37 import jdk.vm.ci.code.TargetDescription;
  38 
  39 /**
  40  * Base class for all {@link LIR low-level} phases. Subclasses should be stateless. There will be
  41  * one global instance for each phase that is shared for all compilations.
  42  */
  43 public abstract class LIRPhase<C> {
  44 
  45     public static class Options {
  46         // @formatter:off
  47         @Option(help = "Enable LIR level optimiztations.", type = OptionType.Debug)
  48         public static final OptionKey<Boolean> LIROptimization = new OptionKey<>(true);
  49         // @formatter:on
  50     }
  51 
  52     /**
  53      * Records time spent within {@link #apply}.
  54      */
  55     private final TimerKey timer;
  56 
  57     /**
  58      * Records memory usage within {@link #apply}.
  59      */
  60     private final MemUseTrackerKey memUseTracker;
  61 
  62     public static final class LIRPhaseStatistics {
  63         /**
  64          * Records time spent within {@link #apply}.
  65          */
  66         public final TimerKey timer;
  67 
  68         /**
  69          * Records memory usage within {@link #apply}.
  70          */
  71         public final MemUseTrackerKey memUseTracker;
  72 
  73         public LIRPhaseStatistics(Class<?> clazz) {
  74             timer = DebugContext.timer("LIRPhaseTime_%s", clazz);
  75             memUseTracker = DebugContext.memUseTracker("LIRPhaseMemUse_%s", clazz);
  76         }
  77     }
  78 
  79     public static final ClassValue<LIRPhaseStatistics> statisticsClassValue = new ClassValue<LIRPhaseStatistics>() {
  80         @Override
  81         protected LIRPhaseStatistics computeValue(Class<?> c) {
  82             return new LIRPhaseStatistics(c);
  83         }
  84     };
  85 
  86     public static LIRPhaseStatistics getLIRPhaseStatistics(Class<?> c) {
  87         return statisticsClassValue.get(c);
  88     }
  89 
  90     /** Lazy initialization to create pattern only when assertions are enabled. */
  91     static class NamePatternHolder {
  92         static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
  93     }
  94 
  95     private static boolean checkName(CharSequence name) {
  96         assert name == null || NamePatternHolder.NAME_PATTERN.matcher(name).matches() : "illegal phase name: " + name;
  97         return true;
  98     }
  99 
 100     public LIRPhase() {
 101         LIRPhaseStatistics statistics = getLIRPhaseStatistics(getClass());
 102         timer = statistics.timer;
 103         memUseTracker = statistics.memUseTracker;
 104     }
 105 
 106     public final void apply(TargetDescription target, LIRGenerationResult lirGenRes, C context) {
 107         apply(target, lirGenRes, context, true);
 108     }
 109 
 110     @SuppressWarnings("try")
 111     public final void apply(TargetDescription target, LIRGenerationResult lirGenRes, C context, boolean dumpLIR) {
 112         DebugContext debug = lirGenRes.getLIR().getDebug();
 113         try (DebugContext.Scope s = debug.scope(getName(), this)) {
 114             try (DebugCloseable a = timer.start(debug); DebugCloseable c = memUseTracker.start(debug)) {
 115                 run(target, lirGenRes, context);
 116                 if (dumpLIR && debug.areScopesEnabled()) {
 117                     dumpAfter(lirGenRes);
 118                 }
 119             }
 120         } catch (Throwable e) {
 121             throw debug.handle(e);
 122         }
 123     }
 124 
 125     private void dumpAfter(LIRGenerationResult lirGenRes) {
 126         boolean isStage = this instanceof LIRPhaseSuite;
 127         if (!isStage) {
 128             DebugContext debug = lirGenRes.getLIR().getDebug();
 129             if (debug.isDumpEnabled(DebugContext.INFO_LEVEL)) {
 130                 debug.dump(DebugContext.INFO_LEVEL, lirGenRes.getLIR(), "After %s", getName());
 131             }
 132         }
 133     }
 134 
 135     protected abstract void run(TargetDescription target, LIRGenerationResult lirGenRes, C context);
 136 
 137     public static CharSequence createName(Class<?> clazz) {
 138         String className = clazz.getName();
 139         String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
 140         int innerClassPos = s.indexOf('$');
 141         if (innerClassPos > 0) {
 142             /* Remove inner class name. */
 143             s = s.substring(0, innerClassPos);
 144         }
 145         if (s.endsWith("Phase")) {
 146             s = s.substring(0, s.length() - "Phase".length());
 147         }
 148         return s;
 149     }
 150 
 151     protected CharSequence createName() {
 152         return createName(getClass());
 153     }
 154 
 155     public final CharSequence getName() {
 156         CharSequence name = createName();
 157         assert checkName(name);
 158         return name;
 159     }
 160 }