Java Primer

From OSDev.wiki
Revision as of 21:54, 5 January 2016 by Combuster (talk | contribs) (Created page with "Time to create an overview of how you can make managed languages work on bare hardware Steps: # define native ABI for Java # create bytecode-to-native compiler (uses objectwe...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Time to create an overview of how you can make managed languages work on bare hardware

Steps:

  1. define native ABI for Java
  2. create bytecode-to-native compiler (uses objectweb asm)
  3. compile compiler
  4. compile managed os to bytecode (uses regular javac)
  5. compile bytecode to native assembly
  6. create runtime for things that have to be non-native
  7. assemble os and runtime (uses yasm)
  8. package the final kernel binary. (uses binutils)


package nl.combuster.minijava;

import org.objectweb.asm.*;
import org.objectweb.asm.tree.*;
import java.util.*;
import java.io.*;

public class Compiler
{
    public static byte[] readEntireFile(String filename)
    {
        File file = new File(filename);
	try 
	{
	    FileInputStream input = new FileInputStream(file);
	    byte bytes[] = new byte[(int)file.length()];
	    input.read(bytes);
	    return bytes;
	}
	catch (IOException e)
	{
            throw new RuntimeException("Unable to read file " + file, e);
	}

    }

    public static void writeOutput(String filename, List<String> lines)
    {
        try 
	{
            BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filename)));
	    for (String string : lines)
	    {
                writer.write(string);
		writer.newLine();
	    }
	    writer.close();
	}
        catch (IOException e)
	{
            throw new RuntimeException("Unable to write output file " + filename, e);
	}
    }

    public static String decorate(String classname, String method, String signature)
    {
        // make all these assembly-friendly names. Note that the 
	// constructor is for instance called <init>
        return classname.replace("/","_") + "__" + method.replace("<","_").replace(">","_");
    }

    public static void main(String args[])
    {
        if (args.length != 2) throw new RuntimeException("Usage: compiler input-file output-file");

        ClassNode node = new ClassNode();
	ClassReader reader = new ClassReader(readEntireFile(args[0]));
	reader.accept(node, 0);

	List<String> outputdata = new LinkedList<String>();

        outputdata.add("section .text");

	for (MethodNode method : node.methods)
	{
            method.visitCode();
	    String methodname = decorate(node.name, method.name, method.signature);

            if ((method.access & Opcodes.ACC_NATIVE) != 0) continue;

	    // prologue
	    System.out.println("; attributes: " + method.attrs);
            outputdata.add("global " + methodname);
	    outputdata.add(methodname + ":");
	    outputdata.add("push ebp");
	    outputdata.add("mov ebp, esp");
	    int locals = (method.localVariables == null) ? 0 : method.localVariables.size();
	    outputdata.add("sub esp, " + locals * 4);

	    Iterator<AbstractInsnNode> iterator = method.instructions.iterator();
	    while (iterator.hasNext())
	    {	 
                AbstractInsnNode insn = iterator.next();
		if (insn instanceof LabelNode)
		{
		    LabelNode labelinsn = (LabelNode)insn;
		    outputdata.add(".l" + labelinsn.getLabel());
		}
		else if (insn instanceof LineNumberNode)
		{
		    // ignore these
		}
		else
		{
		    outputdata.add("Can't deal with " + insn.getClass().getSimpleName() + ", fix it (" + insn.getOpcode() + ")");
		}
            }

            // epilogue
	    outputdata.add("leave");
	    outputdata.add("ret");
        }

        writeOutput(args[1], outputdata);
    }
}