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 java.util.Vector;
016
017 import org.jikesrvm.VM;
018 import org.jikesrvm.Callbacks;
019 import org.jikesrvm.adaptive.recompilation.CompilerDNA;
020 import org.jikesrvm.classloader.RVMClass;
021 import org.jikesrvm.classloader.RVMMethod;
022 import org.jikesrvm.classloader.NormalMethod;
023 import org.jikesrvm.classloader.TypeReference;
024 import org.jikesrvm.compilers.baseline.BaselineCompiler;
025 import org.jikesrvm.compilers.baseline.EdgeCounts;
026 import org.jikesrvm.compilers.common.BootImageCompiler;
027 import org.jikesrvm.compilers.common.CompiledMethod;
028 import org.jikesrvm.compilers.opt.MagicNotImplementedException;
029 import org.jikesrvm.compilers.opt.OptOptions;
030 import org.jikesrvm.compilers.opt.OptimizingCompilerException;
031
032 /**
033 * Use optimizing compiler to build virtual machine boot image.
034 */
035 public final class OptimizingBootImageCompiler extends BootImageCompiler {
036
037 // Cache objects needed to cons up compilation plans
038 private final Vector<OptimizationPlanElement[]> optimizationPlans = new Vector<OptimizationPlanElement[]>();
039 private final Vector<Boolean> optimizationPlanLocks = new Vector<Boolean>();
040 private final Vector<OptOptions> options = new Vector<OptOptions>();
041 private final OptOptions masterOptions = new OptOptions();
042
043 // If excludePattern is null, all methods are opt-compiled (or attempted).
044 // Otherwise, methods that match the pattern are not opt-compiled.
045 // In any case, the class OptSaveVolatile is always opt-compiled.
046 //
047 private String excludePattern;
048
049 private boolean match(RVMMethod method) {
050 if (excludePattern == null) return true;
051 RVMClass cls = method.getDeclaringClass();
052 String clsName = cls.toString();
053 if (clsName.compareTo("org.jikesrvm.compilers.opt.runtimesupport.OptSaveVolatile") == 0) return true;
054 String methodName = method.getName().toString();
055 String fullName = clsName + "." + methodName;
056 return (fullName.indexOf(excludePattern)) < 0;
057 }
058
059 /**
060 * Initialize boot image compiler.
061 * @param args command line arguments to the bootimage compiler
062 */
063 protected void initCompiler(String[] args) {
064 try {
065 BaselineCompiler.initOptions();
066 VM.sysWrite("BootImageCompiler: init (opt compiler)\n");
067
068 // Writing a boot image is a little bit special. We're not really
069 // concerned about compile time, but we do care a lot about the quality
070 // and stability of the generated code. Set the options accordingly.
071 OptimizingCompiler.setBootOptions(masterOptions);
072
073 // Allow further customization by the user.
074 for (int i = 0, n = args.length; i < n; i++) {
075 String arg = args[i];
076 if (!masterOptions.processAsOption("-X:bc:", arg)) {
077 if (arg.startsWith("exclude=")) {
078 excludePattern = arg.substring(8);
079 } else {
080 VM.sysWrite("BootImageCompiler: Unrecognized argument " + arg + "; ignoring\n");
081 }
082 }
083 }
084 EdgeCounts.boot(masterOptions.PROFILE_EDGE_COUNT_INPUT_FILE);
085 OptimizingCompiler.init(masterOptions);
086 } catch (OptimizingCompilerException e) {
087 String msg = "BootImageCompiler: Compiler failed during initialization: " + e + "\n";
088 if (e.isFatal) {
089 // An unexpected error when building the opt boot image should be fatal
090 e.printStackTrace();
091 System.exit(VM.EXIT_STATUS_OPT_COMPILER_FAILED);
092 } else {
093 VM.sysWrite(msg);
094 }
095 }
096 }
097
098 /**
099 * Compile a method with bytecodes.
100 * @param method the method to compile
101 * @return the compiled method
102 */
103 protected CompiledMethod compileMethod(NormalMethod method, TypeReference[] params) {
104 if (method.hasNoOptCompileAnnotation()) {
105 return baselineCompile(method);
106 } else {
107 CompiledMethod cm = null;
108 OptimizingCompilerException escape = new OptimizingCompilerException(false);
109 try {
110 Callbacks.notifyMethodCompile(method, CompiledMethod.OPT);
111 boolean include = match(method);
112 if (!include) {
113 throw escape;
114 }
115 int freeOptimizationPlan = getFreeOptimizationPlan();
116 OptimizationPlanElement[] optimizationPlan = optimizationPlans.get(freeOptimizationPlan);
117 CompilationPlan cp =
118 new CompilationPlan(method, params, optimizationPlan, null, options.get(freeOptimizationPlan));
119 cm = OptimizingCompiler.compile(cp);
120 if (VM.BuildForAdaptiveSystem) {
121 /* We can't accurately measure compilation time on Host JVM, so just approximate with DNA */
122 int compilerId = CompilerDNA.getCompilerConstant(cp.options.getOptLevel());
123 cm.setCompilationTime((float)CompilerDNA.estimateCompileTime(compilerId, method));
124 }
125 releaseOptimizationPlan(freeOptimizationPlan);
126 return cm;
127 } catch (OptimizingCompilerException e) {
128 if (e.isFatal) {
129 // An unexpected error when building the opt boot image should be fatal
130 VM.sysWriteln("Error compiling method: "+method);
131 e.printStackTrace();
132 System.exit(VM.EXIT_STATUS_OPT_COMPILER_FAILED);
133 } else {
134 boolean printMsg = true;
135 if (e instanceof MagicNotImplementedException) {
136 printMsg = !((MagicNotImplementedException) e).isExpected;
137 }
138 if (e == escape) {
139 printMsg = false;
140 }
141 if (printMsg) {
142 if (e.toString().indexOf("method excluded") >= 0) {
143 String msg = "BootImageCompiler: " + method + " excluded from opt-compilation\n";
144 VM.sysWrite(msg);
145 } else {
146 String msg = "BootImageCompiler: can't optimize \"" + method + "\" (error was: " + e + ")\n";
147 VM.sysWrite(msg);
148 }
149 }
150 }
151 return baselineCompile(method);
152 }
153 }
154 }
155
156 private CompiledMethod baselineCompile(NormalMethod method) {
157 Callbacks.notifyMethodCompile(method, CompiledMethod.BASELINE);
158 CompiledMethod cm = BaselineCompiler.compile(method);
159 /* We can't accurately measure compilation time on Host JVM, so just approximate with DNA */
160 cm.setCompilationTime((float)CompilerDNA.estimateCompileTime(CompilerDNA.BASELINE, method));
161 return cm;
162 }
163
164 /**
165 * Return an optimization plan that isn't in use
166 * @return optimization plan
167 */
168 private int getFreeOptimizationPlan() {
169 // Find plan
170 synchronized (optimizationPlanLocks) {
171 for (int i = 0; i < optimizationPlanLocks.size(); i++) {
172 if (!optimizationPlanLocks.get(i)) {
173 optimizationPlanLocks.set(i, Boolean.TRUE);
174 return i;
175 }
176 }
177 // Find failed, so create new plan
178 OptimizationPlanElement[] optimizationPlan;
179 OptOptions cloneOptions = masterOptions.dup();
180 optimizationPlan = OptimizationPlanner.createOptimizationPlan(cloneOptions);
181 optimizationPlans.addElement(optimizationPlan);
182 optimizationPlanLocks.addElement(Boolean.TRUE);
183 options.addElement(cloneOptions);
184 return optimizationPlanLocks.size() - 1;
185 }
186 }
187
188 /**
189 * Release an optimization plan
190 * @param plan an optimization plan
191 */
192 private void releaseOptimizationPlan(int plan) {
193 synchronized (optimizationPlanLocks) {
194 optimizationPlanLocks.set(plan, Boolean.FALSE);
195 }
196 }
197 }