/*
* @(#)Warmup.java 1.24 06/10/10
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program 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 program 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 at /legal/license.txt).
*
* 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 Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package sun.misc;
import java.io.*;
import java.net.*;
import java.util.*;
import java.lang.reflect.*;
import sun.misc.JIT;
import sun.misc.CVM;
//
// A generic warmup module that works with lists of classes to
// pre-load, and methods to pre-compile.
//
// Each list is in its own file
//
public class Warmup
{
private static String classNamesFileString = null;
private static String memberNamesFileString = null;
private static String classNamesFiles[] = null;
private static String memberNamesFiles[] = null;
private static ClassLoader currClassLoader = null;
private static ClassLoader midpClassLoader = null;
private static String midpPathString =
System.getProperty("sun.midp.home.path", "midp/midp_fb") + "/classes.zip";
private static File midpPath[] = null;
private static boolean verbose =
(System.getProperty("cdcams.verbose") != null) &&
(System.getProperty("cdcams.verbose").toLowerCase().equals("true"));
//
// The entry point of the warm-up program
// arg[0] is a filename containing a list of classes to load and initialize
// arg[1] is a filename containing a list of methods to pre-compile
//
public static void main(String[] args)
{
processOptions(args);
runit(classNamesFileString, memberNamesFileString);
}
private static void processOptions(String[] args)
{
classNamesFileString = null;
memberNamesFileString = null;
for (int i = 0; i < args.length; i++) {
if (args[i].equals("-initClasses")) {
classNamesFileString = args[++i];
classNamesFiles = split(classNamesFileString);
} else if (args[i].equals("-precompileMethods")) {
memberNamesFileString = args[++i];
memberNamesFiles = split(memberNamesFileString);
} else {
if (verbose) {
System.err.println("UNRECOGNIZED OPTION \""+args[i]+"\"");
}
}
}
}
//
// Set current classloader, which is used to load warmup classes.
//
private static void setCurrClassLoader(String loaderString)
throws IOException
{
String clname = loaderString.substring(12);
if (clname == null || clname.equals("")) {
/* The current classloader is the null ClassLoader */
currClassLoader = null;
} else if (clname.equals("sun.misc.Launcher$AppClassLoader")) {
/* The current classloader is the AppClassLoader */
currClassLoader = ClassLoader.getSystemClassLoader();
} else if (clname.equals("sun.misc.MIDPImplementationClassLoader")) {
if (midpClassLoader == null) {
if (midpPath == null) {
StringTokenizer mp = new StringTokenizer(midpPathString,
System.getProperty("path.separator", ":"));
int num = mp.countTokens();
midpPath = new File[num];
for (int i = 0; i < num; i++) {
midpPath[i] = new File(mp.nextToken());
}
}
/*
* Create the MIDPImplementationClassLoader.
* Use reflection to avoid hard-coded references
* to dual-stack APIs, which are conditionally
* included.
*/
try {
Class midpconfig = Class.forName("sun.misc.MIDPConfig");
Class args[] = {midpPath.getClass()};
Method newMIDPCL = midpconfig.getMethod(
"newMIDPImplementationClassLoader", args);
Object args2[] = {midpPath};
midpClassLoader = (ClassLoader)newMIDPCL.invoke(null, args2);
} catch(ClassNotFoundException ce) {
throw new IOException("Cannot find required classloader: " + clname);
} catch(NoSuchMethodException me) {
me.printStackTrace();
throw new IOException("Cannot find required classloader: " + clname);
} catch(IllegalAccessException ie) {
ie.printStackTrace();
throw new IOException("Cannot find required classloader: " + clname);
} catch(InvocationTargetException ite) {
ite.printStackTrace();
throw new IOException("Cannot find required classloader: " + clname);
}
}
currClassLoader = midpClassLoader;
} else {
throw new IOException("unrecognized classloader: "+ clname);
}
if (verbose) {
System.err.println("Set " + currClassLoader +
" as the current classloader");
}
}
//
// Read a list of elements and return it as a String[]
//
private static String[] readElements(BufferedReader inReader)
throws IOException
{
/* Reset currClassLoader for the new list */
currClassLoader = null;
java.util.Vector v = new java.util.Vector();
java.io.StreamTokenizer in;
in = new StreamTokenizer(inReader);
in.resetSyntax();
in.eolIsSignificant( false );
in.whitespaceChars( 0, 0x20 );
in.wordChars( '!', '~' );
in.commentChar('#');
while (in.nextToken() != java.io.StreamTokenizer.TT_EOF){
if (in.sval.startsWith("CLASSLOADER=")) {
/* CLASSLOADER indicates which classloader should
* be used to load classes in the list.
*/
setCurrClassLoader(in.sval);
} else {
/* Add class name */
v.addElement(in.sval);
}
}
int n = v.size();
String olist[] = new String[n];
v.copyInto(olist);
return olist;
}
static Class getClassFromName(String className, boolean init){
Class c = null;
try {
// Load and maybe initialize class
c = Class.forName(className, init, currClassLoader);
} catch (ClassNotFoundException e){
return null;
}
return c;
}
//
// If 'init' is not mentioned, assume it's false.
// That's the desired behaviour when looking up argument lists.
//
static Class getClassFromName(String className)
{
return getClassFromName(className, false);
}
//
// Read class or method list from file.
//
private static String[] readLists(String fileName)
{
String[] list = null;
BufferedReader in;
try {
in = new BufferedReader(new FileReader(fileName));
list = readElements(in);
if (verbose) {
System.err.println("read from " + fileName + " done...");
}
in.close();
return list;
} catch (IOException e) {
if (verbose) {
System.err.println("read from "+ fileName + " failed...");
}
e.printStackTrace();
return null;
}
}
//
// Initialize classes from the list.
//
private static boolean processClasses(String classes[])
{
if (verbose) {
System.err.println("CLASSES TO INITIALIZE");
}
if (classes != null) {
for (int i = 0; i < classes.length; i++) {
// Load and initialize class
Class cl = getClassFromName(classes[i], true);
//DEBUG: System.err.println((i+1)+":\t "+cl);
if (cl == null) {
if (verbose) {
System.err.println("\nCould not find class "+classes[i]);
}
return false;
}
}
}
return true;
}
//
// Parsing methods is somewhat more complex.
//
// If we see a class name in the method list, we compile
// all the methods in it.
//
// If we see a method name, we parse it, and then pass it on to
// JIT.compileMethod().
//
private static boolean processPrecompilation(String[] memberNameFiles)
{
int i;
if (!CVM.isCompilerSupported()) {
if (verbose) {
System.err.println("Compiler not supported, cannot precompile");
}
return false;
}
// initialized AOT code
CVM.initializeAOTCode();
for (i = 0; i < memberNamesFiles.length; i++) {
if (verbose) {
System.err.println("membersFile=" + memberNamesFiles[i]);
System.err.println("reading methods...");
}
String methods[] = readLists(memberNamesFiles[i]);
// Parse and precompile
if (methods != null) {
for (int j = 0; j < methods.length; j++) {
// Upon error, fail and return.
if (!parseAndPrecompileMethods(methods[j])) {
CVM.markCodeBuffer(); // mark shared codecache
CVM.initializeJITPolicy();
return false;
}
}
}
}
// mark shared codecache
CVM.markCodeBuffer();
// initialize JIT policy
CVM.initializeJITPolicy();
return true;
}
static private int mLineNo = 1;
private static boolean parseAndPrecompileMethods(String s)
{
// First off replace all '/' by '.'. This saves us the trouble
// of converting these for each signature string found.
s = s.replace('/', '.');
if (s.indexOf('(') == -1) {
// Looks like a class. Check
Class c = getClassFromName(s);
if (c == null) {
if (verbose) {
System.err.println("Class "+s+" not found");
}
return false;
}
// It is a class. Find all of its declared methods...
Method[] cmethods = c.getDeclaredMethods();
if (cmethods == null) {
if (verbose) {
System.err.println("Could not get methods in class "+s);
}
return false;
}
for (int i = 0; i < cmethods.length; i++) {
/* System.err.println(mLineNo+":\t"+cmethods[i]); */
mLineNo++;
if (!JIT.compileMethod(cmethods[i], false)) {
if (verbose) {
System.err.println("Failed to compile "+cmethods[i]);
}
return false;
}
//methods[index].addElement(cmethods[i]);
}
// And find all of its declared constructors...
Constructor[] cconstructors = c.getDeclaredConstructors();
if (cconstructors == null) {
if (verbose) {
System.err.println("Could not get constructors in class "+s);
}
return false;
}
for (int i = 0; i < cconstructors.length; i++) {
/* System.err.println(mLineNo+":\t"+cconstructors[i]); */
mLineNo++;
if (!JIT.compileMethod(cconstructors[i], false)) {
if (verbose) {
System.err.println("Failed to compile "+cconstructors[i]);
}
return false;
}
// methods[index].addElement(cconstructors[i]);
}
} else {
Member m = parseMethod(s);
if (m == null) {
if (verbose) {
System.err.println("Could not find method "+s);
}
return false;
} else {
//DEBUG: System.err.println(mLineNo+":\t"+m);
mLineNo++;
if (!JIT.compileMethod(m, false)) {
if (verbose) {
System.err.println("Failed to compile "+m);
}
return false;
}
}
// methods[index].addElement(m);
}
return true;
}
//
// Parse a string describing a method or constructor, and return a
// Member object
//
private static Member parseMethod(String s)
{
//
// We are looking at a method. Parse that
//
int beginArgs = s.indexOf('(');
int endArgs = s.indexOf(')', beginArgs + 1);
if (endArgs == -1){
if (verbose) {
System.err.println("Missing ')' in "+s);
}
return null;
}
if (false) {
// There is no real need to print out this warning
if (endArgs < s.length() - 1) {
if (verbose) {
System.err.println("Ignoring return type " +
s.substring(endArgs + 1));
}
}
}
int methodDot = s.lastIndexOf('.', beginArgs);
if (methodDot == -1) {
if (verbose) {
System.err.println("Couldn't find method name in "+s);
}
return null;
}
String signature = s.substring(beginArgs, endArgs + 1);
String className = s.substring(0, methodDot);
String methodName = s.substring(methodDot+1, beginArgs);
Class parentClass = getClassFromName(className);
if (parentClass == null) {
if (verbose) {
System.err.println("Class "+className+" not found");
}
return null;
}
Class[] args = parseArglist(signature);
if (args == null) {
if (verbose) {
System.err.println("Could not parse arguments in signature: "+
signature);
}
return null;
}
Member thisMethod = null;
try {
// There is no way to find <clinit> using reflection...
if (methodName.equals("<init>")) {
thisMethod = parentClass.getDeclaredConstructor(args);
} else {
thisMethod = parentClass.getDeclaredMethod(methodName, args);
}
} catch (Throwable t0){
return null;
}
return thisMethod;
}
//
// Given a signature string, return an array of classes for
// each element of the signature, to be used by reflection code.
//
private static Class[] parseArglist(String signature) {
Vector v = new Vector();
int pos = 1;
int endpos = signature.length()-1;
while(pos < endpos){
int arrayDepth = 0;
Class targetClass = null;
while (signature.charAt(pos) == '['){
arrayDepth ++;
pos++;
}
switch (signature.charAt(pos)){
case 'I':
targetClass = Integer.TYPE;
pos++;
break;
case 'S':
targetClass = Short.TYPE;
pos++;
break;
case 'C':
targetClass = Character.TYPE;
pos++;
break;
case 'Z':
targetClass = Boolean.TYPE;
pos++;
break;
case 'B':
targetClass = Byte.TYPE;
pos++;
break;
case 'F':
targetClass = Float.TYPE;
pos++;
break;
case 'D':
targetClass = Double.TYPE;
pos++;
break;
case 'J':
targetClass = Long.TYPE;
pos++;
break;
case 'L':
int semi = signature.indexOf(';', pos);
if (semi == -1){
if (verbose) {
System.err.println("L not followed by ; in "+signature);
}
return null;
}
String targetName;
targetName = signature.substring(pos+1, semi);
targetClass = getClassFromName(targetName);
if (targetClass == null){
if (verbose) {
System.err.println("COULD NOT FIND TARGET="+
targetName);
}
return null;
}
pos = semi+1;
break;
default:
if (verbose) {
System.err.println("Unexpected '" +
signature.charAt(pos) + "' in signature");
}
return null;
}
if (arrayDepth > 0){
// this is grotesque
// make a 1 x 1 x 1 x 1 x 1 x ... array of foo.
// then get its class.
int lArray[] = new int[ arrayDepth ];
for (int i = 0; i < arrayDepth; i++){
lArray[i] = 1;
}
try {
Object arrayOfThing =
java.lang.reflect.Array.newInstance(targetClass,
lArray);
targetClass = arrayOfThing.getClass();
} catch (Throwable t){
if (verbose) {
System.err.println(
"Could not instantiate (or get class of) "+
arrayDepth+ "-dimensional array of "+
targetClass.toString());
}
return null;
}
}
v.addElement(targetClass);
}
Class[] args = new Class[ v.size() ];
v.copyInto(args);
return args;
}
//
// Split path string into separate String components.
//
private static String[] split(String pathString)
{
if (pathString != null) {
StringTokenizer components = new StringTokenizer(pathString,
System.getProperty("path.separator", ":"));
int num = components.countTokens();
String paths[] = new String[num];
for (int i = 0; i < num; i++) {
paths[i] = components.nextToken();
}
return paths;
} else {
return null;
}
}
public static void runit(String cnfs, String mnfs)
{
int i;
// Class name lists
if (cnfs != null && !cnfs.equals(classNamesFileString)) {
classNamesFileString = cnfs;
classNamesFiles = split(cnfs);
}
if (classNamesFiles != null) {
String[] classlist;
for (i = 0; i < classNamesFiles.length; i++) {
if (verbose) {
System.err.println("classesFile=" + classNamesFiles[i]);
System.err.println("reading classes...");
}
classlist = readLists(classNamesFiles[i]);
if (processClasses(classlist)) {
if (verbose) {
System.err.println("processing classes done...");
}
} else {
if (verbose) {
System.err.println("processing classes failed...");
}
}
}
}
// Method lists
if (mnfs != null && !mnfs.equals(memberNamesFileString)) {
memberNamesFileString = mnfs;
memberNamesFiles = split(mnfs);
}
if (memberNamesFiles != null) {
if (processPrecompilation(memberNamesFiles)) {
if (verbose) {
System.err.println("processing methods done...");
}
} else {
if (verbose) {
System.err.println("processing methods failed...");
}
}
}
}
}