001/*
002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.lir.phases;
024
025import java.util.*;
026import java.util.regex.*;
027
028import jdk.internal.jvmci.code.*;
029import com.oracle.graal.debug.*;
030import com.oracle.graal.debug.Debug.*;
031import jdk.internal.jvmci.options.*;
032
033import com.oracle.graal.compiler.common.cfg.*;
034import com.oracle.graal.lir.*;
035import com.oracle.graal.lir.gen.*;
036
037/**
038 * Base class for all {@link LIR low-level} phases. Subclasses should be stateless. There will be
039 * one global instance for each phase that is shared for all compilations.
040 */
041public abstract class LIRPhase<C> {
042
043    public static class Options {
044        // @formatter:off
045        @Option(help = "Enable LIR level optimiztations.", type = OptionType.Debug)
046        public static final OptionValue<Boolean> LIROptimization = new OptionValue<>(true);
047        // @formatter:on
048    }
049
050    private static final int PHASE_DUMP_LEVEL = 2;
051
052    private CharSequence name;
053
054    /**
055     * Records time spent within {@link #apply}.
056     */
057    private final DebugTimer timer;
058
059    /**
060     * Records memory usage within {@link #apply}.
061     */
062    private final DebugMemUseTracker memUseTracker;
063
064    private static class LIRPhaseStatistics {
065        /**
066         * Records time spent within {@link #apply}.
067         */
068        private final DebugTimer timer;
069
070        /**
071         * Records memory usage within {@link #apply}.
072         */
073        private final DebugMemUseTracker memUseTracker;
074
075        LIRPhaseStatistics(Class<?> clazz) {
076            timer = Debug.timer("LIRPhaseTime_%s", clazz);
077            memUseTracker = Debug.memUseTracker("LIRPhaseMemUse_%s", clazz);
078        }
079    }
080
081    private static final ClassValue<LIRPhaseStatistics> statisticsClassValue = new ClassValue<LIRPhaseStatistics>() {
082        @Override
083        protected LIRPhaseStatistics computeValue(Class<?> c) {
084            return new LIRPhaseStatistics(c);
085        }
086    };
087
088    @SuppressWarnings("all")
089    private static boolean assertionsEnabled() {
090        boolean enabled = false;
091        assert enabled = true;
092        return enabled;
093    }
094
095    private static final Pattern NAME_PATTERN = assertionsEnabled() ? Pattern.compile("[A-Z][A-Za-z0-9]+") : null;
096
097    private static boolean checkName(String name) {
098        assert name == null || NAME_PATTERN.matcher(name).matches() : "illegal phase name: " + name;
099        return true;
100    }
101
102    public LIRPhase() {
103        LIRPhaseStatistics statistics = statisticsClassValue.get(getClass());
104        timer = statistics.timer;
105        memUseTracker = statistics.memUseTracker;
106    }
107
108    protected LIRPhase(String name) {
109        assert checkName(name);
110        this.name = name;
111        LIRPhaseStatistics statistics = statisticsClassValue.get(getClass());
112        timer = statistics.timer;
113        memUseTracker = statistics.memUseTracker;
114    }
115
116    public final <B extends AbstractBlockBase<B>> void apply(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context) {
117        apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, true);
118    }
119
120    public final <B extends AbstractBlockBase<B>> void apply(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context, boolean dumpLIR) {
121        try (Scope s = Debug.scope(getName(), this)) {
122            try (DebugCloseable a = timer.start(); DebugCloseable c = memUseTracker.start()) {
123                run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
124                if (dumpLIR && Debug.isDumpEnabled(PHASE_DUMP_LEVEL)) {
125                    Debug.dump(PHASE_DUMP_LEVEL, lirGenRes.getLIR(), "%s", getName());
126                }
127            }
128        } catch (Throwable e) {
129            throw Debug.handle(e);
130        }
131    }
132
133    protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context);
134
135    protected CharSequence createName() {
136        String className = LIRPhase.this.getClass().getName();
137        String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
138        if (s.endsWith("Phase")) {
139            s = s.substring(0, s.length() - "Phase".length());
140        }
141        return s;
142    }
143
144    public final CharSequence getName() {
145        if (name == null) {
146            name = createName();
147        }
148        return name;
149    }
150
151}