diff -r f939432eb32a -r 4da8463b3d33 jdk/test/tools/jlink/JLinkOptimTest.java --- a/jdk/test/tools/jlink/JLinkOptimTest.java Fri Jul 08 17:36:34 2016 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,354 +0,0 @@ - -import java.lang.reflect.Method; -import java.net.URI; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode; -import jdk.internal.org.objectweb.asm.tree.ClassNode; -import jdk.internal.org.objectweb.asm.tree.MethodInsnNode; -import jdk.internal.org.objectweb.asm.tree.MethodNode; -import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode; -import jdk.tools.jlink.internal.PluginRepository; -import jdk.tools.jlink.internal.ModulePoolImpl; -import jdk.tools.jlink.internal.plugins.OptimizationPlugin; -import jdk.tools.jlink.internal.plugins.asm.AsmModulePool; -import jdk.tools.jlink.internal.plugins.asm.AsmPlugin; -import jdk.tools.jlink.internal.plugins.asm.AsmPools; -import jdk.tools.jlink.internal.plugins.optim.ControlFlow; -import jdk.tools.jlink.internal.plugins.optim.ControlFlow.Block; -import jdk.tools.jlink.plugin.ModuleEntry; -import jdk.tools.jlink.plugin.ModulePool; - -import tests.Helper; -import tests.JImageGenerator; - -/* - * Copyright (c) 2015, 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. - */ - - /* - * @test - * @summary Test image creation with class optimization - * @author Jean-Francois Denise - * @library ../lib - * @modules java.base/jdk.internal.jimage - * jdk.jdeps/com.sun.tools.classfile - * jdk.jlink/jdk.tools.jlink.internal - * jdk.jlink/jdk.tools.jmod - * jdk.jlink/jdk.tools.jimage - * jdk.jlink/jdk.tools.jlink.internal.plugins - * jdk.jlink/jdk.tools.jlink.internal.plugins.asm - * jdk.jlink/jdk.tools.jlink.internal.plugins.optim - * java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.org.objectweb.asm.tree - * java.base/jdk.internal.org.objectweb.asm.util - * jdk.compiler - * @build tests.* - * @run main JLinkOptimTest - */ -public class JLinkOptimTest { - - private static final String EXPECTED = "expected"; - private static Helper helper; - - public static class ControlFlowPlugin extends AsmPlugin { - - private boolean called; - private int numMethods; - private int numBlocks; - - private static final String NAME = "test-optim"; - - private ControlFlowPlugin() { - } - - @Override - public void visit(AsmPools pools) { - called = true; - for (AsmModulePool p : pools.getModulePools()) { - - p.visitClassReaders((reader) -> { - ClassNode cn = new ClassNode(); - if ((reader.getAccess() & Opcodes.ACC_INTERFACE) == 0) { - reader.accept(cn, ClassReader.EXPAND_FRAMES); - for (MethodNode m : cn.methods) { - if ((m.access & Opcodes.ACC_ABSTRACT) == 0 - && (m.access & Opcodes.ACC_NATIVE) == 0) { - numMethods += 1; - try { - ControlFlow f - = ControlFlow.createControlFlow(cn.name, m); - for (Block b : f.getBlocks()) { - numBlocks += 1; - f.getClosure(b); - } - } catch (Throwable ex) { - //ex.printStackTrace(); - throw new RuntimeException("Exception in " - + cn.name + "." + m.name, ex); - } - } - } - } - return null; - }); - } - } - - @Override - public String getName() { - return NAME; - } - } - - private static void testForName() throws Exception { - String moduleName = "optimplugin"; - Path src = Paths.get(System.getProperty("test.src")).resolve(moduleName); - Path classes = helper.getJmodClassesDir().resolve(moduleName); - JImageGenerator.compile(src, classes); - - FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); - Path root = fs.getPath("/modules/java.base"); - // Access module-info.class to be reused as fake module-info.class - List javabaseResources = new ArrayList<>(); - try (Stream stream = Files.walk(root)) { - for (Iterator iterator = stream.iterator(); iterator.hasNext();) { - Path p = iterator.next(); - if (Files.isRegularFile(p)) { - try { - javabaseResources.add(ModuleEntry.create(p.toString(). - substring("/modules".length()), Files.readAllBytes(p))); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - } - } - - //forName folding - ModulePoolImpl pool = new ModulePoolImpl(); - byte[] content = Files.readAllBytes(classes. - resolve("optim").resolve("ForNameTestCase.class")); - byte[] content2 = Files.readAllBytes(classes. - resolve("optim").resolve("AType.class")); - byte[] mcontent = Files.readAllBytes(classes.resolve("module-info.class")); - - pool.add(ModuleEntry.create("/optimplugin/optim/ForNameTestCase.class", content)); - pool.add(ModuleEntry.create("/optimplugin/optim/AType.class", content2)); - pool.add(ModuleEntry.create("/optimplugin/module-info.class", mcontent)); - - for (ModuleEntry r : javabaseResources) { - pool.add(r); - } - - OptimizationPlugin plugin = new OptimizationPlugin(); - Map optional = new HashMap<>(); - optional.put(OptimizationPlugin.NAME, OptimizationPlugin.FORNAME_REMOVAL); - optional.put(OptimizationPlugin.LOG, "forName.log"); - plugin.configure(optional); - ModulePool out = new ModulePoolImpl(); - plugin.visit(pool, out); - - ModuleEntry result = out.entries().iterator().next(); - - ClassReader optimReader = new ClassReader(result.getBytes()); - ClassNode optimClass = new ClassNode(); - optimReader.accept(optimClass, ClassReader.EXPAND_FRAMES); - - if (!optimClass.name.equals("optim/ForNameTestCase")) { - throw new Exception("Invalid class " + optimClass.name); - } - if (optimClass.methods.size() < 2) { - throw new Exception("Not enough methods in new class"); - } - for (MethodNode mn : optimClass.methods) { - if (!mn.name.contains("forName") && !mn.name.contains("")) { - continue; - } - if (mn.name.startsWith("negative")) { - checkForName(mn); - } else { - checkNoForName(mn); - } - } - Map newClasses = new HashMap<>(); - newClasses.put("optim.ForNameTestCase", result.getBytes()); - newClasses.put("optim.AType", content2); - MemClassLoader loader = new MemClassLoader(newClasses); - Class loaded = loader.loadClass("optim.ForNameTestCase"); - if (loaded.getDeclaredMethods().length < 2) { - throw new Exception("Not enough methods in new class"); - } - for (Method m : loaded.getDeclaredMethods()) { - if (m.getName().contains("Exception")) { - try { - m.invoke(null); - } catch (Exception ex) { - //ex.getCause().printStackTrace(); - if (!ex.getCause().getMessage().equals(EXPECTED)) { - throw new Exception("Unexpected exception " + ex); - } - } - } else if (!m.getName().startsWith("negative")) { - Class clazz = (Class) m.invoke(null); - if (clazz != String.class && clazz != loader.findClass("optim.AType")) { - throw new Exception("Invalid class " + clazz); - } - } - } - } - - private static void checkNoForName(MethodNode m) throws Exception { - Iterator it = m.instructions.iterator(); - while (it.hasNext()) { - AbstractInsnNode n = it.next(); - if (n instanceof MethodInsnNode) { - MethodInsnNode met = (MethodInsnNode) n; - if (met.name.equals("forName") - && met.owner.equals("java/lang/Class") - && met.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) { - throw new Exception("forName not removed in " + m.name); - } - } - } - for (TryCatchBlockNode tcb : m.tryCatchBlocks) { - if (tcb.type.equals(ClassNotFoundException.class.getName().replaceAll("\\.", "/"))) { - throw new Exception("ClassNotFoundException Block not removed for " + m.name); - } - } - } - - private static void checkForName(MethodNode m) throws Exception { - Iterator it = m.instructions.iterator(); - boolean found = false; - while (it.hasNext()) { - AbstractInsnNode n = it.next(); - if (n instanceof MethodInsnNode) { - MethodInsnNode met = (MethodInsnNode) n; - if (met.name.equals("forName") - && met.owner.equals("java/lang/Class") - && met.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) { - found = true; - break; - } - } - } - if (!found) { - throw new Exception("forName removed but shouldn't have"); - } - found = false; - for (TryCatchBlockNode tcb : m.tryCatchBlocks) { - if (tcb.type.equals(ClassNotFoundException.class.getName().replaceAll("\\.", "/"))) { - found = true; - break; - } - } - if (!found) { - throw new Exception("tryCatchBlocks removed but shouldn't have"); - } - } - - static class MemClassLoader extends ClassLoader { - - private final Map classes; - private final Map> cache = new HashMap<>(); - - MemClassLoader(Map classes) { - super(null); - this.classes = classes; - } - - @Override - public Class findClass(String name) throws ClassNotFoundException { - Class clazz = cache.get(name); - if (clazz == null) { - byte[] b = classes.get(name); - if (b == null) { - return super.findClass(name); - } else { - clazz = defineClass(name, b, 0, b.length); - cache.put(name, clazz); - } - } - return clazz; - } - } - - public static void main(String[] args) throws Exception { - helper = Helper.newHelper(); - if (helper == null) { - System.err.println("Test not run"); - return; - } - - testForName(); - - helper.generateDefaultModules(); - helper.generateDefaultJModule("optim1", "java.se"); - { - String[] userOptions = {"--class-optim=all:log=./class-optim-log.txt"}; - - Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess(); - helper.checkImage(imageDir, "optim1", null, null); - } - - { - String[] userOptions = {"--class-optim=forName-folding:log=./class-optim-log.txt"}; - Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess(); - helper.checkImage(imageDir, "optim1", null, null); - } - - { - ControlFlowPlugin plugin = new ControlFlowPlugin(); - PluginRepository.registerPlugin(plugin); - String[] userOptions = {"--test-optim"}; - Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess(); - helper.checkImage(imageDir, "optim1", null, null); - //System.out.println("Num methods analyzed " + provider.numMethods - // + "num blocks " + provider.numBlocks); - if (!plugin.called) { - throw new Exception("Plugin not called"); - } - if (plugin.numMethods < 1000) { - throw new Exception("Not enough method called, should be " - + "around 10000 but is " + plugin.numMethods); - } - if (plugin.numBlocks < 100000) { - throw new Exception("Not enough blocks, should be " - + "around 640000 but is " + plugin.numMethods); - } - } - } - -}