001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.opt.driver;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.compilers.opt.OptOptions;
017    import org.jikesrvm.compilers.opt.OptimizingCompilerException;
018    import org.jikesrvm.compilers.opt.ir.IR;
019    
020    /**
021     * An element in the opt compiler's optimzation plan
022     * that aggregates together other OptimizationPlan elements.
023     *
024     * NOTE: Instances of subclasses of this class are
025     *       held in OptimizationPlanner.masterPlan
026     *       and thus represent global state.
027     *       It is therefore incorrect for any per-compilation
028     *       state to be stored in an instance field of
029     *       one of these objects.
030     */
031    public class OptimizationPlanCompositeElement extends OptimizationPlanElement {
032      /**
033       * Name of this element.
034       */
035      private final String myName;
036      /**
037       * Ordered list of elements that together comprise this element.
038       */
039      private final OptimizationPlanElement[] myElements;
040    
041      /**
042       * Compose together the argument elements into a composite element
043       * of an optimization plan.
044       *
045       * @param   n     The name for this phase
046       * @param   e     The elements to compose
047       */
048      public OptimizationPlanCompositeElement(String n, OptimizationPlanElement[] e) {
049        myName = n;
050        myElements = e;
051      }
052    
053      /**
054       * Compose together the argument elements into a composite element
055       * of an optimization plan.
056       *
057       * @param   n     The name for this phase
058       * @param   e     The elements to compose
059       */
060      public OptimizationPlanCompositeElement(String n, Object[] e) {
061        myName = n;
062        myElements = new OptimizationPlanElement[e.length];
063        for (int i = 0; i < e.length; i++) {
064          if (e[i] instanceof OptimizationPlanElement) {
065            myElements[i] = (OptimizationPlanElement) (e[i]);
066          } else if (e[i] instanceof CompilerPhase) {
067            myElements[i] = new OptimizationPlanAtomicElement((CompilerPhase) e[i]);
068          } else {
069            throw new OptimizingCompilerException("Unsupported plan element " + e[i]);
070          }
071        }
072      }
073    
074      /**
075       * This method is called to initialize the optimization plan support
076       *  measuring compilation.
077       */
078      public void initializeForMeasureCompilation() {
079        // initialize each composite object
080        for (OptimizationPlanElement myElement : myElements) {
081          myElement.initializeForMeasureCompilation();
082        }
083      }
084    
085      /**
086       * Compose together the argument elements into a composite element
087       * of an optimization plan.
088       *
089       * @param name The name associated with this composite.
090       * @param elems An Object[] of CompilerPhases or
091       *              OptimizationPlanElements to be composed
092       * @return an OptimizationPlanCompositeElement that
093       *         represents the composition.
094       */
095      public static OptimizationPlanCompositeElement compose(String name, Object[] elems) {
096        return new OptimizationPlanCompositeElement(name, elems);
097      }
098    
099      /**
100       * Determine, possibly by consulting the passed options object,
101       * if this optimization plan element should be performed.
102       *
103       * @param options The Options object for the current compilation.
104       * @return true if the plan element should be performed.
105       */
106      public boolean shouldPerform(OptOptions options) {
107        for (OptimizationPlanElement myElement : myElements) {
108          if (myElement.shouldPerform(options)) {
109            return true;
110          }
111        }
112        return false;
113      }
114    
115      /**
116       * Returns true if the phase wants the IR dumped before and/or after it runs.
117       * By default, printing is not enabled.
118       * Subclasses should overide this method if they want to provide IR dumping.
119       *
120       * @param options the compiler options for the compilation
121       * @param before true when invoked before perform, false otherwise.
122       * @return true if the IR should be printed, false otherwise.
123       */
124      public boolean printingEnabled(OptOptions options, boolean before) {
125        return false;
126      }
127    
128      /**
129       * Do the work represented by this element in the optimization plan.
130       * The assumption is that the work will modify the IR in some way.
131       *
132       * @param ir The IR object to work with.
133       */
134      public final void perform(IR ir) {
135        if (printingEnabled(ir.options, true)) {
136          if (!ir.options.hasMETHOD_TO_PRINT() || ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) {
137            CompilerPhase.dumpIR(ir, "Before " + getName());
138          }
139        }
140    
141        for (OptimizationPlanElement myElement : myElements) {
142          if (myElement.shouldPerform(ir.options)) {
143            myElement.perform(ir);
144          }
145        }
146    
147        if (printingEnabled(ir.options, false)) {
148          if (!ir.options.hasMETHOD_TO_PRINT() || ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) {
149            CompilerPhase.dumpIR(ir, "After " + getName());
150          }
151        }
152      }
153    
154      /**
155       * @return a String which is the name of the phase.
156       */
157      public String getName() {
158        return myName;
159      }
160    
161      /**
162       * Generate (to the sysWrite stream) a report of the
163       * time spent performing this element of the optimization plan.
164       *
165       * @param indent Number of spaces to indent report.
166       * @param timeCol Column number of time portion of report.
167       * @param totalTime Total opt compilation time in seconds.
168       */
169      public final void reportStats(int indent, int timeCol, double totalTime) {
170        double myTime = elapsedTime();
171        if (myTime < 0.000001) {
172          return;
173        }
174        // (1) Print header.
175        int curCol = 0;
176        for (curCol = 0; curCol < indent; curCol++) {
177          VM.sysWrite(" ");
178        }
179        int myNamePtr = 0;
180        while (curCol < timeCol && myNamePtr < myName.length()) {
181          VM.sysWrite(myName.charAt(myNamePtr));
182          myNamePtr++;
183          curCol++;
184        }
185        VM.sysWrite("\n");
186        // (2) print elements
187        for (OptimizationPlanElement myElement : myElements) {
188          myElement.reportStats(indent + 4, timeCol, totalTime);
189        }
190        // (3) print total
191        curCol = 0;
192        for (curCol = 0; curCol < indent + 4; curCol++) {
193          VM.sysWrite(" ");
194        }
195        VM.sysWrite("TOTAL ");
196        curCol += 6;
197        while (curCol < timeCol) {
198          VM.sysWrite(" ");
199          curCol++;
200        }
201        prettyPrintTime(myTime, totalTime);
202        VM.sysWriteln();
203      }
204    
205      /**
206       * Report the elapsed time spent in the PlanElement
207       * @return time spend in the plan (in seconds)
208       */
209      public double elapsedTime() {
210        double total = 0.0;
211        for (OptimizationPlanElement myElement : myElements) {
212          total += myElement.elapsedTime();
213        }
214        return total;
215      }
216    }