1 /* 2 * Copyright 2008-2010 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 import java.io.ByteArrayOutputStream; 26 import java.io.IOException; 27 import java.io.OutputStream; 28 import java.io.PrintWriter; 29 import java.io.StringWriter; 30 31 import java.lang.reflect.Method; 32 import java.net.URI; 33 import java.util.Arrays; 34 import java.util.Vector; 35 36 import javax.tools.Diagnostic; 37 import javax.tools.DiagnosticCollector; 38 import javax.tools.FileObject; 39 import javax.tools.ForwardingJavaFileManager; 40 import javax.tools.JavaCompiler; 41 import javax.tools.JavaCompiler.CompilationTask; 42 import javax.tools.JavaFileManager; 43 import javax.tools.JavaFileObject; 44 import javax.tools.JavaFileObject.Kind; 45 import javax.tools.SimpleJavaFileObject; 46 import javax.tools.StandardJavaFileManager; 47 import javax.tools.ToolProvider; 48 49 /* 50 * @test SortMethodsTest 51 * @bug 6925573 52 * @summary verify that class loading does not need quadratic time with regard to the number of class 53 methods. 54 * @run main SortMethodsTest 55 * @author volker.simonis@gmail.com 56 */ 57 58 public class SortMethodsTest { 59 60 static String createClass(String name, int nrOfMethods) { 61 StringWriter sw = new StringWriter(); 62 PrintWriter pw = new PrintWriter(sw); 63 pw.println("public class " + name + "{"); 64 for (int i = 0; i < nrOfMethods; i++) { 65 pw.println(" public void m" + i + "() {}"); 66 } 67 pw.println(" public static String sayHello() {"); 68 pw.println(" return \"Hello from class \" + " + name + 69 ".class.getName() + \" with \" + " + name + 70 ".class.getDeclaredMethods().length + \" methods\";"); 71 pw.println(" }"); 72 pw.println("}"); 73 pw.close(); 74 return sw.toString(); 75 } 76 77 public static void main(String args[]) { 78 79 JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); 80 DiagnosticCollector<JavaFileObject> diags = new DiagnosticCollector<JavaFileObject>(); 81 final String cName = new String("ManyMethodsClass"); 82 Vector<Long> results = new Vector<Long>(); 83 84 for (int i = 6; i < 600000; i*=10) { 85 String klass = createClass(cName, i); 86 JavaMemoryFileObject file = new JavaMemoryFileObject(cName, klass); 87 MemoryFileManager mfm = new MemoryFileManager(comp.getStandardFileManager(diags, null, null), file); 88 CompilationTask task = comp.getTask(null, mfm, diags, null, null, Arrays.asList(file)); 89 90 if (task.call()) { 91 try { 92 MemoryClassLoader mcl = new MemoryClassLoader(file); 93 long start = System.nanoTime(); 94 Class<? extends Object> c = Class.forName(cName, true, mcl); 95 long end = System.nanoTime(); 96 results.add(end - start); 97 Method m = c.getDeclaredMethod("sayHello", new Class[0]); 98 String ret = (String)m.invoke(null, new Object[0]); 99 System.out.println(ret + " (loaded and resloved in " + (end - start) + "ns)"); 100 } catch (Exception e) { 101 System.err.println(e); 102 } 103 } 104 else { 105 System.out.println(klass); 106 System.out.println(); 107 for (Diagnostic diag : diags.getDiagnostics()) { 108 System.out.println(diag.getCode() + "\n" + diag.getKind() + "\n" + diag.getPosition()); 109 System.out.println(diag.getSource() + "\n" + diag.getMessage(null)); 110 } 111 } 112 } 113 114 long lastRatio = 0; 115 for (int i = 2; i < results.size(); i++) { 116 long normalized1 = Math.max(results.get(i-1) - results.get(0), 1); 117 long normalized2 = Math.max(results.get(i) - results.get(0), 1); 118 long ratio = normalized2/normalized1; 119 lastRatio = ratio; 120 System.out.println("10 x more methods requires " + ratio + " x more time"); 121 } 122 // The following is just vague estimation but seems to work on current x86_64 and sparcv9 machines 123 if (lastRatio > 80) { 124 throw new RuntimeException("ATTENTION: it seems that class loading needs quadratic time with regard to the number of class methods!!!"); 125 } 126 } 127 } 128 129 class JavaMemoryFileObject extends SimpleJavaFileObject { 130 131 private final String code; 132 private ByteArrayOutputStream byteCode; 133 134 JavaMemoryFileObject(String name, String code) { 135 super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE); 136 this.code = code; 137 } 138 139 @Override 140 public CharSequence getCharContent(boolean ignoreEncodingErrors) { 141 return code; 142 } 143 144 @Override 145 public OutputStream openOutputStream() { 146 byteCode = new ByteArrayOutputStream(); 147 return byteCode; 148 } 149 150 byte[] getByteCode() { 151 return byteCode.toByteArray(); 152 } 153 } 154 155 class MemoryClassLoader extends ClassLoader { 156 157 private final JavaMemoryFileObject jfo; 158 159 public MemoryClassLoader(JavaMemoryFileObject jfo) { 160 this.jfo = jfo; 161 } 162 163 public Class findClass(String name) { 164 byte[] b = jfo.getByteCode(); 165 return defineClass(name, b, 0, b.length); 166 } 167 } 168 169 class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> { 170 171 private final JavaFileObject jfo; 172 173 public MemoryFileManager(StandardJavaFileManager jfm, JavaFileObject jfo) { 174 super(jfm); 175 this.jfo = jfo; 176 } 177 178 @Override 179 public FileObject getFileForInput(Location location, String packageName, 180 String relativeName) throws IOException { 181 return jfo; 182 } 183 184 @Override 185 public JavaFileObject getJavaFileForOutput(Location location, String qualifiedName, 186 Kind kind, FileObject outputFile) throws IOException { 187 return jfo; 188 } 189 190 }