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/ // class CodeTranslator { // parameter bytes for each of the 256 instructions (-1 = not implemented) private static final int[] PARAMETER_BYTES = { // 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, -1, -1, // 00 1, 2, 1, -1, -1, 1, -1, 1, -1, 1, 0, 0, 0, 0, -1, -1, // 10 -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0, 0, -1, // 20 0, -1, 0, 0, -1, -1, 1, -1, 1, -1, -1, 0, 0, 0, 0, -1, // 30 -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, 0, 0, 0, 0, 0, // 40 -1, 0, -1, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 50 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, // 60 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, // 70 0, -1, 0, -1, 2, -1, 0, -1, -1, -1, -1, 0, -1, -1, -1, -1, // 80 -1, -1, 0, -1, -1, 0, 0, -1, -1, 2, 2, 2, 2, 2, 2, 2, // 90 2, 2, 2, 2, 2, -1, -1, 2, -1, -1, 0, 0, 0, -1, 0, -1, // a0 -1, 0, 2, 2, 2, 2, 2, 2, 2, -1, -1, 2, 1, 2, 0, -1, // b0 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // c0 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // d0 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // e0 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // f0 }; // some java bytecode instructions private static final int OP_NOP = 0x00; private static final int OP_ACONST_NULL = 0x01; private static final int OP_ICONST_0 = 0x03; private static final int OP_SIPUSH = 0x11; private static final int OP_LDC = 0x12; private static final int OP_ILOAD = 0x15; private static final int OP_ALOAD = 0x19; private static final int OP_ILOAD_0 = 0x1a; private static final int OP_ILOAD_1 = 0x1b; private static final int OP_ILOAD_2 = 0x1c; private static final int OP_ILOAD_3 = 0x1d; private static final int OP_ALOAD_0 = 0x2a; private static final int OP_ALOAD_1 = 0x2b; private static final int OP_ALOAD_2 = 0x2c; private static final int OP_ALOAD_3 = 0x2d; private static final int OP_ISTORE = 0x36; private static final int OP_ASTORE = 0x3a; private static final int OP_ISTORE_0 = 0x3b; private static final int OP_ISTORE_1 = 0x3c; private static final int OP_ISTORE_2 = 0x3d; private static final int OP_ISTORE_3 = 0x3e; private static final int OP_ASTORE_0 = 0x4b; private static final int OP_ASTORE_1 = 0x4c; private static final int OP_ASTORE_2 = 0x4d; private static final int OP_ASTORE_3 = 0x4e; private static final int OP_I2B = 0x91; private static final int OP_I2C = 0x92; private static final int OP_I2S = 0x93; private static final int OP_TABLESWITCH = 0xaa; private static final int OP_LOOKUPSWITCH = 0xab; private static final int OP_IRETURN = 0xac; private static final int OP_ARETURN = 0xb0; private static final int OP_GETSTATIC = 0xb2; private static final int OP_PUTSTATIC = 0xb3; private static final int OP_GETFIELD = 0xb4; private static final int OP_PUTFIELD = 0xb5; private static final int OP_INVOKEVIRTUAL = 0xb6; private static final int OP_INVOKESPECIAL = 0xb7; private static final int OP_INVOKESTATIC = 0xb8; private static final int OP_NEW = 0xbb; private static final int OP_IFEQ = 0x99; private static final int OP_IFNE = 0x9a; private static final int OP_IFNULL = 0xc6; private static final int OP_IFNONNULL = 0xc7; private static final int OP_FCONST_0 = 0x0b; // only if floating point compiled in private static final int OP_FCONST_1 = 0x0c; // only if floating point compiled in private static final int OP_FCONST_2 = 0x0d; // only if floating point compiled in private static final int OP_FLOAD = 0x17; // only if floating point compiled in private static final int OP_FLOAD_0 = 0x22; // only if floating point compiled in private static final int OP_FLOAD_1 = 0x23; // only if floating point compiled in private static final int OP_FLOAD_2 = 0x24; // only if floating point compiled in private static final int OP_FLOAD_3 = 0x25; // only if floating point compiled in private static final int OP_IALOAD = 0x2e; // only if array compiled in private static final int OP_FALOAD = 0x30; // only if array and floating point compiled in static final int OP_AALOAD = 0x32; // only if array compiled in private static final int OP_BALOAD = 0x33; // only if array compiled in private static final int OP_FSTORE = 0x38; // only if floating point compiled in private static final int OP_FSTORE_0 = 0x43; // only if floating point compiled in private static final int OP_FSTORE_1 = 0x44; // only if floating point compiled in private static final int OP_FSTORE_2 = 0x45; // only if floating point compiled in private static final int OP_FSTORE_3 = 0x46; // only if floating point compiled in private static final int OP_IASTORE = 0x4f; // only if array compiled in private static final int OP_FASTORE = 0x51; // only if array and floating point compiled in static final int OP_AASTORE = 0x53; // only if array compiled in private static final int OP_BASTORE = 0x54; // only if array compiled in private static final int OP_DUP_X1 = 0x5a; // only if extended stack ops compiled in private static final int OP_DUP_X2 = 0x5b; // only if extended stack ops compiled in private static final int OP_DUP2_X1 = 0x5d; // only if extended stack ops compiled in private static final int OP_DUP2_X2 = 0x5e; // only if extended stack ops compiled in private static final int OP_SWAP = 0x5f; // only if extended stack ops compiled in private static final int OP_FADD = 0x62; // only if floating point compiled in private static final int OP_FSUB = 0x66; // only if floating point compiled in private static final int OP_FMUL = 0x6a; // only if floating point compiled in private static final int OP_FDIV = 0x6e; // only if floating point compiled in private static final int OP_FREM = 0x72; // only if floating point compiled in private static final int OP_FNEG = 0x76; // only if floating point compiled in private static final int OP_I2F = 0x86; // only if floating point compiled in private static final int OP_F2I = 0x8b; // only if floating point compiled in private static final int OP_FCMPL = 0x95; // only if floating point compiled in private static final int OP_FCMPG = 0x96; // only if floating point compiled in private static final int OP_FRETURN = 0xae; // only if floating point compiled in private static final int OP_NEWARRAY = 0xbc; // only if array compiled in private static final int OP_ANEWARRAY = 0xbd; // only if array compiled in private static final int OP_ARRAYLENGTH = 0xbe; // only if array compiled in private static int unsigned(int i) { if (i < 0) return i + 256; return i; } private static byte signed(int i) { if (i > 127) return (byte) (i - 256); return (byte) i; } private static int get32(byte[] code, int i) { int val = 0x00000001 * unsigned(code[i + 3]) + 0x00000100 * unsigned(code[i + 2]) + 0x00010000 * unsigned(code[i + 1]) + 0x01000000 * unsigned(code[i + 0]); return val; } private static void set32(byte[] code, int i, int val) { code[i + 3] = signed(val >> 0); code[i + 2] = signed(val >> 8); code[i + 1] = signed(val >> 16); code[i + 0] = signed(val >> 24); } public static void translate(ClassInfo classInfo, byte[] code) throws ClassNotFoundException { // process all code bytes for (int i = 0; i < code.length; i++) { int cmd = unsigned(code[i]); // code translations to reduce number of instructions if (cmd == OP_ASTORE) cmd = OP_ISTORE; if (cmd == OP_ASTORE_0) cmd = OP_ISTORE_0; if (cmd == OP_ASTORE_1) cmd = OP_ISTORE_1; if (cmd == OP_ASTORE_2) cmd = OP_ISTORE_2; if (cmd == OP_ASTORE_3) cmd = OP_ISTORE_3; if (cmd == OP_ACONST_NULL) cmd = OP_ICONST_0; if (cmd == OP_ALOAD) cmd = OP_ILOAD; if (cmd == OP_ALOAD_0) cmd = OP_ILOAD_0; if (cmd == OP_ALOAD_1) cmd = OP_ILOAD_1; if (cmd == OP_ALOAD_2) cmd = OP_ILOAD_2; if (cmd == OP_ALOAD_3) cmd = OP_ILOAD_3; if (cmd == OP_IFNULL) cmd = OP_IFEQ; if (cmd == OP_IFNONNULL) cmd = OP_IFNE; if (cmd == OP_ARETURN) cmd = OP_IRETURN; // we don't need these conversions, since ints, bytes and // shorts are the same internal type if (cmd == OP_I2B) cmd = OP_NOP; if (cmd == OP_I2C) cmd = OP_NOP; if (cmd == OP_I2S) cmd = OP_NOP; code[i] = signed(cmd); if (PARAMETER_BYTES[cmd] < 0) { System.out.println("Unsupported byte code: 0x" + Integer.toHexString(cmd)); System.exit(-1); } if (cmd == OP_LDC) { // load from constant pool (e.g. strings) int index = unsigned(code[i + 1]); System.out.print("ldc #" + index); code[i + 1] = signed(classInfo.getConstPool(). constantRelocate(index)); } if (cmd == OP_GETFIELD || cmd == OP_PUTFIELD) { int index = 256 * unsigned(code[i + 1]) + unsigned(code[i + 2]); System.out.print("get/putfield #" + index); index = classInfo.getConstPool().constantRelocate(index); code[i + 1] = signed(index >> 8); code[i + 2] = signed(index & 0xff); } if (cmd == OP_GETSTATIC || cmd == OP_PUTSTATIC) { int index = 256 * unsigned(code[i + 1]) + unsigned(code[i + 2]); System.out.print("get/putstatic #" + index); index = classInfo.getConstPool().constantRelocate(index); code[i + 1] = signed(index >> 8); code[i + 2] = signed(index & 0xff); // getstatic usually uses a reference to the object in question. // if the object is native, then this is just an id, that is to // be directly pushed onto the stack, thus we replace the getstatic // instruction with a push instruction if (cmd == OP_GETSTATIC && index >> 8 >= classInfo.getClassLoader().lowestNativeId) code[i] = signed(OP_SIPUSH); } if (cmd == OP_INVOKEVIRTUAL || cmd == OP_INVOKESPECIAL || cmd == OP_INVOKESTATIC) { int index = 256 * unsigned(code[i + 1]) + unsigned(code[i + 2]); System.out.print("invoke #" + index); index = classInfo.getConstPool().constantRelocate(index); code[i + 1] = signed(index >> 8); code[i + 2] = signed(index & 0xff); } if (cmd == OP_NEW) { int index = 256 * unsigned(code[i + 1]) + unsigned(code[i + 2]); System.out.print("new #" + index); index = classInfo.getConstPool().constantRelocate(index); code[i + 1] = signed(index >> 8); code[i + 2] = signed(index & 0xff); } if (cmd == OP_TABLESWITCH) { UsedFeatures.add(UsedFeatures.TABLESWITCH); //System.out.println("tableswitch"); // opcode is followed by up to 3 padding bytes (replaced by nop's) // 4 byte low value follows // 4 byte hi value follows // (hi-lo+1) * 4 bytes build the table int delta = 0; i++; while (i % 4 != 0) { code[i - 1] = signed(OP_NOP); code[i] = signed(OP_TABLESWITCH); i++; delta++; } set32(code, i, get32(code, i) - delta); // realloc default label i += 4; int lo = get32(code, i + 0); int hi = get32(code, i + 4); i += 8; System.out.println("tableswitch: number of cases =" + (hi - lo + 1)); for (int j = 0; j < hi - lo + 1; j++) { set32(code, i, get32(code, i) - delta); // realloc label i += 4; } i--; } if (cmd == OP_LOOKUPSWITCH) { UsedFeatures.add(UsedFeatures.LOOKUPSWITCH); System.out.println("lookupswitch"); // opcode is followed by up to 3 padding bytes // 4 byte default offset follows // 4 byte count follows // count * 2 * 4 bytes build the table int delta = 0; i++; while (i % 4 != 0) { System.out.println("lookupswitch: padding"); code[i - 1] = signed(OP_NOP); code[i] = signed(OP_LOOKUPSWITCH); i++; delta++; } set32(code, i, get32(code, i) - delta); // realloc default label i += 4; int count = get32(code, i); i += 4; System.out.println("lookupswitch: number of cases = " + count); for (int j = 0; j < count; j++) { System.out.println("lookupswitch: case"); i += 4; // skip value set32(code, i, get32(code, i) - delta); // realloc label i += 4; } i--; System.out.println("lookupswitch: finished"); } // update used bits if (cmd == OP_TABLESWITCH) UsedFeatures.add(UsedFeatures.TABLESWITCH); if (cmd == OP_LOOKUPSWITCH) UsedFeatures.add(UsedFeatures.LOOKUPSWITCH); if (cmd == OP_FCONST_0) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FCONST_1) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FCONST_2) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FLOAD) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FLOAD_0) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FLOAD_1) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FLOAD_2) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FLOAD_3) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_IALOAD) UsedFeatures.add(UsedFeatures.ARRAY); if (cmd == OP_FALOAD) UsedFeatures.add(UsedFeatures.ARRAY + UsedFeatures.FLOAT); if (cmd == OP_BALOAD) UsedFeatures.add(UsedFeatures.ARRAY); if (cmd == OP_FSTORE) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FSTORE_0) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FSTORE_1) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FSTORE_2) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FSTORE_3) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_IASTORE) UsedFeatures.add(UsedFeatures.ARRAY); if (cmd == OP_FASTORE) UsedFeatures.add(UsedFeatures.ARRAY + UsedFeatures.FLOAT); if (cmd == OP_BASTORE) UsedFeatures.add(UsedFeatures.ARRAY); if (cmd == OP_FADD) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FSUB) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FMUL) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FDIV) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FREM) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FNEG) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_I2F) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_F2I) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FCMPL) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FCMPG) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_FRETURN) UsedFeatures.add(UsedFeatures.FLOAT); if (cmd == OP_NEWARRAY) UsedFeatures.add(UsedFeatures.ARRAY); if (cmd == OP_ANEWARRAY) UsedFeatures.add(UsedFeatures.ARRAY); if (cmd == OP_ARRAYLENGTH) UsedFeatures.add(UsedFeatures.ARRAY); if (cmd == OP_DUP_X1) UsedFeatures.add(UsedFeatures.EXTSTACK); if (cmd == OP_DUP_X2) UsedFeatures.add(UsedFeatures.EXTSTACK); if (cmd == OP_DUP2_X1) UsedFeatures.add(UsedFeatures.EXTSTACK); if (cmd == OP_DUP2_X2) UsedFeatures.add(UsedFeatures.EXTSTACK); if (cmd == OP_SWAP) UsedFeatures.add(UsedFeatures.EXTSTACK); i += PARAMETER_BYTES[cmd]; } } }