test/runtime/testlibrary/GeneratedClassLoader.java

Wed, 21 May 2014 10:56:41 -0700

author
katleman
date
Wed, 21 May 2014 10:56:41 -0700
changeset 6672
fb9d124d9192
parent 0
f90c822e73f8
permissions
-rw-r--r--

Added tag jdk8u20-b15 for changeset 8c785f9bde6f

     1 /*
     2  * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  */
    24 import java.io.DataInputStream;
    25 import java.io.File;
    26 import java.io.FileInputStream;
    27 import java.io.FileWriter;
    28 import java.io.IOException;
    29 import java.io.PrintWriter;
    30 import javax.tools.JavaCompiler;
    31 import javax.tools.ToolProvider;
    33 /**
    34  * A class loader that generates new classes.
    35  * The generated classes are made by first emitting java sources with nested
    36  * static classes, these are then compiled and the class files are read back.
    37  * Some efforts are made to make the class instances unique and of not insignificant
    38  * size.
    39  */
    40 public class GeneratedClassLoader extends ClassLoader {
    41     /**
    42      * Holds a pair of class bytecodes and class name (for use with defineClass).
    43      */
    44     private static class GeneratedClass {
    45         public byte[] bytes;
    46         public String name;
    47         public GeneratedClass(byte[] bytes, String name) {
    48             this.bytes = bytes; this.name = name;
    49         }
    50     }
    52     /**
    53      * Used to uniquely name every class generated.
    54      */
    55     private static int count = 0;
    56     /**
    57      * Used to enable/disable keeping the class files and java sources for
    58      * the generated classes.
    59      */
    60     private static boolean deleteFiles = Boolean.parseBoolean(
    61         System.getProperty("GeneratedClassLoader.deleteFiles", "true"));
    63     private static String bigstr =
    64         "Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
    65         + "In facilisis scelerisque vehicula. Donec congue nisi a "
    66         + "leo posuere placerat lobortis felis ultrices. Pellentesque "
    67         + "habitant morbi tristique senectus et netus et malesuada "
    68         + "fames ac turpis egestas. Nam tristique velit at felis "
    69         + "iaculis at tempor sem vestibulum. Sed adipiscing lectus "
    70         + "non mi molestie sagittis. Morbi eu purus urna. Nam tempor "
    71         + "tristique massa eget semper. Mauris cursus, nulla et ornare "
    72         + "vehicula, leo dolor scelerisque metus, sit amet rutrum erat "
    73         + "sapien quis dui. Nullam eleifend risus et velit accumsan sed "
    74         + "suscipit felis pulvinar. Nullam faucibus suscipit gravida. "
    75         + "Pellentesque habitant morbi tristique senectus et netus et "
    76         + "malesuada fames ac turpis egestas. Nullam ut massa augue, "
    77         + "nec viverra mauris.";
    79     private static int getNextCount() {
    80         return count++;
    81     }
    83     ////// end statics
    85     private JavaCompiler javac;
    86     private String nameBase;
    88     public GeneratedClassLoader() {
    89         javac = ToolProvider.getSystemJavaCompiler();
    90         nameBase = "TestSimpleClass";
    91     }
    93     private long getBigValue(int which) {
    94         // > 65536 is too large to encode in the bytecode
    95         // so this will force us to emit a constant pool entry for this int
    96         return (long)which + 65537;
    97     }
    99     private String getBigString(int which) {
   100         return bigstr + which;
   101     }
   103     private String getClassName(int count) {
   104         return nameBase + count;
   105     }
   107     private String generateSource(int count, int sizeFactor, int numClasses) {
   108         StringBuilder sb = new StringBuilder();
   109         sb.append("public class ").append(getClassName(count)).append("{\n");
   110         for (int j = 0; j < numClasses; ++j) {
   111             sb.append("public static class ")
   112               .append("Class")
   113               .append(j)
   114               .append("{\n");
   115             for (int i = 0; i < sizeFactor; ++i) {
   116                 int value = i;
   117                 sb.append("private long field")
   118                   .append(i).append(" = ")
   119                   .append(getBigValue(value++))
   120                   .append(";\n");
   121                 sb.append("public long method")
   122                   .append(i)
   123                   .append("() {\n");
   124                 sb.append("return ")
   125                   .append(getBigValue(value++))
   126                   .append(";");
   127                 sb.append("}\n");
   128                 sb.append("private String str").append(i)
   129                   .append(" = \"")
   130                   .append(getBigString(i))
   131                   .append("\";");
   132             }
   133             sb.append("\n}");
   134         }
   135         sb.append("\n}");
   136         return sb.toString();
   137     }
   139     private GeneratedClass[] getGeneratedClass(int sizeFactor, int numClasses) throws IOException {
   140         int uniqueCount = getNextCount();
   141         String src = generateSource(uniqueCount, sizeFactor, numClasses);
   142         String className = getClassName(uniqueCount);
   143         File file = new File(className + ".java");
   144         try (PrintWriter pw = new PrintWriter(new FileWriter(file))) {
   145             pw.append(src);
   146             pw.flush();
   147         }
   148         int exitcode = javac.run(null, null, null, file.getCanonicalPath());
   149         if (exitcode != 0) {
   150             throw new RuntimeException("javac failure when compiling: " +
   151                     file.getCanonicalPath());
   152         } else {
   153             if (deleteFiles) {
   154                 file.delete();
   155             }
   156         }
   157         GeneratedClass[] gc = new GeneratedClass[numClasses];
   158         for (int i = 0; i < numClasses; ++i) {
   159             String name = className + "$" + "Class" + i;
   160             File classFile = new File(name + ".class");
   161             byte[] bytes;
   162             try (DataInputStream dis = new DataInputStream(new FileInputStream(classFile))) {
   163                 bytes = new byte[dis.available()];
   164                 dis.readFully(bytes);
   165             }
   166             if (deleteFiles) {
   167                 classFile.delete();
   168             }
   169             gc[i] = new GeneratedClass(bytes, name);
   170         }
   171         if (deleteFiles) {
   172             new File(className + ".class").delete();
   173         }
   174         return gc;
   175     }
   177     /**
   178      * Generate a single class, compile it and load it.
   179      * @param sizeFactor Fuzzy measure of how large the class should be.
   180      * @return the Class instance.
   181      * @throws IOException
   182      */
   183     public Class<?> generateClass(int sizeFactor) throws IOException {
   184         return getGeneratedClasses(sizeFactor, 1)[0];
   185     }
   187     /**
   188      * Generate several classes, compile and load them.
   189      * @param sizeFactor Fuzzy measure of how large each class should be.
   190      * @param numClasses The number of classes to create
   191      * @return an array of the Class instances.
   192      * @throws IOException
   193      */
   194     public Class<?>[] getGeneratedClasses(int sizeFactor, int numClasses) throws IOException {
   195         GeneratedClass[] gc = getGeneratedClass(sizeFactor, numClasses);
   196         Class<?>[] classes = new Class[numClasses];
   197         for (int i = 0; i < numClasses; ++i) {
   198             classes[i] = defineClass(gc[i].name, gc[i].bytes, 0 , gc[i].bytes.length);
   199         }
   200         return classes;
   201     }
   202 }

mercurial