mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-13 03:45:19 +00:00
8184738: CTW fails with assert(!method->method_holder()->is_not_initialized()) failed: method holder must be initialized
Reviewed-by: kvn
This commit is contained in:
parent
0fb3cfd067
commit
ca17c7a998
@ -23,104 +23,73 @@
|
||||
|
||||
package sun.hotspot.tools.ctw;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Set;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Handler for dirs containing classes to compile.
|
||||
*/
|
||||
public class ClassPathDirEntry extends PathHandler {
|
||||
public class ClassPathDirEntry extends PathHandler.PathEntry {
|
||||
private final int rootLength;
|
||||
|
||||
private final int rootLength = root.toString().length();
|
||||
|
||||
public ClassPathDirEntry(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("# dir: " + root);
|
||||
public ClassPathDirEntry(Path root) {
|
||||
super(root);
|
||||
if (!Files.exists(root)) {
|
||||
return;
|
||||
throw new Error(root + " dir does not exist");
|
||||
}
|
||||
rootLength = root.toString()
|
||||
.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<String> classes() {
|
||||
try {
|
||||
Files.walkFileTree(root, EnumSet.of(FileVisitOption.FOLLOW_LINKS),
|
||||
Integer.MAX_VALUE, new CompileFileVisitor());
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
return Files.walk(root, Integer.MAX_VALUE, FileVisitOption.FOLLOW_LINKS)
|
||||
.filter(p -> Utils.isClassFile(p.toString()))
|
||||
.map(this::pathToClassName);
|
||||
} catch (IOException e) {
|
||||
throw new Error("can not traverse " + root + " : " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long classCount() {
|
||||
try {
|
||||
return Files.walk(root, FileVisitOption.FOLLOW_LINKS).count();
|
||||
} catch (IOException e) {
|
||||
throw new Error("can not walk dir " + root + " : "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
protected String description() {
|
||||
return "# dir: " + root;
|
||||
}
|
||||
|
||||
private void processFile(Path file) {
|
||||
if (Utils.isClassFile(file.toString())) {
|
||||
processClass(pathToClassName(file));
|
||||
@Override
|
||||
protected byte[] findByteCode(String classname) {
|
||||
Path path = root;
|
||||
for (String c : Utils.classNameToFileName(classname).split("/")) {
|
||||
path = path.resolve(c);
|
||||
}
|
||||
if (!path.toFile()
|
||||
.exists()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Files.readAllBytes(path);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(CompileTheWorld.ERR);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String pathToClassName(Path file) {
|
||||
String fileString;
|
||||
if (root == file) {
|
||||
fileString = file.normalize().toString();
|
||||
fileString = file.normalize()
|
||||
.toString();
|
||||
} else {
|
||||
fileString = file.normalize().toString().substring(rootLength + 1);
|
||||
fileString = file.normalize()
|
||||
.toString()
|
||||
.substring(rootLength + 1);
|
||||
}
|
||||
return Utils.fileNameToClassName(fileString);
|
||||
}
|
||||
|
||||
private class CompileFileVisitor extends SimpleFileVisitor<Path> {
|
||||
|
||||
private final Set<Path> ready = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
if (ready.contains(dir)) {
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
ready.add(dir);
|
||||
return super.preVisitDirectory(dir, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file,
|
||||
BasicFileAttributes attrs) throws IOException {
|
||||
if (!ready.contains(file)) {
|
||||
processFile(file);
|
||||
}
|
||||
return isFinished() ? FileVisitResult.TERMINATE
|
||||
: FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file,
|
||||
IOException exc) throws IOException {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,69 +23,62 @@
|
||||
|
||||
package sun.hotspot.tools.ctw;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import java.util.jar.*;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Handler for jar-files containing classes to compile.
|
||||
*/
|
||||
public class ClassPathJarEntry extends PathHandler {
|
||||
public class ClassPathJarEntry extends PathHandler.PathEntry {
|
||||
private final JarFile jarFile;
|
||||
|
||||
public ClassPathJarEntry(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("# jar: " + root);
|
||||
public ClassPathJarEntry(Path root) {
|
||||
super(root);
|
||||
if (!Files.exists(root)) {
|
||||
return;
|
||||
throw new Error(root + " file not found");
|
||||
}
|
||||
try (JarFile jarFile = new JarFile(root.toFile())) {
|
||||
JarEntry entry;
|
||||
for (Enumeration<JarEntry> e = jarFile.entries();
|
||||
e.hasMoreElements(); ) {
|
||||
entry = e.nextElement();
|
||||
processJarEntry(entry);
|
||||
if (isFinished()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
try {
|
||||
jarFile = new JarFile(root.toFile());
|
||||
} catch (IOException e) {
|
||||
throw new Error("can not read " + root + " : " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long classCount() {
|
||||
try (JarFile jarFile = new JarFile(root.toFile())) {
|
||||
return jarFile.stream()
|
||||
.map(JarEntry::getName)
|
||||
.filter(Utils::isClassFile)
|
||||
.count();
|
||||
} catch (IOException e) {
|
||||
throw new Error("can not open jar file " + root + " : "
|
||||
+ e.getMessage() , e);
|
||||
}
|
||||
protected Stream<String> classes() {
|
||||
return jarFile.stream()
|
||||
.map(JarEntry::getName)
|
||||
.filter(Utils::isClassFile)
|
||||
.map(Utils::fileNameToClassName);
|
||||
}
|
||||
|
||||
private void processJarEntry(JarEntry entry) {
|
||||
String filename = entry.getName();
|
||||
if (Utils.isClassFile(filename)) {
|
||||
processClass(Utils.fileNameToClassName(filename));
|
||||
@Override
|
||||
protected String description() {
|
||||
return "# jar: " + root;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] findByteCode(String classname) {
|
||||
try {
|
||||
String filename = Utils.classNameToFileName(classname);
|
||||
JarEntry entry = jarFile.getJarEntry(filename);
|
||||
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try (InputStream is = jarFile.getInputStream(entry)) {
|
||||
return is.readAllBytes();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(CompileTheWorld.ERR);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,46 +27,52 @@ import java.io.IOException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Handler for dirs containing jar-files with classes to compile.
|
||||
*/
|
||||
public class ClassPathJarInDirEntry extends PathHandler {
|
||||
|
||||
public ClassPathJarInDirEntry(Path root, Executor executor) {
|
||||
super(root, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
CompileTheWorld.OUT.println("# jar_in_dir: " + root);
|
||||
if (!Files.exists(root)) {
|
||||
return;
|
||||
public class ClassPathJarInDirEntry {
|
||||
public static List<PathHandler> create(Path path) {
|
||||
Objects.requireNonNull(path);
|
||||
if (!Files.exists(path)) {
|
||||
throw new Error(path + " directory not found");
|
||||
}
|
||||
try (DirectoryStream<Path> ds
|
||||
= Files.newDirectoryStream(root, "*.jar")) {
|
||||
for (Path p : ds) {
|
||||
new ClassPathJarEntry(p, executor).process();
|
||||
if (isFinished()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long classCount() {
|
||||
try {
|
||||
return Files.list(root)
|
||||
.filter(p -> p.getFileName().toString().endsWith(".jar"))
|
||||
.map(p -> new ClassPathJarEntry(p, executor))
|
||||
.mapToLong(ClassPathJarEntry::classCount).sum();
|
||||
return Stream.concat(
|
||||
Stream.of(new PathHandler(new JarInDirEntry(path))),
|
||||
Files.list(path)
|
||||
.filter(p -> p.getFileName().toString().endsWith(".jar"))
|
||||
.map(ClassPathJarEntry::new)
|
||||
.map(PathHandler::new))
|
||||
.collect(Collectors.toList());
|
||||
} catch (IOException e) {
|
||||
throw new Error("can not walk dir " + root + " : "
|
||||
+ e.getMessage(), e);
|
||||
throw new Error("can not read " + path + " directory : " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// dummy path handler, used just to print description before real handlers.
|
||||
private static class JarInDirEntry extends PathHandler.PathEntry {
|
||||
private JarInDirEntry(Path root) {
|
||||
super(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] findByteCode(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<String> classes() {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String description() {
|
||||
return "# jar_in_dir: " + root;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,58 +24,69 @@
|
||||
package sun.hotspot.tools.ctw;
|
||||
|
||||
import jdk.internal.jimage.ImageReader;
|
||||
import jdk.internal.jimage.ImageLocation;
|
||||
|
||||
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;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Handler for jimage-files containing classes to compile.
|
||||
*/
|
||||
public class ClassPathJimageEntry extends PathHandler {
|
||||
public ClassPathJimageEntry(Path root, Executor executor) {
|
||||
super(root, executor);
|
||||
public class ClassPathJimageEntry extends PathHandler.PathEntry {
|
||||
|
||||
@Override
|
||||
protected Stream<String> classes() {
|
||||
return Arrays.stream(reader.getEntryNames())
|
||||
.filter(name -> name.endsWith(".class"))
|
||||
.filter(name -> !name.endsWith("module-info.class"))
|
||||
.map(Utils::fileNameToClassName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String description() {
|
||||
return "# jimage: " + root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long classCount() {
|
||||
try (ImageReader reader = ImageReader.open(root)) {
|
||||
return Arrays.stream(reader.getEntryNames())
|
||||
.filter(name -> name.endsWith(".class"))
|
||||
.filter(name -> !name.endsWith("module-info.class"))
|
||||
.map(Utils::fileNameToClassName)
|
||||
.count();
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
throw new Error("can not open jimage file " + root + " : "
|
||||
+ e.getMessage() , e);
|
||||
throw new Error("error on closing reader for " + root + " : "
|
||||
+ e.getMessage(), e);
|
||||
} finally {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
|
||||
private final ImageReader reader;
|
||||
|
||||
public ClassPathJimageEntry(Path root) {
|
||||
super(root);
|
||||
if (!Files.exists(root)) {
|
||||
throw new Error(root + " image file not found");
|
||||
}
|
||||
try {
|
||||
reader = ImageReader.open(root);
|
||||
} catch (IOException e) {
|
||||
throw new Error("can not open " + root + " : " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] findByteCode(String name) {
|
||||
String resource = Utils.classNameToFileName(name);
|
||||
for (String m : reader.getModuleNames()) {
|
||||
ImageLocation location = reader.findLocation(m, resource);
|
||||
if (location != null) {
|
||||
return reader.getResource(location);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -25,46 +25,52 @@ package sun.hotspot.tools.ctw;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Handler for files containing a list of classes to compile.
|
||||
*/
|
||||
public class ClassesListInFile extends PathHandler {
|
||||
public ClassesListInFile(Path root, Executor executor) {
|
||||
super(root, executor);
|
||||
}
|
||||
public class ClassesListInFile extends PathHandler.PathEntry {
|
||||
private final BufferedReader reader;
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
CompileTheWorld.OUT.println("# list: " + root);
|
||||
public ClassesListInFile(Path root) {
|
||||
super(root);
|
||||
if (!Files.exists(root)) {
|
||||
return;
|
||||
throw new Error(root + " file does not exist");
|
||||
}
|
||||
try {
|
||||
try (BufferedReader reader = Files.newBufferedReader(root)) {
|
||||
String line;
|
||||
while (!isFinished() && ((line = reader.readLine()) != null)) {
|
||||
processClass(line);
|
||||
}
|
||||
}
|
||||
reader = Files.newBufferedReader(root);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new Error("can not open " + root + " : " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long classCount() {
|
||||
protected byte[] findByteCode(String name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<String> classes() {
|
||||
return reader.lines();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String description() {
|
||||
return "# list: " + root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
try (BufferedReader reader = Files.newBufferedReader(root)) {
|
||||
return reader.lines().count();
|
||||
}
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
throw new Error("can not read list " + root + " : "
|
||||
+ e.getMessage(), e);
|
||||
throw new Error("error on closing reader for " + root
|
||||
+ " : " + e.getMessage(), e);
|
||||
} finally {
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@ -73,12 +74,16 @@ public class CompileTheWorld {
|
||||
ExecutorService executor = createExecutor();
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
String path;
|
||||
for (int i = 0, n = paths.length; i < n
|
||||
&& !PathHandler.isFinished(); ++i) {
|
||||
path = paths[i];
|
||||
PathHandler.create(path, executor).process();
|
||||
}
|
||||
Arrays.stream(paths)
|
||||
.map(PathHandler::create)
|
||||
.flatMap(List::stream)
|
||||
.forEach(p -> {
|
||||
try {
|
||||
p.process(executor);
|
||||
} finally {
|
||||
p.close();
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
await(executor);
|
||||
}
|
||||
|
||||
@ -23,14 +23,17 @@
|
||||
|
||||
package sun.hotspot.tools.ctw;
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.internal.reflect.ConstantPool;
|
||||
import java.lang.reflect.Executable;
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
import java.lang.reflect.Executable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Provide method to compile whole class.
|
||||
@ -38,6 +41,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
*/
|
||||
public class Compiler {
|
||||
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
|
||||
private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
|
||||
|
||||
@ -62,35 +66,27 @@ public class Compiler {
|
||||
public static void compileClass(Class<?> aClass, long id, Executor executor) {
|
||||
Objects.requireNonNull(aClass);
|
||||
Objects.requireNonNull(executor);
|
||||
try {
|
||||
ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
|
||||
getConstantPool(aClass);
|
||||
if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
|
||||
preloadClasses(aClass.getName(), id, constantPool);
|
||||
}
|
||||
int startLevel = Utils.INITIAL_COMP_LEVEL;
|
||||
int endLevel = Utils.TIERED_COMPILATION ? Utils.TIERED_STOP_AT_LEVEL : startLevel;
|
||||
for (int i = startLevel; i <= endLevel; ++i) {
|
||||
WHITE_BOX.enqueueInitializerForCompilation(aClass, i);
|
||||
}
|
||||
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);
|
||||
ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
|
||||
getConstantPool(aClass);
|
||||
if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
|
||||
preloadClasses(aClass.getName(), id, constantPool);
|
||||
}
|
||||
UNSAFE.ensureClassInitialized(aClass);
|
||||
compileClinit(aClass, id);
|
||||
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();
|
||||
if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
|
||||
&& (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
|
||||
WHITE_BOX.deoptimizeAll();
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,12 +100,25 @@ public class Compiler {
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
CompileTheWorld.OUT.printf("[%d]\t%s\tpreloading failed : %s%n",
|
||||
CompileTheWorld.OUT.printf("[%d]\t%s\tWARNING preloading failed : %s%n",
|
||||
id, className, t);
|
||||
t.printStackTrace(CompileTheWorld.ERR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void compileClinit(Class<?> aClass, long id) {
|
||||
int startLevel = Utils.INITIAL_COMP_LEVEL;
|
||||
int endLevel = Utils.TIERED_COMPILATION ? Utils.TIERED_STOP_AT_LEVEL : startLevel;
|
||||
for (int i = startLevel; i <= endLevel; ++i) {
|
||||
try {
|
||||
WHITE_BOX.enqueueInitializerForCompilation(aClass, i);
|
||||
} catch (Throwable t) {
|
||||
CompileTheWorld.OUT.printf("[%d]\t%s::<clinit>\tERROR at level %d : %s%n",
|
||||
id, aClass.getName(), i, t);
|
||||
t.printStackTrace(CompileTheWorld.ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compilation of method.
|
||||
@ -168,41 +177,37 @@ public class Compiler {
|
||||
waitCompilation();
|
||||
int tmp = WHITE_BOX.getMethodCompilationLevel(method);
|
||||
if (tmp != compLevel) {
|
||||
log("compilation level = " + tmp
|
||||
log("WARNING compilation level = " + tmp
|
||||
+ ", but not " + compLevel);
|
||||
} else if (Utils.IS_VERBOSE) {
|
||||
log("compilation level = " + tmp + ". OK");
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
log("error on compile at " + compLevel
|
||||
+ " level");
|
||||
t.printStackTrace();
|
||||
log("ERROR at level " + compLevel);
|
||||
t.printStackTrace(CompileTheWorld.ERR);
|
||||
}
|
||||
} else if (Utils.IS_VERBOSE) {
|
||||
log("not compilable at " + compLevel);
|
||||
}
|
||||
}
|
||||
|
||||
private String methodName() {
|
||||
return String.format("%s::%s(%s)",
|
||||
className,
|
||||
method.getName(),
|
||||
Arrays.stream(method.getParameterTypes())
|
||||
.map(Class::getName)
|
||||
.collect(Collectors.joining(", ")));
|
||||
}
|
||||
|
||||
private void log(String message) {
|
||||
StringBuilder builder = new StringBuilder("[");
|
||||
builder.append(classId);
|
||||
builder.append("]\t");
|
||||
builder.append(className);
|
||||
builder.append("::");
|
||||
builder.append(method.getName());
|
||||
builder.append('(');
|
||||
Class[] params = method.getParameterTypes();
|
||||
for (int i = 0, n = params.length - 1; i < n; ++i) {
|
||||
builder.append(params[i].getName());
|
||||
builder.append(", ");
|
||||
}
|
||||
if (params.length != 0) {
|
||||
builder.append(params[params.length - 1].getName());
|
||||
}
|
||||
builder.append(')');
|
||||
StringBuilder builder = new StringBuilder("[")
|
||||
.append(classId)
|
||||
.append("]\t")
|
||||
.append(methodName());
|
||||
if (message != null) {
|
||||
builder.append('\t');
|
||||
builder.append(message);
|
||||
builder.append('\t')
|
||||
.append(message);
|
||||
}
|
||||
CompileTheWorld.ERR.println(builder);
|
||||
}
|
||||
|
||||
@ -162,8 +162,12 @@ public class CtwRunner {
|
||||
}
|
||||
|
||||
private long classCount() {
|
||||
return PathHandler.create(targetPath.toString(), Runnable::run)
|
||||
.classCount();
|
||||
List<PathHandler> phs = PathHandler.create(targetPath.toString());
|
||||
long result = phs.stream()
|
||||
.mapToLong(PathHandler::classCount)
|
||||
.sum();
|
||||
phs.forEach(PathHandler::close);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Pair<String, Long> getLastClass(Path errFile) {
|
||||
|
||||
@ -23,73 +23,118 @@
|
||||
|
||||
package sun.hotspot.tools.ctw;
|
||||
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Abstract handler for path.
|
||||
* Concrete subclasses should implement method {@link #process()}.
|
||||
* Handler for a path, responsible for processing classes in the path.
|
||||
*/
|
||||
public abstract class PathHandler {
|
||||
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
public class PathHandler implements Closeable {
|
||||
public static abstract class PathEntry implements Closeable {
|
||||
private final ClassLoader loader = new PathEntryClassLoader(this::findByteCode);
|
||||
|
||||
/**
|
||||
* returns bytecode for the class
|
||||
* @param name binary name of the class
|
||||
* @return bytecode of the class or null if handler does not have any
|
||||
* code for this name
|
||||
*/
|
||||
protected abstract byte[] findByteCode(String name);
|
||||
|
||||
protected final Path root;
|
||||
|
||||
/**
|
||||
* @param root path entry root
|
||||
* @throws NullPointerException if {@code root} is {@code null}
|
||||
*/
|
||||
protected PathEntry(Path root) {
|
||||
Objects.requireNonNull(root, "root can not be null");
|
||||
this.root = root.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return classloader which will be used to define classes
|
||||
*/
|
||||
protected final ClassLoader loader() {
|
||||
return loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return stream of all classes in the specified path.
|
||||
*/
|
||||
protected abstract Stream<String> classes();
|
||||
|
||||
/**
|
||||
* @return string description of the specific path.
|
||||
*/
|
||||
protected abstract String description();
|
||||
|
||||
public void close() { }
|
||||
|
||||
}
|
||||
|
||||
private static class PathEntryClassLoader extends java.lang.ClassLoader {
|
||||
private final Function<String, byte[]> findByteCode;
|
||||
|
||||
private PathEntryClassLoader(Function<String, byte[]> findByteCode) {
|
||||
this.findByteCode = findByteCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
byte[] code = findByteCode.apply(name);
|
||||
if (code == null) {
|
||||
return super.findClass(name);
|
||||
} else {
|
||||
return defineClass(name, code, 0, code.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
protected final Executor executor;
|
||||
private ClassLoader loader;
|
||||
|
||||
/**
|
||||
* @param root root path to process
|
||||
* @param executor executor used for process task invocation
|
||||
* @throws NullPointerException if {@code root} or {@code executor} is
|
||||
* {@code null}
|
||||
*/
|
||||
protected PathHandler(Path root, Executor executor) {
|
||||
Objects.requireNonNull(root);
|
||||
Objects.requireNonNull(executor);
|
||||
this.root = root.normalize();
|
||||
this.executor = executor;
|
||||
this.loader = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method. Construct concrete handler in depends from {@code path}.
|
||||
* Factory method. Constructs list of handlers for {@code path}.
|
||||
*
|
||||
* @param path the path to process
|
||||
* @param executor executor used for compile task invocation
|
||||
* @throws NullPointerException if {@code path} or {@code executor} is
|
||||
* {@code null}
|
||||
*/
|
||||
public static PathHandler create(String path, Executor executor) {
|
||||
public static List<PathHandler> create(String path) {
|
||||
Objects.requireNonNull(path);
|
||||
Objects.requireNonNull(executor);
|
||||
Matcher matcher = JAR_IN_DIR_PATTERN.matcher(path);
|
||||
if (matcher.matches()) {
|
||||
path = matcher.group(1);
|
||||
path = path.isEmpty() ? "." : path;
|
||||
return new ClassPathJarInDirEntry(Paths.get(path), executor);
|
||||
return ClassPathJarInDirEntry.create(Paths.get(path));
|
||||
} else {
|
||||
path = path.isEmpty() ? "." : path;
|
||||
Path p = Paths.get(path);
|
||||
PathEntry entry;
|
||||
if (isJarFile(p)) {
|
||||
return new ClassPathJarEntry(p, executor);
|
||||
entry = new ClassPathJarEntry(p);
|
||||
} else if (isListFile(p)) {
|
||||
return new ClassesListInFile(p, executor);
|
||||
entry = new ClassesListInFile(p);
|
||||
} else if (isJimageFile(p)) {
|
||||
return new ClassPathJimageEntry(p, executor);
|
||||
entry = new ClassPathJimageEntry(p);
|
||||
} else {
|
||||
return new ClassPathDirEntry(p, executor);
|
||||
entry = new ClassPathDirEntry(p);
|
||||
}
|
||||
return Collections.singletonList(new PathHandler(entry));
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,35 +162,42 @@ public abstract class PathHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
private final PathEntry entry;
|
||||
protected PathHandler(PathEntry entry) {
|
||||
Objects.requireNonNull(entry);
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
entry.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes all classes in the specified path.
|
||||
* @param executor executor used for process task invocation
|
||||
*/
|
||||
public abstract void process();
|
||||
public final void process(Executor executor) {
|
||||
CompileTheWorld.OUT.println(entry.description());
|
||||
entry.classes().forEach(s -> processClass(s, executor));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return count of all classes in the specified path.
|
||||
*/
|
||||
public abstract long classCount();
|
||||
|
||||
/**
|
||||
* Sets class loader, that will be used to define class at
|
||||
* {@link #processClass(String)}.
|
||||
*
|
||||
* @param loader class loader
|
||||
* @throws NullPointerException if {@code loader} is {@code null}
|
||||
*/
|
||||
protected final void setLoader(ClassLoader loader) {
|
||||
Objects.requireNonNull(loader);
|
||||
this.loader = loader;
|
||||
public long classCount() {
|
||||
return entry.classes().count();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes specified class.
|
||||
* @param name fully qualified name of class to process
|
||||
*/
|
||||
protected final void processClass(String name) {
|
||||
protected final void processClass(String name, Executor executor) {
|
||||
Objects.requireNonNull(name);
|
||||
if (CLASSES_LIMIT_REACHED) {
|
||||
if (isFinished()) {
|
||||
return;
|
||||
}
|
||||
long id = CLASS_COUNT.incrementAndGet();
|
||||
@ -154,18 +206,16 @@ public abstract class PathHandler {
|
||||
return;
|
||||
}
|
||||
if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
|
||||
Class<?> aClass;
|
||||
Thread.currentThread().setContextClassLoader(entry.loader());
|
||||
try {
|
||||
Class<?> aClass = loader.loadClass(name);
|
||||
if (!"sun.reflect.misc.Trampoline".equals(name)
|
||||
// workaround for JDK-8159155
|
||||
&& !"sun.tools.jconsole.OutputViewer".equals(name)) {
|
||||
UNSAFE.ensureClassInitialized(aClass);
|
||||
}
|
||||
CompileTheWorld.OUT.printf("[%d]\t%s%n", id, name);
|
||||
aClass = entry.loader().loadClass(name);
|
||||
Compiler.compileClass(aClass, id, executor);
|
||||
} catch (ClassNotFoundException e) {
|
||||
CompileTheWorld.OUT.printf("Class %s loading failed : %s%n",
|
||||
name, e.getMessage());
|
||||
} catch (Throwable e) {
|
||||
CompileTheWorld.OUT.printf("[%d]\t%s\tWARNING skipped: %s%n",
|
||||
id, name, e);
|
||||
e.printStackTrace(CompileTheWorld.ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,4 +217,9 @@ public class Utils {
|
||||
return filename.substring(nameStart, filename.length() - CLASSFILE_EXT.length())
|
||||
.replace(nameSeparator, '.');
|
||||
}
|
||||
|
||||
public static String classNameToFileName(String classname) {
|
||||
return classname.replace('.', '/')
|
||||
.concat(CLASSFILE_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user