This commit is contained in:
Tom Rodriguez 2016-06-28 20:08:43 +00:00
commit 7c7e22abfd
11 changed files with 213 additions and 130 deletions

View File

@ -28,6 +28,8 @@ import jdk.test.lib.Utils;
import sun.hotspot.code.NMethod;
import sun.hotspot.cpuinfo.CPUInfo;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2013, 2016. Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -35,12 +35,13 @@ endif
SRC_DIR = src
BUILD_DIR = build
OUTPUT_DIR = $(BUILD_DIR)/classes
WHITEBOX_DIR = ../whitebox
TESTLIBRARY_DIR = ../../../../test/lib
JAVAC = $(JDK_HOME)/bin/javac
JAR = $(JDK_HOME)/bin/jar
SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
SRC_FILES = $(shell find $(SRC_DIR) $(TESTLIBRARY_DIR)/share/classes -name '*.java')
WB_SRC_FILES = $(shell find $(TESTLIBRARY_DIR)/sun/hotspot -name '*.java')
MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld
@ -52,22 +53,29 @@ clean: cleantmp
@rm -rf ctw.jar wb.jar
cleantmp:
@rm -rf filelist manifest.mf
@rm -rf filelist wb_filelist manifest.mf
@rm -rf $(BUILD_DIR)
ctw.jar: filelist wb.jar manifest.mf
ctw.jar: filelist wb.jar
@mkdir -p $(OUTPUT_DIR)
$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp wb.jar @filelist
$(JAR) cfm ctw.jar manifest.mf -C $(OUTPUT_DIR) .
$(JAVAC) -XaddExports:java.base/jdk.internal.jimage=ALL-UNNAMED \
-XaddExports:java.base/jdk.internal.misc=ALL-UNNAMED \
-XaddExports:java.base/jdk.internal.reflect=ALL-UNNAMED \
-sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp wb.jar @filelist
$(JAR) --create --file=$@ --main-class $(MAIN_CLASS) -C $(OUTPUT_DIR) .
wb.jar:
make -C ${WHITEBOX_DIR} wb.jar
cp ${WHITEBOX_DIR}/wb.jar ./
make -C ${WHITEBOX_DIR} clean
wb.jar: wb_filelist
@mkdir -p $(OUTPUT_DIR)
$(JAVAC) -sourcepath $(TESTLIBRARY_DIR) \
-d $(OUTPUT_DIR) \
-cp $(OUTPUT_DIR) \
@wb_filelist
$(JAR) --create --file=$@ -C $(OUTPUT_DIR) .
wb_filelist: $(WB_SRC_FILES)
@rm -f $@
@echo $(WB_SRC_FILES) > $@
filelist: $(SRC_FILES)
@rm -f $@
@echo $(SRC_FILES) > $@
manifest.mf:
@echo "Main-Class: ${MAIN_CLASS}" > manifest.mf

View File

