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 */ 013package org.jikesrvm.compilers.opt.driver; 014 015import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_OPT_COMPILER_FAILED; 016 017import java.util.Vector; 018 019import org.jikesrvm.VM; 020import org.jikesrvm.adaptive.recompilation.CompilerDNA; 021import org.jikesrvm.classloader.NormalMethod; 022import org.jikesrvm.classloader.RVMClass; 023import org.jikesrvm.classloader.RVMMethod; 024import org.jikesrvm.classloader.TypeReference; 025import org.jikesrvm.compilers.baseline.BaselineCompiler; 026import org.jikesrvm.compilers.baseline.EdgeCounts; 027import org.jikesrvm.compilers.common.BootImageCompiler; 028import org.jikesrvm.compilers.common.CompiledMethod; 029import org.jikesrvm.compilers.opt.MagicNotImplementedException; 030import org.jikesrvm.compilers.opt.OptOptions; 031import org.jikesrvm.compilers.opt.OptimizingCompilerException; 032import org.jikesrvm.runtime.Callbacks; 033 034/** 035 * Use optimizing compiler to build virtual machine boot image. 036 */ 037public final class OptimizingBootImageCompiler extends BootImageCompiler { 038 039 // Cache objects needed to cons up compilation plans 040 private final Vector<OptimizationPlanElement[]> optimizationPlans = new Vector<OptimizationPlanElement[]>(); 041 private final Vector<Boolean> optimizationPlanLocks = new Vector<Boolean>(); 042 private final Vector<OptOptions> options = new Vector<OptOptions>(); 043 private final OptOptions masterOptions = new OptOptions(); 044 045 /** 046 * If excludePattern is {@code null}, all methods are opt-compiled (or attempted). 047 * Otherwise, methods that match the pattern are not opt-compiled. 048 * In any case, the class OptSaveVolatile is always opt-compiled. 049 */ 050 private String excludePattern; 051 052 private boolean match(RVMMethod method) { 053 if (excludePattern == null) return true; 054 RVMClass cls = method.getDeclaringClass(); 055 String clsName = cls.toString(); 056 if (clsName.compareTo("org.jikesrvm.compilers.opt.runtimesupport.OptSaveVolatile") == 0) return true; 057 String methodName = method.getName().toString(); 058 String fullName = clsName + "." + methodName; 059 return (fullName.indexOf(excludePattern)) < 0; 060 } 061 062 @Override 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.loadCountsFromFileIfAvailable(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(EXIT_STATUS_OPT_COMPILER_FAILED); 092 } else { 093 VM.sysWrite(msg); 094 } 095 } 096 } 097 098 @Override 099 protected CompiledMethod compileMethod(NormalMethod method, TypeReference[] params) { 100 if (method.hasNoOptCompileAnnotation()) { 101 return baselineCompile(method); 102 } else { 103 CompiledMethod cm = null; 104 OptimizingCompilerException escape = new OptimizingCompilerException(false); 105 try { 106 Callbacks.notifyMethodCompile(method, CompiledMethod.OPT); 107 boolean include = match(method); 108 if (!include) { 109 throw escape; 110 } 111 int freeOptimizationPlan = getFreeOptimizationPlan(); 112 OptimizationPlanElement[] optimizationPlan = optimizationPlans.get(freeOptimizationPlan); 113 CompilationPlan cp = 114 new CompilationPlan(method, params, optimizationPlan, null, options.get(freeOptimizationPlan)); 115 cm = OptimizingCompiler.compile(cp); 116 if (VM.BuildForAdaptiveSystem) { 117 /* We can't accurately measure compilation time on Host JVM, so just approximate with DNA */ 118 int compilerId = CompilerDNA.getCompilerConstant(cp.options.getOptLevel()); 119 cm.setCompilationTime((float)CompilerDNA.estimateCompileTime(compilerId, method)); 120 } 121 releaseOptimizationPlan(freeOptimizationPlan); 122 return cm; 123 } catch (OptimizingCompilerException e) { 124 if (e.isFatal) { 125 // An unexpected error when building the opt boot image should be fatal 126 VM.sysWriteln("Error compiling method: " + method); 127 e.printStackTrace(); 128 System.exit(EXIT_STATUS_OPT_COMPILER_FAILED); 129 } else { 130 boolean printMsg = true; 131 boolean expected = false; 132 if (e instanceof MagicNotImplementedException) { 133 printMsg = !((MagicNotImplementedException) e).isExpected; 134 expected = ((MagicNotImplementedException) e).isExpected; 135 } 136 if (e == escape) { 137 printMsg = false; 138 } 139 if (printMsg) { 140 if (e.toString().indexOf("method excluded") >= 0) { 141 String msg = "BootImageCompiler: " + method + " excluded from opt-compilation\n"; 142 VM.sysWrite(msg); 143 } else { 144 String msg = "BootImageCompiler: can't optimize \"" + method + "\" (error was: " + e + ")\n"; 145 VM.sysWrite(msg); 146 } 147 } else if (!expected && e != escape) { 148 // Treat any unexpected OptimizingCompilerException that occur 149 // when compiling the boot image as fatal. 150 throw new Error(e); 151 } 152 } 153 return baselineCompile(method); 154 } 155 } 156 } 157 158 private CompiledMethod baselineCompile(NormalMethod method) { 159 Callbacks.notifyMethodCompile(method, CompiledMethod.BASELINE); 160 CompiledMethod cm = BaselineCompiler.compile(method); 161 /* We can't accurately measure compilation time on Host JVM, so just approximate with DNA */ 162 cm.setCompilationTime((float)CompilerDNA.estimateCompileTime(CompilerDNA.BASELINE, method)); 163 return cm; 164 } 165 166 /** 167 * Return an optimization plan that isn't in use 168 * @return optimization plan 169 */ 170 private int getFreeOptimizationPlan() { 171 // Find plan 172 synchronized (optimizationPlanLocks) { 173 for (int i = 0; i < optimizationPlanLocks.size(); i++) { 174 if (!optimizationPlanLocks.get(i)) { 175 optimizationPlanLocks.set(i, Boolean.TRUE); 176 return i; 177 } 178 } 179 // Find failed, so create new plan 180 OptimizationPlanElement[] optimizationPlan; 181 OptOptions cloneOptions = masterOptions.dup(); 182 optimizationPlan = OptimizationPlanner.createOptimizationPlan(cloneOptions); 183 optimizationPlans.add(optimizationPlan); 184 optimizationPlanLocks.add(Boolean.TRUE); 185 options.add(cloneOptions); 186 return optimizationPlanLocks.size() - 1; 187 } 188 } 189 190 /** 191 * Release an optimization plan 192 * @param plan an optimization plan 193 */ 194 private void releaseOptimizationPlan(int plan) { 195 synchronized (optimizationPlanLocks) { 196 optimizationPlanLocks.set(plan, Boolean.FALSE); 197 } 198 } 199}