package org.nanovm.converter;
import org.nanovm.converter.ClassInfo;
//
// 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/
//
public class CodeTranslator {
// parameter bytes for each of the 256 instructions (-1 = not implemented)
final static 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
final static int OP_NOP = 0x00;
final static int OP_ACONST_NULL = 0x01;
final static int OP_ICONST_0 = 0x03;
final static int OP_SIPUSH = 0x11;
final static int OP_LDC = 0x12;
final static int OP_ILOAD = 0x15;
final static int OP_ALOAD = 0x19;
final static int OP_ILOAD_0 = 0x1a;
final static int OP_ILOAD_1 = 0x1b;
final static int OP_ILOAD_2 = 0x1c;
final static int OP_ILOAD_3 = 0x1d;
final static int OP_ALOAD_0 = 0x2a;
final static int OP_ALOAD_1 = 0x2b;
final static int OP_ALOAD_2 = 0x2c;
final static int OP_ALOAD_3 = 0x2d;
final static int OP_ISTORE = 0x36;
final static int OP_ASTORE = 0x3a;
final static int OP_ISTORE_0 = 0x3b;
final static int OP_ISTORE_1 = 0x3c;
final static int OP_ISTORE_2 = 0x3d;
final static int OP_ISTORE_3 = 0x3e;
final static int OP_ASTORE_0 = 0x4b;
final static int OP_ASTORE_1 = 0x4c;
final static int OP_ASTORE_2 = 0x4d;
final static int OP_ASTORE_3 = 0x4e;
final static int OP_I2B = 0x91;
final static int OP_I2C = 0x92;
final static int OP_I2S = 0x93;
final static int OP_TABLESWITCH = 0xaa;
final static int OP_LOOKUPSWITCH = 0xab;
final static int OP_IRETURN = 0xac;
final static int OP_ARETURN = 0xb0;
final static int OP_GETSTATIC = 0xb2;
final static int OP_PUTSTATIC = 0xb3;
final static int OP_GETFIELD = 0xb4;
final static int OP_PUTFIELD = 0xb5;
final static int OP_INVOKEVIRTUAL = 0xb6;
final static int OP_INVOKESPECIAL = 0xb7;
final static int OP_INVOKESTATIC = 0xb8;
final static int OP_NEW = 0xbb;
final static int OP_IFEQ = 0x99;
final static int OP_IFNE = 0x9a;
final static int OP_IFNULL = 0xc6;
final static int OP_IFNONNULL = 0xc7;
final static int OP_FCONST_0 = 0x0b; // only if floating point compiled in
final static int OP_FCONST_1 = 0x0c; // only if floating point compiled in
final static int OP_FCONST_2 = 0x0d; // only if floating point compiled in
final static int OP_FLOAD = 0x17; // only if floating point compiled in
final static int OP_FLOAD_0 = 0x22; // only if floating point compiled in
final static int OP_FLOAD_1 = 0x23; // only if floating point compiled in
final static int OP_FLOAD_2 = 0x24; // only if floating point compiled in
final static int OP_FLOAD_3 = 0x25; // only if floating point compiled in
final static int OP_IALOAD = 0x2e; // only if array compiled in
final static int OP_FALOAD = 0x30; // only if array and floating point compiled in
final static int OP_AALOAD = 0x32; // only if array compiled in
final static int OP_BALOAD = 0x33; // only if array compiled in
final static int OP_FSTORE = 0x38; // only if floating point compiled in
final static int OP_FSTORE_0 = 0x43; // only if floating point compiled in
final static int OP_FSTORE_1 = 0x44; // only if floating point compiled in
final static int OP_FSTORE_2 = 0x45; // only if floating point compiled in
final static int OP_FSTORE_3 = 0x46; // only if floating point compiled in
final static int OP_IASTORE = 0x4f; // only if array compiled in
final static int OP_FASTORE = 0x51; // only if array and floating point compiled in
final static int OP_AASTORE = 0x53; // only if array compiled in
final static int OP_BASTORE = 0x54; // only if array compiled in
final static int OP_DUP_X1 = 0x5a; // only if extended stack ops compiled in
final static int OP_DUP_X2 = 0x5b; // only if extended stack ops compiled in
final static int OP_DUP2_X1 = 0x5d; // only if extended stack ops compiled in
final static int OP_DUP2_X2 = 0x5e; // only if extended stack ops compiled in
final static int OP_SWAP = 0x5f; // only if extended stack ops compiled in
final static int OP_FADD = 0x62; // only if floating point compiled in
final static int OP_FSUB = 0x66; // only if floating point compiled in
final static int OP_FMUL = 0x6a; // only if floating point compiled in
final static int OP_FDIV = 0x6e; // only if floating point compiled in
final static int OP_FREM = 0x72; // only if floating point compiled in
final static int OP_FNEG = 0x76; // only if floating point compiled in
final static int OP_I2F = 0x86; // only if floating point compiled in
final static int OP_F2I = 0x8b; // only if floating point compiled in
final static int OP_FCMPL = 0x95; // only if floating point compiled in
final static int OP_FCMPG = 0x96; // only if floating point compiled in
final static int OP_FRETURN = 0xae; // only if floating point compiled in
final static int OP_NEWARRAY = 0xbc; // only if array compiled in
final static int OP_ANEWARRAY = 0xbd; // only if array compiled in
final static int OP_ARRAYLENGTH = 0xbe; // only if array compiled in
static int unsigned(int i) {
if(i<0) return i + 256;
return i;
}
static byte signed(int i) {
if(i>127) return (byte)(i - 256);
return (byte)i;
}
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;
}
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) {
// 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) >= NativeMapper.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];
}
}
}