1 /* 2 * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package sun.hotspot.tools.ctw; 25 26 import sun.hotspot.WhiteBox; 27 import jdk.internal.misc.SharedSecrets; 28 import jdk.internal.reflect.ConstantPool; 29 import java.lang.reflect.Executable; 30 31 import java.util.Objects; 32 import java.util.concurrent.Executor; 33 import java.util.concurrent.atomic.AtomicLong; 34 35 /** 36 * Provide method to compile whole class. 37 * Also contains compiled methods and classes counters. 38 */ 39 public class Compiler { 40 41 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 42 private static final AtomicLong METHOD_COUNT = new AtomicLong(0L); 43 44 private Compiler() { } 45 46 /** 47 * @return count of processed methods 48 */ 49 public static long getMethodCount() { 50 return METHOD_COUNT.get(); 51 } 52 53 /** 54 * Compiles all methods and constructors. 55 * 56 * @param aClass class to compile 57 * @param id an id of the class 58 * @param executor executor used for compile task invocation 59 * @throws NullPointerException if {@code class} or {@code executor} 60 * is {@code null} 61 */ 62 public static void compileClass(Class<?> aClass, long id, Executor executor) { 63 Objects.requireNonNull(aClass); 64 Objects.requireNonNull(executor); 65 try { 66 ConstantPool constantPool = SharedSecrets.getJavaLangAccess(). 67 getConstantPool(aClass); 68 if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) { 69 preloadClasses(aClass.getName(), id, constantPool); 70 } 71 long methodCount = 0; 72 for (Executable e : aClass.getDeclaredConstructors()) { 73 ++methodCount; 74 executor.execute(new CompileMethodCommand(id, e)); 75 } 76 for (Executable e : aClass.getDeclaredMethods()) { 77 ++methodCount; 78 executor.execute(new CompileMethodCommand(id, e)); 79 } 80 METHOD_COUNT.addAndGet(methodCount); 81 82 if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0 83 && (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) { 84 WHITE_BOX.deoptimizeAll(); 85 } 86 } catch (Throwable t) { 87 CompileTheWorld.OUT.printf("[%d]\t%s\tskipping %s%n", id, aClass.getName(), t); 88 t.printStackTrace(); 89 } 90 } 91 92 private static void preloadClasses(String className, long id, 93 ConstantPool constantPool) { 94 try { 95 for (int i = 0, n = constantPool.getSize(); i < n; ++i) { 96 try { 97 constantPool.getClassAt(i); 98 } catch (IllegalArgumentException ignore) { 99 } 100 } 101 } catch (Throwable t) { 102 CompileTheWorld.OUT.printf("[%d]\t%s\tpreloading failed : %s%n", 103 id, className, t); 104 } 105 } 106 107 108 109 /** 110 * Compilation of method. 111 * Will compile method on all available comp levels. 112 */ 113 private static class CompileMethodCommand implements Runnable { 114 private final long classId; 115 private final String className; 116 private final Executable method; 117 118 /** 119 * @param classId id of class 120 * @param method compiled for compilation 121 */ 122 public CompileMethodCommand(long classId, Executable method) { 123 this.classId = classId; 124 this.className = method.getDeclaringClass().getName(); 125 this.method = method; 126 } 127 128 @Override 129 public final void run() { 130 int compLevel = Utils.INITIAL_COMP_LEVEL; 131 if (Utils.TIERED_COMPILATION) { 132 for (int i = compLevel; i <= Utils.TIERED_STOP_AT_LEVEL; ++i) { 133 WHITE_BOX.deoptimizeMethod(method); 134 compileAtLevel(i); 135 } 136 } else { 137 compileAtLevel(compLevel); 138 } 139 } 140 141 private void waitCompilation() { 142 if (!Utils.BACKGROUND_COMPILATION) { 143 return; 144 } 145 final Object obj = new Object(); 146 synchronized (obj) { 147 for (int i = 0; 148 i < 10 && WHITE_BOX.isMethodQueuedForCompilation(method); 149 ++i) { 150 try { 151 obj.wait(1000); 152 } catch (InterruptedException e) { 153 Thread.currentThread().interrupt(); 154 } 155 } 156 } 157 } 158 159 private void compileAtLevel(int compLevel) { 160 if (WHITE_BOX.isMethodCompilable(method, compLevel)) { 161 try { 162 WHITE_BOX.enqueueMethodForCompilation(method, compLevel); 163 waitCompilation(); 164 int tmp = WHITE_BOX.getMethodCompilationLevel(method); 165 if (tmp != compLevel) { 166 log("compilation level = " + tmp 167 + ", but not " + compLevel); 168 } else if (Utils.IS_VERBOSE) { 169 log("compilation level = " + tmp + ". OK"); 170 } 171 } catch (Throwable t) { 172 log("error on compile at " + compLevel 173 + " level"); 174 t.printStackTrace(); 175 } 176 } else if (Utils.IS_VERBOSE) { 177 log("not compilable at " + compLevel); 178 } 179 } 180 181 private void log(String message) { 182 StringBuilder builder = new StringBuilder("["); 183 builder.append(classId); 184 builder.append("]\t"); 185 builder.append(className); 186 builder.append("::"); 187 builder.append(method.getName()); 188 builder.append('('); 189 Class[] params = method.getParameterTypes(); 190 for (int i = 0, n = params.length - 1; i < n; ++i) { 191 builder.append(params[i].getName()); 192 builder.append(", "); 193 } 194 if (params.length != 0) { 195 builder.append(params[params.length - 1].getName()); 196 } 197 builder.append(')'); 198 if (message != null) { 199 builder.append('\t'); 200 builder.append(message); 201 } 202 CompileTheWorld.ERR.println(builder); 203 } 204 } 205 206 }