/*
 * kaffe.def
 * Kaffe instruction definitions.
 *
 * Copyright (c) 1996, 1997
 *	Transvirtual Technologies, Inc.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution 
 * of this file. 
 */

/* 
 * This file has been modified by JJC, for its use as part of his debugger, bdbj.
 * Modifications are delimited by START JJC, END JJC blocks and single lines
 * modified are marked by simply JJC.
 *
 * Last modified: April 2002.
 */

define_insn(NOP)
{
  /*
   * No operation.
   */
}

define_insn(ACONST_NULL)
{
  /*
   * ... -> ..., 0
   */
  push(1);
  move_ref_const(stack(0), 0);
  markisobj; /* JJC */
}

define_insn(ICONST_M1)
     define_insn_alias(ICONST_0)
     define_insn_alias(ICONST_1)
     define_insn_alias(ICONST_2)
     define_insn_alias(ICONST_3)
     define_insn_alias(ICONST_4)
     define_insn_alias(ICONST_5)
{
  /*
   * ... -> ..., [-1 .. 5]
   */
  push(1);
  move_int_const(stack(0), getopcode() - ICONST_0);
  marknotobj_int; /* JJC */
}

define_insn(LCONST_0)
     define_insn_alias(LCONST_1)
{
  /*
   * ... -> ..., 0, [0 .. 1]
   */
  push(2);
  move_long_const(stack_long(0), getopcode() - LCONST_0);
  marknotobj2_long; /* JJC */
}

define_insn(FCONST_0)
     define_insn_alias(FCONST_1)
     define_insn_alias(FCONST_2)
{
  /*
   * ... -> ..., [0.0 .. 2.0]
   */
  push(1);
  move_float_const(stack(0), (jfloat)(getopcode() - FCONST_0));
  marknotobj_float; /* JJC */
}

define_insn(DCONST_0)
     define_insn_alias(DCONST_1)
{
  /*
   * ... -> ..., [0.0 .. 1.0]
   */
  push(2);
  move_double_const(stack_double(0), (jdouble)(getopcode() - DCONST_0));
  marknotobj2_double; /* JJC */
}

define_insn(BIPUSH)
{
  /*
   * ... -> ..., val
   */
  check_pc (0);

  low = (int8)getpc(0);
  push(1);
  move_int_const(stack(0), low);
  marknotobj_int; /* JJC */
}

define_insn(SIPUSH)
{
  /*
   * ... -> ..., val
   */
  check_pcidx (0);

  low = (int16)((getpc(0) << 8) | getpc(1));
  push(1);
  move_int_const(stack(0), low);
  marknotobj_int; /* JJC */
}

define_insn(LDC1)
{
  /*
   * ... -> ..., const
   */
  check_pc (0);

  idx = (uint8)getpc(0);
  push(1);
  switch (CLASS_CONST_TAG(current_class(), idx)) {
  case CONSTANT_String:
    {
      errorInfo _kdef_einfo;
      void *s = resolveString(current_class(), idx, &_kdef_einfo);

      if (!s) { compile_time_error(_kdef_einfo); }
      move_string_const(stack(0), s);
      markisobj; /* JJC */
    }
    break;
  case CONSTANT_ResolvedString:
    move_string_const(stack(0), (void*)CLASS_CONST_DATA(current_class(),idx));
    markisobj; /* JJC */
    break;
  case CONSTANT_Float:
    move_float_const(stack(0), *(float*)&CLASS_CONST_DATA(current_class(),idx));
    marknotobj_float; /* JJC */
    break;
  case CONSTANT_Integer:
    move_int_const(stack(0), CLASS_CONST_DATA(current_class(),idx));
    marknotobj_int; /* JJC */ 
    break;
  default:
    ABORT();
  }
}

define_insn(LDC2)
{
  /*
   * ... -> ..., const
   */
  check_pcidx (0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));
  push(1);
  switch (CLASS_CONST_TAG(current_class(), idx)) {
  case CONSTANT_String:
    {
      errorInfo _kdef_einfo;
      void *st = resolveString
	(current_class(), idx,
	 &_kdef_einfo);

      if (!st) { compile_time_error(_kdef_einfo); }
      move_string_const(stack(0), st);
      markisobj; /* JJC */
    }
    break;
  case CONSTANT_ResolvedString:
    move_string_const(stack(0), (void*)CLASS_CONST_DATA(current_class(),idx));
    markisobj; /* JJC */
    break;
  case CONSTANT_Float:
    move_float_const(stack(0), *(jfloat*)&CLASS_CONST_DATA(current_class(),idx));
    marknotobj_float; /* JJC */
    break;
  case CONSTANT_Integer:
    move_int_const(stack(0), CLASS_CONST_DATA(current_class(),idx));
    marknotobj_int; /* JJC */
    break;
  default:
    ABORT();
  }
}

define_insn(LDC2W)
{
  /*
   * ... -> ..., long const
   */
  check_pcidx (0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));
  tmpl = CLASS_CONST_LONG (current_class(), idx);
  push(2);
  switch (CLASS_CONST_TAG(current_class(), idx)) {
  case CONSTANT_Long:
    move_long_const(stack_long(0), tmpl);
    marknotobj2_long; /* JJC */
    break;
  case CONSTANT_Double:
    move_double_const(stack_double(0), *(jdouble*)&tmpl);
    marknotobj2_double; /* JJC */
    break;
  default:
    ABORT();
  }
}

define_insn(ILOAD)
{
  /*
   * ..., -> ..., local variable
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_local_int(idx);

  push(1);
  move_int(stack(0), local(idx));
  marknotobj_int; /* JJC */
}

define_insn(LLOAD)
{
  /*
   * ..., -> ..., long local variable
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_local_long(idx+1);

  push(2);
  move_long(stack_long(0), local_long(idx));
  marknotobj2_long; /* JJC */
}

define_insn(FLOAD)
{
  /*
   * ..., -> ..., local variable
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_local_float(idx);

  push(1);
  move_float(stack(0), local_float(idx));
  marknotobj_float; /* JJC */
}

define_insn(DLOAD)
{
  /*
   * ..., -> ..., double local variable
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_local_double(idx+1);

  push(2);
  move_double(stack_double(0), local_double(idx));
  marknotobj2_double; /* JJC */
}

define_insn(ALOAD)
{
  /*
   * ..., -> ..., local variable
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_local_ref(idx);

  push(1);
  move_ref(stack(0), local(idx));
  /* START JJC */
  if( valid_log )
    if( opsobjs )
      *opsobjs = lvtobjs[ idx ];
  /* markisobj; */ /* JJC */
  /* END JJC */
}

define_insn(ILOAD_0)
     define_insn_alias(ILOAD_1)
     define_insn_alias(ILOAD_2)
     define_insn_alias(ILOAD_3)
{
  /*
   * ..., -> ..., local variable
   */
  check_local_int(getopcode() - ILOAD_0);

  push(1);
  move_int(stack(0), local(getopcode() - ILOAD_0));
  marknotobj_int; /* JJC */
}

define_insn(LLOAD_0)
     define_insn_alias(LLOAD_1)
     define_insn_alias(LLOAD_2)
     define_insn_alias(LLOAD_3)
{
  /*
   * ..., -> ..., local variable
   */
  check_local_long((getopcode() - LLOAD_0)+1);

  push(2);
  move_long(stack_long(0), local_long(getopcode() - LLOAD_0));
  marknotobj2_long; /* JJC */
}

define_insn(FLOAD_0)
     define_insn_alias(FLOAD_1)
     define_insn_alias(FLOAD_2)
     define_insn_alias(FLOAD_3)
{
  /*
   * ..., -> ..., local variable
   */
  check_local_float(getopcode() - FLOAD_0);

  push(1);
  move_float(stack(0), local_float(getopcode() - FLOAD_0));
  marknotobj_float; /* JJC */
}

define_insn(DLOAD_0)
     define_insn_alias(DLOAD_1)
     define_insn_alias(DLOAD_2)
     define_insn_alias(DLOAD_3)
{
  /*
   * ..., -> ..., local variable
   */
  check_local_double((getopcode() - DLOAD_0)+1);

  push(2);
  move_double(stack_double(0), local_double(getopcode() - DLOAD_0));
  marknotobj2_double; /* JJC */
}

define_insn(ALOAD_0)
     define_insn_alias(ALOAD_1)
     define_insn_alias(ALOAD_2)
     define_insn_alias(ALOAD_3)
{
  /*
   * ..., -> ..., local variable
   */
  check_local_ref(getopcode() - ALOAD_0);

  push(1);
  move_ref(stack(0), local(getopcode() - ALOAD_0));
  /* START JJC */
  if( valid_log )
    if( opsobjs )
      *opsobjs = lvtobjs[ getopcode() - ALOAD_0 ];
  /* END JJC */
}

define_insn(IALOAD)
{
  /*
   * ..., array ref, index -> ..., value
   */
  check_stack_int(0);
  check_stack_intarray(1);

  CHECK_NULL (IALOAD, rstack(1), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(1), rstack(0));

  load_offset_scaled_int(stack(1), rstack(1), rstack(0), object_array_offset);
  pop(1);
  marknotobj_int; /* JJC */
}

define_insn(LALOAD)
{
  /*
   * ..., array ref, index -> ..., long value
   */
  check_stack_int(0);
  check_stack_longarray(1);

  CHECK_NULL (LALOAD, stack(1), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(1), rstack(0));

  load_offset_scaled_long(stack_long(0), stack(1), stack(0), object_array_offset);
  marknotobj2_long; /* JJC */
}

define_insn(FALOAD)
{
  /*
   * ..., array ref, index -> ..., float value
   */
  check_stack_int(0);
  check_stack_floatarray(1);

  CHECK_NULL (FALOAD, stack(1), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(1), rstack(0));

  load_offset_scaled_float(stack(1), stack(1), stack(0), object_array_offset);

  pop(1);
  marknotobj_float; /* JJC */
}

define_insn(DALOAD)
{
  /*
   * ..., array ref, index -> ..., double value
   */
  check_stack_int(0);
  check_stack_doublearray(1);

  CHECK_NULL (DALOAD, stack(1), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(1), rstack(0));

  load_offset_scaled_double(stack_double(0), stack(1), stack(0), object_array_offset);
  marknotobj2_double; /* JJC */
}

define_insn(AALOAD)
{
  /*
   * ..., array ref, index -> ..., ref value
   */
  check_stack_int(0);
  check_stack_refarray(1);

  CHECK_NULL(AALOAD, rstack(1), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(1), rstack(0));

  /* START JJC */
  if( valid_log )
    oldopsobjs = ( strncmp( CLASS_ELEMENT_TYPE(OBJECT_CLASS((Hjava_lang_Object*)(stack(1)[0].v.taddr)))->name->data, "Lkaffe/util/Ptr;", 16 ) == 0 ) ? NOTSUREOBJ : ISOBJ;
  /* END JJC */

  load_offset_scaled_ref(stack(1), rstack(1), rstack(0), object_array_offset);

  pop(1);

  /* START JJC */
  if( valid_log ) {
    if( oldopsobjs == 0 )
      *opsobjs = oldopsobjs;
  }
  /* END JJC */
}

