clarify licensing
[nestedvm.git] / src / org / ibex / nestedvm / Compiler.java
index 68d2dee..acf1c48 100644 (file)
@@ -1,4 +1,6 @@
-// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL]
+// Copyright 2000-2005 the Contributors, as shown in the revision logs.
+// Licensed under the Apache License 2.0 ("the License").
+// You may not use this file except in compliance with the License.
 
 package org.ibex.nestedvm;
 
@@ -7,38 +9,36 @@ import java.io.*;
 
 import org.ibex.nestedvm.util.*;
 
-// FEATURE: -d option for classfilecompiler (just like javac's -d)
-
 public abstract class Compiler implements Registers {    
     /** The ELF binary being read */
-    protected ELF elf;
+    ELF elf;
     
     /** The name of the class beging generated */
-    protected final String fullClassName;
+    final String fullClassName;
     
     /** The name of the binary this class is begin generated from */
-    protected String source = "unknown.mips.binary";
+    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); } }
+    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;
+    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;
+    int maxInsnPerMethod = 128;
     
     // non-configurable
-    protected int maxBytesPerMethod;
-    protected int methodMask;
-    protected int methodShift;
-    protected void maxInsnPerMethodInit() throws Exn {
+    int maxBytesPerMethod;
+    int methodMask;
+    int methodShift;
+    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);
@@ -46,52 +46,46 @@ public abstract class Compiler implements Registers {
     }
     
     // True to try to determine which case statement are needed and only include them
-    protected boolean pruneCases = true;
-    
-    protected boolean assumeTailCalls = true;
+    boolean pruneCases = true;
     
-    protected boolean optimizedMemcpy = true;
+    boolean assumeTailCalls = true;
     
     // True to insert some code in the output to help diagnore compiler problems
-    protected boolean debugCompiler = false;
+    boolean debugCompiler = false;
     
     // True to print various statistics about the compilation
-    protected boolean printStats = false;
+    boolean printStats = false;
     
     // True to generate runtime statistics that slow execution down significantly
-    protected boolean runtimeStats = false;
+    boolean runtimeStats = false;
+    
+    boolean supportCall = true;
     
-    protected boolean supportCall = true;
+    boolean nullPointerCheck = false;
     
-    protected boolean nullPointerCheck = false;
+    String runtimeClass = "org.ibex.nestedvm.Runtime";
     
-    protected String runtimeClass = "org.ibex.nestedvm.Runtime";
+    String hashClass = "java.util.Hashtable";
     
-    protected String hashClass = "java.util.Hashtable";
+    boolean unixRuntime;
     
-    protected boolean unixRuntime;
+    boolean lessConstants;
     
-    protected boolean lessConstants = false;
+    boolean singleFloat;
             
-    protected int pageSize = 4096;
-    protected int totalPages = 65536;
-    protected int pageShift;
-    protected boolean onePage;
+    int pageSize = 4096;
+    int totalPages = 65536;
+    int pageShift;
+    boolean onePage;
     
