/* Direct threaded code interpreter for JVM subset. */
/* Expand byte code to words, replacing op-codes with addresses */

#include <stdio.h>
#include "basics.h"
#include "class.h"
// #include "bytecode.h"

#define STACKSIZE 32768

/* Globals */

/* The class we're interpreting. */
Class this_class;

/* The stack (grows up) */
u4 stack[STACKSIZE];

/* The stack pointer. 
   Invariant: sp points to highest occupied slot. */
u4* sp = stack-1;   

/* The stack limit. */
u4 *limit = stack+STACKSIZE;

/* Exception printer */
void exception(char *exn) {
  printf("Uncaught Exception %s\n",exn);
  exit(1);
}


/* Interpret a method. */
interp(Method method) {
  static void *dispatch_table[] = 
  {&&NOP,
   &&ACONST_NULL, 
   &&ICONST_M1, 
   &&ICONST_0, 
   &&ICONST_1, 
   &&ICONST_2, 
   &&ICONST_3,
   &&ICONST_4,
   &&ICONST_5, 
   &&UNDEF, // &&LCONST_0,
   &&UNDEF, // &&LCONST_1,
   &&UNDEF, // &&FCONST_0,
   &&UNDEF, // &&FCONST_1,
   &&UNDEF, // &&FCONST_2,
   &&UNDEF, // &&DCONST_0,
   &&UNDEF, // &&DCONST_1,
   &&BIPUSH, 
   &&SIPUSH, 
   &&LDC, 
   &&LDC_W,
   &&UNDEF, // &&LDC2_W,
   &&ILOAD, 
   &&UNDEF, // &&LLOAD,2
   &&UNDEF, // &&FLOAD,3
   &&UNDEF, // &&DLOAD,4
   &&ALOAD, 
   &&ILOAD_0,
   &&ILOAD_1,
   &&ILOAD_2,
   &&ILOAD_3,
   &&UNDEF, // &&LLOAD_0,
   &&UNDEF, // &&LLOAD_1,
   &&UNDEF, // &&LLOAD_2,
   &&UNDEF, // &&LLOAD_3,
   &&UNDEF, // &&FLOAD_0,
   &&UNDEF, // &&FLOAD_1,
   &&UNDEF, // &&FLOAD_2,
   &&UNDEF, // &&FLOAD_3,
   &&UNDEF, // &&DLOAD_0,
   &&UNDEF, // &&DLOAD_1,
   &&UNDEF, // &&DLOAD_2,
   &&UNDEF, // &&DLOAD_3,
   &&ALOAD_0,
   &&ALOAD_1,
   &&ALOAD_2,
   &&ALOAD_3,
   &&IALOAD, 
   &&UNDEF, // &&LALOAD,
   &&UNDEF, // &&FALOAD,
   &&UNDEF, // &&DALOAD,
   &&UNDEF, // &&AALOAD,
   &&UNDEF, // &&BALOAD,
   &&UNDEF, // &&CALOAD,
   &&UNDEF, // &&SALOAD,
   &&UNDEF, // &&ISTORE,
   &&UNDEF, // &&LSTORE,
   &&UNDEF, // &&FSTORE,
   &&UNDEF, // &&DSTORE,
   &&ASTORE, 
   &&ISTORE_0, 
   &&ISTORE_1,
   &&ISTORE_2,
   &&ISTORE_3,
   &&UNDEF, // &&LSTORE_0,
   &&UNDEF, // &&LSTORE_1,
   &&UNDEF, // &&LSTORE_2,
   &&UNDEF, // &&LSTORE_3,
   &&UNDEF, // &&FSTORE_0,
   &&UNDEF, // &&FSTORE_1,
   &&UNDEF, // &&FSTORE_2,
   &&UNDEF, // &&FSTORE_3,
   &&UNDEF, // &&DSTORE_0,
   &&UNDEF, // &&DSTORE_1,
   &&UNDEF, // &&DSTORE_2,
   &&UNDEF, // &&DSTORE_3,
   &&ASTORE_0, 
   &&ASTORE_1,
   &&ASTORE_2,
   &&ASTORE_3,
   &&IASTORE, 
   &&UNDEF, // &&LASTORE,
   &&UNDEF, // &&FASTORE,
   &&UNDEF, // &&DASTORE,
   &&UNDEF, // &&AASTORE,
   &&UNDEF, // &&BASTORE,
   &&UNDEF, // &&CASTORE,
   &&UNDEF, // &&SASTORE,
   &&POP,
   &&POP2, 
   &&DUP,
   &&UNDEF, // &&DUP_X1,
   &&UNDEF, // &&DUP_X2,
   &&UNDEF, // &&DUP2
   &&UNDEF, // &&DUP2_X1,
   &&UNDEF, // &&DUP2_X2,
   &&SWAP, 
   &&IADD, 
   &&UNDEF, // &&LADD,
   &&UNDEF, // &&FADD,
   &&UNDEF, // &&DADD,
   &&ISUB, 
   &&UNDEF, // &&LSUB,
   &&UNDEF, // &&FSUB,
   &&UNDEF, // &&DSUB,
   &&IMUL, 
   &&UNDEF, // &&LMUL,
   &&UNDEF, // &&FMUL,
   &&UNDEF, // &&DMUL,
   &&IDIV, 
   &&UNDEF, // &&LDIV,
   &&UNDEF, // &&FDIV,
   &&UNDEF, // &&DDIV,
   &&IREM, 
   &&UNDEF, // &&LREM,
   &&UNDEF, // &&FREM,
   &&UNDEF, // &&DREM,
   &&INEG, 
   &&UNDEF, // &&LNEG,
   &&UNDEF, // &&FNEG,
   &&UNDEF, // &&DNEG,
   &&UNDEF, // &&ISHL,
   &&UNDEF, // &&LSHL,
   &&UNDEF, // &&ISHR,
   &&UNDEF, // &&LSHR,
   &&UNDEF, // &&IUSHR,
   &&UNDEF, // &&LUSHR,
   &&IAND, 
   &&UNDEF, // &&LAND,
   &&IOR, 
   &&UNDEF, // &&LOR,
   &&IXOR, 
   &&UNDEF, // &&LXOR,
   &&IINC, 
   &&UNDEF, // &&I2L,
   &&UNDEF, // &&I2F,
   &&UNDEF, // &&I2D,
   &&UNDEF, // &&L2I,
   &&UNDEF, // &&L2F,
   &&UNDEF, // &&L2D,
   &&UNDEF, // &&F2I,
   &&UNDEF, // &&F2L,
   &&UNDEF, // &&F2D,
   &&UNDEF, // &&D2I,
   &&UNDEF, // &&D2L,
   &&UNDEF, // &&D2F,
   &&UNDEF, // &&INT2BYTE,
   &&UNDEF, // &&INT2CHAR,
   &&UNDEF, // &&INT2SHORT,
   &&UNDEF, // &&LCMP,
   &&UNDEF, // &&FCMPL,
   &&UNDEF, // &&FCMPG,
   &&UNDEF, // &&DCMPL,
   &&UNDEF, // &&DCMPG,
   &&IFEQ, 
   &&IFNE, 
   &&IFLT,
   &&IFGE,
   &&IFGT,
   &&IFLE,
   &&IF_ICMPEQ, 
   &&IF_ICMPNE, 
   &&IF_ICMPLT,
   &&IF_ICMPGE,
   &&IF_ICMPGT,
   &&IF_ICMPLE,
   &&IF_ACMPEQ, 
   &&IF_ACMPNE, 
   &&GOTO, 
   &&UNDEF, // &&JSR,
   &&UNDEF, // &&RET,
   &&UNDEF, // &&TABLESWITCH,
   &&UNDEF, // &&LOOKUPSWITCH,
   &&IRETURN, 
   &&UNDEF, // &&LRETURN,
   &&UNDEF, // &&FRETURN,
   &&UNDEF, // &&DRETURN,
   &&ARETURN, 
   &&RETURN, 
   &&GETSTATIC, 
   &&UNDEF, // &&PUTSTATIC,
   &&UNDEF, // &&GETFIELD,
   &&UNDEF, // &&PUTFIELD,
   &&INVOKEVIRTUAL,
   &&UNDEF, // &&INVOKESPECIAL,
   &&INVOKESTATIC, 
   &&UNDEF, // &&INVOKEINTERFACE,
   &&UNDEF, // unused
   &&UNDEF, // &&NEW,
   &&NEWARRAY,  
   &&UNDEF, // &&ANEWARRAY, 
   &&ARRAYLENGTH, 
   &&UNDEF, // &&ATHROW,
   &&UNDEF, // &&CHECKCAST,
   &&UNDEF, // &&INSTANCEOF,
   &&UNDEF, // &&MONITORENTER,
   &&UNDEF, // &&MONITOREXIT,
   &&UNDEF, // &&WIDE,
   &&UNDEF, // &&MULTIANEWARRAY,
   &&IFNULL,
   &&IFNONNULL,  
   &&GOTO_W,  
   &&UNDEF  // &&JSR_W
  };

#define UNKNOWN 0

  static int param_size[] =
  {0, // NOP,
   0, // ACONST_NULL, 
   0, // ICONST_M1, 
   0, // ICONST_0, 
   0, // ICONST_1, 
   0, // ICONST_2, 
   0, // ICONST_3,
   0, // ICONST_4,
   0, // ICONST_5, 
   UNKNOWN, // LCONST_0,
   UNKNOWN, // LCONST_1,
   UNKNOWN, // FCONST_0,
   UNKNOWN, // FCONST_1,
   UNKNOWN, // FCONST_2,
   UNKNOWN, // DCONST_0,
   UNKNOWN, // DCONST_1,
   1, // BIPUSH, 
   2, // SIPUSH, 
   1, // LDC, 
   2, // LDC_W,
   UNKNOWN, // LDC2_W,
   1, // ILOAD, 
   UNKNOWN, // LLOAD,2
   UNKNOWN, // FLOAD,3
   UNKNOWN, // DLOAD,4
   1, // ALOAD, 
   0, // ILOAD_0,
   0, // ILOAD_1,
   0, // ILOAD_2,
   0, // ILOAD_3,
   UNKNOWN, // LLOAD_0,
   UNKNOWN, // LLOAD_1,
   UNKNOWN, // LLOAD_2,
   UNKNOWN, // LLOAD_3,
   UNKNOWN, // FLOAD_0,
   UNKNOWN, // FLOAD_1,
   UNKNOWN, // FLOAD_2,
   UNKNOWN, // FLOAD_3,
   UNKNOWN, // DLOAD_0,
   UNKNOWN, // DLOAD_1,
   UNKNOWN, // DLOAD_2,
   UNKNOWN, // DLOAD_3,
   0, // ALOAD_0,
   0, // ALOAD_1,
   0, // ALOAD_2,
   0, // ALOAD_3,
   0, // IALOAD, 
   UNKNOWN, // LALOAD,
   UNKNOWN, // FALOAD,
   UNKNOWN, // DALOAD,
   UNKNOWN, // AALOAD,
   UNKNOWN, // BALOAD,
   UNKNOWN, // CALOAD,
   UNKNOWN, // SALOAD,
   UNKNOWN, // ISTORE,
   UNKNOWN, // LSTORE,
   UNKNOWN, // FSTORE,
   UNKNOWN, // DSTORE,
   1, // ASTORE, 
   0, // ISTORE_0, 
   0, // ISTORE_1,
   0, // ISTORE_2,
   0, // ISTORE_3,
   UNKNOWN, // LSTORE_0,
   UNKNOWN, // LSTORE_1,
   UNKNOWN, // LSTORE_2,
   UNKNOWN, // LSTORE_3,
   UNKNOWN, // FSTORE_0,
   UNKNOWN, // FSTORE_1,
   UNKNOWN, // FSTORE_2,
   UNKNOWN, // FSTORE_3,
   UNKNOWN, // DSTORE_0,
   UNKNOWN, // DSTORE_1,
   UNKNOWN, // DSTORE_2,
   UNKNOWN, // DSTORE_3,
   0, // ASTORE_0, 
   0, // ASTORE_1,
   0, // ASTORE_2,
   0, // ASTORE_3,
   0, // IASTORE, 
   UNKNOWN, // LASTORE,
   UNKNOWN, // FASTORE,
   UNKNOWN, // DASTORE,
   UNKNOWN, // AASTORE,
   UNKNOWN, // BASTORE,
   UNKNOWN, // CASTORE,
   UNKNOWN, // SASTORE,
   0, // POP,
   0, // POP2, 
   0, // DUP,
   UNKNOWN, // DUP_X1,
   UNKNOWN, // DUP_X2,
   UNKNOWN, // DUP2
   UNKNOWN, // DUP2_X1,
   UNKNOWN, // DUP2_X2,
   0, // SWAP, 
   0, // IADD, 
   UNKNOWN, // LADD,
   UNKNOWN, // FADD,
   UNKNOWN, // DADD,
   0, // ISUB, 
   UNKNOWN, // LSUB,
   UNKNOWN, // FSUB,
   UNKNOWN, // DSUB,
   0, // IMUL, 
   UNKNOWN, // LMUL,
   UNKNOWN, // FMUL,
   UNKNOWN, // DMUL,
   0, // IDIV, 
   UNKNOWN, // LDIV,
   UNKNOWN, // FDIV,
   UNKNOWN, // DDIV,
   0, // IREM, 
   UNKNOWN, // LREM,
   UNKNOWN, // FREM,
   UNKNOWN, // DREM,
   0, // INEG, 
   UNKNOWN, // LNEG,
   UNKNOWN, // FNEG,
   UNKNOWN, // DNEG,
   UNKNOWN, // ISHL,
   UNKNOWN, // LSHL,
   UNKNOWN, // ISHR,
   UNKNOWN, // LSHR,
   UNKNOWN, // IUSHR,
   UNKNOWN, // LUSHR,
   0, // IAND, 
   UNKNOWN, // LAND,
   0, // IOR, 
   UNKNOWN, // LOR,
   0, // IXOR, 
   UNKNOWN, // LXOR,
   2, // IINC, 
   UNKNOWN, // I2L,
   UNKNOWN, // I2F,
   UNKNOWN, // I2D,
   UNKNOWN, // L2I,
   UNKNOWN, // L2F,
   UNKNOWN, // L2D,
   UNKNOWN, // F2I,
   UNKNOWN, // F2L,
   UNKNOWN, // F2D,
   UNKNOWN, // D2I,
   UNKNOWN, // D2L,
   UNKNOWN, // D2F,
   UNKNOWN, // INT2BYTE,
   UNKNOWN, // INT2CHAR,
   UNKNOWN, // INT2SHORT,
   UNKNOWN, // LCMP,
   UNKNOWN, // FCMPL,
   UNKNOWN, // FCMPG,
   UNKNOWN, // DCMPL,
   UNKNOWN, // DCMPG,
   2, // IFEQ, 
   2, // IFNE, 
   2, // IFLT,
   2, // IFGE,
   2, // IFGT,
   2, // IFLE,
   2, // IF_ICMPEQ, 
   2, // IF_ICMPNE, 
   2, // IF_ICMPLT,
   2, // IF_ICMPGE,
   2, // IF_ICMPGT,
   2, // IF_ICMPLE,
   2, // IF_ACMPEQ, 
   2, // IF_ACMPNE, 
   2, // GOTO, 
   UNKNOWN, // JSR,
   UNKNOWN, // RET,
   UNKNOWN, // TABLESWITCH,
   UNKNOWN, // LOOKUPSWITCH,
   0, // IRETURN, 
   UNKNOWN, // LRETURN,
   UNKNOWN, // FRETURN,
   UNKNOWN, // DRETURN,
   0, // ARETURN, 
   0, // RETURN, 
   2, // GETSTATIC, 
   UNKNOWN, // PUTSTATIC,
   UNKNOWN, // GETFIELD,
   UNKNOWN, // PUTFIELD,
   2, // INVOKEVIRTUAL,
   UNKNOWN, // INVOKESPECIAL,
   2, // INVOKESTATIC, 
   UNKNOWN, // INVOKEINTERFACE,
   UNKNOWN, // unused
   UNKNOWN, // NEW,
   1, // NEWARRAY,  
   UNKNOWN, // ANEWARRAY, 
   0, // ARRAYLENGTH, 
   UNKNOWN, // ATHROW,
   UNKNOWN, // CHECKCAST,
   UNKNOWN, // INSTANCEOF,
   UNKNOWN, // MONITORENTER,
   UNKNOWN, // MONITOREXIT,
   UNKNOWN, // WIDE,
   UNKNOWN, // MULTIANEWARRAY,
   2, // IFNULL,
   2, // IFNONNULL,  
   4, // GOTO_W,  
   UNKNOWN  // JSR_W
  };


  u2 nargs = count_args(get_utf8(this_class,method.descriptor_index));
  u4 *locals = sp - nargs + 1; /* address of local #0 */
  sp = locals + method.max_locals - 1;  /* allocate space for locals */
  if (sp + method.max_stack >= limit) /* check there is room for operand stack. */
    die("stack overflow");

  /* Convert method code to longs, filling in opcode snippet addresses */
  u4 longcode[method.code_length];
  int k = 0;
  int i = 0;
  while (i < method.code_length) {
    u1 opcode = method.code[i++];
    longcode[k++] = (u4) (dispatch_table[opcode]);
    int j;
    for (j= 0; j < param_size[opcode]; j++)
      longcode[k++] = (u4) (method.code[i++]);
  }
  u4 *pc = longcode;  /* program counter */
  goto *(*pc);

 ARRAYLENGTH:
  {
    int32 *a = (int32 *) (*sp);
    if (a == 0)
      exception ("NullPointer");
    *sp = (u4) (*a);
    pc++;
    goto *(*pc);
  }
 BIPUSH:
  {	
    *(++sp) = (int8)((u1)(pc[1]));
    pc+=2;
    goto *(*pc); 
  }
 DUP: 
  {	
    sp++;
    *sp = *(sp-1);
    pc++;
    goto *(*pc);
  }
 GETSTATIC:
  { 
    u2 index = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    /* kludge for java.lang.System.out */
    if ((strcmp (get_field_class(this_class,index),"java/lang/System") == 0) &&
	(strcmp (get_field_name(this_class,index),"out") == 0)) 
      sp++;  /* just push an empty slot */
    else 
      die("unimplemented instruction GETSTATIC");
    pc+=3;
    goto *(*pc);
  }
 GOTO:
  {
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    pc += offset;
    goto *(*pc);
  }
 GOTO_W:
  { 
    int32 offset = (((u1)pc[1]) << 24) | (((u1)pc[2]) << 16) | (((u1)pc[3]) << 8) | ((u1)pc[4]);
    pc += offset;
    goto *(*pc);
  }
 IADD:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*sp);
    *sp = (u4) (v1+v2);
    pc++;
    goto *(*pc);
  }
 IALOAD:
  {
    int32 index = (int32) (*(sp--));
    int32 *a = (int32 *) (*sp);
    int32 length;
    if (a == 0)
      exception ("NullPointer");
    length = *a;
    if (index < 0 || index >= length)
      exception ("ArrayIndexOutOfBounds");
    *sp = (u4) (a[index+1]);  /* adjust for length field */
    pc ++;
    goto *(*pc);
  }
 IAND:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*sp);
    *sp = (u4) (v1&v2);
    pc++;
    goto *(*pc);
  }
 IASTORE:
  {
    int32 v = (int32) (*(sp--));
    int32 index = (int32) (*(sp--));
    int32 *a = (int32 *) (*sp--);
    int32 length;
    if (a == 0)
      exception ("NullPointer");
    length = *a;
    if (index < 0 || index >= length)
      exception ("ArrayIndexOutOfBounds");
    a[index+1] = v;  /* adjust for length field */
    pc ++;
    goto *(*pc);
  }
 ICONST_M1:
  {
    *(++sp) = (u4) (-1);
    pc++;
    goto *(*pc);
  }
 ACONST_NULL:
 ICONST_0:
  {
    *(++sp) = (u4) 0;
    pc++;
    goto *(*pc);
  }
 ICONST_1:
  {
    *(++sp) = (u4) 1;
    pc++;
    goto *(*pc);
  }
 ICONST_2:
  {
    *(++sp) = (u4) 2;
    pc++;
    goto *(*pc);
  }
 ICONST_3:
  {
    *(++sp) = (u4) 3;
    pc++;
    goto *(*pc);
  }
 ICONST_4:
  {
    *(++sp) = (u4) 4;
    pc++;
    goto *(*pc);
  }
 ICONST_5:
  {
    *(++sp) = (u4) 5;
    pc++;
    goto *(*pc);
  }
 IDIV:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*sp);
    *sp = (u4) (v1/v2);
    pc++;
    goto *(*pc);
  }
 IF_ACMPEQ:
  {
    int32 *a2 = (int32 *) (*(sp--));
    int32 *a1 = (int32 *) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (a1 == a2)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IF_ACMPNE:
  {
    int32 *a2 = (int32 *) (*(sp--));
    int32 *a1 = (int32 *) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (a1 != a2)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IF_ICMPEQ:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v1 == v2)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IF_ICMPGE:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v1 >= v2)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IF_ICMPGT:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v1 > v2)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IF_ICMPLE:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v1 <= v2)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IF_ICMPLT:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v1 < v2)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IF_ICMPNE:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v1 != v2)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IFEQ:
  {
    int32 v = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v == 0)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IFGE:
  {
    int32 v = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v >= 0)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IFGT:
  {
    int32 v = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v > 0)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IFLE:
  {
    int32 v = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v <= 0)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IFLT:
  {
    int32 v = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v < 0)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IFNE:
  {
    int32 v = (int32) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (v != 0)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IFNONNULL:
  {
    int32 *a = (int32 *) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (a != 0)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IFNULL:
  {
    int32 *a = (int32 *) (*(sp--));
    int16 offset = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    if (a == 0)
      pc += offset;
    else
      pc += 3;
    goto *(*pc);
  }
 IINC:
  {
    u1 index = ((u1)pc[1]);
    int8 incr = (int8) (((u1)pc[2]));
    locals[index] += incr;
    pc += 3;
    goto *(*pc);
  }
 ALOAD:
 ILOAD:
  {
    u1 index = ((u1)pc[1]);
    *(++sp) = locals[index];
    pc += 2;
    goto *(*pc);
  }
 ALOAD_0:
 ILOAD_0:
  {
    *(++sp) = locals[0];
    pc ++;
    goto *(*pc);
  }
 ALOAD_1:
 ILOAD_1:
  {
    *(++sp) = locals[1];
    pc ++;
    goto *(*pc);
  }
 ALOAD_2:
 ILOAD_2:
  {
    *(++sp) = locals[2];
    pc ++;
    goto *(*pc);
  }
 ALOAD_3:
 ILOAD_3:
  {
    *(++sp) = locals[3];
    pc ++;
    goto *(*pc);
  }
 IMUL:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*sp);
    *sp = (u4) (v1*v2);
    pc++;
    goto *(*pc);
  }
 INEG:
  {
    int32 v = (int32) (*sp);
    *sp = (u4) (-v);
    pc++;
    goto *(*pc);
  }
 INVOKESTATIC:
  {
    u2 index = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    char *method_class = get_method_class(this_class,index);
    /* only support static calls into this class */
    if ((strcmp(method_class,get_class(this_class,this_class.class_index)) == 0)) {
      Method m = find_method(this_class,
			     get_method_name(this_class,index),
			     get_method_type(this_class,index));
      interp(m);
    } else
      die ("unimplemented INVOKESTATIC to method in different class %s", method_class);
    pc +=3;
    goto *(*pc);
  }
 INVOKEVIRTUAL:
  { 
    u2 index = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    /* kludge for java.io.PrintStream.print */
    if ((strcmp(get_method_class(this_class,index),"java/io/PrintStream") == 0)
	&& (strcmp(get_method_name(this_class,index),"print") == 0)) {
      char *type = get_method_type(this_class,index);
      if (strcmp(type,"(Ljava/lang/String;)V") == 0) {
	/* arg is string */
	printf("%s",(char *)(*(sp--)));
      } else if (strcmp(type,"(I)V") == 0) {
	/* arg is int */
	printf("%i",(int32)(*(sp--)));
      } else 
	die ("unimplemented PrintStream.print method with signature %s", type);
      sp--;  /* pop the empty slot corresponding to the object argument */
    } else 
      die ("unimplemented instruction INVOKEVIRTUAL");
    pc+=3;
    goto *(*pc);
  }
 IOR:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*sp);
    *sp = (u4) (v1|v2);
    pc++;
    goto *(*pc);
  }
 IREM:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*sp);
    *sp = (u4) (v1%v2);
    pc++;
    goto *(*pc);
  }
 ARETURN:
 IRETURN:
  { 
    u4 v = *sp;
    sp = locals;
    *sp = v;
    return;
  }
 ASTORE:
 ISTORE:
  {
    u1 index = ((u1)pc[1]);
    locals[index] = *(sp--);
    pc += 2;
    goto *(*pc);
  }
 ASTORE_0:
 ISTORE_0:
  {
    locals[0] = *(sp--);
    pc++;
    goto *(*pc);
  }
 ASTORE_1:
 ISTORE_1:
  {
    locals[1] = *(sp--);
    pc++;
    goto *(*pc);
  }
 ASTORE_2:
 ISTORE_2:
  {
    locals[2] = *(sp--);
    pc++;
    goto *(*pc);
  }
 ASTORE_3:
 ISTORE_3:
  {
    locals[3] = *(sp--);
    pc++;
    goto *(*pc);
  }
 ISUB:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*sp);
    *sp = (u4) (v1-v2);
    pc++;
    goto *(*pc);
  }
 IXOR:
  {
    int32 v2 = (int32) (*(sp--));
    int32 v1 = (int32) (*sp);
    *sp = (u4) (v1^v2);
    pc++;
    goto *(*pc);
  }
 LDC:
  {
    u1 index = ((u1)pc[1]);
    u1 tag = get_constant_tag(this_class,index);
    if (tag == CONSTANT_String) 
      *(++sp) = (u4) (get_string(this_class,index));
    else if (tag == CONSTANT_Integer) 
      *(++sp) = (u4) (get_integer(this_class,index));
    else 
      die ("unsupported constant type %d", tag);
    pc+=2;
    goto *(*pc);
  }
 LDC_W:
  {
    u2 index = (((u1)pc[1]) << 8) | ((u1)pc[2]);
    u1 tag = get_constant_tag(this_class,index);
    if (tag == CONSTANT_String) 
      *(++sp) = (u4) (get_string(this_class,index));
    else if (tag == CONSTANT_Integer) 
      *(++sp) = (u4) (get_integer(this_class,index));
    else 
      die ("unsupported constant type %d", tag);
    pc+=3;
    goto *(*pc);
  }
 NEWARRAY:
  {
    u1 atype = ((u1)pc[1]);
    int32 count;
    int32 *a;
    int i;
    if (atype != 10) 
      die("unimplemented array type %d",atype);
    count = (int32) (*sp);
    if (count < 0)
      exception ("NegativeArraySize");
    a = alloc(sizeof(int32) * (count+1));
    *a = count;
    for (i = 0; i < count; i++) 
      a[i+1] = 0;
    *sp = (int32) a;
    pc += 2;
    goto *(*pc);
  }
 NOP: 
  {
    pc++;
    goto *(*pc);
  }
 POP:
  {
    sp--;
    pc++;
    goto *(*pc);
  }
 POP2:
  {
    sp -= 2;
    pc++;
    goto *(*pc);
  }
 RETURN:
  {
    sp = locals - 1;
    return;
  }
 SIPUSH:
  {
    *(++sp) = (int16) ((((u1)pc[1]) << 8) | ((u1)pc[2]));
    pc +=3;
    goto *(*pc);
  }
 SWAP:
  {
    u4 t = *sp;
    *sp = *(sp-1);
    *(sp-1) = t;
    pc++;
    goto *(*pc);
  }
 UNDEF:
  die("unimplemented instruction code %i", *pc);

}

int main(int argc, char **argv) {
  char file[255];
  FILE *cf;
  Method main_method;
  strcpy(file,*++argv);
  strcat(file,".class");
  cf = fopen(file,"r");
  read_class(cf,&this_class);
  fclose(cf);
  main_method = find_method(this_class,"main","([Ljava/lang/String;)V");
  interp(main_method);
  return 0;
}