define_insn(BALOAD)
{
  /*
   * ..., array ref, index -> ..., byte value
   */
  check_stack_int(0);
  check_stack_bytearray(1);

  CHECK_NULL(BALOAD, rstack(1), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(1), rstack(0));

  load_offset_scaled_byte(stack(1), rstack(1), rstack(0), object_array_offset);
  pop(1);
  marknotobj_int; /* JJC */
}

define_insn(CALOAD)
{
  /*
   * ..., array ref, index -> ..., char value
   */
  check_stack_int(0);
  check_stack_chararray(1);

  CHECK_NULL(CALOAD, rstack(1), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(1), rstack(0));

  load_offset_scaled_char(stack(1), rstack(1), rstack(0), object_array_offset);
  pop(1);
  marknotobj_int; /* JJC */
}

define_insn(SALOAD)
{
  /*
   * ..., array ref, index -> ..., short value
   */
  check_stack_int(0);
  check_stack_shortarray(1);

  CHECK_NULL(SALOAD, rstack(1), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(1), rstack(0));

  load_offset_scaled_short(stack(1), rstack(1), rstack(0), object_array_offset);
  pop(1);
  marknotobj_int; /* JJC */
}

define_insn(ISTORE)
{
  /*
   * ..., var -> ...
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_stack_int(0);

  if( valid_log ) wcbuffs( local( idx )[ 0 ], opsobjs ? lvtobjs[ idx ] : 0, debug, thr ); /* JJC */
  move_int(local(idx), stack(0));
  if( opsobjs ) lvtobjs[ idx ] = NOTOBJ_INT; /* JJC */
  pop(1);
}

define_insn(LSTORE)
{
  /*
   * ..., long var -> ...
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_stack_long(0);

	

  /* move_long(local_long(idx), stack_long(0)); */
  swap_long( local_long( idx ), stack_long( 0 ) ); /* JJC */
  /* START JJC */
  if( opsobjs ) {
    *( opsobjs - 1 ) = lvtobjs[ idx ];
    *opsobjs = lvtobjs[ idx + 1 ];
    /*  *( opsobjs - 1 ) = *opsobjs = lvtobjs[ idx ]; */
    lvtobjs[ idx ] = NOTOBJ_LONG;
    lvtobjs[ idx + 1 ] = NOTOBJ_SKIP;
  }
  /* END JJC */
  if( valid_log ) savestack( 2 );                  /* JJC */

  pop(2);
}

define_insn(FSTORE)
{
  /*
   * ..., var -> ...
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_stack_float(0);

  if( valid_log ) wcbuffs( local( idx )[ 0 ], opsobjs ? lvtobjs[ idx ] : 0, debug, thr ); /* JJC */
  move_float(local_float(idx), stack(0)); 
  if( opsobjs ) lvtobjs[ idx ] = NOTOBJ_FLOAT; /* JJC */
  pop(1);
}

define_insn(DSTORE)
{
  /*
   * ..., var -> ...
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_stack_double(0);

  /* move_double(local_double(idx), stack_double(0)); */
  swap_long( local_double( idx ), stack_double( 0 ) ); /* JJC */
  /* START JJC */
  if( opsobjs ) {
    *( opsobjs - 1 ) = lvtobjs[ idx ]; 
    *opsobjs = lvtobjs[ idx + 1 ];
    lvtobjs[ idx ] = NOTOBJ_DOUBLE;
    lvtobjs[ idx + 1 ] = NOTOBJ_SKIP;
  }
  /* END JJC */
  if( valid_log ) savestack( 2 );                      /* JJC */

  pop(2);
}

define_insn(ASTORE)
{
  /*
   * ..., var -> ...
   */
  check_pc (0);
  idx = (uint8)getpc(0);

  check_stack_ref(0);

  /* move_ref(local(idx), stack(0)); */

  /* START JJC */
  swap_any( local( idx ), stack( 0 ) );    
  if( opsobjs ) {
    oldopsobjs = *opsobjs;
    *opsobjs = lvtobjs[ idx ];
    if( local( idx )[ 0 ].v.tint <= 0xFFFF )	
      lvtobjs[ idx ] = 0; /* almost certainly a return address */
    else
      lvtobjs[ idx ] = oldopsobjs;
  }
  if( valid_log ) savestack( 1 );       
  /* END JJC */
   
  pop(1);
}

define_insn(ISTORE_0)
     define_insn_alias(ISTORE_1)
     define_insn_alias(ISTORE_2)
     define_insn_alias(ISTORE_3)
{
  /*
   * ..., val -> ...
   */
  check_stack_int(0);

  if( valid_log ) wcbuffs( local( getopcode() - ISTORE_0 )[ 0 ], opsobjs ?      /* JJC */
			   lvtobjs[ getopcode() - ISTORE_0 ] : 0, debug, thr ); /* JJC */
  move_int(local(getopcode() - ISTORE_0), stack(0));
  if( opsobjs ) lvtobjs[ getopcode() - ISTORE_0 ] = NOTOBJ_INT; /* JJC */

  /* swap_any(local(getopcode() - ISTORE_0), stack(0)); */ /* JJC */
  /* START JJC */
  /*
    if( opsobjs ) {
    *opsobjs = lvtobjs[ getopcode() - ISTORE_0 ];
    lvtobjs[ getopcode() - ISTORE_0 ] = NOTOBJ_INT;
    }
  */
  /* END JJC */
  /* if( valid_log ) savestack( 1 ); */ /* JJC */

  pop(1);
}

define_insn(LSTORE_0)
     define_insn_alias(LSTORE_1)
     define_insn_alias(LSTORE_2)
     define_insn_alias(LSTORE_3)
{
  /*
   * ..., long val -> ...
   */
  check_stack_long(0);

  /* move_long(local_long(getopcode() - LSTORE_0), stack_long(0)); removed by JJC */
  swap_long(local_long(getopcode() - LSTORE_0), stack_long(0)); /* JJC */
  /* START JJC */
  if( opsobjs ) {
    *( opsobjs - 1 ) = lvtobjs[ getopcode() - LSTORE_0 ]; 
    *opsobjs = lvtobjs[ getopcode() - LSTORE_0 + 1 ];

    lvtobjs[ getopcode() - LSTORE_0 ] = NOTOBJ_LONG;
    lvtobjs[ getopcode() - LSTORE_0 + 1 ] = NOTOBJ_SKIP;
  }
  /* END JJC */

  if( valid_log ) savestack( 2 ); /* JJC */

  pop(2);
}

define_insn(FSTORE_0)
     define_insn_alias(FSTORE_1)
     define_insn_alias(FSTORE_2)
     define_insn_alias(FSTORE_3)
{
  /*
   * ..., val -> ...
   */
  check_stack_float(0);

  /* move_float(local_float(getopcode() - FSTORE_0), stack(0)); removed by JJC */
  swap_any(local_float(getopcode() - FSTORE_0), stack(0)); /* JJC */
  /* START JJC */
  if( opsobjs ) {
    *opsobjs = lvtobjs[ getopcode() - FSTORE_0 ];
    lvtobjs[ getopcode() - FSTORE_0 ] = NOTOBJ_FLOAT;
  }
  /* END JJC */
  if( valid_log ) savestack( 1 ); /* JJC */
  pop(1);
}

define_insn(DSTORE_0)
     define_insn_alias(DSTORE_1)
     define_insn_alias(DSTORE_2)
     define_insn_alias(DSTORE_3)
{
  /*
   * ..., double val -> ...
   */
  check_stack_double(0);

  /* move_double(local_double(getopcode() - DSTORE_0), stack_double(0)); removed by JJC */
  swap_long(local_double(getopcode() - DSTORE_0), stack_double(0)); /* JJC */
  /* START JJC */
  if( opsobjs ) {
    *( opsobjs - 1 ) = lvtobjs[ getopcode() - DSTORE_0 ];
    *opsobjs = lvtobjs[ getopcode() - DSTORE_0 + 1 ];
    lvtobjs[ getopcode() - DSTORE_0 ] = NOTOBJ_DOUBLE;
    lvtobjs[ getopcode() - DSTORE_0 + 1] = NOTOBJ_SKIP;
  }
  /* END JJC */
  if( valid_log ) savestack( 2 ); /* JJC */

  pop(2);
}

define_insn(ASTORE_0)
     define_insn_alias(ASTORE_1)
     define_insn_alias(ASTORE_2)
     define_insn_alias(ASTORE_3)
{
  /*
   * ..., val -> ...
   */
  check_stack_ref(0);

  /*move_ref(local(getopcode() - ASTORE_0), stack(0));*/
	
  /* START JJC */
  swap_any(local(getopcode() - ASTORE_0), stack(0)); /* JJC */
  if( opsobjs ) {
    oldopsobjs = *opsobjs;
    *opsobjs = lvtobjs[ getopcode() - ASTORE_0 ];
    if( local(getopcode() - ASTORE_0)[ 0 ].v.tint <= 0xFFFF )
      lvtobjs[ getopcode() - ASTORE_0 ] = 0; /* almost certainly a return address */
    else
      lvtobjs[ getopcode() - ASTORE_0 ] = oldopsobjs;
  }
  if( valid_log ) savestack( 1 ); 
  /* END JJC */

  pop(1);
}

define_insn(IASTORE)
{
  /*
   * ..., array ref, index, val -> ...
   */
  check_stack_int(0);
  check_stack_int(1);
  check_stack_intarray(2);

  CHECK_NULL(IASTORE, rstack(2), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(2), rstack(1));

  load_offset_scaled_int( tmp, stack( 2 ), stack( 1 ), object_array_offset ); /* JJC */
  store_offset_scaled_int(rstack(2), rstack(1), object_array_offset, rstack(0));
  move_int( stack( 0 ), tmp ); /* JJC */
  if( valid_log ) savestack( 3 );            /* JJC */
  pop(3);
}

define_insn(LASTORE)
{
  /*
   * ..., array ref, index, long val -> ...
   */
  check_stack_int(0);
  check_stack_int(1);
  check_stack_longarray(2);

  CHECK_NULL(LASTORE, stack(3), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(3), rstack(2));
  load_offset_scaled_long( tmp, stack( 3 ), stack( 2 ), object_array_offset ); /* JJC */
  store_offset_scaled_long(stack(3), stack(2), object_array_offset, stack_long(0));
  move_long( stack_long( 0 ), tmp ); /* JJC */
  if( valid_log ) savestack( 4 ); /* JJC */
  pop(4);
}

define_insn(FASTORE)
{
  /*
   * ..., array ref, index, float val -> ...
   */
  check_stack_int(0);
  check_stack_int(1);
  check_stack_floatarray(2);

  CHECK_NULL(FASTORE, stack(2), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(2), rstack(1));
       
  load_offset_scaled_float( tmp, stack( 2 ), stack( 1 ), object_array_offset ); /* JJC */
  store_offset_scaled_float(stack(2), stack(1), object_array_offset, stack(0));
  move_float( stack( 0 ), tmp ); /* JJC */
  if( valid_log ) savestack( 3 ); /* JJC */ 	

  pop(3);
}