-    protected void pageSizeInit() throws Exn {
+    void pageSizeInit() throws Exn {
         if((pageSize&(pageSize-1)) != 0) throw new Exn("pageSize not a multiple of two");
         if((totalPages&(totalPages-1)) != 0) throw new Exn("totalPages not a multiple of two");
         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;
+    Hashtable jumpableAddresses;
     
     /** Some important symbols */
     ELF.Symbol userInfo, gp;
@@ -107,6 +101,7 @@ public abstract class Compiler implements Registers {
     
     public static void main(String[] args) throws IOException {
         String outfile = null;
+        String outdir = null;
         String o = null;
         String className = null;
         String mipsBinaryFileName = null;
@@ -118,6 +113,10 @@ public abstract class Compiler implements Registers {
                 arg++;
                 if(arg==args.length) usage();
                 outfile = args[arg];
+            } else if(args[arg].equals("-d")) {
+                arg++;
+                if(arg==args.length) usage();
+                outdir = args[arg];
             } else if(args[arg].equals("-outformat")) {
                 arg++;
                 if(arg==args.length) usage();
@@ -148,12 +147,20 @@ public abstract class Compiler implements Registers {
         OutputStream os = null;
         Compiler comp = null;
         if(outformat == null || outformat.equals("class")) {
-            if(outfile == null) {
+            if(outfile != null) {
+                os = new FileOutputStream(outfile);
+                comp = new ClassFileCompiler(mipsBinary,className,os);
+            } else if(outdir != null) {
+                File f = new File(outdir);
+                if(!f.isDirectory()) {
+                    System.err.println(outdir + " doesn't exist or is not a directory");
+                    System.exit(1);
+                }
+                comp = new ClassFileCompiler(mipsBinary,className,f);
+            } else {
                 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);
@@ -187,12 +194,12 @@ public abstract class Compiler implements Registers {
         this.fullClassName = fullClassName;
         elf = new ELF(binary);
         
-        if(elf.header.type != ELF.ELFHeader.ET_EXEC) throw new IOException("Binary is not an executable");
-        if(elf.header.machine != ELF.ELFHeader.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture");
-        if(elf.ident.data != ELF.ELFIdent.ELFDATA2MSB) throw new IOException("Binary is not big endian");
+        if(elf.header.type != ELF.ET_EXEC) throw new IOException("Binary is not an executable");
+        if(elf.header.machine != ELF.EM_MIPS) throw new IOException("Binary is not for the MIPS I Architecture");
+        if(elf.ident.data != ELF.ELFDATA2MSB) throw new IOException("Binary is not big endian");
     }
 
-    protected abstract void _go() throws Exn, IOException;
+    abstract void _go() throws Exn, IOException;
     
     private boolean used;
     public void go() throws Exn, IOException {
@@ -213,22 +220,15 @@ public abstract class Compiler implements Registers {
         if(symtab == null) throw new Exn("Binary has no symtab (did you strip it?)");
         ELF.Symbol sym;
         
-        // Check for some functions we can override
-        sym = symtab.getGlobalSymbol("memcpy");
-        memcpy = sym == null ? -1 : sym.addr;
-        
-        sym = symtab.getGlobalSymbol("memset");
-        memset = sym == null ? -1 : sym.addr;
-        
         userInfo = symtab.getGlobalSymbol("user_info");
         gp = symtab.getGlobalSymbol("_gp");
         if(gp == null) throw new Exn("no _gp symbol (did you strip the binary?)");   
         
         if(pruneCases) {
             // Find all possible branches
-            jumpableAddresses = new HashSet();
+            jumpableAddresses = new Hashtable();
             
-            jumpableAddresses.add(new Integer(elf.header.entry));
+            jumpableAddresses.put(new Integer(elf.header.entry),Boolean.TRUE);
             
             ELF.SHeader text = elf.sectionWithName(".text");
             if(text == null) throw new Exn("No .text segment");
@@ -251,7 +251,7 @@ public abstract class Compiler implements Registers {
         
         for(int i=0;i<elf.sheaders.length;i++) {
             String name = elf.sheaders[i].name;
-            if(elf.sheaders[i].addr != 0 && !(
+            if((elf.sheaders[i].flags & ELF.SHF_ALLOC) !=0 && !(
                 name.equals(".text")|| name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") ||
                 name.equals(".ctors") || name.equals(".dtors") || name.equals(".bss") || name.equals(".sbss")))
                     throw new Exn("Unknown section: " + name);
@@ -259,13 +259,13 @@ public abstract class Compiler implements Registers {
         _go();
     }
     
-    private void findBranchesInSymtab(ELF.Symtab symtab, Set jumps) {
+    private void findBranchesInSymtab(ELF.Symtab symtab, Hashtable jumps) {
         ELF.Symbol[] symbols = symtab.symbols;
         int n=0;
         for(int i=0;i<symbols.length;i++) {
             ELF.Symbol s = symbols[i];
             if(s.type == ELF.Symbol.STT_FUNC) {
-                if(jumps.add(new Integer(s.addr))) {
+                if(jumps.put(new Integer(s.addr),Boolean.TRUE) == null) {
                     //System.err.println("Adding symbol from symtab: " + s.name + " at " + toHex(s.addr));
                     n++;
                 }
@@ -274,7 +274,7 @@ public abstract class Compiler implements Registers {
         if(printStats) System.err.println("Found " + n + " additional possible branch targets in Symtab");
     }
     
-    private void findBranchesInText(int base, DataInputStream dis, int size, Set jumps) throws IOException {
+    private void findBranchesInText(int base, DataInputStream dis, int size, Hashtable jumps) throws IOException {
         int count = size/4;
         int pc = base;
         int n=0;
@@ -297,10 +297,10 @@ public abstract class Compiler implements Registers {
                 case 0:
                     switch(subcode) {
                         case 9: // JALR
-                            if(jumps.add(new Integer(pc+8))) n++; // return address
+                            if(jumps.put(new Integer(pc+8),Boolean.TRUE) == null) n++; // return address
                             break;
                         case 12: // SYSCALL
-                            if(jumps.add(new Integer(pc+4))) n++; 
+                            if(jumps.put(new Integer(pc+4),Boolean.TRUE) == null) n++; 
                             break;
                     }
                     break;
@@ -308,31 +308,31 @@ public abstract class Compiler implements Registers {
                     switch(rt) {
                         case 16: // BLTZAL
                         case 17: // BGTZAL
-                            if(jumps.add(new Integer(pc+8))) n++; // return address
+                            if(jumps.put(new Integer(pc+8),Boolean.TRUE) == null) n++; // return address
                             // fall through
                         case 0: // BLTZ
                         case 1: // BGEZ
-                            if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
+                            if(jumps.put(new Integer(pc+branchTarget*4+4),Boolean.TRUE) == null) n++;
                             break;
                     }
                     break;
                 case 3: // JAL
-                    if(jumps.add(new Integer(pc+8))) n++; // return address
+                    if(jumps.put(new Integer(pc+8),Boolean.TRUE) == null) n++; // return address
                     // fall through
                 case 2: // J
-                    if(jumps.add(new Integer((pc&0xf0000000)|(jumpTarget << 2)))) n++;
+                    if(jumps.put(new Integer((pc&0xf0000000)|(jumpTarget << 2)),Boolean.TRUE) == null) n++;
                     break;
                 case 4: // BEQ
                 case 5: // BNE
                 case 6: // BLEZ
                 case 7: // BGTZ
-                    if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
+                    if(jumps.put(new Integer(pc+branchTarget*4+4),Boolean.TRUE) == null) 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))) {
+                            if(jumps.put(new Integer(t),Boolean.TRUE) == null) {
                                 //System.err.println("Possible jump to " + toHex(t) + " (" + inter.sourceLine(t) + ") from " + toHex(pc) + " (" + inter.sourceLine(pc) + ")");
                                 n++;
                             }
@@ -351,7 +351,7 @@ public abstract class Compiler implements Registers {
                 case 17: // FPU Instructions
                     switch(rs) {
                         case 8: // BC1F, BC1T
-                            if(jumps.add(new Integer(pc+branchTarget*4+4))) n++;
+                            if(jumps.put(new Integer(pc+branchTarget*4+4),Boolean.TRUE) == null) n++;
                             break;
                     }
                     break;
@@ -361,13 +361,13 @@ public abstract class Compiler implements Registers {
         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 {
+    private void findBranchesInData(DataInputStream dis, int size, Hashtable jumps, int textStart, int textEnd) throws IOException {
         int count = size/4;
         int n=0;
         for(int i=0;i<count;i++) {
             int word = dis.readInt();
             if((word&3)==0 && word >= textStart && word < textEnd) {
-                if(jumps.add(new Integer(word))) {
+                if(jumps.put(new Integer(word),Boolean.TRUE) == null) {
                     //System.err.println("Added " + toHex(word) + " as possible branch target (fron data segment)");
                     n++;
                 }
@@ -378,8 +378,8 @@ public abstract class Compiler implements Registers {
     }
     
     // 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) {
+    final static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
+    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');
@@ -387,7 +387,7 @@ public abstract class Compiler implements Registers {
         return sb.toString();
     }
 
-    protected final static String toOctal3(int n) {
+    final static String toOctal3(int n) {
         char[] buf = new char[3];
         for(int i=2;i>=0;i--) {
             buf[i] = (char) ('0' + (n & 7));
@@ -403,7 +403,7 @@ public abstract class Compiler implements Registers {
         public void set(Object val) {
             if(field == null) return;
             try {
-                field.setAccessible(true);
+                /*field.setAccessible(true); NOT in JDK 1.1 */
                 field.set(Compiler.this,val);
             } catch(IllegalAccessException e) {
                 System.err.println(e);
@@ -412,7 +412,7 @@ public abstract class Compiler implements Registers {
         public Object get() {
             if(field == null) return null;
             try {
-                field.setAccessible(true);
+                /*field.setAccessible(true); NOT in JDK 1.1 */
                 return field.get(Compiler.this);
             } catch(IllegalAccessException e) {
                 System.err.println(e); return null;
@@ -438,7 +438,8 @@ public abstract class Compiler implements Registers {
         "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)"
+        "lessConstants",    "Use less constants at the cost of speed (FIXME: document this better)",
+        "singleFloat",      "Support single precision (32-bit) FP ops only"
     };
         
     private Option getOption(String name) {
@@ -527,7 +528,7 @@ public abstract class Compiler implements Registers {
     
     // 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() {
+    static String dateTime() {
         try {
             return new Date().toString();
         } catch(RuntimeException e) {