X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FCompiler.java;fp=src%2Forg%2Fibex%2Fnestedvm%2FCompiler.java;h=de5a04802da8c4174e96345c5027a9b929731da5;hp=0000000000000000000000000000000000000000;hb=c2b2704764af1ade923ba8f15d517b87f9d16189;hpb=90f1aff73ed698ab5992fbd7eb53c1ba7329b1a5 diff --git a/src/org/ibex/nestedvm/Compiler.java b/src/org/ibex/nestedvm/Compiler.java new file mode 100644 index 0000000..de5a048 --- /dev/null +++ b/src/org/ibex/nestedvm/Compiler.java @@ -0,0 +1,539 @@ +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] + +package org.ibex.nestedvm; + +import java.util.*; +import java.io.*; + +import org.ibex.nestedvm.util.*; + +public abstract class Compiler implements Registers { + /** The ELF binary being read */ + protected ELF elf; + + /** The name of the class beging generated */ + protected final String fullClassName; + + /** The name of the binary this class is begin generated from */ + protected String source = "unknown.mips.binary"; + public void setSource(String source) { this.source = source; } + + /** Thrown when the compilation fails for some reason */ + protected static class Exn extends Exception { public Exn(String s) { super(s); } } + + // Set this to true to enable fast memory access + // When this is enabled a Java RuntimeException will be thrown when a page fault occures. When it is disabled + // a FaultException will be throw which is easier to catch and deal with, however. as the name implies, this is slower + protected boolean fastMem = true; + + // This MUST be a power of two. If it is not horrible things will happen + // NOTE: This value can be much higher without breaking the classfile + // specs (around 1024) but Hotstop seems to do much better with smaller + // methods. + protected int maxInsnPerMethod = 128; + + // non-configurable + protected int maxBytesPerMethod; + protected int methodMask; + protected int methodShift; + protected void maxInsnPerMethodInit() throws Exn { + if((maxInsnPerMethod&(maxInsnPerMethod-1)) != 0) throw new Exn("maxBytesPerMethod is not a power of two"); + maxBytesPerMethod = maxInsnPerMethod*4; + methodMask = ~(maxBytesPerMethod-1); + while(maxBytesPerMethod>>>methodShift != 1) methodShift++; + } + + // True to try to determine which case statement are needed and only include them + protected boolean pruneCases = true; + + protected boolean assumeTailCalls = true; + + protected boolean optimizedMemcpy = true; + + // True to insert some code in the output to help diagnore compiler problems + protected boolean debugCompiler = false; + + // True to print various statistics about the compilation + protected boolean printStats = false; + + // True to generate runtime statistics that slow execution down significantly + protected boolean runtimeStats = false; + + protected boolean supportCall = true; + + protected boolean nullPointerCheck = false; + + protected String runtimeClass = "org.ibex.nestedvm.Runtime"; + + protected String hashClass = "java.util.Hashtable"; + + protected boolean unixRuntime; + + protected boolean lessConstants = false; + + protected int pageSize = 4096; + protected int totalPages = 65536; + protected int pageShift; + protected boolean onePage; + + protected void pageSizeInit() throws Exn { + try { + Runtime.checkPageSize(pageSize,totalPages); + } catch(IllegalArgumentException e) { + throw new Exn(e.getMessage()); + } + while(pageSize>>>pageShift != 1) pageShift++; + } + + /** The address of the memcpy function in the binary (used for optimizedMemcpy) */ + protected int memcpy; + + /** The address of the memset function in the binary (used for optimizedMemcpy) */ + protected int memset; + + /** A set of all addresses that can be jumped too (only available if pruneCases == true) */ + protected Set jumpableAddresses; + + /** Some important symbols */ + ELF.Symbol userInfo, gp; + + private static void usage() { + System.err.println("Usage: java Compiler [-outfile output.java] [-o options] [-dumpoptions] "); + System.err.println("-o takes mount(8) like options and can be specified multiple times"); + System.err.println("Available options:"); + for(int i=0;i 0) { + if(args[arg].equals("-outfile")) { + arg++; + if(arg==args.length) usage(); + outfile = args[arg]; + } else if(args[arg].equals("-outformat")) { + arg++; + if(arg==args.length) usage(); + outformat = args[arg]; + } else if(args[arg].equals("-o")) { + arg++; + if(arg==args.length) usage(); + if(o==null || o.length() == 0) + o = args[arg]; + else if(args[arg].length() != 0) + o += "," + args[arg]; + } else if(args[arg].equals("-dumpoptions")) { + dumpOptions = true; + } else if(className == null) { + className = args[arg]; + } else if(mipsBinaryFileName == null) { + mipsBinaryFileName = args[arg]; + } else { + usage(); + } + arg++; + } + if(className == null || mipsBinaryFileName == null) usage(); + + Seekable mipsBinary = new Seekable.File(mipsBinaryFileName); + + Writer w = null; + OutputStream os = null; + Compiler comp = null; + if(outformat == null || outformat.equals("class")) { + if(outfile == null) { + System.err.println("Refusing to write a classfile to stdout - use -outfile foo.class"); + System.exit(1); + } + os = new FileOutputStream(outfile); + comp = new ClassFileCompiler(mipsBinary,className,os); + } else if(outformat.equals("javasource") || outformat .equals("java")) { + w = outfile == null ? new OutputStreamWriter(System.out): new FileWriter(outfile); + comp = new JavaSourceCompiler(mipsBinary,className,w); + } else { + System.err.println("Unknown output format: " + outformat); + System.exit(1); + } + + comp.parseOptions(o); + comp.setSource(mipsBinaryFileName); + + if(dumpOptions) { + System.err.println("== Options =="); + for(int i=0;i>> 26) & 0xff; + int rs = (insn >>> 21) & 0x1f; + int rt = (insn >>> 16) & 0x1f; + int signedImmediate = (insn << 16) >> 16; + int unsignedImmediate = insn & 0xffff; + int branchTarget = signedImmediate; + int jumpTarget = (insn & 0x03ffffff); + int subcode = insn & 0x3f; + + switch(op) { + case 0: + switch(subcode) { + case 9: // JALR + if(jumps.add(new Integer(pc+8))) n++; // return address + break; + case 12: // SYSCALL + if(jumps.add(new Integer(pc+4))) n++; + break; + } + break; + case 1: + switch(rt) { + case 16: // BLTZAL + case 17: // BGTZAL + if(jumps.add(new Integer(pc+8))) n++; // return address + // fall through + case 0: // BLTZ + case 1: // BGEZ + if(jumps.add(new Integer(pc+branchTarget*4+4))) n++; + break; + } + break; + case 3: // JAL + if(jumps.add(new Integer(pc+8))) n++; // return address + // fall through + case 2: // J + if(jumps.add(new Integer((pc&0xf0000000)|(jumpTarget << 2)))) n++; + break; + case 4: // BEQ + case 5: // BNE + case 6: // BLEZ + case 7: // BGTZ + if(jumps.add(new Integer(pc+branchTarget*4+4))) n++; + break; + case 9: { // ADDIU + if(pc - lui_pc[rs] <= 4*32) { + int t = (lui_val[rs]<<16)+signedImmediate; + if((t&3)==0 && t >= base && t < base+size) { + if(jumps.add(new Integer(t))) { + //System.err.println("Possible jump to " + toHex(t) + " (" + inter.sourceLine(t) + ") from " + toHex(pc) + " (" + inter.sourceLine(pc) + ")"); + n++; + } + } + // we just blew it away + if(rt == rs) lui_pc[rs] = 0; + } + break; + } + case 15: { // LUI + lui_val[rt] = unsignedImmediate; + lui_pc[rt] = pc; + break; + } + + case 17: // FPU Instructions + switch(rs) { + case 8: // BC1F, BC1T + if(jumps.add(new Integer(pc+branchTarget*4+4))) n++; + break; + } + break; + } + } + dis.close(); + if(printStats) System.err.println("Found " + n + " additional possible branch targets in Text segment"); + } + + private void findBranchesInData(DataInputStream dis, int size, Set jumps, int textStart, int textEnd) throws IOException { + int count = size/4; + int n=0; + for(int i=0;i= textStart && word < textEnd) { + if(jumps.add(new Integer(word))) { + //System.err.println("Added " + toHex(word) + " as possible branch target (fron data segment)"); + n++; + } + } + } + dis.close(); + if(n>0 && printStats) System.err.println("Found " + n + " additional possible branch targets in Data segment"); + } + + // Helper functions for pretty output + protected final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); } + protected final static String toHex8(int n) { + String s = Long.toString(n & 0xffffffffL, 16); + StringBuffer sb = new StringBuffer("0x"); + for(int i=8-s.length();i>0;i--) sb.append('0'); + sb.append(s); + return sb.toString(); + } + + protected final static String toOctal3(int n) { + char[] buf = new char[3]; + for(int i=2;i>=0;i--) { + buf[i] = (char) ('0' + (n & 7)); + n >>= 3; + } + return new String(buf); + } + + // Option parsing + private class Option { + private java.lang.reflect.Field field; + public Option(String name) throws NoSuchFieldException { field = name==null ? null : Compiler.class.getDeclaredField(name); } + public void set(Object val) { + if(field == null) return; + try { + field.setAccessible(true); + field.set(Compiler.this,val); + } catch(IllegalAccessException e) { + System.err.println(e); + } + } + public Object get() { + if(field == null) return null; + try { + field.setAccessible(true); + return field.get(Compiler.this); + } catch(IllegalAccessException e) { + System.err.println(e); return null; + } + } + public Class getType() { return field == null ? null : field.getType(); } + } + + private static String[] options = { + "fastMem", "Enable fast memory access - RuntimeExceptions will be thrown on faults", + "nullPointerCheck", "Enables checking at runtime for null pointer accessses (slows things down a bit, only applicable with fastMem)", + "maxInsnPerMethod", "Maximum number of MIPS instructions per java method (128 is optimal with Hotspot)", + "pruneCases", "Remove unnecessary case 0xAABCCDD blocks from methods - may break some weird code", + "assumeTailCalls", "Assume the JIT optimizes tail calls", + "optimizedMemcpy", "Use an optimized java version of memcpy where possible", + "debugCompiler", "Output information in the generated code for debugging the compiler - will slow down generated code significantly", + "printStats", "Output some useful statistics about the compilation", + "runtimeStats", "Keep track of some statistics at runtime in the generated code - will slow down generated code significantly", + "supportCall", "Keep a stripped down version of the symbol table in the generated code to support the call() method", + "runtimeClass", "Full classname of the Runtime class (default: Runtime) - use this is you put Runtime in a package", + "hashClass", "Full classname of a Hashtable class (default: java.util.HashMap) - this must support get() and put()", + "unixRuntime", "Use the UnixRuntime (has support for fork, wai, du, pipe, etc)", + "pageSize", "The page size (must be a power of two)", + "totalPages", "Total number of pages (total mem = pageSize*totalPages, must be a power of two)", + "onePage", "One page hack (FIXME: document this better)", + "lessConstants", "Use less constants at the cost of speed (FIXME: document this better)" + }; + + private Option getOption(String name) { + name = name.toLowerCase(); + try { + for(int i=0;i 2 && s.startsWith("0x")) n = Integer.parseInt(s.substring(2),16); + else n = Integer.parseInt(s); + return new Integer(n*mult); + } + + private static String wrapAndIndent(String s, int firstindent, int indent, int width) { + StringTokenizer st = new StringTokenizer(s," "); + StringBuffer sb = new StringBuffer(); + for(int i=0;i width && sofar > 0) { + sb.append('\n'); + for(int i=0;i 0) { + sb.append(' '); + sofar++; + } + sb.append(tok); + sofar += tok.length(); + } + sb.append('\n'); + return sb.toString(); + } + + // This ugliness is to work around a gcj static linking bug (Bug 12908) + // The best solution is to force gnu.java.locale.Calendar to be linked in but this'll do + protected static String dateTime() { + try { + return new Date().toString(); + } catch(RuntimeException e) { + return ""; + } + } +} +