define_insn(DASTORE)
{
  /*
   * ..., array ref, index, double val -> ...
   */
  check_stack_int(0);
  check_stack_int(1);
  check_stack_doublearray(2);

  CHECK_NULL(DASTORE, stack(3), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(3), rstack(2));

  load_offset_scaled_double( tmp, stack( 3 ), stack( 2 ), object_array_offset ); /* JJC */
  store_offset_scaled_double(stack(3), stack(2), object_array_offset, stack_double(0));
  move_double( stack_long( 0 ), tmp ); /* JJC */
  if( valid_log ) savestack( 4 ); /* JJC */

  pop(4);
}

define_insn(AASTORE)
{
  /*
   * ..., array ref, index, val -> ...
   */
  check_stack_int(0);
  check_stack_int(1);
  check_stack_refarray(2);

  CHECK_NULL(AASTORE, rstack(2), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(2), rstack(1));

  softcall_checkarraystore(rstack(2), rstack(0));

  /* rstack(2) may be a kaffe.util.Ptr[].  GC_WRITE must
   * check for that, but at least rstack(2) is a real java
   * object. 
   */
  SOFT_ADDREFERENCE(rstack(2), rstack(0));

  load_offset_scaled_ref( tmp, stack( 2 ), stack( 1 ), object_array_offset ); /* JJC */
  store_offset_scaled_ref(rstack(2), rstack(1), object_array_offset, rstack(0));
  move_ref( stack( 0 ), tmp ); /* JJC */
  /* START JJC */
  if( valid_log ) {
    if( strncmp( CLASS_ELEMENT_TYPE(OBJECT_CLASS((Hjava_lang_Object*)(stack(2)[0].v.taddr)))->name->data, "Lkaffe/util/Ptr;", 16 ) == 0 ) {
      markunknown;
    }
    savestack( 3 ); 
  }
  /* END JJC */
  pop(3);
}

define_insn(BASTORE)
{
  /*
   * ..., array ref, index, byte value  -> ...
   */
  check_stack_int(0);
  check_stack_int(1);
  check_stack_bytearray(2);

  CHECK_NULL(BASTORE, rstack(2), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(2), rstack(1));

  load_offset_scaled_byte( tmp, stack( 2 ), stack( 1 ), object_array_offset ); /* JJC */
  store_offset_scaled_byte(rstack(2), rstack(1), object_array_offset, rstack(0));
  move_int( stack( 0 ), tmp ); /* JJC */
  if( valid_log ) savestack( 3 ); /* JJC */
  pop(3);
}

define_insn(CASTORE)
{
  /*
   * ..., array ref, index, char value  -> ...
   */
  check_stack_int(0);
  check_stack_int(1);
  check_stack_chararray(2);

  CHECK_NULL(CASTORE, rstack(2), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(2), rstack(1));

  load_offset_scaled_char( tmp, stack( 2 ), stack( 1 ), object_array_offset ); /* JJC */
  store_offset_scaled_char(rstack(2), rstack(1), object_array_offset, rstack(0));
  move_int( stack( 0 ), tmp ); /* JJC */
  if( valid_log ) savestack( 3 ); /* JJC */
  pop(3);
}

define_insn(SASTORE)
{
  /*
   * ..., array ref, index, short value  -> ...
   */
  check_stack_int(0);
  check_stack_int(1);
  check_stack_shortarray(2);

  CHECK_NULL(SASTORE, rstack(2), 34);

  /* Check we are within the array bounds */
  check_array_index(rstack(2), rstack(1));

  load_offset_scaled_short( tmp, stack( 2 ), stack( 1 ), object_array_offset ); /* JJC */
  store_offset_scaled_short(rstack(2), rstack(1), object_array_offset, rstack(0));
  move_int( stack( 0 ), tmp ); /* JJC */
  if( valid_log ) savestack( 3 ); /* JJC */
  pop(3);
}

define_insn(POP)
{
  pop(1);
}

define_insn(POP2)
{
  pop(2);
}

define_insn(DUP)
{
  push(1);
  move_any(stack(0), stack(1));
  if( opsobjs ) *opsobjs = *( opsobjs - 1); /* JJC */
}

define_insn(DUP_X1)
{
  push(1);
  move_any(stack(0), stack(1));
  move_any(stack(1), stack(2));
  move_any(stack(2), stack(0));
  /* START JJC */
  if( opsobjs ) {
    *opsobjs = *( opsobjs - 1 );
    *( opsobjs - 1 ) = *( opsobjs - 2 );
    *( opsobjs - 2 ) = *opsobjs;
  }
  /* END JJC */
}

define_insn(DUP_X2)
{
  push(1);
  move_any(stack(0), stack(1));
  move_any(stack(1), stack(2));
  move_any(stack(2), stack(3));
  move_any(stack(3), stack(0));
  /* START JJC */
  if( opsobjs ) {
    *opsobjs = *( opsobjs - 1 );
    *( opsobjs - 1 ) = *( opsobjs - 2 );
    *( opsobjs - 2 ) = *( opsobjs - 3 );
    *( opsobjs - 3 ) = *opsobjs;
  }
  /* END JJC */
}

define_insn(DUP2)
{
  push(2);
  move_any(stack(0), stack(2));
  move_any(stack(1), stack(3));
  /* START JJC */
  if( opsobjs ) {
    *opsobjs = *( opsobjs - 2 );
    *( opsobjs - 1 ) = *( opsobjs - 3 );
  }
  /* END JJC */
}

define_insn(DUP2_X1)
{
  push(2);
  move_any(stack(0), stack(2));
  move_any(stack(1), stack(3));
  move_any(stack(2), stack(4));
  move_any(stack(3), stack(0));
  move_any(stack(4), stack(1));
  /* START JJC */
  if( opsobjs ) {
    *opsobjs = *( opsobjs - 2 );
    *( opsobjs - 1 ) = *( opsobjs - 3 );
    *( opsobjs - 2 ) = *( opsobjs - 4 );
    *( opsobjs - 3 ) = *opsobjs;
    *( opsobjs - 4 ) = *( opsobjs - 1 );
  }
  /* END JJC */
}

define_insn(DUP2_X2)
{
  push(2);
  move_any(stack(0), stack(2));
  move_any(stack(1), stack(3));
  move_any(stack(2), stack(4));
  move_any(stack(3), stack(5));
  move_any(stack(4), stack(0));
  move_any(stack(5), stack(1));
  /* START JJC */
  if( opsobjs ) {
    *opsobjs = *( opsobjs - 2 );
    *( opsobjs - 1 ) = *( opsobjs - 3 );
    *( opsobjs - 2 ) = *( opsobjs - 4 );
    *( opsobjs - 3 ) = *( opsobjs - 5 );
    *( opsobjs - 4 ) = *opsobjs;
    *( opsobjs - 5 ) = *( opsobjs - 1 );
  }
  /* END JJC */
}

define_insn(SWAP)
{
  /*
   * ..., val1, val2 -> ..., val2, val1
   */
  swap_any(stack(0), stack(1));
  /* START JJC */
  if( opsobjs ) {
    int8 t = *opsobjs;
    *opsobjs = *( opsobjs - 1 );
    *( opsobjs - 1 ) = t;
  }
  /* END JJC */
}

define_insn(IADD)
{
  /*
   * ..., val1, val2 -> ..., val1+val2
   */
  check_stack_int(0);
  check_stack_int(1);

  add_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LADD)
{
  /*
   * ..., long val1, long val2 -> ..., long val1+val2
   */
  check_stack_long(0);
  check_stack_long(2);

  slot_nowriteback2(stack_long(0));
  slot_nowriteback2(stack_long(2));

  add_long(stack_long(2), rstack_long(2), rstack_long(0));
  pop(2);
}

define_insn(FADD)
{
  /*
   * ..., val1, val2 -> ..., val1+val2
   */
  check_stack_float(0);
  check_stack_float(1);

  add_float(stack_float(1), rstack_float(1), rstack_float(0));
  pop(1);
}

define_insn(DADD)
{
  /*
   * ..., double val1, long val2 -> ..., double val1+val2
   */
  check_stack_double(0);
  check_stack_double(2);

  add_double(stack_double(2), rstack_double(2), rstack_double(0));
  pop(2);
}

define_insn(ISUB)
{
  /*
   * ..., val1, val2 -> ..., val1-val2
   */
  check_stack_int(0);
  check_stack_int(1);

  sub_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LSUB)
{
  /*
   * ..., long val1, long val2 -> ..., long val1-val2
   */
  check_stack_long(0);
  check_stack_long(2);

  slot_nowriteback2(stack_long(0));
  slot_nowriteback2(stack_long(2));

  sub_long(stack_long(2), rstack_long(2), rstack_long(0));
  pop(2);
}

define_insn(FSUB)
{
  /*
   * ..., val1, val2 -> ..., val1-val2
   */
  check_stack_float(0);
  check_stack_float(1);

  sub_float(stack_float(1), rstack_float(1), rstack_float(0));
  pop(1);
}

define_insn(DSUB)
{
  /*
   * ..., double val1, long val2 -> ..., double val1-val2
   */
  check_stack_double(0);
  check_stack_double(2);

  sub_double(stack_double(2), rstack_double(2), rstack_double(0));
  pop(2);
}

define_insn(IMUL)
{
  /*
   * ..., val1, val2 -> ..., val1*val2
   */
  check_stack_int(0);
  check_stack_int(1);

  mul_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LMUL)
{
  /*
   * ..., long val1, long val2 -> ..., long val1*val2
   */
  check_stack_long(0);
  check_stack_long(2);

  slot_nowriteback2(stack_long(0));
  slot_nowriteback2(stack_long(2));

  mul_long(stack_long(2), rstack_long(2), rstack_long(0));
  pop(2);
}

define_insn(FMUL)
{
  /*
   * ..., val1, val2 -> ..., val1*val2
   */
  check_stack_float(0);
  check_stack_float(1);

  mul_float(stack_float(1), rstack_float(1), rstack_float(0));
  pop(1);
}

define_insn(DMUL)
{
  /*
   * ..., double val1, long val2 -> ..., double val1*val2
   */
  check_stack_double(0);
  check_stack_double(2);

  mul_double(stack_double(2), rstack_double(2), rstack_double(0));
  pop(2);
}

define_insn(IDIV)
{
  /*
   * ..., val1, val2 -> ..., val1/val2
   */
  check_stack_int(0);
  check_stack_int(1);

  div_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LDIV)
{
  /*
   * ..., long val1, long val2 -> ..., long val1/val2
   */
  check_stack_long(0);
  check_stack_long(2);

  slot_nowriteback2(stack_long(0));
  slot_nowriteback2(stack_long(2));

  div_long(stack_long(2), rstack_long(2), rstack_long(0));
  pop(2);
}

