// $Id: op.cpp,v 1.3 1999/01/25 20:00:31 shields Exp $ copyright notice #include "config.h" #include <stdio.h> #include <stdlib.h> #include <iostream.h> #include <string.h> #include "op.h" void opdesc(int opc,char **name, char **desc) { struct op_entry { char *op_name; char *op_desc; }; struct op_entry table[] = { {"nop", "do nothing"}, {"aconst_null", "push null"}, {"iconst_m1", "push int constant -1"}, {"iconst_0", "push int constant 0"}, {"iconst_1", "push int constant 1"}, {"iconst_2", "push int constant 2"}, {"iconst_3", "push int constant 3"}, {"iconst_4", "push int constant 4"}, {"iconst_5", "push int constant 5"}, {"lconst_0", "push long constant 0"}, {"lconst_1", "push long constant 1"}, {"fconst_0", "push float 0.0"}, {"fconst_1", "push float 1.0"}, {"fconst_2", "push float 2.0"}, {"dconst_0", "push double 0.0 onto stack"}, {"dconst_1", "push double 1.0 onto stack"}, {"bipush", "push byte"}, {"sipush", "push short"}, {"ldc", "push item from constant pool"}, {"ldc_w", "push item from constant pool (wide index)"}, {"ldc2_w", "push long or double from constant pool (wide index)"}, {"iload", "load int from local variable"}, {"lload", "load long from local variable"}, {"fload", "load float from local variable"}, {"dload", "load double from local variable"}, {"aload", "load reference from local variable"}, {"iload_0", "load int from local variable 0"}, {"iload_1", "load int from local variable 1"}, {"iload_2", "load int from local variable 2"}, {"iload_3", "load int from local variable 3"}, {"lload_0", "load long from local variable 0"}, {"lload_1", "load long from local variable 1"}, {"lload_2", "load long from local variable 2"}, {"lload_3", "load long from local variable 3"}, {"fload_0", "load float from local variable 0"}, {"fload_1", "load float from local variable 1"}, {"fload_2", "load float from local variable 2"}, {"fload_3", "load float from local variable 3"}, {"dload_0", "load double from local variable 0"}, {"dload_1", "load double from local variable 1"}, {"dload_2", "load double from local variable 2"}, {"dload_3", "load double from local variable 3"}, {"aload_0", "load reference from local variable 0"}, {"aload_1", "load reference from local variable 1"}, {"aload_2", "load reference from local variable 2"}, {"aload_3", "load reference from local variable 3"}, {"iaload", "load int from array"}, {"laload", "load long from array"}, {"faload", "load float from array"}, {"daload", "load double from array"}, {"aaload", "load reference from array"}, {"baload", "load byte from array"}, {"caload", "load char from array"}, {"saload", "load short from array"}, {"istore", "store int into local variable"}, {"lstore", "store long into local variable"}, {"fstore", "store float into local variable"}, {"dstore", "store double into local variable"}, {"astore", "store reference into local variable"}, {"istore_0", "store int into local variable 0"}, {"istore_1", "store int into local variable 1"}, {"istore_2", "store int into local variable 2"}, {"istore_3", "store int into local variable 3"}, {"lstore_0", "store long into local variable 0"}, {"lstore_1", "store long into local variable 1"}, {"lstore_2", "store long into local variable 2"}, {"lstore_3", "store long into local variable 3"}, {"fstore_0", "store float into local variable 0"}, {"fstore_1", "store float into local variable 1"}, {"fstore_2", "store float into local variable 2"}, {"fstore_3", "store float into local variable 3"}, {"dstore_0", "store double into local variable 0"}, {"dstore_1", "store double into local variable 1"}, {"dstore_2", "store double into local variable 2"}, {"dstore_3", "store double into local variable 3"}, {"astore_0", "store reference into local variable 0"}, {"astore_1", "store reference into local variable 1"}, {"astore_2", "store reference into local variable 2"}, {"astore_3", "store reference into local variable 3"}, {"iastore", "store into int array"}, {"lastore", "store into long array"}, {"fastore", "store into float array"}, {"dastore", "store into double array"}, {"aastore", "store into reference array"}, {"bastore", "store into byte array"}, {"castore", "store into char array"}, {"sastore", "store into short array"}, {"pop", "pop top operand stack word"}, {"pop2", "pop two two operand stack words"}, {"dup", "duplicate top operand stack word"}, {"dup_x1", "duplicate top operand stack word and put two down"}, {"dup_x2", "duplicate top operand stack word and put three down"}, {"dup2", "duplicate top two operand stack words"}, {"dup2_x1", "duplicate top two operand stack words and put three down"}, {"dup2_x2", "duplicate top two operand stack words and put four down"}, {"swap", "swap top two operand stack words"}, {"iadd", "add int"}, {"ladd", "add long"}, {"fadd", "add float"}, {"dadd", "add double"}, {"isub", "subtract int"}, {"lsub", "subtract long"}, {"fsub", "substract float"}, {"dsub", "subtract double"}, {"imul", "multiply int"}, {"lmul", "multiply long"}, {"fmul", "multiply float"}, {"dmul", "multiply double"}, {"idiv", "divide int"}, {"ldiv", "divide long"}, {"fdiv", "divide float"}, {"ddiv", "divide double"}, {"irem", "remainder int"}, {"lrem", "remainder long"}, {"frem", "remainder float"}, {"drem", "remainder double"}, {"ineg", "negate int"}, {"lneg", "negate long"}, {"fneg", "negate float"}, {"dneg", "negate double"}, {"ishl", "shift left int"}, {"lshl", "shift left long"}, {"ishr", "shift right int"}, {"lshr", "shift right long"}, {"iushr", "logical shift right int"}, {"lushr", "logical shift right long"}, {"iand", "boolean and int"}, {"land", "boolean and long"}, {"ior", "boolean or int"}, {"lor", "boolean or long"}, {"ixor", "boolean xor int"}, {"lxor", "boolean xor long"}, {"iinc", "increment local variable by constant"}, {"i2l", "convert int to long"}, {"i2f", "convert int to float"}, {"i2d", "convert int to double"}, {"l2i", "convert long to int"}, {"l2f", "convert long to float"}, {"l2d", "convert long to double"}, {"f2i", "convert float to int"}, {"f2l", "convert float to long"}, {"f2d", "convert float to double"}, {"d2i", "convert double to int"}, {"d2l", "convert double to long"}, {"d2f", "convert double to float"}, {"i2b", "convert int to byte"}, {"i2c", "convert int to char"}, {"i2s", "convert int to short"}, {"lcmp", "compare long"}, {"fcmpl", "compare float less"}, {"fcmpg", "compare float greater"}, {"dcmpl", "compare double less"}, {"dcmpg", "compare double greater"}, {"ifeq", "branch if int eq zero"}, {"ifne", "branch if int ne zero"}, {"iflt", "branch if int lt zero"}, {"ifge", "branch if int ge zero"}, {"ifgt", "branch if int gt zero"}, {"ifle", "branch if int le zero"}, {"if_icmpeq", "branch if int comparison eq"}, {"if_icmpne", "branch if int comparison ne"}, {"if_icmplt", "branch if int comparison lt"}, {"if_icmpge", "branch if int comparison ge"}, {"if_icmpgt", "branch if int comparison gt"}, {"if_icmple", "branch if int comparison le"}, {"if_acmpeq", "branch if reference comparison eq"}, {"if_acmpne", "branch if reference comparison ne"}, {"goto", "branch always"}, {"jsr", "jump subroutine"}, {"ret", "return from subroutine"}, {"tableswitch", "access jump table by index and jump"}, {"lookupswitch", "access jump table by key match and jump"}, {"ireturn", "return int from method"}, {"lreturn", "return long from method"}, {"freturn", "return float from method"}, {"dreturn", "return double from method"}, {"areturn", "return reference from method"}, {"return", "return void from method"}, {"getstatic", "get static field from class"}, {"putstatic", "set static field in class"}, {"getfield", "fetch field from object"}, {"putfield", "set field in object"}, {"invokevirtual", "invoke instance method; dispatch based on runtime type"}, {"invokenonvirtual", "invoke instance method; dispatch based on compile-time type"}, {"invokestatic", "invoke a class (static) method"}, {"invokeinterface", "invoke interface method"}, {"xxxunusedxxx", "xxxunusedxxx"}, {"new", "create new object"}, {"newarray", "create new array"}, {"anewarray", "create new array of references"}, {"arraylength", "get length of array"}, {"athrow", "throw exception or error"}, {"checkcast", "check whether object is of given type"}, {"instanceof", "determine if object is of given type"}, {"monitorenter", "enter monitor for object"}, {"monitorexit", "exit monitor for object"}, {"wide", "extend local variable index by additional bytes"}, {"multianewarray", "create new multidimensional array"}, {"ifnull", "branch if reference is null"}, {"ifnonnuull", "branch if reference not null"}, {"goto_w", "branch always (wide index) ?"}, {"jsr_w", "jump subroutine (wide index)"} }; if (opc==OP_SOFTWARE) { // software *name = *desc = "software"; } else if (opc == OP_HARDWARE) { // hardware *name = *desc = "hardware"; } else if (opc >=0 && opc <= 0xc9) { *name = table[opc].op_name; *desc = table[opc].op_desc; } else { *name = *desc = "illegal"; } } #define INFO_NONE 0 #define INFO_LOCAL 1 #define INFO_CONST 2 #define INFO_DONE 3 // set code to be array of opcodes, codei to be code index static void chaos(char * str) { cout << "chaos: " << str << "\n"; cerr << "chaos: " << str << "\n"; exit(1); } signed char get_i1(Tuple<u1>& code, int pc) { return code[pc]; } short get_i2(Tuple<u1>& code, int pc) { return code[pc] << 8 | code[pc+1]; } int get_i4(Tuple<u1>& code, int pc) { return code[pc] << 24 | code[pc+1] << 16 | code[pc+2] << 8 | code[pc+3]; } unsigned int get_u1(Tuple<u1>& code, int pc) { unsigned val; val = code[pc]; return val; } unsigned int get_u2(Tuple<u1>& code, int pc) { unsigned int val; val = (code[pc] << 8 | code[pc+1]); return val; } unsigned int get_u4(Tuple<u1>& code, int pc) { unsigned int val; val = (code[pc] << 24 | code[pc+1] << 16 | code[pc+2] << 8 | code[pc+3]); return val; } extern void const_string(Tuple<cp_info *>& constant_pool, int indx); void opline(Tuple<cp_info *>& constant_pool,char * hdr, int pc, int opc, char *name, char* args, char* desc, int info_kind, int info_index) { int len; // generate line of opcode dump, info is extra info cout<< *hdr; cout.width(4); cout << pc; cout << "\t" << name; len = strlen(name); if (strlen(args)) { cout << " " << args; len += (strlen(args) + 1); } if (len < 8) cout << "\t\t\t"; else if (len < 16) cout << "\t\t"; // else if (len <= 24) cout << "\t"; else cout << "\t"; switch (info_kind) { case INFO_CONST: cout << " "; if (info_index<=0 || info_index >constant_pool.Length()) { cout << "OUT-OF_BOUNDS CONSTANT_POOL-INDEX " << info_index; } else { // constant_pool[info_index]->describe(constant_pool); } break; case INFO_LOCAL: cout << " local#" << info_index; break; } // DS (17 jun) - skip desc for now: it's too long and shoud only // be written at user request. // cout <<" " << desc; cout << "\n"; } extern void opdesc(unsigned opc, char ** name, char ** desc); void opdmp(Tuple<cp_info *>& constant_pool, Tuple<u1>& code){ char argdesc[100]; int pc_max = code.Length(); int pc_start; unsigned opc; unsigned int au1; int ai1,ai2,ai4; int info_kind; int info_index; char *name, *desc; // set to name (mnemonic) and description of opcode. int pc=0; while (pc <pc_max) { // for (pc=0; pc<pc_max; pc++) { info_kind = INFO_NONE; // assume no extra info info_index=0; pc_start = pc; opc = get_u1(code,pc); opdesc(code[pc_start], &name, &desc); pc++; argdesc[0] = U_NULL; // assume no argument description needed switch (opc) { case OP_BIPUSH: ai1 = get_i1(code,pc); pc++; sprintf(argdesc,"%d",ai1); break; case OP_SIPUSH: ai2 = get_i2(code,pc); pc +=2; sprintf(argdesc,"%d",ai2); break; case OP_LDC: info_index = get_u1(code,pc); pc++; sprintf(argdesc,"%d",info_index); info_kind = INFO_CONST; break; case OP_LDC_W: case OP_LDC2_W: info_index = get_u2(code,pc);pc +=2; sprintf(argdesc, "%u",info_index); info_kind = INFO_CONST; break; case OP_ILOAD: case OP_LLOAD: case OP_FLOAD: case OP_DLOAD: case OP_ALOAD: case OP_ISTORE: case OP_LSTORE: case OP_FSTORE: case OP_DSTORE: case OP_ASTORE: info_index = get_u1(code,pc);pc++; sprintf(argdesc, "%u",info_index); info_kind = INFO_LOCAL; break; case OP_ILOAD_0: case OP_LLOAD_0: case OP_FLOAD_0: case OP_DLOAD_0: case OP_ALOAD_0: case OP_ISTORE_0: case OP_LSTORE_0: case OP_FSTORE_0: case OP_DSTORE_0: case OP_ASTORE_0: info_kind = INFO_LOCAL; info_index = 0; break; case OP_ILOAD_1: case OP_LLOAD_1: case OP_FLOAD_1: case OP_DLOAD_1: case OP_ALOAD_1: case OP_ISTORE_1: case OP_LSTORE_1: case OP_FSTORE_1: case OP_DSTORE_1: case OP_ASTORE_1: info_kind = INFO_LOCAL; info_index = 1; break; case OP_ILOAD_2: case OP_LLOAD_2: case OP_FLOAD_2: case OP_DLOAD_2: case OP_ALOAD_2: case OP_ISTORE_2: case OP_LSTORE_2: case OP_DSTORE_2: case OP_FSTORE_2: case OP_ASTORE_2: info_kind = INFO_LOCAL; info_index = 2; break; case OP_ILOAD_3: case OP_LLOAD_3: case OP_FLOAD_3: case OP_DLOAD_3: case OP_ALOAD_3: case OP_ISTORE_3: case OP_LSTORE_3: case OP_FSTORE_3: case OP_DSTORE_3: case OP_ASTORE_3: info_kind= INFO_LOCAL; info_index = 3; break; case OP_IINC: info_index = get_u1(code,pc); pc++; au1 = get_u1(code,pc); pc++; ai1 = get_i1(code,pc); pc++; info_kind = INFO_LOCAL; sprintf(argdesc,"%d %d",au1,ai1); break; case OP_IFEQ: case OP_IFNE: case OP_IFLT: case OP_IFGE: case OP_IFGT: case OP_IFLE: case OP_IF_ICMPEQ: case OP_IF_ICMPNE: case OP_IF_ICMPLT: case OP_IF_ICMPGE: case OP_IF_ICMPGT: case OP_IF_ICMPLE: case OP_IF_ACMPEQ: case OP_IF_ACMPNE: case OP_GOTO: case OP_JSR: case OP_IFNULL: case OP_IFNONNULL: ai2 = get_i2(code, pc); sprintf(argdesc,"%d",(int) ( ai2+pc_start)); // compute branch target pc +=2; break; case OP_RET: au1 = get_u1(code,pc); pc++; sprintf(argdesc,"%d",(int)au1); break; case OP_TABLESWITCH: { int def,low,high,len,val,pc_this,op_this; unsigned iu1; op_this = OP_TABLESWITCH; // account for padding while (pc % 4) { iu1 = get_u1(code, pc); pc++; } def = get_i4(code, pc); pc += 4; low = get_i4(code,pc); pc +=4; high = get_i4(code,pc); pc += 4; sprintf(argdesc,"default:%d low:%d high:%d",def+pc_start,low,high); opline(constant_pool," ",pc_start, opc, name, argdesc, desc,info_kind,info_index); len = high - low + 1; while (len) { pc_this = pc; val = get_i4(code,pc); sprintf(argdesc,"match:%d offset:%d",low++,val+pc_start); opline(constant_pool,"*",pc_this, op_this,name,argdesc,desc,INFO_NONE,0); pc += 4; len--; } info_kind=INFO_DONE; } break; case OP_LOOKUPSWITCH: { int def,npairs,len,match,offset,op_this; // account for padding unsigned iu1; op_this = OP_LOOKUPSWITCH; while (pc % 4) { iu1 = get_u1(code, pc); pc++; } def = get_i4(code, pc); pc += 4; npairs = get_i4(code,pc); pc +=4; sprintf(argdesc,"default:%d npairs:%d",(def + pc_start), npairs); opline(constant_pool," ",pc_start, op_this, name, argdesc, desc, info_kind, info_index); len = npairs; while (npairs) {int pcb; pcb = pc; match = get_i4(code,pc); pc +=4 ; offset = get_i4(code,pc); pc +=4; sprintf(argdesc,"match:%d offset:%d ",match,offset+pc_start); opline(constant_pool,"*", pcb, op_this, name, argdesc, desc, INFO_NONE,0); npairs--; } info_kind=INFO_DONE; } break; case OP_GETSTATIC: case OP_PUTSTATIC: case OP_GETFIELD: case OP_PUTFIELD: case OP_INVOKEVIRTUAL: case OP_INVOKENONVIRTUAL: case OP_INVOKESTATIC: case OP_NEW: case OP_ANEWARRAY: case OP_CHECKCAST: case OP_INSTANCEOF: info_index = get_u2(code,pc); pc += 2; sprintf(argdesc,"%d",info_index); info_kind = INFO_CONST; break; case OP_INVOKEINTERFACE: { int nargs; info_index = get_u2(code,pc); pc += 2; au1 = get_u1(code,pc); pc++; nargs = au1; au1 = get_u1(code,pc); pc++; if (au1) { chaos("zero byte required in this position"); } sprintf(argdesc,"%d %d",nargs,info_index); info_kind=INFO_CONST; } break; case OP_NEWARRAY: au1 = get_u1(code,pc); pc++; switch(au1) { case 4: sprintf(argdesc,"%s","BOOLEAN");break; case 5: sprintf(argdesc,"%s","CHAR");break; case 6: sprintf(argdesc,"%s","FLOAT");break; case 7: sprintf(argdesc,"%s","DOUBLE");break; case 8: sprintf(argdesc,"%s","BYTE");break; case 9: sprintf(argdesc,"%s","SHORT");break; case 10: sprintf(argdesc,"%s","INT");break; case 11: sprintf(argdesc,"%s","LONG");break; default: sprintf(argdesc,"%s","<UNKNOWN>");break; } break; case OP_WIDE: chaos("dmp for op_wide not supported yet"); break; case OP_MULTIANEWARRAY: info_index = get_u2(code,pc); pc += 2; au1 = get_u1(code,pc); pc++; info_kind = INFO_CONST; // au1 gives dimensions sprintf(argdesc,"%u",au1); break; case OP_GOTO_W: case OP_JSR_W: ai4 = get_i4(code,pc); pc += 4; // ai4 gives offset (wide) of branch target sprintf(argdesc,"%d", pc_start + ai4); break; default: break; } // output first part of description if (info_kind!=INFO_DONE) opline(constant_pool," ",pc_start, opc, name, argdesc, desc,info_kind,info_index); } }