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 + -
显示快捷键?