1 /*
   2  * Copyright (c) 2011, 2013, 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.phases;
  24 
  25 import java.util.regex.Pattern;
  26 
  27 import org.graalvm.compiler.debug.Debug;
  28 import org.graalvm.compiler.debug.Debug.Scope;
  29 import org.graalvm.compiler.debug.DebugCloseable;
  30 import org.graalvm.compiler.debug.DebugCounter;
  31 import org.graalvm.compiler.debug.DebugMemUseTracker;
  32 import org.graalvm.compiler.debug.DebugTimer;
  33 import org.graalvm.compiler.debug.Fingerprint;
  34 import org.graalvm.compiler.graph.Graph;
  35 import org.graalvm.compiler.graph.Graph.Mark;
  36 import org.graalvm.compiler.nodes.StructuredGraph;
  37 import org.graalvm.compiler.options.Option;
  38 import org.graalvm.compiler.options.OptionType;
  39 import org.graalvm.compiler.options.OptionValue;
  40 import org.graalvm.compiler.options.StableOptionValue;
  41 import org.graalvm.compiler.phases.contract.NodeCostUtil;
  42 import org.graalvm.compiler.phases.contract.PhaseSizeContract;
  43 import org.graalvm.compiler.phases.tiers.PhaseContext;
  44 
  45 /**
  46  * Base class for all compiler phases. Subclasses should be stateless. There will be one global
  47  * instance for each compiler phase that is shared for all compilations. VM-, target- and
  48  * compilation-specific data can be passed with a context object.
  49  */
  50 public abstract class BasePhase<C> implements PhaseSizeContract {
  51 
  52     public static class PhaseOptions {
  53         // @formatter:off
  54         @Option(help = "Verify before - after relation of the relative, computed, code size of a graph", type = OptionType.Debug)
  55         public static final OptionValue<Boolean> VerifyGraalPhasesSize = new StableOptionValue<>(false);
  56         // @formatter:on
  57     }
  58 
  59     /**
  60      * Records time spent in {@link #apply(StructuredGraph, Object, boolean)}.
  61      */
  62     private final DebugTimer timer;
  63 
  64     /**
  65      * Counts calls to {@link #apply(StructuredGraph, Object, boolean)}.
  66      */
  67     private final DebugCounter executionCount;
  68 
  69     /**
  70      * Accumulates the {@linkplain Graph#getNodeCount() live node count} of all graphs sent to
  71      * {@link #apply(StructuredGraph, Object, boolean)}.
  72      */
  73     private final DebugCounter inputNodesCount;
  74 
  75     /**
  76      * Records memory usage within {@link #apply(StructuredGraph, Object, boolean)}.
  77      */
  78     private final DebugMemUseTracker memUseTracker;
  79 
  80     /** Lazy initialization to create pattern only when assertions are enabled. */
  81     static class NamePatternHolder {
  82         static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
  83     }
  84 
  85     private static class BasePhaseStatistics {
  86         /**
  87          * Records time spent in {@link #apply(StructuredGraph, Object, boolean)}.
  88          */
  89         private final DebugTimer timer;
  90 
  91         /**
  92          * Counts calls to {@link #apply(StructuredGraph, Object, boolean)}.
  93          */
  94         private final DebugCounter executionCount;
  95 
  96         /**
  97          * Accumulates the {@linkplain Graph#getNodeCount() live node count} of all graphs sent to
  98          * {@link #apply(StructuredGraph, Object, boolean)}.
  99          */
 100         private final DebugCounter inputNodesCount;
 101 
 102         /**
 103          * Records memory usage within {@link #apply(StructuredGraph, Object, boolean)}.
 104          */
 105         private final DebugMemUseTracker memUseTracker;
 106 
 107         BasePhaseStatistics(Class<?> clazz) {
 108             timer = Debug.timer("PhaseTime_%s", clazz);
 109             executionCount = Debug.counter("PhaseCount_%s", clazz);
 110             memUseTracker = Debug.memUseTracker("PhaseMemUse_%s", clazz);
 111             inputNodesCount = Debug.counter("PhaseNodes_%s", clazz);
 112         }
 113     }
 114 
 115     private static final ClassValue<BasePhaseStatistics> statisticsClassValue = new ClassValue<BasePhaseStatistics>() {
 116         @Override
 117         protected BasePhaseStatistics computeValue(Class<?> c) {
 118             return new BasePhaseStatistics(c);
 119         }
 120     };
 121 
 122     protected BasePhase() {
 123         BasePhaseStatistics statistics = statisticsClassValue.get(getClass());
 124         timer = statistics.timer;
 125         executionCount = statistics.executionCount;
 126         memUseTracker = statistics.memUseTracker;
 127         inputNodesCount = statistics.inputNodesCount;
 128     }
 129 
 130     public final void apply(final StructuredGraph graph, final C context) {
 131         apply(graph, context, true);
 132     }
 133 
 134     @SuppressWarnings("try")
 135     protected final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) {
 136         try (DebugCloseable a = timer.start(); Scope s = Debug.scope(getClass(), this); DebugCloseable c = memUseTracker.start()) {
 137             int sizeBefore = 0;
 138             Mark before = null;
 139             if (PhaseOptions.VerifyGraalPhasesSize.getValue() && checkContract()) {
 140                 if (context instanceof PhaseContext) {
 141                     sizeBefore = NodeCostUtil.computeGraphSize(graph, ((PhaseContext) context).getNodeCostProvider());
 142                     before = graph.getMark();
 143                 }
 144             }
 145             if (dumpGraph && Debug.isDumpEnabled(Debug.VERBOSE_LOG_LEVEL)) {
 146                 Debug.dump(Debug.VERBOSE_LOG_LEVEL, graph, "Before phase %s", getName());
 147             }
 148             inputNodesCount.add(graph.getNodeCount());
 149             this.run(graph, context);
 150             executionCount.increment();
 151             if (PhaseOptions.VerifyGraalPhasesSize.getValue() && checkContract()) {
 152                 if (context instanceof PhaseContext) {
 153                     if (!before.isCurrent()) {
 154                         int sizeAfter = NodeCostUtil.computeGraphSize(graph, ((PhaseContext) context).getNodeCostProvider());
 155                         NodeCostUtil.phaseFulfillsSizeContract(graph, sizeBefore, sizeAfter, this);
 156                     }
 157                 }
 158             }
 159             if (dumpGraph && Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) {
 160                 Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", getName());
 161             }
 162             if (Fingerprint.ENABLED) {
 163                 String graphDesc = graph.method() == null ? graph.name : graph.method().format("%H.%n(%p)");
 164                 Fingerprint.submit("After phase %s nodes in %s are %s", getName(), graphDesc, graph.getNodes().snapshot());
 165             }
 166             if (Debug.isVerifyEnabled()) {
 167                 Debug.verify(graph, "%s", getName());
 168             }
 169             assert graph.verify();
 170         } catch (Throwable t) {
 171             throw Debug.handle(t);
 172         }
 173     }
 174 
 175     protected CharSequence getName() {
 176         String className = BasePhase.this.getClass().getName();
 177         String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
 178         int innerClassPos = s.indexOf('$');
 179         if (innerClassPos > 0) {
 180             /* Remove inner class name. */
 181             s = s.substring(0, innerClassPos);
 182         }
 183         if (s.endsWith("Phase")) {
 184             s = s.substring(0, s.length() - "Phase".length());
 185         }
 186         return s;
 187     }
 188 
 189     protected abstract void run(StructuredGraph graph, C context);
 190 
 191     @Override
 192     public String contractorName() {
 193         return (String) getName();
 194     }
 195 
 196     @Override
 197     public float codeSizeIncrease() {
 198         return 1.25f;
 199     }
 200 
 201 }