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