test/runtime/testlibrary/GeneratedClassLoader.java

Wed, 22 Jan 2014 12:37:28 -0800

author
katleman
date
Wed, 22 Jan 2014 12:37:28 -0800
changeset 6575
2bac854670c0
parent 0
f90c822e73f8
permissions
-rw-r--r--

Added tag jdk8u5-b05 for changeset b90de55aca30

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

mercurial