/*
* @(#)CompilerTest.java 1.16 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.
*
*/
import java.lang.reflect.*;
import java.util.*;
import sun.misc.JIT;
/*
* A simple class to parse name+signatures on the command line,
* look them up using reflection, and pass to the method compiler.
*
* Examples of use:
* cvm CompilerTest -v 'java.lang.String.length()'
* cvm CompilerTest -n 'java.lang.String.length()' 'java.util.Vector'
* cvm CompilerTest 'java.lang.String.substring(II)'
* cvm CompilerTest 'java.lang.String.regionMatches(ILjava.lang.String;II)'
* cvm CompilerTest 'java.lang.String.regionMatches(ILjava.lang.String;II)'
*
* Passing in a class name finds all methods in the class
* Passing in a method name just finds that method
* Multiple classes and methods can be given on the command line.
* -n just prints out method names, but will not run compiler
*
* Output depends on the compiler.
* The 'verbose' boolean and the CVMMethodBlock* of the indicated method
* are available to it.
*/
public class CompilerTest {
static final int GOOD = 1;
static final int BAD = 0;
static Class getClassFromName(String className){
Class c = null;
try {
c = Class.forName(className, false,
CompilerTest.class.getClassLoader());
} catch (ClassNotFoundException e){
return null;
}
return c;
}
//
// Parse a string describing a method or constructor, and return a
// Member object
//
private 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){
System.err.println("Missing ')' in "+s);
return null;
}
if (endArgs < s.length() - 1) {
System.err.println("Ignoring return type " +
s.substring(endArgs + 1));
}
int methodDot = s.lastIndexOf('.', beginArgs);
if (methodDot == -1) {
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) {
System.err.println("Class "+parentClass+" not found");
return null;
}
Class[] args = parseArglist(signature);
if (args == null) {
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;
}
//
// Parse an input string and add contained methods to a vector of methods.
//
// If the input string is a class (no parens), add all methods in the class
// If the input string is a method, just add it
//
private boolean
parseInputString(String s, Vector[] methods) {
boolean good = true;
if (s.charAt(0) == '~') {
good = false;
s = s.substring(1);
}
s = s.replace('/', '.');
int index = good ? GOOD : BAD;
if (s.indexOf('(') == -1) {
// Looks like a class. Check
Class c = getClassFromName(s);
if (c == null) {
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) {
System.err.println("Could not get methods in class "+s);
return false;
}
for (int i = 0; i < cmethods.length; i++) {
methods[index].addElement(cmethods[i]);
}
// And find all of its declared constructors...
Constructor[] cconstructors = c.getDeclaredConstructors();
if (cconstructors == null) {
System.err.println("Could not get constructors in class "+s);
return false;
}
for (int i = 0; i < cconstructors.length; i++) {
methods[index].addElement(cconstructors[i]);
}
} else {
Member m = parseMethod(s);
if (m == null) {
System.err.println("Could not find method "+s);
return false;
}
methods[index].addElement(m);
}
return true;
}
private 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){
System.err.println("L not followed by ; in "+signature);
return null;
}
targetClass = getClassFromName(signature.substring(pos+1,
semi));
if (targetClass == null){
return null;
}
pos = semi+1;
break;
default:
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){
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;
}
/*
* Read the named file.
* Tokenize the input.
* Returns an array of Strings which are the tokens.
* Propagates FileNotFound if the named file cannot be opened.
* In the input stream, the character '#' is understood
* to start a comment which continues to end-of-line.
*/
private static String[]
parseOptionFile(String fname) throws java.io.IOException {
java.util.Vector v = new java.util.Vector();
java.io.StreamTokenizer in;
in = new java.io.StreamTokenizer(
new java.io.BufferedReader(
new java.io.FileReader(fname)));
in.resetSyntax();
in.eolIsSignificant( false );
in.whitespaceChars( 0, 0x20 );
in.wordChars( '!', '~' );
in.commentChar('#');
while (in.nextToken() != java.io.StreamTokenizer.TT_EOF){
v.addElement(in.sval);
}
int n = v.size();
String olist[] = new String[ n ];
v.copyInto( olist );
return olist;
}
public static void
main(String args[]){
boolean verbose = false;
boolean printOnly = false;
Vector[] methods = new Vector[] {new Vector(), new Vector()};
CompilerTest cd = new CompilerTest();
for (int i = 0; i < args.length; i++){
if (args[i].equals("-v")){
verbose = true;
continue;
} else if (args[i].equals("-n")){
printOnly = true;
continue;
} else if (args[i].equals("-f")){
String filename = args[++i];
try {
String newargs[] = parseOptionFile(filename);
for (int j = 0; j < newargs.length; j++) {
if (!cd.parseInputString(newargs[j], methods)) {
System.err.println("Failed to parse "+newargs[j]);
}
}
} catch (java.io.IOException ioe) {
System.err.println("Failed to process file "+filename);
ioe.printStackTrace();
}
continue;
} else {
// Treat this one as a class or method
if (!cd.parseInputString(args[i], methods)) {
System.err.println("Failed to parse "+args[i]);
}
continue;
}
}
Member[] badMemberArray = new Member[methods[BAD].size()];
methods[BAD].copyInto(badMemberArray);
for (int i = 0; i < badMemberArray.length; i++) {
Member m = badMemberArray[i];
if (!printOnly) {
sun.misc.JIT.neverCompileMethod(m);
} else {
System.err.println("Found method ~"+m);
}
}
Member[] goodMemberArray = new Member[methods[GOOD].size()];
methods[GOOD].copyInto(goodMemberArray);
for (int i = 0; i < goodMemberArray.length; i++) {
Member m = goodMemberArray[i];
if (!printOnly) {
sun.misc.JIT.compileMethod(m, verbose);
} else {
System.err.println("Found method "+m);
}
}
}
}