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 jdk.internal.misc.SharedSecrets; 27 import jdk.internal.misc.Unsafe; 28 import jdk.internal.reflect.ConstantPool; 29 import sun.hotspot.WhiteBox; 30 31 import java.lang.reflect.Executable; 32 import java.util.Arrays; 33 import java.util.Objects; 34 import java.util.concurrent.Executor; 35 import java.util.concurrent.atomic.AtomicLong; 36 import java.util.stream.Collectors; 37 38 /** 39 * Provide method to compile whole class. 40 * Also contains compiled methods and classes counters. 41 */ 42 public class Compiler { 43 44 private static final Unsafe UNSAFE = Unsafe.getUnsafe(); 45 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 46 private static final AtomicLong METHOD_COUNT = new AtomicLong(0L); 47 48 private Compiler() { } 49 50 /** 51 * @return count of processed methods 52 */ 53 public static long getMethodCount() { 54 return METHOD_COUNT.get(); 55 } 56 57 /** 58 * Compiles all methods and constructors. 59 * 60 * @param aClass class to compile 61 * @param id an id of the class 62 * @param executor executor used for compile task invocation 63 * @throws NullPointerException if {@code class} or {@code executor} 64 * is {@code null} 65 */ 66 public static void compileClass(Class<?> aClass, long id, Executor executor) { 67 Objects.requireNonNull(aClass); 68 Objects.requireNonNull(executor); 69 ConstantPool constantPool = SharedSecrets.getJavaLangAccess(). 70 getConstantPool(aClass); 71 if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) { 72 preloadClasses(aClass.getName(), id, constantPool); 73 } 74 UNSAFE.ensureClassInitialized(aClass); 75 compileClinit(aClass, id); 76 long methodCount = 0; 77 for (Executable e : aClass.getDeclaredConstructors()) { 78 ++methodCount; 79 executor.execute(new CompileMethodCommand(id, e)); 80 } 81 for (Executable e : aClass.getDeclaredMethods()) { 82 ++methodCount; 83 executor.execute(new CompileMethodCommand(id, e)); 84 } 85 METHOD_COUNT.addAndGet(methodCount); 86 87 if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0 88 && (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) { 89 WHITE_BOX.deoptimizeAll(); 90 } 91 } 92 93 private static void preloadClasses(String className, long id, 94 ConstantPool constantPool) { 95 try { 96 for (int i = 0, n = constantPool.getSize(); i < n; ++i) { 97 try { 98 constantPool.getClassAt(i); 99 } catch (IllegalArgumentException ignore) { 100 } 101 } 102 } catch (Throwable t) { 103 CompileTheWorld.OUT.println(String.format("[%d]\t%s\tWARNING preloading failed : %s", 104 id, className, t)); 105 t.printStackTrace(CompileTheWorld.ERR); 106 } 107 } 108 109 private static void compileClinit(Class<?> aClass, long id) { 110 int startLevel = Utils.INITIAL_COMP_LEVEL; 111 int endLevel = Utils.TIERED_COMPILATION ? Utils.TIERED_STOP_AT_LEVEL : startLevel; 112 for (int i = startLevel; i <= endLevel; ++i) { 113 try { 114 WHITE_BOX.enqueueInitializerForCompilation(aClass, i); 115 } catch (Throwable t) { 116 CompileTheWorld.OUT.println(String.format("[%d]\t%s::<clinit>\tERROR at level %d : %s", 117 id, aClass.getName(), i, t)); 118 t.printStackTrace(CompileTheWorld.ERR); 119 } 120 } 121 } 122 123 /** 124 * Compilation of method. 125 * Will compile method on all available comp levels. 126 */ 127 private static class CompileMethodCommand implements Runnable { 128 private final long classId; 129 private final String className; 130 private final Executable method; 131 132 /** 133 * @param classId id of class 134 * @param method compiled for compilation 135 */ 136 public CompileMethodCommand(long classId, Executable method) { 137 this.classId = classId; 138 this.className = method.getDeclaringClass().getName(); 139 this.method = method; 140 } 141 142 @Override 143 public final void run() { 144 int compLevel = Utils.INITIAL_COMP_LEVEL; 145 if (Utils.TIERED_COMPILATION) { 146 for (int i = compLevel; i <= Utils.TIERED_STOP_AT_LEVEL; ++i) { 147 WHITE_BOX.deoptimizeMethod(method); 148 compileAtLevel(i); 149 } 150 } else { 151 compileAtLevel(compLevel); 152 } 153 } 154 155 private void waitCompilation() { 156 if (!Utils.BACKGROUND_COMPILATION) { 157 return; 158 } 159 final Object obj = new Object(); 160 synchronized (obj) { 161 for (int i = 0; 162 i < 10 && WHITE_BOX.isMethodQueuedForCompilation(method); 163 ++i) { 164 try { 165 obj.wait(1000); 166 } catch (InterruptedException e) { 167 Thread.currentThread().interrupt(); 168 } 169 } 170 } 171 } 172 173 private void compileAtLevel(int compLevel) { 174 if (WHITE_BOX.isMethodCompilable(method, compLevel)) { 175 try { 176 WHITE_BOX.enqueueMethodForCompilation(method, compLevel); 177 waitCompilation(); 178 int tmp = WHITE_BOX.getMethodCompilationLevel(method); 179 if (tmp != compLevel) { 180 log("WARNING compilation level = " + tmp 181 + ", but not " + compLevel); 182 } else if (Utils.IS_VERBOSE) { 183 log("compilation level = " + tmp + ". OK"); 184 } 185 } catch (Throwable t) { 186 log("ERROR at level " + compLevel); 187 t.printStackTrace(CompileTheWorld.ERR); 188 } 189 } else if (Utils.IS_VERBOSE) { 190 log("not compilable at " + compLevel); 191 } 192 } 193 194 private String methodName() { 195 return String.format("%s::%s(%s)", 196 className, 197 method.getName(), 198 Arrays.stream(method.getParameterTypes()) 199 .map(Class::getName) 200 .collect(Collectors.joining(", "))); 201 } 202 203 private void log(String message) { 204 StringBuilder builder = new StringBuilder("[") 205 .append(classId) 206 .append("]\t") 207 .append(methodName()); 208 if (message != null) { 209 builder.append('\t') 210 .append(message); 211 } 212 CompileTheWorld.ERR.println(builder); 213 } 214 } 215 216 }