--- a/jdk/test/tools/jlink/JLinkOptimTest.java Thu Jul 07 17:53:55 2016 +0900
+++ /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<ModuleEntry> javabaseResources = new ArrayList<>();
- try (Stream<Path> stream = Files.walk(root)) {
- for (Iterator<Path> 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<String, String> 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("<clinit>")) {
- continue;
- }
- if (mn.name.startsWith("negative")) {
- checkForName(mn);
- } else {
- checkNoForName(mn);
- }
- }
- Map<String, byte[]> 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<AbstractInsnNode> 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<AbstractInsnNode> 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<String, byte[]> classes;
- private final Map<String, Class<?>> cache = new HashMap<>();
-
- MemClassLoader(Map<String, byte[]> 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);
- }
- }
- }
-
-}