define_insn(FDIV)
{
  /*
   * ..., val1, val2 -> ..., val1/val2
   */
  check_stack_float(0);
  check_stack_float(1);

  div_float(stack_float(1), rstack_float(1), rstack_float(0));
  pop(1);
}

define_insn(DDIV)
{
  /*
   * ..., val1, val2 -> ..., val1/val2
   */
  check_stack_double(0);
  check_stack_double(2);

  div_double(stack_double(2), rstack_double(2), rstack_double(0));
  pop(2);
}

define_insn(IREM)
{
  /*
   * ..., val1, val2 -> ..., val1%val2
   */
  check_stack_int(0);
  check_stack_int(1);

  rem_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LREM)
{
  /*
   * ..., long val1, long val2 -> ..., long val1%val2
   */
  check_stack_long(0);
  check_stack_long(2);

  slot_nowriteback2(stack_long(0));
  slot_nowriteback2(stack_long(2));

  rem_long(stack_long(2), rstack_long(2), rstack_long(0));
  pop(2);
}

define_insn(FREM)
{
  /*
   * ..., val1, val2 -> ..., val1%val2
   */
  check_stack_float(0);
  check_stack_float(1);

  rem_float(stack_float(1), rstack_float(1), rstack_float(0));
  pop(1);
}

define_insn(DREM)
{
  /*
   * ..., val1, val2 -> ..., val1%val2
   */
  check_stack_double(0);
  check_stack_double(2);

  rem_double(stack_double(2), rstack_double(2), rstack_double(0));
  pop(2);
}

define_insn(INEG)
{
  check_stack_int(0);

  neg_int(stack(0), rstack(0));
}

define_insn(LNEG)
{
  check_stack_long(0);

  slot_nowriteback2(stack_long(0));

  neg_long(stack_long(0), rstack_long(0));
}

define_insn(FNEG)
{
  check_stack_float(0);

  neg_float(stack_float(0), rstack_float(0));
}

define_insn(DNEG)
{
  check_stack_double(0);

  neg_double(stack_double(0), rstack_double(0));
}

define_insn(ISHL)
{
  /*
   * ..., val1, val2 -> ... val1 << val2
   */
  check_stack_int(0);
  check_stack_int(1);

  lshl_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LSHL)
{
  /*
   * ..., long val1, val2 -> ... long val1 << val2
   */
  check_stack_int(0);
  check_stack_long(1);

  slot_nowriteback(stack(0));
  slot_nowriteback2(stack_long(1));

  lshl_long(stack_long(1), stack_long(1), stack(0));
  pop(1);
}

define_insn(ISHR)
{
  /*
   * ..., val1, val2 -> ... val1 >> val2
   */
  check_stack_int(0);
  check_stack_int(1);

  ashr_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LSHR)
{
  /*
   * ..., long val1, val2 -> ... long val1 >> val2
   */
  check_stack_int(0);
  check_stack_long(1);

  slot_nowriteback(stack(0));
  slot_nowriteback2(stack_long(1));

  ashr_long(stack_long(1), stack_long(1), stack(0));
  pop(1);
}

define_insn(IUSHR)
{
  /*
   * ..., val1, val2 -> ... val1 >> val2
   */
  check_stack_int(0);
  check_stack_int(1);

  lshr_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LUSHR)
{
  /*
   * ..., long val1, val2 -> ... long val1 >> val2
   */
  check_stack_int(0);
  check_stack_long(1);

  slot_nowriteback(stack(0));
  slot_nowriteback2(stack_long(1));

  lshr_long(stack_long(1), stack_long(1), stack(0));
  pop(1);
}

define_insn(IAND)
{
  /*
   * ..., val1, val2 -> ..., val1 & val2
   */
  check_stack_int(0);
  check_stack_int(1);

  and_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LAND)
{
  /*
   * ..., long val1, long val2 -> ..., long val1 & val2
   */
  check_stack_long(0);
  check_stack_long(2);

  slot_nowriteback2(stack_long(0));
  slot_nowriteback2(stack_long(2));

  and_long(stack_long(2), rstack_long(2), rstack_long(0));
  pop(2);
}

define_insn(IOR)
{
  /*
   * ..., val1, val2 -> ..., val1 | val2
   */
  check_stack_int(0);
  check_stack_int(1);

  or_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LOR)
{
  /*
   * ..., long val1, long val2 -> ..., long val1 | val2
   */
  check_stack_long(0);
  check_stack_long(2);

  slot_nowriteback2(stack_long(0));
  slot_nowriteback2(stack_long(2));

  or_long(stack_long(2), rstack_long(2), rstack_long(0));
  pop(2);
}

define_insn(IXOR)
{
  /*
   * ..., val1, val2 -> ..., val1 ^ val2
   */
  check_stack_int(0);
  check_stack_int(1);

  xor_int(stack(1), rstack(1), rstack(0));
  pop(1);
}

define_insn(LXOR)
{
  /*
   * ..., long val1, long val2 -> ..., long val1 ^ val2
   */
  check_stack_long(0);
  check_stack_long(2);

  slot_nowriteback2(stack_long(0));
  slot_nowriteback2(stack_long(2));

  xor_long(stack_long(2), rstack_long(2), rstack_long(0));
  pop(2);
}

define_insn(IINC)
{
  check_pc (0);
  check_pc (1);
  idx = (uint8)getpc(0);
  low = (int8)getpc(1);

  check_local_int(idx);

  add_int_const(local(idx), local(idx), low);
}

define_insn(I2L)
{
  check_stack_int(0);

  push(1);
  cvt_int_long(stack_long(0), stack(1));
}

define_insn(I2F)
{
  check_stack_int(0);

  cvt_int_float(stack(0), stack(0));
}

define_insn(I2D)
{
  check_stack_int(0);

  push(1);
  cvt_int_double(stack_double(0), stack(1));
}

define_insn(L2I)
{
  check_stack_long(0);

  cvt_long_int(stack(1), stack_long(0));
  pop(1);
}

define_insn(L2F)
{
  check_stack_long(0);

  cvt_long_float(stack(1), stack_long(0));
  pop(1);
}

define_insn(L2D)
{
  check_stack_long(0);

  cvt_long_double(stack_double(0), stack_long(0));
}

define_insn(F2I)
{
  check_stack_float(0);

  cvt_float_int(stack(0), stack(0));
}

define_insn(F2L)
{
  check_stack_float(0);

  push(1);
  cvt_float_long(stack_long(0), stack(1));
}

define_insn(F2D)
{
  check_stack_float(0);

  push(1);
  cvt_float_double(stack_double(0), stack(1));
}

define_insn(D2I)
{
  check_stack_double(0);

  cvt_double_int(stack(1), stack_double(0));
  pop(1);
}

define_insn(D2L)
{
  check_stack_double(0);

  cvt_double_long(stack_long(0), stack_double(0));
}

define_insn(D2F)
{
  check_stack_double(0);

  cvt_double_float(stack(1), stack_double(0));
  pop(1);
}

define_insn(INT2BYTE)
{
  check_stack_int(0);

  cvt_int_byte(stack(0), rstack(0));
}

define_insn(INT2CHAR)
{
  check_stack_int(0);

  cvt_int_char(stack(0), rstack(0));
}

define_insn(INT2SHORT)
{
  check_stack_int(0);

  cvt_int_short(stack(0), rstack(0));
}

define_insn(LCMP)
{
  /*
   * ..., long val1, long val2 -> ..., result
   */
  check_stack_long(0);
  check_stack_long(2);

  slot_nowriteback2(stack_long(0));
  slot_nowriteback2(stack_long(2));

  lcmp(stack(3), rstack_long(0), rstack_long(2));
  pop(3);
}

define_insn(FCMPL)
{
  /*
   * ..., float val1, float val2 -> ..., result
   */
  check_stack_float(0);
  check_stack_float(1);

  cmpl_float(stack(1), stack(1), stack(0));
  pop(1);
}

define_insn(FCMPG)
{
  /*
   * ..., float val1, float val2 -> ..., result
   */
  check_stack_float(0);
  check_stack_float(1);

  cmpg_float(stack(1), stack(1), stack(0));
  pop(1);
}

define_insn(DCMPL)
{
  /*
   * ..., double val1, double val2 -> ..., result
   */
  check_stack_double(0);
  check_stack_double(2);

  cmpl_double(stack(3), stack_double(2), stack_double(0));
  pop(3);
}

define_insn(DCMPG)
{
  /*
   * ..., double val1, double val2 -> ..., result
   */
  check_stack_double(0);
  check_stack_double(2);

  cmpg_double(stack(3), stack_double(2), stack_double(0));
  pop(3);
}

