Path: blob/master/test/hotspot/jtreg/vmTestbase/gc/g1/unloading/GenClassPoolJar.java
41159 views
/*1* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package gc.g1.unloading;2425import java.io.File;26import java.io.FileOutputStream;27import java.io.IOException;28import java.nio.file.FileVisitResult;29import java.nio.file.FileVisitor;30import java.nio.file.Files;31import java.nio.file.Path;32import java.nio.file.Paths;33import java.nio.file.attribute.BasicFileAttributes;34import java.util.ArrayList;35import java.util.Arrays;36import java.util.List;37import java.util.jar.JarEntry;38import java.util.jar.JarOutputStream;39import java.util.jar.Manifest;40import javax.tools.JavaCompiler;41import javax.tools.JavaFileObject;42import javax.tools.StandardJavaFileManager;43import javax.tools.ToolProvider;44import jdk.internal.org.objectweb.asm.ClassReader;45import jdk.internal.org.objectweb.asm.ClassVisitor;46import jdk.internal.org.objectweb.asm.ClassWriter;47import jdk.internal.org.objectweb.asm.Opcodes;4849/**50* Class that imitates shell script to produce jar file with many similar51* classes inside.52*53* The class generates sources, compiles the first one, applies magic of ASM54* to multiply classes and packs into classPool.jar55*56* Generation template is supposed to be ClassNNN.java.template57*/58public class GenClassPoolJar {5960private final String templateFile;61private final String destDir;62private final int count;6364private final File tmpArea;65private final File pkgDir;6667private static final String JAR_NAME = "classPool.jar";68private static final String PKG_DIR_NAME = "gc/g1/unloading/rootSetHelper/classesPool";6970public static void main(String args[]) {71new GenClassPoolJar(args).script();72}7374/**75* Creates generator and parses command line args.76* @param args command line args77*/78public GenClassPoolJar(String args[]) {79if (args.length != 3) {80System.err.println("Usage:");81System.err.println("java " + GenClassPoolJar.class.getCanonicalName() +82" <template-file> <ouput-dir> <count>" );83throw new Error("Illegal number of parameters");84}85templateFile = args[0];86destDir = args[1];87count = Integer.parseInt(args[2]);8889tmpArea = new File(destDir, "tmp-area");90pkgDir = new File(tmpArea, PKG_DIR_NAME);9192}93/**94* Does everything.95*/96public void script() {97long startTime = System.currentTimeMillis();98System.out.println("Trying to produce: " + destDir + "/" + JAR_NAME);99try {100101if (!pkgDir.exists() && !pkgDir.mkdirs()) {102throw new Error("Failed to create " + pkgDir);103}104105106String javaTemplate = readTemplate(templateFile);107File java0 = new File(pkgDir, "Class0.java");108File class0 = new File(pkgDir, "Class0.class");109writeSource(java0, generateSource(javaTemplate, 0));110111/*112* Generating and compiling all the sources is not our way -113* too easy and too slow.114* We compile just first class and use ASM to obtain others115* via instrumenting.116*/117File[] toCompile = {java0};118compile(toCompile, tmpArea.getAbsolutePath());119byte[] classTemplate = readFile(class0); // the first compiled class120createJar(new File(destDir, JAR_NAME), javaTemplate, classTemplate, count);121122123deleteFolder(tmpArea);124long endTime = System.currentTimeMillis();125System.out.println("Success in " + ((endTime - startTime)/1000) + " seconds");126} catch (Throwable whatever) {127throw new Error(whatever);128}129}130131/**132* Generates source number num.133* @param template template to generate from134* @param num number135* @return content of java file136*/137String generateSource(String template, int num) {138return template.replaceAll("_NNN_", "" + num);139}140141/**142* Reads content of the given file.143* @param file name of file to read144* @return file content145* @throws IOException if something bad has happened146*/147String readTemplate(String file) throws IOException {148if (!new File(file).exists()) {149throw new Error("Template " + file + " doesn't exist");150}151List<String> lines = Files.readAllLines(Paths.get(file));152StringBuilder sb = new StringBuilder();153for (String line: lines) {154if (line.trim().startsWith("#")) {155continue;156}157sb.append(line).append(System.lineSeparator());158}159return sb.toString();160}161162/**163* Writes given content to the given file.164*165* @param file to create166* @param content java source167* @throws IOException if something bad has happened168*/169void writeSource(File file, String content) throws IOException {170List<String> list = Arrays.asList(content.split(System.lineSeparator()));171Files.write(Paths.get(file.getAbsolutePath()), list);172}173174175/**176* Compiles given files into given folder.177*178* @param files to compile179* @param destDir where to compile180* @throws IOException181*/182void compile(File[] files, String destDir) throws IOException {183JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();184List<String> optionList = new ArrayList<>();185optionList.addAll(Arrays.asList("-d", destDir));186StandardJavaFileManager sjfm = compiler.getStandardFileManager(null, null, null);187Iterable<? extends JavaFileObject> fileObjects = sjfm.getJavaFileObjects(files);188JavaCompiler.CompilationTask task = compiler.getTask(null, null, null, optionList, null, fileObjects);189task.call();190sjfm.close();191}192193/**194* Puts a number of classes and java sources in the given jar.195*196* @param jarFile name of jar file197* @param javaTemplate content of java source template198* @param classTemplate content of compiled java class199* @param count number of classes to generate200* @throws IOException201*/202void createJar(File jarFile, String javaTemplate, byte[] classTemplate, int count) throws IOException {203try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(jarFile), new Manifest())) {204for (int i = 1; i <= count; i++) {205String name = PKG_DIR_NAME + "/Class" + i;206jar.putNextEntry(new JarEntry(name + ".java"));207byte[] content = generateSource(javaTemplate, 0).getBytes();208jar.write(content, 0, content.length);209210jar.putNextEntry(new JarEntry(name + ".class"));211content = morphClass(classTemplate, name);212jar.write(content, 0, content.length);213}214}215}216217byte[] readFile(File f) throws IOException {218return Files.readAllBytes(Paths.get(f.getAbsolutePath()));219}220221void writeFile(File f, byte[] content) throws IOException {222Files.write(Paths.get(f.getAbsolutePath()), content);223}224225void deleteFolder(File dir) throws IOException {226Files.walkFileTree(Paths.get(dir.getAbsolutePath()), new FileVisitor<Path>() {227228@Override229public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {230return FileVisitResult.CONTINUE;231}232233@Override234public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {235Files.delete(file);236return FileVisitResult.CONTINUE;237}238239@Override240public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {241return FileVisitResult.CONTINUE;242}243244@Override245public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {246Files.delete(dir);247return FileVisitResult.CONTINUE;248}249250});251}252253/**254* Puts new name on the given class.255*256* @param classToMorph class file content257* @param newName new name258* @return new class file to write into class259*/260byte[] morphClass(byte[] classToMorph, String newName) {261ClassReader cr = new ClassReader(classToMorph);262ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);263ClassVisitor cv = new ClassRenamer(cw, newName);264cr.accept(cv, 0);265return cw.toByteArray();266}267268/**269* Visitor to rename class.270*/271static class ClassRenamer extends ClassVisitor implements Opcodes {272private final String newName;273274public ClassRenamer(ClassVisitor cv, String newName) {275super(ASM4, cv);276this.newName = newName;277}278279@Override280public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {281cv.visit(version, access, newName, signature, superName, interfaces);282}283284}285}286287288