# HG changeset patch # User Thomas Wuerthinger # Date 1365971926 -7200 # Node ID 616d93ef8ff8f813480dea80baca50571c6d475a # Parent 23c96de5338692a2f76608871df4523354d70d4f# Parent b78686983a75a0a091bbaa1d938911dafd98c569 Merge. diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantPool.java --- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantPool.java Sun Apr 14 22:38:34 2013 +0200 +++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ConstantPool.java Sun Apr 14 22:38:46 2013 +0200 @@ -30,6 +30,13 @@ public interface ConstantPool { /** + * Returns the number of entries the constant pool. + * + * @return number of entries in the constant pool + */ + int length(); + + /** * Ensures that the type referenced by the specified constant pool entry is loaded and * initialized. This can be used to compile time resolve a type. It works for field, method, or * type constant pool entries. diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java Sun Apr 14 22:38:46 2013 +0200 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2013, 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. + */ +package com.oracle.graal.hotspot.test; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.hotspot.*; + +/** + * Tests {@link CompileTheWorld} functionality. + */ +public class CompileTheWorldTest extends GraalCompilerTest { + + @Test + public void testRtJar() throws Throwable { + // Compile a couple classes in rt.jar + String file = System.getProperty("java.home") + "/lib/rt.jar"; + new CompileTheWorld(file, 1, 5).compile(); + } + +} diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java Sun Apr 14 22:38:46 2013 +0200 @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2013, 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. + */ +package com.oracle.graal.hotspot; + +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.*; +import java.util.Enumeration; +import java.util.jar.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.bytecode.Bytecodes; +import com.oracle.graal.debug.*; +import com.oracle.graal.hotspot.bridge.*; +import com.oracle.graal.hotspot.meta.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.replacements.*; + +/** + * This class implements compile-the-world functionality in Graal. + */ +public final class CompileTheWorld { + + /** + * This is our magic token to trigger reading files from the boot class path. + */ + public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path"; + + // Some runtime instances we need. + private final HotSpotGraalRuntime graalRuntime = HotSpotGraalRuntime.getInstance(); + private final VMToCompilerImpl vmToCompiler = (VMToCompilerImpl) graalRuntime.getVMToCompiler(); + + /** List of Zip/Jar files to compile (see {@link GraalOptions#CompileTheWorld}. */ + private final String files; + + /** Class index to start compilation at (see {@link GraalOptions#CompileTheWorldStartAt}. */ + private final int startAt; + + /** Class index to stop compilation at (see {@link GraalOptions#CompileTheWorldStopAt}. */ + private final int stopAt; + + // Counters + private int classFileCounter = 0; + private int compiledMethodsCounter = 0; + private long compileTime = 0; + + /** + * Create a compile-the-world instance with default values from + * {@link GraalOptions#CompileTheWorld}, {@link GraalOptions#CompileTheWorldStartAt} and + * {@link GraalOptions#CompileTheWorldStopAt}. + */ + public CompileTheWorld() { + this(GraalOptions.CompileTheWorld, GraalOptions.CompileTheWorldStartAt, GraalOptions.CompileTheWorldStopAt); + } + + /** + * Create a compile-the-world instance. + * + * @param files {@link File#pathSeparator} separated list of Zip/Jar files to compile + * @param startAt index of the class file to start compilation at + * @param stopAt index of the class file to stop compilation at + */ + public CompileTheWorld(String files, int startAt, int stopAt) { + this.files = files; + this.startAt = startAt; + this.stopAt = stopAt; + + // We don't want the VM to exit when a method fails to compile. + GraalOptions.ExitVMOnException = false; + } + + /** + * Compile all methods in all classes in the Zip/Jar files in + * {@link GraalOptions#CompileTheWorld}. If the GraalOptions.CompileTheWorld contains the magic + * token {@link CompileTheWorld#SUN_BOOT_CLASS_PATH} passed up from HotSpot we take the files + * from the boot class path. + * + * @throws Throwable + */ + public void compile() throws Throwable { + if (SUN_BOOT_CLASS_PATH.equals(files)) { + final String[] entries = System.getProperty(SUN_BOOT_CLASS_PATH).split(File.pathSeparator); + String bcpFiles = ""; + for (int i = 0; i < entries.length; i++) { + final String entry = entries[i]; + + // We stop at rt.jar, unless it is the first boot class path entry. + if (entry.endsWith("rt.jar") && (i > 0)) { + break; + } + if (i > 0) { + bcpFiles += File.pathSeparator; + } + bcpFiles += entry; + } + compile(bcpFiles); + } else { + compile(files); + } + } + + /** + * Compile all methods in all classes in the Zip/Jar files passed. + * + * @param fileList {@link File#pathSeparator} separated list of Zip/Jar files to compile + * @throws Throwable + */ + private void compile(String fileList) throws Throwable { + final String[] entries = fileList.split(File.pathSeparator); + + for (int i = 0; i < entries.length; i++) { + final String entry = entries[i]; + + // For now we only compile all methods in all classes in zip/jar files. + if (!entry.endsWith(".zip") && !entry.endsWith(".jar")) { + TTY.println("CompileTheWorld : Skipped classes in " + entry); + TTY.println(); + continue; + } + + TTY.println("CompileTheWorld : Compiling all classes in " + entry); + TTY.println(); + + URL url = new URL("jar", "", "file:" + entry + "!/"); + ClassLoader loader = new URLClassLoader(new URL[]{url}); + + JarFile jarFile = new JarFile(entry); + Enumeration e = jarFile.entries(); + + while (e.hasMoreElements()) { + JarEntry je = e.nextElement(); + if (je.isDirectory() || !je.getName().endsWith(".class")) { + continue; + } + + // Are we done? + if (classFileCounter >= stopAt) { + break; + } + + String className = je.getName().substring(0, je.getName().length() - ".class".length()); + className = className.replace('/', '.'); + classFileCounter++; + + try { + // Load and initialize class + Class javaClass = Class.forName(className, true, loader); + + // Pre-load all classes in the constant pool. + try { + HotSpotResolvedObjectType objectType = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(javaClass); + ConstantPool constantPool = objectType.constantPool(); + for (int cpi = 1; cpi < constantPool.length(); cpi++) { + constantPool.loadReferencedType(cpi, Bytecodes.LDC); + } + } catch (Throwable t) { + // If something went wrong during pre-loading we just ignore it. + TTY.println("CompileTheWorld (%d) : Preloading failed for %s", classFileCounter, className); + } + + // Are we compiling this class? + if (classFileCounter >= startAt) { + TTY.println("CompileTheWorld (%d) : %s", classFileCounter, className); + + // Enqueue each constructor/method in the class for compilation. + for (Constructor constructor : javaClass.getDeclaredConstructors()) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) graalRuntime.getRuntime().lookupJavaConstructor(constructor); + if (canBeCompiled(javaMethod, constructor.getModifiers())) { + compileMethod(javaMethod); + } + } + for (Method method : javaClass.getDeclaredMethods()) { + HotSpotResolvedJavaMethod javaMethod = (HotSpotResolvedJavaMethod) graalRuntime.getRuntime().lookupJavaMethod(method); + if (canBeCompiled(javaMethod, method.getModifiers())) { + compileMethod(javaMethod); + } + } + } + } catch (Throwable t) { + TTY.println("CompileTheWorld (%d) : Skipping %s", classFileCounter, className); + } + } + jarFile.close(); + } + + TTY.println(); + TTY.println("CompileTheWorld : Done (%d classes, %d methods, %d ms)", classFileCounter, compiledMethodsCounter, compileTime); + } + + /** + * Helper method to schedule a method for compilation and gather some statistics. + */ + private void compileMethod(HotSpotResolvedJavaMethod method) { + try { + long start = System.currentTimeMillis(); + vmToCompiler.compileMethod(method, StructuredGraph.INVOCATION_ENTRY_BCI, true, 10); + compileTime += (System.currentTimeMillis() - start); + compiledMethodsCounter++; + method.reprofile(); // makes the method also not-entrant + } catch (Throwable t) { + // Catch everything and print a message + TTY.println("CompileTheWorld (%d) : Error compiling method: %s", classFileCounter, MetaUtil.format("%H.%n(%p):%r", method)); + t.printStackTrace(TTY.cachedOut); + } + } + + /** + * Helper method for CompileTheWorld to determine if a method should be compiled (Cf. + * CompilationPolicy::can_be_compiled). + * + * @return true if it can be compiled, false otherwise + */ + private static boolean canBeCompiled(HotSpotResolvedJavaMethod javaMethod, int modifiers) { + if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) { + return false; + } + // This number is from HotSpot: + final int hugeMethodLimit = 8000; + if (javaMethod.getCodeSize() > hugeMethodLimit) { + return false; + } + // Skip @Snippets for now + if (javaMethod.getAnnotation(Snippet.class) != null) { + return false; + } + return true; + } + +} diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Sun Apr 14 22:38:34 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Sun Apr 14 22:38:46 2013 +0200 @@ -140,6 +140,15 @@ config.check(); // Set some global options: + if (config.compileTheWorld) { + GraalOptions.CompileTheWorld = CompileTheWorld.SUN_BOOT_CLASS_PATH; + } + if (config.compileTheWorldStartAt != 1) { + GraalOptions.CompileTheWorldStartAt = config.compileTheWorldStartAt; + } + if (config.compileTheWorldStopAt != Integer.MAX_VALUE) { + GraalOptions.CompileTheWorldStopAt = config.compileTheWorldStopAt; + } GraalOptions.HotSpotPrintCompilation = config.printCompilation; GraalOptions.HotSpotPrintInlining = config.printInlining; diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Sun Apr 14 22:38:34 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Sun Apr 14 22:38:46 2013 +0200 @@ -37,6 +37,9 @@ public int codeEntryAlignment; public boolean verifyOops; public boolean ciTime; + public boolean compileTheWorld; + public int compileTheWorldStartAt; + public int compileTheWorldStopAt; public boolean printCompilation; public boolean printInlining; public boolean useFastLocking; diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Sun Apr 14 22:38:34 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java Sun Apr 14 22:38:46 2013 +0200 @@ -128,6 +128,8 @@ */ JavaType lookupType(String name, HotSpotResolvedObjectType accessingClass, boolean eagerResolve); + int constantPoolLength(HotSpotResolvedObjectType pool); + Object lookupConstantInPool(HotSpotResolvedObjectType pool, int cpi); JavaMethod lookupMethodInPool(HotSpotResolvedObjectType pool, int cpi, byte opcode); diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Sun Apr 14 22:38:34 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java Sun Apr 14 22:38:46 2013 +0200 @@ -79,6 +79,9 @@ public native JavaType lookupType(String name, HotSpotResolvedObjectType accessingClass, boolean eagerResolve); @Override + public native int constantPoolLength(HotSpotResolvedObjectType pool); + + @Override public native Object lookupConstantInPool(HotSpotResolvedObjectType pool, int cpi); @Override diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Sun Apr 14 22:38:34 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompiler.java Sun Apr 14 22:38:46 2013 +0200 @@ -34,8 +34,23 @@ */ public interface VMToCompiler { + /** + * Compiles a method to machine code. This method is called from the VM + * (VMToCompiler::compileMethod). + * + * @return true if the method is in the queue (either added to the queue or already in the + * queue) + */ boolean compileMethod(long metaspaceMethod, HotSpotResolvedObjectType holder, int entryBCI, boolean blocking, int priority) throws Throwable; + /** + * Compiles a method to machine code. + * + * @return true if the method is in the queue (either added to the queue or already in the + * queue) + */ + boolean compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, boolean blocking, int priority) throws Throwable; + void shutdownCompiler() throws Throwable; void startCompiler() throws Throwable; diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Sun Apr 14 22:38:34 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java Sun Apr 14 22:38:46 2013 +0200 @@ -393,6 +393,10 @@ System.gc(); phaseTransition("bootstrap2"); + if (GraalOptions.CompileTheWorld != null) { + new CompileTheWorld().compile(); + System.exit(0); + } } private MetricRateInPhase parsedBytecodesPerSecond; diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Sun Apr 14 22:38:34 2013 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java Sun Apr 14 22:38:46 2013 +0200 @@ -40,6 +40,11 @@ } @Override + public int length() { + return HotSpotGraalRuntime.getInstance().getCompilerToVM().constantPoolLength(type); + } + + @Override public Object lookupConstant(int cpi) { assert cpi != 0; Object constant = HotSpotGraalRuntime.getInstance().getCompilerToVM().lookupConstantInPool(type, cpi); diff -r 23c96de53386 -r 616d93ef8ff8 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Sun Apr 14 22:38:34 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java Sun Apr 14 22:38:46 2013 +0200 @@ -88,6 +88,9 @@ public static int SlowQueueCutoff = 100000; public static boolean SlowCompileThreads = ____; public static boolean DynamicCompilePriority = ____; + public static String CompileTheWorld = null; + public static int CompileTheWorldStartAt = 1; + public static int CompileTheWorldStopAt = Integer.MAX_VALUE; // graph caching public static boolean CacheGraphs = true; diff -r 23c96de53386 -r 616d93ef8ff8 src/share/vm/graal/graalCompiler.cpp --- a/src/share/vm/graal/graalCompiler.cpp Sun Apr 14 22:38:34 2013 +0200 +++ b/src/share/vm/graal/graalCompiler.cpp Sun Apr 14 22:38:46 2013 +0200 @@ -91,6 +91,10 @@ VMToCompiler::startCompiler(); _initialized = true; if (BootstrapGraal) { + // We turn off CompileTheWorld and complete the VM startup so that + // Graal can be compiled by C1/C2 when we do a CTW. + NOT_PRODUCT(CompileTheWorld = false); + CompilationPolicy::completed_vm_startup(); VMToCompiler::bootstrap(); } } diff -r 23c96de53386 -r 616d93ef8ff8 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Sun Apr 14 22:38:34 2013 +0200 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Sun Apr 14 22:38:46 2013 +0200 @@ -320,6 +320,11 @@ return code == NULL ? 0 : code->insts_size(); C2V_END +C2V_VMENTRY(jint, constantPoolLength, (JNIEnv *env, jobject, jobject type)) + ConstantPool* cp = InstanceKlass::cast(java_lang_Class::as_Klass(HotSpotResolvedObjectType::javaMirror(type)))->constants(); + return cp->length(); +C2V_END + C2V_VMENTRY(jobject, lookupType, (JNIEnv *env, jobject, jstring jname, jobject accessingClass, jboolean eagerResolve)) ResourceMark rm; @@ -621,6 +626,9 @@ #endif set_boolean("verifyOops", VerifyOops); set_boolean("ciTime", CITime); + set_boolean("compileTheWorld", CompileTheWorld); + set_int("compileTheWorldStartAt", CompileTheWorldStartAt); + set_int("compileTheWorldStopAt", CompileTheWorldStopAt); set_boolean("printCompilation", PrintCompilation); set_boolean("printInlining", PrintInlining); set_boolean("useFastLocking", GraalUseFastLocking); @@ -1112,6 +1120,7 @@ {CC"getInvocationCount", CC"("METASPACE_METHOD")I", FN_PTR(getInvocationCount)}, {CC"getCompiledCodeSize", CC"("METASPACE_METHOD")I", FN_PTR(getCompiledCodeSize)}, {CC"getVtableEntryOffset", CC"("METASPACE_METHOD")I", FN_PTR(getVtableEntryOffset)}, + {CC"constantPoolLength", CC"("HS_RESOLVED_TYPE")I", FN_PTR(constantPoolLength)}, {CC"lookupType", CC"("STRING HS_RESOLVED_TYPE"Z)"TYPE, FN_PTR(lookupType)}, {CC"lookupConstantInPool", CC"("HS_RESOLVED_TYPE"I)"OBJECT, FN_PTR(lookupConstantInPool)}, {CC"lookupAppendixInPool", CC"("HS_RESOLVED_TYPE"IB)"OBJECT, FN_PTR(lookupAppendixInPool)}, diff -r 23c96de53386 -r 616d93ef8ff8 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Sun Apr 14 22:38:34 2013 +0200 +++ b/src/share/vm/runtime/globals.hpp Sun Apr 14 22:38:46 2013 +0200 @@ -3337,10 +3337,10 @@ "ConcurrentMarkSweep thread runs at critical scheduling priority")\ \ /* compiler debugging */ \ - notproduct(intx, CompileTheWorldStartAt, 1, \ + develop(intx, CompileTheWorldStartAt, 1, \ "First class to consider when using +CompileTheWorld") \ \ - notproduct(intx, CompileTheWorldStopAt, max_jint, \ + develop(intx, CompileTheWorldStopAt, max_jint, \ "Last class to consider when using +CompileTheWorld") \ \ develop(intx, NewCodeParameter, 0, \