define_insn(IFEQ)
{
  check_pcidx (0);
  check_stack_int(0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  end_sub_block();

  cbranch_int_const_eq(rstack(0), 0, reference_code_label(pc+idx));

  pop(1);
}

define_insn(IFNE)
{
  check_pcidx (0);
  check_stack_int(0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  end_sub_block();

  cbranch_int_const_ne(rstack(0), 0, reference_code_label(pc+idx));

  pop(1);
}

define_insn(IFLT)
{
  check_pcidx (0);
  check_stack_int(0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  end_sub_block();

  cbranch_int_const_lt(rstack(0), 0, reference_code_label(pc+idx));

  pop(1);
}

define_insn(IFGE)
{
  check_pcidx (0);
  check_stack_int(0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  end_sub_block();

  cbranch_int_const_ge(rstack(0), 0, reference_code_label(pc+idx));

  pop(1);
}

define_insn(IFGT)
{
  check_pcidx (0);
  check_stack_int(0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  end_sub_block();

  cbranch_int_const_gt(rstack(0), 0, reference_code_label(pc+idx));

  pop(1);
}

define_insn(IFLE)
{
  check_pcidx (0);
  check_stack_int(0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  end_sub_block();

  cbranch_int_const_le(rstack(0), 0, reference_code_label(pc+idx));

  pop(1);
}

define_insn(IF_ICMPEQ)
{
  check_pcidx (0);
  check_stack_int(0);
  check_stack_int(1);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  slot_nowriteback(stack(1));
  end_sub_block();

  cbranch_int_eq(rstack(1), rstack(0), reference_code_label(pc+idx));

  pop(2);
}

define_insn(IF_ICMPNE)
{
  check_pcidx (0);
  check_stack_int(0);
  check_stack_int(1);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  slot_nowriteback(stack(1));
  end_sub_block();

  cbranch_int_ne(rstack(1), rstack(0), reference_code_label(pc+idx));

  pop(2);
}

define_insn(IF_ICMPLT)
{
  check_pcidx (0);
  check_stack_int(0);
  check_stack_int(1);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  slot_nowriteback(stack(1));
  end_sub_block();

  cbranch_int_lt(rstack(1), rstack(0), reference_code_label(pc+idx));

  pop(2);
}

define_insn(IF_ICMPGE)
{
  check_pcidx (0);
  check_stack_int(0);
  check_stack_int(1);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  slot_nowriteback(stack(1));
  end_sub_block();

  cbranch_int_ge(rstack(1), rstack(0), reference_code_label(pc+idx));

  pop(2);
}

define_insn(IF_ICMPGT)
{
  check_pcidx (0);
  check_stack_int(0);
  check_stack_int(1);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  slot_nowriteback(stack(1));
  end_sub_block();

  cbranch_int_gt(rstack(1), rstack(0), reference_code_label(pc+idx));

  pop(2);
}

define_insn(IF_ICMPLE)
{
  check_pcidx (0);
  check_stack_int(0);
  check_stack_int(1);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  slot_nowriteback(stack(1));
  end_sub_block();

  cbranch_int_le(rstack(1), rstack(0), reference_code_label(pc+idx));

  pop(2);
}

define_insn(IF_ACMPEQ)
{
  check_pcidx (0);
  check_stack_ref(0);
  check_stack_ref(1);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  slot_nowriteback(stack(1));
  end_sub_block();

  cbranch_int_eq(rstack(1), rstack(0), reference_code_label(pc+idx));

  pop(2);
}

define_insn(IF_ACMPNE)
{
  check_pcidx (0);
  check_stack_ref(0);
  check_stack_ref(1);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  slot_nowriteback(stack(1));
  end_sub_block();

  cbranch_ref_ne(rstack(1), rstack(0), reference_code_label(pc+idx));

  pop(2);
}

define_insn(GOTO)
{
  check_pcidx (0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  end_sub_block();
  branch_a(reference_code_label(pc+idx));
}

define_insn(JSR)
{
  /*
   * ... -> ..., ret-addr
   */
  check_pcidx (0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  push(1);
  move_label_const(stack(0), reference_code_label(npc));

  marknotobj_int; /* JJC */ 

  end_sub_block();
  branch_a(reference_code_label(pc+idx));
}

define_insn(RET)
{
  check_pc (0);

  idx = (uint8)getpc(0);

  check_local_ref(idx);

  end_sub_block();
  branch_indirect(stored_code_label(local(idx)));
}

define_insn(TABLESWITCH)
{
  /*
   * ..., index -> ...
   */
  check_stack_int(0);

  slot_alloctmp(tmp2);

  npc = (pc + 1 + 3) & -4;
  low = (int32)((getcode(npc+4) << 24) | (getcode(npc+5) << 16) |
		(getcode(npc+6) << 8) | getcode(npc+7));
  high = (int32)((getcode(npc+8) << 24) | (getcode(npc+9) << 16) |
		 (getcode(npc+10) << 8) | getcode(npc+11));
  npc = npc + 12;

  end_sub_block();
  cbranch_int_const_lt(stack(0), low, reference_label(TABLESWITCH, 8));
  cbranch_int_const_le(stack(0), high, reference_label(TABLESWITCH, 7));

  start_sub_block();
  set_label(TABLESWITCH, 8);
  move_int_const(stack(0), low-3); /* Position at default entry */
  end_sub_block();

  start_sub_block();
  set_label(TABLESWITCH, 7);
  if (low != 0) {
    start_sub_block();
    sub_int_const(stack(0), stack(0), low);
    end_sub_block();
  }
  lshl_int_const(stack(0), stack(0), switchtable_shift);
  move_label_const(tmp2, reference_table_label(9));
  add_ref(stack(0), tmp2, stack(0));
  load_code_ref(stack(0), stack(0));
  end_sub_block();
  branch_indirect(table_code_label(stack(0)));
  pop(1);

#if defined(TRANSLATOR)
  {
    build_code_ref(&getcode(npc-12), pc);	/* Default entry */
    build_code_ref(&getcode(npc-12), pc);	/* Dummy */
    build_code_ref(&getcode(npc-12), pc);	/* Dummy */
    set_label(TABLESWITCH, 9);
    for (idx = 0; idx < high-low+1; idx++) {
      build_code_ref(&getcode(npc + (idx << switchtable_shift)), pc);
    }
  }
#endif
  adjustpc((4 - (pc % 4)) + 12 + (high - low + 1) * 4);
}

define_insn(LOOKUPSWITCH)
{
  /*
   * ..., key -> ...
   */
  check_stack_int(0);

  npc = (pc + 1 + 3) & -4;
  idx = (int32)((getcode(npc+4) << 24) | (getcode(npc+5) << 16) |
		(getcode(npc+6) << 8) | getcode(npc+7));

  slot_alloctmp(mtable);
  slot_alloctmp(tmp);

  move_label_const(tmp, reference_table_label(7));

  if (idx != 0) {
    slot_alloctmp(tmp2);
    move_ref(tmp2, tmp);
    add_ref_const(tmp, tmp, idx * switchpair_size);

    end_sub_block();
    set_label(LOOKUPSWITCH, 5);
    start_sub_block();
    load_key(mtable, tmp);
    end_sub_block();
    cbranch_int_eq(mtable, stack(0), reference_label(LOOKUPSWITCH, 6));

    start_sub_block();
    add_ref_const(tmp, tmp, -switchpair_size);
    end_sub_block();
    cbranch_ref_ne(tmp, tmp2, reference_label(LOOKUPSWITCH, 5));

    start_sub_block();
    add_ref_const(tmp, tmp, -switchpair_addr);
    end_sub_block();

    set_label(LOOKUPSWITCH, 6);
    start_sub_block();
    add_ref_const(tmp, tmp, switchpair_addr);
  }
  load_code_ref(tmp, tmp);
  end_sub_block();
  branch_indirect(table_code_label(tmp));
  pop(1);

#if defined(TRANSLATOR)
  {
    set_label(LOOKUPSWITCH, 7);
    build_code_ref(&getcode(npc), pc);
    build_key(&getcode(npc)); /* Dummy key */
    for (low = 1; low <= idx; low++) {
      build_key(&getcode(npc + (low * switchpair_size)));
      build_code_ref(&getcode(npc + (low * switchpair_size) + switchpair_addr), pc);
    }
  }
#endif
  adjustpc((4 - (pc % 4)) + (idx + 1) * 8);
}

define_insn(IRETURN)
{
  if( valid_log ) {         /* JJC */
    savewholestack;   /* JJC */
    savelocals;       /* JJC */
  }                         /* JJC */
  check_stack_int(0);

  monitor_exit();
  returnarg_int(rstack(0));
  end_function();
  ret();
}

define_insn(LRETURN)
{
  if( valid_log ) {         /* JJC */
    savewholestack;   /* JJC */
    savelocals;       /* JJC */
  }                         /* JJC */
  check_stack_long(0);

  monitor_exit();
  returnarg_long(rstack_long(0));
  end_function();
  ret();
}

define_insn(FRETURN)
{
  if( valid_log ) {         /* JJC */
    savewholestack;   /* JJC */
    savelocals;       /* JJC */
  }                         /* JJC */

  check_stack_float(0);

  monitor_exit();
  returnarg_float(rstack_float(0));
  end_function();
  ret();
}

define_insn(DRETURN)
{
  if( valid_log ) {         /* JJC */
    savewholestack;   /* JJC */
    savelocals;       /* JJC */
  }                         /* JJC */

  check_stack_double(0);

  monitor_exit();
  returnarg_double(rstack_double(0));
  end_function();
  ret();
}

define_insn(ARETURN)
{
  if( valid_log ) {         /* JJC */
    savewholestack;   /* JJC */
    savelocals;       /* JJC */
  }                         /* JJC */

  check_stack_ref(0);

  monitor_exit();
  returnarg_ref(rstack_ref(0));
  end_function();
  ret();
}

define_insn(RETURN)
{
  if( valid_log ) {         /* JJC */
    savewholestack;   /* JJC */
    savelocals;       /* JJC */
  }                         /* JJC */

  monitor_exit();
  end_function();
  ret();
}

/*
 * This macro initialises the static data associated with a class.
 */
#define	INIT_STATIC_CLASS(c)				\
	if (c != 0 && c->state != CSTATE_COMPLETE /* ??? is that right ??? */) {	\
		softcall_initialise_class(c);		\
	}

define_insn(GETSTATIC)
{
  /*
   * ... -> ..., value
   */
  check_pcidx (0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  get_static_field_info(idx);
  INIT_STATIC_CLASS(field_class());

  /* Use the proper load to increase the chances of the translator
     getting data in the right type of register.  */

  if (!FIELD_ISPRIM(finfo.field)) {
    push(1);
    /* START JJC */
    if( valid_log ) {
      if( strncmp( finfo.signature->data, "Lkaffe/util/Ptr;", 16 ) == 0 ) {
	markunknown;
      }
      else
        markisobj;
    }
    /* END JJC */
    load_addr_ref(stack(0), FIELD_ADDRESS(finfo.field));
  }
  else { 

    switch (CLASS_PRIM_SIG(FIELD_TYPE(finfo.field))) {
    case 'I':
      push(1);
      load_addr_int(stack(0), FIELD_ADDRESS(finfo.field));
      marknotobj_int; /* JJC */
      break;
    case 'S':
      push(1);
      load_addr_short(stack(0), FIELD_ADDRESS(finfo.field));
      marknotobj_int; /* JJC */
      break;
    case 'B':
    case 'Z':
      push(1);
      load_addr_byte(stack(0), FIELD_ADDRESS(finfo.field));
      marknotobj_int; /* JJC */
      break;
    case 'C':
      push(1);
      load_addr_char(stack(0), FIELD_ADDRESS(finfo.field));
      marknotobj_int; /* JJC */
      break;
    case 'F':
      push(1);
      load_addr_float(stack(0), FIELD_ADDRESS(finfo.field));
      marknotobj_float; /* JJC */
      break;
    case 'J':
      push(2);
      load_addr_long(stack_long(0), FIELD_ADDRESS(finfo.field));
      marknotobj2_long; /* JJC */
      break;
    case 'D':
      push(2);
      load_addr_double(stack_double(0), FIELD_ADDRESS(finfo.field));
      marknotobj2_double; /* JJC */
      break;
    default:
      ABORT();
    }

  }
}

define_insn(PUTSTATIC)
{
  /*
   * ..., value  -> ...
   */
  check_pcidx (0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  get_static_field_info(idx);
  INIT_STATIC_CLASS(field_class());

  if (!FIELD_ISPRIM(finfo.field)) {
    if (FIELD_ISREF(finfo.field))
      SOFT_ADDREFERENCE_STATIC(field_statics(), stack(0));
    load_addr_ref( tmp, FIELD_ADDRESS( finfo.field ) ); /* JJC */
    store_addr_ref(FIELD_ADDRESS(finfo.field), stack(0));
    move_ref( stack( 0 ), tmp ); /* JJC */
    /* START JJC */
    if( valid_log ) {
      if( strncmp( finfo.signature->data, "Lkaffe/util/Ptr;", 16 ) == 0 ) {
	markunknown;
      }
      if( valid_log ) savestack( 1 );
    }
    /* END JJC */
    pop(1);
  }
  else switch (CLASS_PRIM_SIG(FIELD_TYPE(finfo.field))) {
  case 'I':
    load_addr_int( tmp, FIELD_ADDRESS( finfo.field ) ); /* JJC */
    store_addr_int(FIELD_ADDRESS(finfo.field), stack(0));
    move_int( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 1 ); /* JJC */
    pop(1);
    break;
  case 'S':
    load_addr_short( tmp, FIELD_ADDRESS( finfo.field ) ); /* JJC */
    store_addr_short(FIELD_ADDRESS(finfo.field), stack(0));
    move_int( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 1 ); /* JJC */
    pop(1);
    break;
  case 'B':
  case 'Z':
    load_addr_byte( tmp, FIELD_ADDRESS( finfo.field ) ); /* JJC */
    store_addr_byte(FIELD_ADDRESS(finfo.field), stack(0));
    move_int( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 1 ); /* JJC */
    pop(1);
    break;
  case 'C':
    load_addr_char( tmp, FIELD_ADDRESS( finfo.field ) ); /* JJC */
    store_addr_char(FIELD_ADDRESS(finfo.field), stack(0));
    move_int( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 1 ); /* JJC */
    pop(1);
    break;
  case 'F':
    load_addr_float( tmp, FIELD_ADDRESS( finfo.field ) ); /* JJC */
    store_addr_float(FIELD_ADDRESS(finfo.field), stack(0));
    move_float( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 1 ); /* JJC */
    pop(1);
    break;
  case 'J':
    load_addr_long( tmp, FIELD_ADDRESS( finfo.field ) ); /* JJC */
    store_addr_long(FIELD_ADDRESS(finfo.field), stack_long(0));
    move_long( stack_long( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 2 ); /* JJC */
    pop(2);
    break;
  case 'D':
    load_addr_double( tmp, FIELD_ADDRESS( finfo.field ) ); /* JJC */
    store_addr_double(FIELD_ADDRESS(finfo.field), stack_double(0));
    move_double( stack_long( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 2 ); /* JJC */
    pop(2);
    break;
  default:
    ABORT();
  }
}

define_insn(GETFIELD)
{
  /*
   * ..., obj-ref -> ..., value
   */
  if( valid_log ) /* JJC */
    savestack( 1 ); /* JJC */

  check_pcidx (0);
  check_stack_ref(0);

  CHECK_NULL(GETFIELD, stack(0), 34);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  get_field_info(idx);

  /* Use the proper load to increase the chances of the translator
     getting data in the right type of register.  */

  if (!FIELD_ISPRIM(finfo.field)) {
    load_offset_ref(stack(0), rstack(0), FIELD_BOFFSET(finfo.field));
    if( valid_log ) wcbuffi( 0, debug ); /* JJC */
    /* START JJC */
    if( valid_log ) {
      if( strncmp( finfo.signature->data, "Lkaffe/util/Ptr;", 16 ) == 0 ) {
	markunknown;
      }
      else
	markisobj;
    }
    /* END JJC */
  }
  else { 

    switch (CLASS_PRIM_SIG(FIELD_TYPE(finfo.field))) {
    case 'I':
      load_offset_int(stack(0), rstack(0), FIELD_BOFFSET(finfo.field));
      marknotobj_int;
      if( valid_log ) wcbuffi( 0, debug ); /* JJC */
      break;
    case 'S':
      load_offset_short(stack(0), rstack(0), FIELD_BOFFSET(finfo.field));
      marknotobj_int;
      if( valid_log ) wcbuffi( 0, debug ); /* JJC */
      break;
    case 'B':
    case 'Z':
      load_offset_byte(stack(0), rstack(0), FIELD_BOFFSET(finfo.field));
      marknotobj_int;
      if( valid_log ) wcbuffi( 0, debug ); /* JJC */
      break;
    case 'C':
      load_offset_char(stack(0), rstack(0), FIELD_BOFFSET(finfo.field));
      marknotobj_int;
      if( valid_log ) wcbuffi( 0, debug ); /* JJC */
      break;
    case 'F':
      load_offset_float(stack(0), stack(0), FIELD_BOFFSET(finfo.field));
      marknotobj_float;
      if( valid_log ) wcbuffi( 0, debug ); /* JJC */
      break;
    case 'J':
      load_offset_long(stack_long(-1), stack(0), FIELD_BOFFSET(finfo.field));
      push(1);
      marknotobj2_long; /* JJC */
      if( valid_log ) wcbuffi( 1, debug ); /* JJC */
      break;
    case 'D':
      load_offset_double(stack_double(-1), stack(0), FIELD_BOFFSET(finfo.field));
      push(1);
      marknotobj2_double; /* JJC */
      if( valid_log ) wcbuffi( 1, debug ); /* JJC */
      break;

    default:
      ABORT();
    }

  }
}

define_insn(PUTFIELD)
{
  /*
   * ..., obj-ref, value  -> ...
   */
  check_pcidx (0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  get_field_info(idx);

  /* Use the proper store to increase the chances of the translator
     having the data in the right type of register already.  */

  if (!FIELD_ISPRIM(finfo.field)) {
    check_stack_ref(1);
    CHECK_NULL(PUTFIELD, rstack(1), 35);
    if (FIELD_ISREF(finfo.field))
      SOFT_ADDREFERENCE(rstack(1), rstack(0));
    load_offset_ref( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) ); /* JJC */ 
    store_offset_ref(rstack(1), FIELD_BOFFSET(finfo.field), rstack(0));
    move_ref( stack( 0 ), tmp ); /* JJC */
    /* START JJC */
    if( valid_log ) {
      if( strncmp( finfo.signature->data, "Lkaffe/util/Ptr;", 16 ) == 0 ) {
	markunknown;
      }
      savestack( 2 );
    }
    /* END JJC */
    pop(2);
  }
  else switch (CLASS_PRIM_SIG(FIELD_TYPE(finfo.field))) {
  case 'I':
    check_stack_ref(1);
    CHECK_NULL(PUTFIELD, stack(1), 36);
    load_offset_int( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) ); /* JJC */
    store_offset_int(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
    move_int( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 2 ); /* JJC */
    pop(2);
    break;
  case 'S':
    check_stack_ref(1);
    CHECK_NULL(PUTFIELD, stack(1), 37);
    load_offset_short( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) );
    /* JJC */
    store_offset_short(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
    move_int( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 2 ); /* JJC */
    pop(2);
    break;
  case 'B':
  case 'Z':
    check_stack_ref(1);
    CHECK_NULL(PUTFIELD, stack(1), 40);
    load_offset_byte( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) ); /* JJC */
    store_offset_byte(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
    move_int( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 2 ); /* JJC */
    pop(2);
    break;
  case 'C':
    check_stack_ref(1);
    CHECK_NULL(PUTFIELD, stack(1), 41);
    load_offset_char( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) ); /* JJC */
    store_offset_char(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
    move_int( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 2 ); /* JJC */
    pop(2);
    break;
  case 'F':
    check_stack_ref(1);
    CHECK_NULL(PUTFIELD, stack(1), 42);
    load_offset_float( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) ); /* JJC */
    store_offset_float(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
    move_float( stack( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 2 ); /* JJC */
    pop(2);
    break;
  case 'J':
    check_stack_ref(2);
    CHECK_NULL(PUTFIELD, stack(2), 38);
    load_offset_long( tmp, stack( 2 ), FIELD_BOFFSET( finfo.field ) );/* JJC */
    store_offset_long(stack(2), FIELD_BOFFSET(finfo.field), stack_long(0));
    move_long( stack_long( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 3 ); /* JJC */
    pop(3);
    break;
  case 'D':
    check_stack_ref(2);
    CHECK_NULL(PUTFIELD, stack(2), 39);
    load_offset_double( tmp, stack( 2 ), FIELD_BOFFSET( finfo.field ) ); /* JJC */
    store_offset_double(stack(2), FIELD_BOFFSET(finfo.field), stack_double(0));
    move_double( stack_long( 0 ), tmp ); /* JJC */
    if( valid_log ) savestack( 3 ); /* JJC */
    pop(3);
    break;
  default:
    ABORT();
  }
}
/* START JJC */

#define METHOD_RETURN_TYPE() ( ( method_method()->parsed_sig->signature->data ) + ( method_method()->parsed_sig->ret_and_args[ 0 ] ) )

/* END JJC */

#define	METHOD_RETURN_VALUE()									\
do {												\
	/* Store the return type (if necessary) */						\
	switch (low) {										\
	case 'V':										\
		break;										\
        /* START JJC */										\
        case 'L': push(1);									\
                  return_ref(stack(0));								\
                  if( valid_log ) {								\
		    if( strncmp( METHOD_RETURN_TYPE(), "Lkaffe/util/Ptr;", 16 ) == 0 ) {	\
		      markunknown;								\
		    }										\
		    else									\
		      markisobj;								\
		  }										\
		  break;									\
        /* END JJC */										\
	case '[':										\
		push(1);									\
		return_ref(stack(0));								\
		markisobj; /* JJC */								\
		break;										\
	case 'I':										\
	case 'Z':										\
	case 'S':										\
	case 'B':										\
	case 'C':										\
		push(1);									\
		return_int(stack(0));								\
        marknotobj_int; /* JJC */								\
		break;										\
	case 'F':										\
		push(1);									\
		return_float(stack(0));								\
        marknotobj_float; /* JJC */								\
		break;										\
	case 'J':										\
		push(2);									\
		return_long(stack_long(0));							\
        marknotobj2_long; /* JJC */								\
		break;										\
	case 'D':										\
		push(2);									\
		return_double(stack_double(0));							\
        marknotobj2_double; /* JJC */								\
		break;										\
	default:										\
		ABORT();									\
	}											\
} while (0)

#define PASSON ( reverse_method == T_RETRY_OVER_FIRST ? T_RETRY_OVER : reverse_method == T_FWDS_INTO && running_over ? T_FWDS_OVER : reverse_method )

/*( ( !IS_LOG( reverse_method ) || IS_RETRY( reverse_method ) ) 
  ? reverse_method : ( running_over ? T_FWDS_OVER : T_FWDS_INTO ) ) */

define_insn(INVOKEVIRTUAL)
{
  /*
   * ..., obj, ..args.., -> ...
   */
  int8 beg = F_END; /* JJC */
  if( valid_log ) (debug->last_method) = meth; /* JJC */

  check_pcidx (0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  slot_alloctmp(tmp);
  slot_alloctmp(mtable);

  get_method_info(idx);

  if( valid_log ) savestackandn( method_nargs( ) + 1 ); /* JJC */

  /* If method doesn't exists, call 'NoSuchMethodError' */
  if (method_method() == 0) {
    softcall_nosuchmethod(method_class(), method_name(), method_sig());
    low = method_returntype();
    pop(method_nargs() + 1);
    METHOD_RETURN_VALUE();
  }
  else {
    void *ptf; /* JJC */
    int is_virtual = method_method()->idx >= 0;
    idx = method_nargs();

    ptf = (stack(idx))[0].v.taddr; /* JJC */

    CHECK_NULL(INVOKEVIRTUAL, stack(idx), 34);

    check_stack_ref(idx);

    if (is_virtual) {
      /* Find dispatch table in object */
      load_offset_ref(mtable, stack(idx), 
		      method_dtable_offset);

      /* Check method table for cached entry */
      load_offset_ref(tmp, mtable,
		      DTABLE_METHODOFFSET + 
		      method_idx() * DTABLE_METHODSIZE);
    } else {
      /* Explicitly check that object is non-null.
       * (Implicitly done in the dispatch table lookup.) */
      EXPLICIT_CHECK_NULL(INVOKEVIRTUAL, stack(idx), 35);
    }

    /* Push arguments & object */
    build_call_frame(method_sig(), stack(idx), idx);
    idx++;

    if (is_virtual) {
      slot_nowriteback(tmp);
    }

    pop(idx);
    end_sub_block();

    /* Call it */
    low = method_returntype();
    if (is_virtual) {
      softcall_initialise_class(method_class()); 
      beg = virtualMachine((methods*)(tmp)[0].v.taddr, sp+1, retval, tid, PASSON, thr ); /* JJC */
    } else {
      softcall_initialise_class(method_class()); 
      beg = virtualMachine(method_method(), sp+1, retval, tid, PASSON, thr ); /* JJC */
    }

    /* START JJC */
    if( reverse_method == T_RETRY ) {
      reverse_method = T_FWDS_INTO;
      valid_log = 1;
    } else if( reverse_method == T_RETRY_OVER || reverse_method == T_RETRY_OVER_FIRST ) {
      valid_log = 1;
    }
    /* END JJC */

    /* START JJC (mark end of function) */
    if( valid_log && ( beg == F_END ) ) {
      slots s;
      s.v.taddr = ptf;
      wcbuffs( s, 1, debug, thr );			
      wcbuffpc( pc + METHOD_OFFSET, debug );
    }
    /* END JJC */

    /* Pop args */
    popargs();

    start_sub_block();

    METHOD_RETURN_VALUE();

    /* START JJC (if exited from start reverse to last line) */
    if( beg == F_BEG ) {
      ret = reverseVirtualMachine( meth, lcl, &sp, &npc, retval, mjbuf, tid,
				   debug, callback, meth->fullSourceFile, &opsobjs, lvtobjs,
				   reverse_method == T_RETRY_OVER ? R_OVER : R_INTO, 
				   &cl, &seen_new_line, code, thr, false );
      if( ret == F_BEG ) {
	D_FL( fprintf( stderr, "------RUN VIRTUAL MACHINE: exit: ret == F_BEG\n" ) );
	return F_BEG;
      }
      else if( ret == F_CATCH ) {
	assert( 0 ); /* almost completely sure that this can't happen now */
	D_FL( fprintf( stderr, "------RUN VIRTUAL MACHINE: exit: ret == F_CATCH\n" ) );
	return reverse_method; 
      }
    }
    assert( reverse_method != T_RETRY_OVER );
    if( reverse_method == T_RETRY_OVER || reverse_method == T_RETRY_OVER_FIRST )
        reverse_method = T_FWDS_INTO;
    /* END JJC */
  }
}

define_insn(INVOKESPECIAL)
{
  /*
   * ..., obj, ..args.., -> ...
   */
  int8 beg = F_END; /* JJC */
  if( valid_log ) (debug->last_method) = meth; /* JJC */

  check_pcidx (0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  slot_alloctmp(mtable);

  get_special_method_info(idx);

  if( valid_log ) {                         /* JJC */
    savestackandn( method_nargs( ) + 1 );  /* JJC */
  }                                         /* JJC */

  /* If method doesn't exists, call 'NoSuchMethodError' */
  if (method_method() == 0) {
    softcall_nosuchmethod(method_class(), method_name(), method_sig());
    low = method_returntype();
    pop(method_nargs() + 1);
    METHOD_RETURN_VALUE();
  }
  else {  void* ptf; /* JJC */
  idx = method_nargs();
  ptf = ( stack( idx ) )[0].v.taddr; /* JJC */

  EXPLICIT_CHECK_NULL(INVOKESPECIAL, stack(idx), 34);

  check_stack_ref(idx);

  /* Push arguments & object */
  build_call_frame(method_sig(), stack(idx), idx);
  idx++;

  pop(idx);
  end_sub_block();

  /* Call it */
  low = method_returntype();

  softcall_initialise_class(method_class()); /* JJC */
  beg = virtualMachine(method_method(), sp+1, retval, tid, PASSON, thr ); /* JJC */

  /* START JJC */
  if( reverse_method == T_RETRY ) {
    reverse_method = T_FWDS_INTO;
    valid_log = 1;
  } else if( reverse_method == T_RETRY_OVER || reverse_method == T_RETRY_OVER_FIRST ) {
    valid_log = 1;
  }
  /* END JJC */

  /* START JJC (mark end of function) */
  if( valid_log && ( beg == F_END ) ) {
    slots s;
    s.v.taddr = ptf;
    wcbuffs( s, 1, debug, thr );
    wcbuffpc( pc + METHOD_OFFSET, debug ); 
  }
  /* END JJC */
		
  /* Pop args */
  popargs();

  start_sub_block();

  METHOD_RETURN_VALUE();

  /* START JJC (if exited from start reverse to last line) */
  if( beg == F_BEG ) {
    ret = reverseVirtualMachine( meth, lcl, &sp, &npc, retval, mjbuf, tid,
				 debug, callback, meth->fullSourceFile, &opsobjs, lvtobjs,
				 reverse_method == T_RETRY_OVER ? R_OVER : R_INTO, 
				 &cl, &seen_new_line, code, thr, false );
    if( ret == F_BEG ) {
      D_FL( fprintf( stderr, "------RUN VIRTUAL MACHINE: exit: ret == F_BEG\n" ) );
      return F_BEG;
    }
    else if( ret == F_CATCH ) {
      assert( 0 );
      D_FL( fprintf( stderr, "------RUN VIRTUAL MACHINE: exit: ret == F_CATCH\n" ) );
      return reverse_method; 
    }
  }
  assert( reverse_method != T_RETRY_OVER );
  if( reverse_method == T_RETRY_OVER || reverse_method == T_RETRY_OVER_FIRST )
    reverse_method = T_FWDS_INTO;

  /* END JJC */

  }
}

define_insn(INVOKESTATIC)
{
  /*
   * ..., ..args.., -> ...
   */
  int8 beg = F_END; /* JJC */
  if( valid_log ) (debug->last_method) = meth; /* JJC */

  check_pcidx (0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  get_method_info(idx);

  if( valid_log ) {                         /* JJC */
    savestackandn( method_nargs( ) );      /* JJC */
  }                                         /* JJC */

  /* If method doesn't exists, call 'NoSuchMethodError' */
  if (method_method() == 0) {
    softcall_nosuchmethod(method_class(), method_name(), method_sig());
    low = method_returntype();
    pop(method_nargs());
    METHOD_RETURN_VALUE();
  }
  else {
    idx = method_nargs();

    /* Push arguments */
    build_call_frame(method_sig(), 0, idx);

    pop(idx);
    end_sub_block();

    /* Call it */
    low = method_returntype();
                
    softcall_initialise_class(method_class()); /* JJC */
    beg = virtualMachine(method_method(), sp+1, retval, tid, PASSON, thr); /* JJC */

    /* START JJC */
    if( reverse_method == T_RETRY ) {
      reverse_method = T_FWDS_INTO;
      valid_log = 1;
    } else if( reverse_method == T_RETRY_OVER || reverse_method == T_RETRY_OVER_FIRST ) {
      valid_log = 1;
    }
    /* END JJC */

    if( valid_log && ( beg == F_END ) ) wcbuffpc( pc + METHOD_OFFSET, debug ); /* JJC */

    /* Pop args */
    popargs();

    start_sub_block();

    METHOD_RETURN_VALUE();

    /* START JJC (if exited from start reverse to last line) */
    if( beg == F_BEG ) {
      ret = reverseVirtualMachine( meth, lcl, &sp, &npc, retval, mjbuf, tid,
				   debug, callback, meth->fullSourceFile, &opsobjs, lvtobjs,
				   reverse_method == T_RETRY_OVER ? R_OVER : R_INTO, 
				   &cl, &seen_new_line, code, thr, false );
      if( ret == F_BEG ) {
	D_FL( fprintf( stderr, "------RUN VIRTUAL MACHINE: exit: ret == F_BEG\n" ) );
	return F_BEG;
      }
      else if( ret == F_CATCH ) {
	assert( 0 );
	D_FL( fprintf( stderr, "------RUN VIRTUAL MACHINE: exit: ret == F_CATCH\n" ) );
	return reverse_method;
      }
    }
    assert( reverse_method != T_RETRY_OVER );
    if( reverse_method == T_RETRY_OVER || reverse_method == T_RETRY_OVER_FIRST )
        reverse_method = T_FWDS_INTO; 
    /* END JJC */

  }
}

define_insn(INVOKEINTERFACE)
{
  /*
   * ..., obj, ..args.., -> ...
   */
  int8 beg = F_END; /* JJC */
  if( valid_log ) (debug->last_method) = meth; /* JJC */

  check_pcidx (0);
  check_pc (2);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  slot_alloctmp(tmp);

  get_interface_method_info(idx);

  if( valid_log ) {                         /* JJC */
    savestackandn( (uint8)getpc( 2 ) );    /* JJC */
  }                                         /* JJC */

  /* If method doesn't exist, call 'NoSuchMethodError' */
  /* NB: This means that the interface class does not have the method
   * that is asked for, not that this class does not implement the
   * interface method.
   */
  if (method_method() == 0) {
    softcall_nosuchmethod(method_class(), method_name(), method_sig());
    low = method_returntype();
    pop((uint8)getpc(2));
    METHOD_RETURN_VALUE();
  }
  else {  void *ptf; /* JJC */
  idx = (uint8)getpc(2) - 1;
  ptf = ( stack( idx ) )[0].v.taddr; /* JJC */

  CHECK_NULL(INVOKEINTERFACE, stack(idx), 34);

  check_stack_ref(idx);

  softcall_lookupinterfacemethod(tmp, method_method(), stack(idx));

  /* Push arguments & object */
  build_call_frame(method_sig(), stack(idx), idx);
  idx++;

  slot_nowriteback(tmp);
  pop(idx);
  end_sub_block();

  /* Call it */
  low = method_returntype();

  softcall_initialise_class(method_class()); /* JJC */
  beg = virtualMachine((methods*)(tmp)[0].v.taddr, sp+1, retval, tid, PASSON, thr); /* JJC */
  /* START JJC */
  if( reverse_method == T_RETRY ) {
    reverse_method = T_FWDS_INTO;
    valid_log = 1;
  } else if( reverse_method == T_RETRY_OVER || reverse_method == T_RETRY_OVER_FIRST ) {
    valid_log = 1;
  }
  /* END JJC */

  /* START JJC (mark end of function) */
  if( valid_log && ( beg == F_END ) ) {
    slots s;
    s.v.taddr = ptf;
    wcbuffs( s, 1, debug, thr );
    wcbuffpc( pc + METHOD_OFFSET, debug );
  }
  /* END JJC */

  /* Pop args */
  popargs();

  start_sub_block();

  METHOD_RETURN_VALUE();

  /* START JJC (if exited from start reverse to last line) */
  if( beg == F_BEG ) {
    ret = reverseVirtualMachine( meth, lcl, &sp, &npc, retval, mjbuf, tid,
				 debug, callback, meth->fullSourceFile, &opsobjs, lvtobjs,
				 reverse_method == T_RETRY_OVER ? R_OVER : R_INTO, 
				 &cl, &seen_new_line, code, thr, false );
    if( ret == F_BEG ) {
      D_FL( fprintf( stderr, "------RUN VIRTUAL MACHINE: exit: ret == F_BEG\n" ) );
      return F_BEG;
    }
    else if( ret == F_CATCH ) {
      assert( 0 );
      D_FL( fprintf( stderr, "------RUN VIRTUAL MACHINE: exit: ret == F_CATCH\n" ) );
      return reverse_method; 
    }
  }
  assert( reverse_method != T_RETRY_OVER );
  if( reverse_method == T_RETRY_OVER || reverse_method == T_RETRY_OVER_FIRST )
      reverse_method = T_FWDS_INTO;
  /* END JJC */

  }
}

define_insn(NEW)
{
  /*
   * ... ->  ..., object ref
   */
  check_pcidx (0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  get_class_info(idx);
  push(1);
  markisobj; /* JJC */
  softcall_new(stack(0), class_object());
}

define_insn(NEWARRAY)
{
  /*
   * ... size ->  ..., object ref
   */
  check_pc (0);
  check_stack_int(0);

  low = (uint8)getpc(0);
  softcall_newarray(stack(0), stack(0), low);
  markisobj; /* JJC */
}

define_insn(ANEWARRAY)
{
  /*
   * ... size ->  ..., object ref
   */
  check_pcidx (0);
  check_stack_int(0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  get_class_info(idx);
  softcall_anewarray(stack(0), stack(0), class_object());
  markisobj; /* JJC */
}

define_insn(ARRAYLENGTH)
{
  /*
   * ..., obj -> ..., length
   */
  CHECK_NULL(ARRAYLENGTH, rstack(0), 34);

  check_stack_array(0);

  load_offset_int(stack(0), rstack(0), object_array_length);
  marknotobj_int; /* JJC */
}

define_insn(ATHROW)
{
  /*
   * ..., obj -> undefined
   */
  CHECK_NULL(ATHROW, rstack(0), 34);

  check_stack_ref(0);
	
  softcall_athrow(rstack(0));
}

define_insn(CHECKCAST)
{
  /*
   * ..., obj -> ..., obj
   */
  check_pcidx (0);
  check_stack_ref(0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  get_class_info(idx);
  softcall_checkcast(stack(0), rstack(0), class_object());
}

define_insn(INSTANCEOF)
{
  /*
   * ..., obj -> ..., result
   */
  check_pcidx (0);
  check_stack_ref(0);

  idx = (uint16)((getpc(0) << 8) | getpc(1));

  get_class_info(idx);
  softcall_instanceof(stack(0), rstack(0), class_object());
  marknotobj_int; /* JJC */
}

define_insn(MONITORENTER)
{
  /*
   * ... obj -> ...
   */
  CHECK_NULL(MONITORENTER, rstack(0), 34);

  check_stack_ref(0);

  softcall_monitorenter(rstack(0));
  pop(1);
}

define_insn(MONITOREXIT)
{
  /*
   * ... obj -> ...
   */
  CHECK_NULL(MONITOREXIT, rstack(0), 34);

  check_stack_ref(0);

  softcall_monitorexit(rstack(0));
  pop(1);
}

define_insn(WIDE)
{
  /* Move PC to widened instruction */
  pc = npc;
  npc = pc + insnLen[getopcode()] + 1;

  switch(getopcode()) {
  default:
    ABORT();

    define_insn(ILOAD)
      {
	/*
	 * ..., -> ..., local variable
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));

	check_local_int(idx);
 
	push(1);
	move_int(stack(0), local(idx));
        marknotobj_int; /* JJC */
      }
    define_insn(FLOAD)
      {
	/*
	 * ..., -> ..., local variable
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));

	check_local_float(idx);
 
	push(1);
	move_float(stack(0), local_float(idx));
        marknotobj_float; /* JJC */
      }
    define_insn(ALOAD)
      {
	/*
	 * ..., -> ..., local variable
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));
                
	check_local_ref(idx);  
 
	push(1);
	move_ref(stack(0), local(idx));
	/* START JJC */
	if( valid_log )
	  if( opsobjs )
	    *opsobjs = lvtobjs[ idx ];
	/* markisobj; */ /* JJC */
	/* END JJC */
      }
    define_insn(LLOAD)
      {
	/*      
	 * ..., -> ..., long local variable
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));
                
	check_local_long(idx+1);

	push(2);
	move_long(stack_long(0), local_long(idx));
        marknotobj2_long; /* JJC */
      }
    define_insn(DLOAD)
      {
	/*      
	 * ..., -> ..., double local variable
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));
                
	check_local_double(idx+1);

	push(2);
	move_double(stack_double(0), local_double(idx));
        marknotobj2_double; /* JJC */
      }
    define_insn(ISTORE)
      {
	/*      
	 * ..., var -> ...
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));

	check_stack_int(0);
         
	/*move_int(local(idx), stack(0));*/
	swap_any( local( idx ), stack( 0 ) ); /* JJC */
	/* START JJC */
	if( opsobjs ) {
	  *opsobjs = lvtobjs[ idx ];
	  lvtobjs[ idx ] = NOTOBJ_INT;
	}
	/* END JJC */
	if( valid_log ) savestack( 1 ); /* JJC */
	pop(1); 
      }
    define_insn(FSTORE)
      {
	/*      
	 * ..., var -> ...
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));
 
	check_stack_float(0);
         
	/*move_float(local_float(idx), stack(0));*/
	swap_any( local_float( idx ), stack( 0 ) ); /* JJC */
	/* START JJC */
	if( opsobjs ) {
	  *opsobjs = lvtobjs[ idx ];
	  lvtobjs[ idx ] = NOTOBJ_FLOAT;
	}
	/* END JJC */
	if( valid_log ) savestack( 1 ); /* JJC */
	pop(1); 
      }
    define_insn(ASTORE)
      {
	/*
	 * ..., var -> ...
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));

	check_stack_ref(0);

	/*move_ref(local(idx), stack(0));*/

	/* START JJC */
	swap_any( local( idx ), stack( 0 ) ); 
	if( opsobjs ) {
	  oldopsobjs = *opsobjs;
	  *opsobjs = lvtobjs[ idx ];
	  lvtobjs[ idx ] = oldopsobjs;
	}
	if( valid_log ) savestack( 1 ); 
	/* END JJC */

	pop(1);
      }
    define_insn(LSTORE)
      {
	/*      
	 * ..., long var -> ...
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));

	check_stack_long(0);
 
	/*move_long(local_long(idx), stack_long(0));*/
	swap_long( local_long( idx ), stack_long( 0 ) ); /* JJC */
	/* START JJC */
	if( opsobjs ) {
	  *( opsobjs - 1 ) = lvtobjs[ idx ];
	  *opsobjs = lvtobjs[ idx + 1 ];
	  lvtobjs[ idx ] = NOTOBJ_LONG;
	  lvtobjs[ idx + 1 ] = NOTOBJ_SKIP;
	}
	/* END JJC */
	if( valid_log ) savestack( 2 ); /* JJC */
	pop(2);
      }
    define_insn(DSTORE)
      {
	/*      
	 * ..., var -> ...
	 */
	check_pcidx (0);
	idx = (uint16)((getpc(0) << 8) | getpc(1));

	check_stack_double(0);
 
	/*move_double(local_double(idx), stack_double(0));*/
	swap_long( local_double( idx ), stack_double( 0 ) ); /* JJC */
	/* START JJC */
	if( opsobjs ) {
	  *( opsobjs - 1 ) = lvtobjs[ idx ];
	  *opsobjs = lvtobjs[ idx + 1 ];
	  lvtobjs[ idx ] = NOTOBJ_DOUBLE;
	  lvtobjs[ idx + 1 ] = NOTOBJ_SKIP;
	}
	/* END JJC */
	if( valid_log ) savestack( 2 ); /* JJC */
	pop(2);
      }
    define_insn(IINC)
      {
	check_pcidx (0);
	check_pcidx (2);
	idx = (uint16)((getpc(0) << 8) | getpc(1));
	low = (int16)((getpc(2) << 8) | getpc(3));
 
	check_local_int(idx);

	add_int_const(local(idx), local(idx), low);

	npc += 1;	/* Extra one */
      }
  }
}

define_insn(MULTIANEWARRAY)
{
  /*
   * ... size1, size2, ... sizen ->  ..., object ref
   */
  check_pcidx (0);
  check_pc (2);

  idx = (uint16)((getpc(0) << 8) | getpc(1));
  low = (uint8)getpc(2);
                
  if( valid_log ) savestackandn( low ); /* JJC */

  for (high = 0; high < low; high++) {
    check_stack_int(high);
  }

  get_class_info(idx);
  softcall_multianewarray(stack(low-1), low, stack(0), class_object());

  pop(low-1);
  markisobj; /* JJC */
}

define_insn(IFNULL)
{
  check_pcidx (0);
  check_stack_ref(0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  end_sub_block();

  cbranch_ref_const_eq(rstack(0), 0, reference_code_label(pc+idx));

  pop(1);
}

define_insn(IFNONNULL)
{
  check_pcidx (0);
  check_stack_ref(0);

  idx = (int16)((getpc(0) << 8) | getpc(1));

  slot_nowriteback(stack(0));
  end_sub_block();

  cbranch_ref_const_ne(rstack(0), 0, reference_code_label(pc+idx));

  pop(1);
}

define_insn(GOTO_W)
{
  check_pcwidx (0);

  idx = (int32)((getpc(0) << 24) | (getpc(1) << 16) |
		(getpc(2) << 8) | getpc(3));

  end_sub_block();
  branch_a(reference_code_label(pc+idx));
}

define_insn(JSR_W)
{
  /*
   * ... -> ..., ret-addr
   */
  check_pcwidx (0);

  idx = (int32)((getpc(0) << 24) | (getpc(1) << 16) |
		(getpc(2) << 8) | getpc(3));

  push(1);
  move_label_const(stack(0), reference_code_label(npc));
  end_sub_block();
  branch_a(reference_code_label(pc+idx));
}

define_insn(BREAKPOINT)
{
  breakpoint();
}