@ -54,7 +54,7 @@ public class ClassPathDirEntry extends PathHandler {
@Override
public void process() {
System.out.println("# dir: " + root);
CompileTheWorld.OUT.println("# dir: " + root);
if (!Files.exists(root)) {
return;
}

View File

@ -50,7 +50,7 @@ public class ClassPathJarEntry extends PathHandler {
@Override
public void process() {
System.out.println("# jar: " + root);
CompileTheWorld.OUT.println("# jar: " + root);
if (!Files.exists(root)) {
return;
}

View File

@ -40,7 +40,7 @@ public class ClassPathJarInDirEntry extends PathHandler {
@Override
public void process() {
System.out.println("# jar_in_dir: " + root);
CompileTheWorld.OUT.println("# jar_in_dir: " + root);
if (!Files.exists(root)) {
return;
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.hotspot.tools.ctw;
import jdk.internal.jimage.ImageReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.concurrent.Executor;
/**
* Handler for jimage-files containing classes to compile.
*/
public class ClassPathJimageEntry extends PathHandler {
public ClassPathJimageEntry(Path root, Executor executor) {
super(root, executor);
try {
URL url = root.toUri().toURL();
setLoader(new URLClassLoader(new URL[]{url}));
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@Override
public void process() {
CompileTheWorld.OUT.println("# jimage: " + root);
if (!Files.exists(root)) {
return;
}
try {
ImageReader reader = ImageReader.open(root);
Arrays.stream(reader.getEntryNames())
.filter(name -> name.endsWith(".class"))
.filter(name -> !name.endsWith("module-info.class"))
.map(Utils::fileNameToClassName)
.forEach(this::processClass);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}

View File

@ -40,7 +40,7 @@ public class ClassesListInFile extends PathHandler {
@Override
public void process() {
System.out.println("# list: " + root);
CompileTheWorld.OUT.println("# list: " + root);
if (!Files.exists(root)) {
return;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,14 +33,20 @@ import java.util.List;
import java.util.concurrent.*;
public class CompileTheWorld {
// in case when a static constructor changes System::out and System::err
// we hold these values of output streams
public static final PrintStream OUT = System.out;
public static final PrintStream ERR = System.err;
/**
* Entry point. Compiles classes in {@code args}, or all classes in
* boot-classpath if args is empty
* Entry point. Compiles classes in {@code paths}
*
* @param args paths to jar/zip, dir contains classes, or to .lst file
* contains list of classes to compile
* @param paths paths to jar/zip, dir contains classes, or to .lst file
* contains list of classes to compile
*/
public static void main(String[] args) {
public static void main(String[] paths) {
if (paths.length == 0) {
throw new IllegalArgumentException("Expect a path to a compile target.");
}
String logfile = Utils.LOG_FILE;
PrintStream os = null;
if (logfile != null) {
@ -62,12 +68,6 @@ public class CompileTheWorld {
} catch (java.lang.NoClassDefFoundError e) {
// compact1, compact2 support
}
String[] paths = args;
boolean skipRtJar = false;
if (args.length == 0) {
paths = getDefaultPaths();
skipRtJar = true;
}
ExecutorService executor = createExecutor();
long start = System.currentTimeMillis();
try {
@ -75,17 +75,13 @@ public class CompileTheWorld {
for (int i = 0, n = paths.length; i < n
&& !PathHandler.isFinished(); ++i) {
path = paths[i];
if (skipRtJar && i > 0 && isRtJar(path)) {
// rt.jar is not first, so skip it
continue;
}
PathHandler.create(path, executor).process();
}
} finally {
await(executor);
}
System.out.printf("Done (%d classes, %d methods, %d ms)%n",
Compiler.getClassCount(),
CompileTheWorld.OUT.printf("Done (%d classes, %d methods, %d ms)%n",
PathHandler.getClassCount(),
Compiler.getMethodCount(),
System.currentTimeMillis() - start);
} finally {
@ -93,6 +89,9 @@ public class CompileTheWorld {
os.close();
}
}
// in case when a static constructor creates and runs a new thread
// we force it to exit
System.exit(0);
}
private static ExecutorService createExecutor() {
@ -111,13 +110,6 @@ public class CompileTheWorld {
return result;
}
private static String[] getDefaultPaths() {
String property = System.getProperty("sun.boot.class.path");
System.out.println(
"# use 'sun.boot.class.path' as args: " + property);
return Utils.PATH_SEPARATOR.split(property);
}
private static void await(ExecutorService executor) {
executor.shutdown();
while (!executor.isTerminated()) {
@ -130,10 +122,6 @@ public class CompileTheWorld {
}
}
private static boolean isRtJar(String path) {
return Utils.endsWithIgnoreCase(path, File.separator + "rt.jar");
}
private static class CurrentThreadExecutor extends AbstractExecutorService {
private boolean isShutdown;

View File

@ -26,7 +26,6 @@ package sun.hotspot.tools.ctw;
import sun.hotspot.WhiteBox;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.reflect.ConstantPool;
import java.lang.reflect.Executable;
import java.util.Objects;
@ -38,18 +37,11 @@ import java.util.concurrent.atomic.AtomicLong;
* Also contains compiled methods and classes counters.
*/
public class Compiler {
private Compiler() { }
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
private static final AtomicLong CLASS_COUNT = new AtomicLong(0L);
private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
private static volatile boolean CLASSES_LIMIT_REACHED = false;
/**
* @return count of processed classes
*/
public static long getClassCount() {
return CLASS_COUNT.get();
}
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
private Compiler() { }
/**
* @return count of processed methods
@ -58,59 +50,42 @@ public class Compiler {
return METHOD_COUNT.get();
}
/**
* @return {@code true} if classes limit is reached
*/
public static boolean isLimitReached() {
return CLASSES_LIMIT_REACHED;
}
/**
* Compiles all methods and constructors.
*
* @param aClass class to compile
* @param id an id of the class
* @param executor executor used for compile task invocation
* @throws NullPointerException if {@code class} or {@code executor}
* is {@code null}
*/
public static void compileClass(Class aClass, Executor executor) {
public static void compileClass(Class<?> aClass, long id, Executor executor) {
Objects.requireNonNull(aClass);
Objects.requireNonNull(executor);
long id = CLASS_COUNT.incrementAndGet();
if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
CLASS_COUNT.decrementAndGet();
CLASSES_LIMIT_REACHED = true;
return;
}
if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
String name = aClass.getName();
try {
System.out.printf("[%d]\t%s%n", id, name);
ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
getConstantPool(aClass);
if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
preloadClasses(name, id, constantPool);
}
long methodCount = 0;
for (Executable e : aClass.getDeclaredConstructors()) {
++methodCount;
executor.execute(new CompileMethodCommand(id, name, e));
}
for (Executable e : aClass.getDeclaredMethods()) {
++methodCount;
executor.execute(new CompileMethodCommand(id, name, e));
}
METHOD_COUNT.addAndGet(methodCount);
if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
&& (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
WHITE_BOX.deoptimizeAll();
}
} catch (Throwable t) {
System.out.printf("[%d]\t%s\tskipping %s%n", id, name, t);
t.printStackTrace();
try {
ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
getConstantPool(aClass);
if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
preloadClasses(aClass.getName(), id, constantPool);
}
long methodCount = 0;
for (Executable e : aClass.getDeclaredConstructors()) {
++methodCount;
executor.execute(new CompileMethodCommand(id, e));
}
for (Executable e : aClass.getDeclaredMethods()) {
++methodCount;
executor.execute(new CompileMethodCommand(id, e));
}
METHOD_COUNT.addAndGet(methodCount);
if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
&& (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
WHITE_BOX.deoptimizeAll();
}
} catch (Throwable t) {
CompileTheWorld.OUT.printf("[%d]\t%s\tskipping %s%n", id, aClass.getName(), t);
t.printStackTrace();
}
}
@ -124,8 +99,8 @@ public class Compiler {
}
}
} catch (Throwable t) {
System.out.printf("[%d]\t%s\tpreloading failed : %s%n", id,
className, t);
CompileTheWorld.OUT.printf("[%d]\t%s\tpreloading failed : %s%n",
id, className, t);
}
}
@ -142,13 +117,11 @@ public class Compiler {
/**
* @param classId id of class
* @param className name of class
* @param method compiled for compilation
*/
public CompileMethodCommand(long classId, String className,
Executable method) {
public CompileMethodCommand(long classId, Executable method) {
this.classId = classId;
this.className = className;
this.className = method.getDeclaringClass().getName();
this.method = method;
}
@ -158,10 +131,10 @@ public class Compiler {
if (Utils.TIERED_COMPILATION) {
for (int i = compLevel; i <= Utils.TIERED_STOP_AT_LEVEL; ++i) {
WHITE_BOX.deoptimizeMethod(method);
compileMethod(method, i);
compileAtLevel(i);
}
} else {
compileMethod(method, compLevel);
compileAtLevel(compLevel);
}
}
@ -183,29 +156,29 @@ public class Compiler {
}
}
private void compileMethod(Executable method, int compLevel) {
private void compileAtLevel(int compLevel) {
if (WHITE_BOX.isMethodCompilable(method, compLevel)) {
try {
WHITE_BOX.enqueueMethodForCompilation(method, compLevel);
waitCompilation();
int tmp = WHITE_BOX.getMethodCompilationLevel(method);
if (tmp != compLevel) {
logMethod(method, "compilation level = " + tmp
log("compilation level = " + tmp
+ ", but not " + compLevel);
} else if (Utils.IS_VERBOSE) {
logMethod(method, "compilation level = " + tmp + ". OK");
log("compilation level = " + tmp + ". OK");
}
} catch (Throwable t) {
logMethod(method, "error on compile at " + compLevel
log("error on compile at " + compLevel
+ " level");
t.printStackTrace();
}
} else if (Utils.IS_VERBOSE) {
logMethod(method, "not compilable at " + compLevel);
log("not compilable at " + compLevel);
}
}
private void logMethod(Executable method, String message) {
private void log(String message) {
StringBuilder builder = new StringBuilder("[");
builder.append(classId);
builder.append("]\t");
@ -226,7 +199,7 @@ public class Compiler {
builder.append('\t');
builder.append(message);
}
System.err.println(builder);
CompileTheWorld.ERR.println(builder);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,12 +23,14 @@
package sun.hotspot.tools.ctw;
import jdk.internal.misc.Unsafe;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.File;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.concurrent.Executor;
@ -38,6 +40,8 @@ import java.util.concurrent.Executor;
* Concrete subclasses should implement method {@link #process()}.
*/
public abstract class PathHandler {
private static final AtomicLong CLASS_COUNT = new AtomicLong(0L);
private static volatile boolean CLASSES_LIMIT_REACHED = false;
private static final Pattern JAR_IN_DIR_PATTERN
= Pattern.compile("^(.*[/\\\\])?\\*$");
protected final Path root;
@ -81,6 +85,8 @@ public abstract class PathHandler {
return new ClassPathJarEntry(p, executor);
} else if (isListFile(p)) {
return new ClassesListInFile(p, executor);
} else if (isJimageFile(p)) {
return new ClassPathJimageEntry(p, executor);
} else {
return new ClassPathDirEntry(p, executor);
}
@ -96,6 +102,13 @@ public abstract class PathHandler {
return false;
}
private static boolean isJimageFile(Path path) {
String filename = path.getFileName().toString();
return Files.isRegularFile(path)
&& ("modules".equals(filename)
|| Utils.endsWithIgnoreCase(filename, ".jimage"));
}
private static boolean isListFile(Path path) {
if (Files.isRegularFile(path)) {
String name = path.toString();
@ -122,24 +135,50 @@ public abstract class PathHandler {
}
/**
* Processes specificed class.
* Processes specified class.
* @param name fully qualified name of class to process
*/
protected final void processClass(String name) {
try {
Class aClass = Class.forName(name, true, loader);
Compiler.compileClass(aClass, executor);
} catch (ClassNotFoundException | LinkageError e) {
System.out.printf("Class %s loading failed : %s%n", name,
e.getMessage());
Objects.requireNonNull(name);
if (CLASSES_LIMIT_REACHED) {
return;
}
long id = CLASS_COUNT.incrementAndGet();
if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
CLASSES_LIMIT_REACHED = true;
return;
}
if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
try {
Class<?> aClass = loader.loadClass(name);
CompileTheWorld.OUT.printf("[%d]\t%s%n", id, name);
Compiler.compileClass(aClass, id, executor);
} catch (ClassNotFoundException e) {
CompileTheWorld.OUT.printf("Class %s loading failed : %s%n",
name, e.getMessage());
}
}
}
/**
* @return {@code true} if processing should be stopped
* @return count of processed classes
*/
public static long getClassCount() {
long id = CLASS_COUNT.get();
if (id < Utils.COMPILE_THE_WORLD_START_AT) {
return 0;
}
if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
return Utils.COMPILE_THE_WORLD_STOP_AT - Utils.COMPILE_THE_WORLD_START_AT + 1;
}
return id - Utils.COMPILE_THE_WORLD_START_AT + 1;
}
/**
* @return {@code true} if classes limit is reached and processing should be stopped
*/
public static boolean isFinished() {
return Compiler.isLimitReached();
return CLASSES_LIMIT_REACHED;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -207,7 +207,12 @@ public class Utils {
*/
public static String fileNameToClassName(String filename) {
assert isClassFile(filename);
return filename.substring(0, filename.length() - CLASSFILE_EXT.length())
.replace(File.separatorChar, '.');
// workaround for the class naming in jimage : /<module>/<class_name>
final char nameSeparator = '/';
int nameStart = filename.charAt(0) == nameSeparator
? filename.indexOf(nameSeparator, 1) + 1
: 0;
return filename.substring(nameStart, filename.length() - CLASSFILE_EXT.length())
.replace(nameSeparator, '.');
}
}