package org.nanovm.converter; // // NanoVMTool, Converter and Upload Tool for the NanoVM // Copyright (C) 2005 by Till Harbaum <Till@Harbaum.org> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // 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 for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // // Parts of this tool are based on public domain code written by Kimberley // Burchett: http://www.kimbly.com/code/classfile/ // // // UVMWriter.java // import org.nanovm.*; public class Generator { private NanoVMByteCode code; static final int MAGIC = 0xBE000000; static final int VERSION = 2; int cur; void updateHeader() throws ConvertException { int old_cur = cur; cur = 0; writeHeader(); cur = old_cur; } // write uvm file header void writeHeader() throws ConvertException { int offset = 15; // header size: 15 bytes code.write32(MAGIC | UsedFeatures.get()); code.write8(VERSION); code.write8(ClassLoader.totalMethods()); code.write16(ClassLoader.getMainIndex()); // offset to constant data offset += 2 * ClassLoader.totalClasses(); // class header size: 2bytes code.write16(offset); // offset to string data offset += 4 * ClassLoader.totalConstantEntries(); // constant value size: 4bytes code.write16(offset); // offset to method data offset += 2 * ClassLoader.totalStrings(); // string indices offset += ClassLoader.totalStringSize(); // string data code.write16(offset); code.write8(ClassLoader.totalStaticFields()); // static fields } // write all class headers void writeClassHeaders() throws ConvertException { for (int i = 0; i < ClassLoader.totalClasses(); i++) { ClassInfo classInfo = ClassLoader.getClassInfo(i); code.write8(classInfo.getSuperClassIndex()); code.write8(classInfo.nonStaticFields()); } } // write all 32bit constant values void writeConstantEntries() throws ConvertException { System.out.println("Writing " + ClassLoader.totalConstantEntries() + " constant entries"); for (int i = 0; i < ClassLoader.totalConstantEntries(); i++) { System.out.println(" entry[" + i + "] = 0x" + Integer.toHexString(ClassLoader.getConstantEntry(i))); code.write32(ClassLoader.getConstantEntry(i)); } } // write all string headers and data void writeStrings() throws ConvertException { System.out.println("Writing " + ClassLoader.totalStrings() + " strings"); // write array of string offsets int offset = 2 * ClassLoader.totalStrings(); for (int i = 0; i < ClassLoader.totalStrings(); i++) { code.write16(offset); offset += ClassLoader.getString(i).length() + 1; } // write the strings itself for (int i = 0; i < ClassLoader.totalStrings(); i++) { String str = ClassLoader.getString(i); System.out.println(" entry[" + (i + ClassLoader.totalConstantEntries()) + "] = \"" + str + "\""); // write zero terminated c strings for (int j = 0; j < str.length(); j++) { code.write8(str.charAt(j)); } code.write8(0); } } // write all methods void writeMethods() throws ConvertException { int codeOffset = 0; // build the method id table MethodIdTable.build(); // write all Method headers for (int i = 0; i < ClassLoader.totalMethods(); i++) { MethodInfo methodInfo = ClassLoader.getMethod(i); // offset from this header to bytecode (this header is 8 bytes // in size) code.write16((ClassLoader.totalMethods() - i) * 8 + codeOffset); // code_index code.write16((ClassLoader.getClassIndex(i) << 8) + MethodIdTable.getEntry(i)); // id code.write8(methodInfo.getName().equals("<clinit>") ? 1 : 0); // flags code.write8(methodInfo.getArgs()); // args code.write8(methodInfo.getCodeInfo().getMaxLocals()); // max_locals code.write8(methodInfo.getCodeInfo().getMaxStack()); // max_stack codeOffset += methodInfo.getCodeInfo().getBytecode().length; } // write bytecode for (int i = 0; i < ClassLoader.totalMethods(); i++) { ClassInfo classInfo = ClassLoader.getClassInfoFromMethodIndex(i); MethodInfo methodInfo = ClassLoader.getMethod(i); System.out.println("Converting " + classInfo.getName() + "." + methodInfo.getName() + ":" + methodInfo.getSignature()); byte bcode[] = ClassLoader.getMethod(i).getCodeInfo().getBytecode(); // adjust references etc CodeTranslator.translate(classInfo, bcode); // and write bytecode for (int j = 0; j < bcode.length; j++) { code.write8(bcode[j]); } System.out.println(""); } } public Generator() { } public void generate(NanoVMByteCode code) { this.code = code; System.out.println("Generating unified class file ..."); // create output buffer and reset output pointer cur = 0; try { writeHeader(); // write file header writeClassHeaders(); // write class headers writeConstantEntries(); // write all 32-bit constants writeStrings(); // write all string data writeMethods(); // write method headers and byte code updateHeader(); // update feature values } catch (ConvertException e) { System.out.println("Conversion failed: " + e.toString()); System.exit(-1); } } }