genopcodes.java

来自「This is a resource based on j2me embedde」· Java 代码 · 共 1,011 行 · 第 1/2 页

JAVA
1,011
字号
/* * @(#)GenOpcodes.java	1.36 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.  * *//* * GenOpcodes is a program for reading the file * src/share/javavm/include/opcodes.list and deriving from it "source" * files for building a Java Virtual Machine and associated tools. * * The format of opcodes.list is explained in that * file, which I quote here: * * # * # Any line that doesn't have a-z in the 1st column is a comment. * # * # The first column is the name of the opcode. * # * # The second column is the opcode's number, or "-" to assign the * # next available sequential number. * # * # The third column is the total length of the instruction.  We use 0 * # for opcodes of variable length, as well as unrecognized/unused * # opcodes. * # * # The fourth and fifth column give what the opcode pops off the stack, and * # what it then pushes back onto the stack * #    -       <no effect on stack>    * #    I       integer * #    L       long integer * #    F       float * #    D       double float * #    A       address [array or object] * #    O       object only * #    R       return address (for jsr) * #    a       integer, array, or object * #    ?       unknown * #    [I], [L], [F], [D], [A], [B], [C], [?] * #            array of integer, long, float, double, address, bytes,  * #                  chars, or anything * #    1,2,3,4,+ used by stack duplicating/popping routines.   * #  * # 1,2,3,4 represent >>any<< stack type except long or double.  Two numbers * # separated by a + (in the third column) indicate that the two, together, can * # be used for a double or long.  (Or they can represent two non-long items). * # * # The sixth column has a comma-separated list of attributes of the * # opcode. These are necessary in the stackmap computation dataflow  * # analysis. * # * # GC    -- a GC point * # CGC   -- a conditional GC point; only if the thread is at a quickening point * # BR    -- a branch * # EXC   -- May throw exception * # INV   -- A method invocation * # NFLW  -- An instruction that doesn't let control flow through * #           (returns, athrow, switches, goto, ret) * # QUICK -- A quick instruction, re-written by the interpreter. * # RET   -- A return opcode. * # FP    -- A floating point opcode * # -     -- No special attributes to speak of * #             * # The seventh column is a "simplification" of the opcode, for opcode * # sequence measurements (see CVM_INSTRUCTION_COUNTING in executejava.c). * # * # The eigth column has the attribute of CVMJITIROpcodeTag. * # The ninth column has the attribute of type tag listed in typeid.h. * # The tenth column has the attribute of value representing constant value, * # local variable number, etc. *  * The general flow of this program is: * - parse command-line arguments and instantiate output file writers * - read input file. For each non-commentary line of input * 	- parse the line into words * 	- create an Opcode with the line's information and save it *        in an ordered list of Opcodes. * - call each writer to write the Opcodes to its file. *  * The output file writers are all implementations of interface FileGenerator. * Most of them subclass FileGenOpcodeWriter, which contains some useful * methods and fields. Their names are all of the form XXXGenOpcodeWriter, * and they are instantiated when the command-line argument -XXX is * seen. Adding another one is easy by following the pattern. Just don't forget * to update the usage message as well! * * One special note on output file writing: all the output file writers I provide * use util.FileCompare.ConditionalCopy to avoid touching derived files that * are unchanged. This is intended to avoid re-compiling due to extraneous * file date changes when you are using make/gnumake/something-like-make. * You may or may not desire this behavior. */import java.io.BufferedReader;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.FileReader;import java.io.IOException;import java.io.PrintStream;import java.util.StringTokenizer;import util.BufferedPrintStream;class GenOpcodes{    private static final String[] _usage = {	"usage: java GenOpcodes input_file_name [ opt target_file_name ]+",	"	where opt is a flavor of output file. Choices are:",	"	-h	- C header file, generally opcodes.h",	"	-c	- C file containing CVMopnames",	"	-bcAttr	- C file containing CVMbcAttributes",	"	-opcodeMap - C file containing CVMJITOpcodeMap",	"	-opcodeLengths - C file containing CVMopcodeLengths",	"	-simplification - C file containing CVMopcodeSimplification",	"	-label	- #defines for use in executejava label array",	"	-javaConst - Java class OpcodeConst"    };    private static String		_inFileName;    private static FileGenerator[]	_fileGenerators;    /*     * Main entry point. If there are too few arguments, print a      * usage message. Otherwise, parse the arguments. If successful,     * process the input file. Return status appropriately.     */    public static void main(String[] args) {	processArgs(args);	try {	    // Read in the opcodes.	    Opcode[] opcodes = readOpcodes(_inFileName);	    // Run each generator.	    for (int i = 0; i < _fileGenerators.length; i++) {		_fileGenerators[i].processOpcodes(opcodes);	    }	    System.exit(0);	} catch (GenOpcodesException ex) {	    System.err.println("GenOpcodes: " + ex.getMessage());	    ex.printStackTrace(System.err);	    System.exit(1);	}    }    private static void printUsage() {	for (int i = 0; i < _usage.length; i++) {	    System.err.println(_usage[i]);	}    }    /*     * Parse command-line arguments.     * Instantiate output writers and init them.     */    private static void processArgs(String[] args) {	/* The first argument is the incoming opcodes definition file	   (required).  Subsequent arguments are {-<output file type>	   <output file name>} pairs where at least one pair is	   specified.  So we expect at least three arguments, and the	   number of arguments must not be even. */	if (args.length < 3 || (args.length % 2) == 0) {	    printUsage();	    System.exit(1);	}	_inFileName = args[0];	if (_inFileName.length() == 0 || _inFileName.charAt(0) == '-') {	    System.err.println("Warning: treating \"" + _inFileName +			       "\" as a file name");	}	_fileGenerators = new FileGenerator[args.length / 2];	for (int i = 1; i < args.length; i += 2) {	    String arg = args[i];	    if (arg.charAt(0) != '-') {		System.err.println("Command line argument \"" + arg +				   "\" unexpected");		printUsage();		System.exit(1);	    }	    // The name of the output writer class we are going to	    // instantiate is the option name (without leading -)	    // capitalized and concatenated with "GenOpcodeWriter".	    // It is also an inner class of GenOpcodes.	    // Thus the option "-c" causes us to instantiate a	    // "GenOpcodes$CGenOpcodeWriter".	    String fileGeneratorName = "GenOpcodes$" +		Character.toUpperCase(arg.charAt(1)) + arg.substring(2) +		"GenOpcodeWriter";	    Class fileGeneratorClass;	    try {		fileGeneratorClass = Class.forName(fileGeneratorName);	    } catch (ClassNotFoundException ex) {		System.err.println("\"" + arg + "\" not supported:\n" + ex);		printUsage();		System.exit(1);		return;	    }	    FileGenerator fileGenerator;	    try {		fileGenerator =		    (FileGenerator) fileGeneratorClass.newInstance();	    } catch (InstantiationException ex) {		System.err.println("Error instantiating " + fileGeneratorName +				   ":\n" + ex);		printUsage();		System.exit(1);		return;	    } catch (IllegalAccessException ex) {		System.err.println("Error instantiating " + fileGeneratorName +				   ":\n" + ex);		printUsage();		System.exit(1);		return;	    }	    fileGenerator.init(args[i + 1]);	    _fileGenerators[i / 2] = fileGenerator;	}    }    /*     * Reads in all the opcodes and returns an array of 256 Opcodes.     * Array elements with no assigned Opcode will be null.     */    private static Opcode[] readOpcodes(String filename)	throws GenOpcodesException {	Opcode[] opcodes = new Opcode[256];	int nextOpcodeNo = 0;	BufferedReader in;	try {	    in = new BufferedReader(new FileReader(filename));	} catch (FileNotFoundException ex) {	    throw new GenOpcodesException(		"Error opening " + filename + ".", ex);	}	while (true) {	    String line;	    try {		line = in.readLine();	    } catch (IOException ex) {		throw new GenOpcodesException(		    "Error reading " + filename + ".", ex);	    }	    if (line == null) {		// EOF.		break;	    }	    // Skip comments and blank lines.	    if (line.length() == 0 || !Character.isLetter(line.charAt(0))) {		continue;	    }	    // Extract the fields.	    StringTokenizer st = new StringTokenizer(line);	    String name = st.nextToken();	    String number = st.nextToken();	    String length = st.nextToken();	    st.nextToken();	// pops	    st.nextToken();	// pushes	    String[] attributes = parseAttributes(st.nextToken());	    String simplification = st.nextToken();	    String tag = st.nextToken();	    String typeid = st.nextToken();	    String value = st.nextToken();	    // Advance to the next unused opcode number.	    while (opcodes[nextOpcodeNo] != null) {		nextOpcodeNo++;	    }	    // If an opcode number is given then use it, else use	    // the next available opcode number.	    int opcodeNo;	    boolean assigned;	    if (number.equals("-")) {		if (nextOpcodeNo > 253) {		    throw new GenOpcodesException(			"Too many opcodes (> 253).");		}		opcodeNo = nextOpcodeNo;		assigned = false;	    } else {		try {		    opcodeNo = Integer.parseInt(number);		} catch (NumberFormatException ex) {		    throw new GenOpcodesException(			"Bad opcode number " + number +			" for opcode " + name, ex);		}		if (opcodeNo < 0 || opcodeNo > 253) {		    throw new GenOpcodesException(			"Opcode number " + number +			" for opcode " + name +			" must be in the range 0 - 253");		}		assigned = true;		// If opcodeNo is in use by another Opcode then move		// it out of the way, unless it was explicitly		// assigned.		Opcode opcode = opcodes[opcodeNo];		if (opcode != null) {		    if (opcode.isAssigned()) {			throw new GenOpcodesException(			    "Opcode number " + opcodeNo +			    " has already been assigned.");		    }		    if (nextOpcodeNo > 253) {			throw new GenOpcodesException(			    "Too many opcodes (> 253).");		    }		    opcodes[nextOpcodeNo] = opcode;		}	    }	    opcodes[opcodeNo] = new Opcode(		assigned,		name,		length,		attributes,		simplification,		tag,		typeid,		value);	}	return opcodes;    }    /*     * Converts a comma-separated list of attributes to a String[] of     * attributes.     */    private static String[] parseAttributes(String attributes) {	StringTokenizer st = new StringTokenizer(attributes, ",");	String[] result = new String[st.countTokens()];	for (int i = 0; i < result.length; i++) {	    result[i] = st.nextToken();	}	return result;    }    /*     * FileGenerator is the interface between the GenOpcode driver and     * the individual output writers.     */    private interface FileGenerator    {	/*	 * init is called immediately after instantiation, with the	 * file name command-line argument. Do not open the file yet!	 * If any other error occurs during command-line processing,	 * the program will exit without further ado.	 */	public void init(String fileName);	/*	 * Processes and writes all the opcodes.	 */	public void processOpcodes(Opcode[] opcodes)	    throws GenOpcodesException;    }    /*     * FileGenOpcodeWriter is used to implement common functions     * in most (or all) of the output writers. It does file opening     * and closing, temporary file management and conditional copying.     */    private static abstract class FileGenOpcodeWriter implements FileGenerator    {	private final String[] _prolog;	private final String[] _epilog;	private String _destFileName;	private File _destFile;	// Actual file to create.	private File _outFile;	// Temporary file to write to.	private PrintStream _out;	protected FileGenOpcodeWriter(String[] prolog, String[] epilog) {	    _prolog = prolog;	    _epilog = epilog;	}	/*	 * This init method just saves the file name.	 */	public void init(String destFileName) {	    _destFileName = destFileName;	}	public void processOpcodes(Opcode[] opcodes)	    throws GenOpcodesException {	    start();	    processAllOpcodes(opcodes);	    done();	}	/**	 * Processes all opcodes.  Subclasses may override this.	 */	protected void processAllOpcodes(Opcode[] opcodes) {	    for (int i = 0; i < opcodes.length; i++) {		processOneOpcode(i, opcodes[i]);	    }	}	/**	 * Processes one opcode.  This is what subclasses will usually	 * need to override.	 */	protected void processOneOpcode(int ordinal, Opcode opcode) {}	private void start() throws GenOpcodesException {	    openFile();	    printBlock(_prolog);	}	private void openFile() throws GenOpcodesException {	    _destFile = new File(_destFileName);	    if (_destFile.exists()) {		_outFile = new File(_destFileName + ".TMP");	    } else {		_outFile = _destFile;	    }	    try {		_out = new BufferedPrintStream(new FileOutputStream(_outFile));	    } catch (IOException ex) {		throw new GenOpcodesException(		    "Could not open output file " + _outFile, ex);	    }	}	private void done() {	    printBlock(_epilog);	    closeFile();	}	/*	 * Close output stream, do conditional copy to final	 * destination if the output file isn't the destination file.	 */	private void closeFile() {	    _out.close();	    if (_destFile != _outFile) {		util.FileCompare.conditionalCopy(_outFile, _destFile);		_outFile.delete();	    }	}	/*	 * Prints a String[], a common operation when writing 	 * file prolog/epilog.	 */	private void printBlock(String[] block) {	    for (int i = 0; i < block.length; i++) {		_out.println(block[i]);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?