/* -*- Mode: C; c-file-style: "gnu" -*-
   interpfunc.c -- opcode functions (this file is included into interploop.c).
   Created: Chris Toshok <toshok@hungry.com>
 */
/*
  This file is part of Japhar, the GNU Virtual Machine for Java Bytecodes.
  Japhar is a project of The Hungry Programmers, GNU, and OryxSoft.

  Copyright (C) 1997, 1998, 1999 The Hungry Programmers

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#define OutOfMemoryError	"java/lang/OutOfMemoryError"

OPCODE_START(nop, 0, 0, 0, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_nop ()\n");
}

OPCODE(wide, 196, -1, -1, -1)
{
  JAVARLOG0(MYLOG, 1, "in op_wide ()\n");

  WIDE(f) = JNI_TRUE;
}

OPCODE(breakpoint, 202, 0, 0, 0) /* reserved opcode */
{
#ifdef WITH_JVMDI
  /* the bytecode verifier has already checked to make sure this
     opcode doesn't show up in the bytestream, so we must be running
     in a debugger.  generate a JVMDI event. */

  jvmdi_BreakpointEvent(ENV(f), THREAD_INFO(f)->java_thread,
			clazzfile_to_jclass(ENV(f), METHOD(f)->clazz), METHOD(f),
			PC(f) - 1);
#endif
}

OPCODE(bipush, 16, 1, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_bipush()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), (jbyte)get_next_u1(f));
}

OPCODE(sipush, 17 , 2, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_sipush()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), (jshort)get_next_u2(f));
}

OPCODE(ldc, 18, 1, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_ldc()\n");

  push_item_from_constant_pool (f, get_next_u1(f));
}

OPCODE(ldc_w, 19, 2, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_ldc_w()\n");

  push_item_from_constant_pool (f, get_next_u2(f));
}

OPCODE(ldc2_w, 20, 2, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_ldc2_w()\n");
  
  push_item_from_constant_pool (f, get_next_u2(f));
}

OPCODE(aconst_null, 1, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_aconst_null()\n");

  op_stack_push_object(ENV(f), OPSTACK(f), 0);
}

OPCODE(iconst_m1, 2, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iconst_m1()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), -1);
}

OPCODE(iconst_0, 3, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iconst_0()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), 0);
}

OPCODE(iconst_1, 4, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iconst_1()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), 1);
}

OPCODE(iconst_2, 5, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iconst_2()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), 2);
}

OPCODE(iconst_3, 6, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iconst_3()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), 3);
}

OPCODE(iconst_4, 7, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iconst_4()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), 4);
}

OPCODE(iconst_5, 8, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iconst_5()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), 5);
}

OPCODE(lconst_0, 9, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_lconst_0()\n");

  op_stack_push_long(ENV(f), OPSTACK(f), 0);
}

OPCODE(lconst_1, 10, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_lconst_1()\n");

  op_stack_push_long(ENV(f), OPSTACK(f), 1l);
}

OPCODE(fconst_0, 11, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_fconst_0()\n");

  op_stack_push_float(ENV(f), OPSTACK(f), 0.0);
}

OPCODE(fconst_1, 12, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_fconst_1()\n");

  op_stack_push_float(ENV(f), OPSTACK(f), 1.0);
}

OPCODE(fconst_2, 13, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_fconst_2()\n");

  op_stack_push_float(ENV(f), OPSTACK(f), 2.0);
}

OPCODE(dconst_0, 14, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_dconst_0()\n");

  op_stack_push_double(ENV(f), OPSTACK(f), 0.0);
}

OPCODE(dconst_1, 15, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_dconst_1()\n");

  op_stack_push_double(ENV(f), OPSTACK(f), 1.0);
}

OPCODE(iload, 21, 1, 0, 1)
{
  u2 vindex;

  JAVARLOG1(MYLOG, 1, "in op_iload() wide=%d\n", WIDE(f));
  
  if (WIDE(f))
    {
      vindex = get_next_u2(f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);

  op_stack_push_int(ENV(f), OPSTACK(f),
		    VARS(f)[vindex].value.i);
}

OPCODE(iload_0, 26, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iload_0()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), VARS(f)[0].value.i);
}

OPCODE(iload_1, 27, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iload_1()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), VARS(f)[1].value.i);
}

OPCODE(iload_2, 28, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iload_2()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), VARS(f)[2].value.i);
}

OPCODE(iload_3, 29, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_iload_3()\n");

  op_stack_push_int(ENV(f), OPSTACK(f), VARS(f)[3].value.i);
}

OPCODE(lload, 22, 1, 0, 2)
{
  u2 vindex;

  JAVARLOG1(MYLOG, 1, "in op_lload() wide=%d\n", WIDE(f));

  if (WIDE(f))
    {
      vindex = get_next_u2 (f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);
  
  op_stack_push_long_w(ENV(f), OPSTACK(f),
		       VARS(f)[vindex].value.i,
		       VARS(f)[vindex + 1].value.i);
}

OPCODE(lload_0, 30, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_lload_0()\n");

  op_stack_push_long_w(ENV(f), OPSTACK(f),
		       VARS(f)[0].value.i,
		       VARS(f)[1].value.i);
}

OPCODE(lload_1, 31, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_lload_1()\n");

  op_stack_push_long_w(ENV(f), OPSTACK(f),
		       VARS(f)[1].value.i,
		       VARS(f)[2].value.i);
}

OPCODE(lload_2, 32, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_lload_2()\n");

  op_stack_push_long_w(ENV(f), OPSTACK(f),
		       VARS(f)[2].value.i,
		       VARS(f)[3].value.i);
}

OPCODE(lload_3, 33, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_lload_3()\n");

  op_stack_push_long_w(ENV(f), OPSTACK(f),
		       VARS(f)[3].value.i,
		       VARS(f)[4].value.i);
}

OPCODE(fload, 23, 1, 0, 1)
{
  u2 vindex;

  JAVARLOG1(MYLOG, 1, "in op_fload() wide=%d\n", WIDE(f));

  if (WIDE(f))
    {
      vindex = get_next_u2(f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);

  op_stack_push_float(ENV(f), OPSTACK(f), VARS(f)[vindex].value.f);
}

OPCODE(fload_0, 34, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_fload_0()\n");
  
  op_stack_push_float(ENV(f), OPSTACK(f), VARS(f)[0].value.f);
}

OPCODE(fload_1, 35, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_fload_1()\n");

  op_stack_push_float(ENV(f), OPSTACK(f), VARS(f)[1].value.f);
}

OPCODE(fload_2, 36, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_fload_2()\n");

  op_stack_push_float(ENV(f), OPSTACK(f), VARS(f)[2].value.f);
}

OPCODE(fload_3, 37, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_fload_2()\n");

  op_stack_push_float(ENV(f), OPSTACK(f), VARS(f)[3].value.f);
}

OPCODE(dload, 24, 1, 0, 2)
{
  u2 vindex;

  JAVARLOG1(MYLOG, 1, "in op_dload() wide=%d\n", WIDE(f));

  if (WIDE(f))
    {
      vindex = get_next_u2(f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);
  
  op_stack_push_double_w(ENV(f), OPSTACK(f),
			 VARS(f)[vindex].value.i,
			 VARS(f)[vindex + 1].value.i);
}

OPCODE(dload_0, 38, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_dload_0()\n");

  op_stack_push_double_w(ENV(f), OPSTACK(f),
			 VARS(f)[0].value.i,
			 VARS(f)[1].value.i);
}

OPCODE(dload_1, 39, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_dload_1()\n");

  op_stack_push_double_w(ENV(f), OPSTACK(f),
			 VARS(f)[1].value.i,
			 VARS(f)[2].value.i);
}

OPCODE(dload_2, 40, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_dload_2()\n");

  op_stack_push_double_w(ENV(f), OPSTACK(f),
			 VARS(f)[2].value.i,
			 VARS(f)[3].value.i);
}

OPCODE(dload_3, 41, 0, 0, 2)
{
  JAVARLOG0(MYLOG, 1, "in op_dload_3()\n");

  op_stack_push_double_w(ENV(f), OPSTACK(f),
			 VARS(f)[3].value.i,
			 VARS(f)[4].value.i);
}

OPCODE(aload, 25, 1, 0, 1)
{
  u2 vindex;

  JAVARLOG1(MYLOG, 1, "in op_aload() wide=%d\n", WIDE(f));

  if (WIDE(f))
    {
      vindex = get_next_u2 (f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);

  op_stack_push_object(ENV(f), OPSTACK(f),
		       VARS(f)[vindex].value.l);
}

OPCODE(aload_0, 42, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_aload_0()\n");

  op_stack_push_object(ENV(f), OPSTACK(f),
		       VARS(f)[0].value.l);
}

OPCODE(aload_1, 43, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_aload_1()\n");

  op_stack_push_object(ENV(f), OPSTACK(f), VARS(f)[1].value.l);
}

OPCODE(aload_2, 44, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_aload_2()\n");

  op_stack_push_object(ENV(f), OPSTACK(f), VARS(f)[2].value.l);
}

OPCODE(aload_3, 45, 0, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_aload_3()\n");

  op_stack_push_object(ENV(f), OPSTACK(f), VARS(f)[3].value.l);
}

OPCODE(ishl, 120, 0, 2, 1)
{
  jint value1;
  jint value2;

  JAVARLOG0(MYLOG, 1, "in op_ishl()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int (ENV(f), OPSTACK(f), &value1);  

  value1 = value1 << (value2 & 31); /* value2 & low 5 bits */

  op_stack_push_int(ENV(f), OPSTACK(f), value1);
}

OPCODE(ishr, 122, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_ishr()\n");
  
  op_stack_pop_int (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int (ENV(f), OPSTACK(f), &value1);  

  value1 = value1 >> (value2 & 31); /* value2 & low 5 bits */

  /* sign extension ???
     leave the top bit alone, do the shift, and then put the sign back */

  op_stack_push_int(ENV(f), OPSTACK(f), value1);
}

OPCODE(iushr, 124, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_iushr()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int (ENV(f), OPSTACK(f), &value1);
  
  value1 = value1 >> (value2 & 31); /* value2 & low 5 bits */

  /* sign extension ???  (no sign extension) */

  op_stack_push_int(ENV(f), OPSTACK(f), value1);
}

OPCODE(iand, 126, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_iand()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int (ENV(f), OPSTACK(f), &value1);  

  op_stack_push_int(ENV(f), OPSTACK(f), value1 & value2);
}

OPCODE(land, 127, 0, 4, 2)
{
  jlong value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_land()\n");

  op_stack_pop_long (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_long (ENV(f), OPSTACK(f), &value1);

  op_stack_push_long(ENV(f), OPSTACK(f), value1 & value2);
}

OPCODE(ior, 128, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_ior()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int (ENV(f), OPSTACK(f), &value1);  

  op_stack_push_int(ENV(f), OPSTACK(f), value1 | value2); 
}

OPCODE(lor, 129, 0, 4, 2)
{
  jlong value1, value2, result;

  JAVARLOG0(MYLOG, 1, "in op_lor()\n");

  op_stack_pop_long (ENV(f), OPSTACK(f), &value1);
  op_stack_pop_long (ENV(f), OPSTACK(f), &value2);

  result = value1 | value2;

  op_stack_push_long (ENV(f), OPSTACK(f), result);
}

OPCODE(ixor, 130, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_ixor()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int (ENV(f), OPSTACK(f), &value1);  

  op_stack_push_int (ENV(f), OPSTACK(f), value1 ^ value2); 
}

OPCODE(lxor, 131, 0, 4, 2)
{
  jlong value1, value2, result;

  JAVARLOG0(MYLOG, 1, "in op_lxor()\n");

  op_stack_pop_long (ENV(f), OPSTACK(f), &value1);
  op_stack_pop_long (ENV(f), OPSTACK(f), &value2);

  result = value1 ^ value2;

  op_stack_push_long (ENV(f), OPSTACK(f), result);
}

OPCODE(lshl, 121, 0, 3, 2)
{
  jlong value1, result;
  jint value2;

  JAVARLOG0(MYLOG, 1, "in op_lshl()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_long (ENV(f), OPSTACK(f), &value1);

  result = value1 << (value2 & 63); /* value2 & low 6 bits */

  op_stack_push_long(ENV(f), OPSTACK(f), result);
}

OPCODE(lshr, 123, 0, 3, 2)
{
  jlong value1, result;
  jint value2;

  JAVARLOG0(MYLOG, 1, "in op_lshr()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_long (ENV(f), OPSTACK(f), &value1);

  result = value1 >> (value2 & 63); /* value2 & low 6 bits */

  op_stack_push_long(ENV(f), OPSTACK(f), result);
}

OPCODE(lushr, 125, 0, 3, 2)
{
  jlong value1, result;
  jint value2;

  JAVARLOG0(MYLOG, 1, "in op_lushr()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value2);
  op_stack_pop_long (ENV(f), OPSTACK(f), &value1);

  result = value1 >> (value2 & 63); /* value2 & low 6 bits */

  /* sign extension ???  (no sign extension) */

  op_stack_push_long(ENV(f), OPSTACK(f), result);
}

OPCODE(istore, 54, 1, 0, 3)
{
  u2 vindex;

  JAVARLOG1(MYLOG, 1, "in op_istore () wide=%d\n", WIDE(f));
  
  if (WIDE(f))
    {
      vindex = get_next_u2(f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);

  op_stack_pop_int (ENV(f), OPSTACK(f), &VARS (f)[ vindex ].value.i);
  VARS(f)[ vindex ].tag = SIG_JINT;
}

OPCODE(lstore, 55, 1, 0, 4)
{
  u2 vindex;

  JAVARLOG1(MYLOG, 1, "in op_lstore () wide=%d\n", WIDE(f));

  if (WIDE(f))
    {
      vindex = get_next_u2(f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);

  op_stack_pop_long_w (ENV(f), OPSTACK(f),
		       &VARS (f)[ vindex ].value.i,
		       &VARS (f)[ vindex+1 ].value.i);
  VARS(f)[ vindex ].tag = SIG_JLONG1;
  VARS(f)[ vindex ].tag = SIG_JLONG2;
}

OPCODE(lstore_0, 63, 0, 2, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_lstore_0 ()\n");

  op_stack_pop_long_w (ENV(f), OPSTACK(f),
		       &VARS (f)[ 0 ].value.i,
		       &VARS (f)[ 1 ].value.i);
  VARS(f)[ 0 ].tag = SIG_JLONG1;
  VARS(f)[ 1 ].tag = SIG_JLONG2;
}

OPCODE(lstore_1, 64, 0, 2, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_lstore_1 ()\n");

  op_stack_pop_long_w (ENV(f), OPSTACK(f),
		       &VARS (f)[ 1 ].value.i,
		       &VARS (f)[ 2 ].value.i);
  VARS(f)[ 1 ].tag = SIG_JLONG1;
  VARS(f)[ 2 ].tag = SIG_JLONG2;
}

OPCODE(lstore_2, 65, 0, 2, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_lstore_2 ()\n");

  op_stack_pop_long_w (ENV(f), OPSTACK(f),
		       &VARS (f)[ 2 ].value.i,
		       &VARS (f)[ 3 ].value.i);
  VARS(f)[ 2 ].tag = SIG_JLONG1;
  VARS(f)[ 3 ].tag = SIG_JLONG2;
}

OPCODE(lstore_3, 66, 0, 2, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_lstore_3 ()\n");

  op_stack_pop_long_w (ENV(f), OPSTACK(f),
		       &VARS (f)[ 3 ].value.i,
		       &VARS (f)[ 4 ].value.i);
  VARS(f)[ 3 ].tag = SIG_JLONG1;
  VARS(f)[ 4 ].tag = SIG_JLONG2;
}

OPCODE(fstore, 56, 1, 0, 3)
{
  u2 vindex;
  /*double value;*/

  JAVARLOG1(MYLOG, 1, "in op_fstore () wide=%d\n", WIDE(f));

  if (WIDE(f))
    {
      vindex = get_next_u2(f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);

  op_stack_pop_float (ENV(f), OPSTACK(f),
		      &VARS (f)[ vindex ].value.f);
  VARS(f)[ vindex ].tag = SIG_JFLOAT;
}

OPCODE(fstore_0, 67, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_fstore_0 ()\n");

  op_stack_pop_float (ENV(f), OPSTACK(f),
		      &VARS (f)[ 0 ].value.f);
  VARS(f)[ 0 ].tag = SIG_JFLOAT;
}

OPCODE(fstore_1, 68, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_fstore_1 ()\n");

  op_stack_pop_float (ENV(f), OPSTACK(f),
		      &VARS (f)[ 1 ].value.f);
  VARS(f)[ 1 ].tag = SIG_JFLOAT;
}

OPCODE(fstore_2, 69, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_fstore_2 ()\n");

  op_stack_pop_float (ENV(f), OPSTACK(f),
		      &VARS (f)[ 2 ].value.f);
  VARS(f)[ 2 ].tag = SIG_JFLOAT;
}

OPCODE(fstore_3, 70, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_fstore_3 ()\n");

  op_stack_pop_float (ENV(f), OPSTACK(f),
		      &VARS (f)[ 3 ].value.f);
  VARS(f)[ 3 ].tag = SIG_JFLOAT;
}

OPCODE(dstore, 57, 1, 0, 4)
{
  u2 vindex;
  /* double value1, value2; */

  JAVARLOG1(MYLOG, 1, "in op_dstore () wide=%d\n", WIDE(f));

  if (WIDE(f))
    {
      vindex = get_next_u2(f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);

  op_stack_pop_double_w (ENV(f), OPSTACK(f),
			 &VARS (f)[ vindex ].value.i,
			 &VARS (f)[ vindex+1 ].value.i);
  VARS(f)[ vindex ].tag = SIG_JDOUBLE1;
  VARS(f)[ vindex + 1 ].tag = SIG_JDOUBLE2;
}

OPCODE(dstore_0, 71, 0, 2, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_dstore_0 ()\n");

  op_stack_pop_double_w (ENV(f), OPSTACK(f),
			 &VARS (f)[ 0 ].value.i,
			 &VARS (f)[ 1 ].value.i);
  VARS(f)[ 0 ].tag = SIG_JDOUBLE1;
  VARS(f)[ 1 ].tag = SIG_JDOUBLE2;
}

OPCODE(dstore_1, 72, 0, 2, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_dstore_1 ()\n");

  op_stack_pop_double_w (ENV(f), OPSTACK(f),
			 &VARS (f)[ 1 ].value.i,
			 &VARS (f)[ 2 ].value.i);
  VARS(f)[ 1 ].tag = SIG_JDOUBLE1;
  VARS(f)[ 2 ].tag = SIG_JDOUBLE2;
}

OPCODE(dstore_2, 73, 0, 2, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_dstore_2 ()\n");

  op_stack_pop_double_w (ENV(f), OPSTACK(f),
			 &VARS (f)[ 2 ].value.i,
			 &VARS (f)[ 3 ].value.i);
  VARS(f)[ 2 ].tag = SIG_JDOUBLE1;
  VARS(f)[ 3 ].tag = SIG_JDOUBLE2;
}

OPCODE(dstore_3, 74, 0, 2, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_dstore_3()\n");

  op_stack_pop_double_w (ENV(f), OPSTACK(f),
			 &VARS (f)[ 3 ].value.i,
			 &VARS (f)[ 4 ].value.i);
  VARS(f)[ 3 ].tag = SIG_JDOUBLE1;
  VARS(f)[ 4 ].tag = SIG_JDOUBLE2;
}

OPCODE(astore, 58, 1, 0, 3)
{
  u2 vindex;

  JAVARLOG1(MYLOG, 1, "in op_astore() wide=%d\n", WIDE(f));

  if (WIDE(f))
    {
      vindex = get_next_u2(f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);

  op_stack_pop_object (ENV(f), OPSTACK(f),
		       &VARS (f)[ vindex ].value.l);
  VARS(f)[ vindex ].tag = SIG_JOBJECT;
}

OPCODE(istore_0, 59, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_istore_0()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f),
		    &VARS (f)[ 0 ].value.i);
  VARS(f)[ 0 ].tag = SIG_JINT;
}

OPCODE(istore_1, 60, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_istore_1 ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f),
		    &VARS (f)[ 1 ].value.i);
  VARS(f)[ 1 ].tag = SIG_JINT;
}

OPCODE(istore_2, 61, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_istore_2 ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f),
		    &VARS (f)[ 2 ].value.i);
  VARS(f)[ 2 ].tag = SIG_JINT;
}

OPCODE(istore_3, 62, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_istore_3 ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f),
		    &VARS (f)[ 3 ].value.i);
  VARS(f)[ 3 ].tag = SIG_JINT;
}

OPCODE(astore_0, 75, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_astore_0 ()\n");

  op_stack_pop_object (ENV(f), OPSTACK(f),
		       &VARS (f)[ 0 ].value.l);
  VARS(f)[ 0 ].tag = SIG_JOBJECT;
}

OPCODE(astore_1, 76, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_astore_1 ()\n");

  op_stack_pop_object (ENV(f), OPSTACK(f),
		       &VARS (f)[ 1 ].value.l);
  VARS(f)[ 1 ].tag = SIG_JOBJECT;
}

OPCODE(astore_2, 77, 0, 1, 0)
{

  JAVARLOG0(MYLOG, 1, "in op_astore_2 ()\n");

  op_stack_pop_object (ENV(f), OPSTACK(f),
		       &VARS (f)[ 2 ].value.l);
  VARS(f)[ 2 ].tag = SIG_JOBJECT;
}

OPCODE(astore_3, 78, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_astore_3 ()\n");

  op_stack_pop_object (ENV(f), OPSTACK(f),
		       &VARS (f)[ 3 ].value.l);
  VARS(f)[ 3 ].tag = SIG_JOBJECT;
}

OPCODE(putfield, 181, 2, -1, 0)
{
  u2 index;
  jvalue value;
  jobject objectref;
  japhar_obj casted_object;
  FieldStruct *field;

  JAVARLOG0(MYLOG, 1, "in op_putfield()\n");

  index = get_next_u2(f);
  
  field = ResolveFieldRef(ENV(f), METHOD(f)->clazz,
			  get_constant(METHOD(f)->clazz,index));

  initialize_class(ENV(f), field->clazz);

  if (field->access_flags & ACC_STATIC)
    {
      throw_Exception(ENV(f), "java/lang/IncompatibleClassChangeError", NULL);
      return;
    }

  JAVARLOG1(MYLOG, 2, "        field_name='%s'\n",
	    field->name);

  if (UNRESOLVED ( field->field_offset )
      || UNRESOLVED ( field->java_type ))
    {
      throw_Exception(ENV(f), "java/lang/RuntimeException", NULL);
      return;
    }

  op_stack_pop_value(ENV(f), OPSTACK(f), field->java_type, &value);

  op_stack_pop_object (ENV(f), OPSTACK(f), &objectref);

  if (objectref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  casted_object = cast_obj((japhar_obj)objectref,
			   field->clazz);

  if (!casted_object)
    {
      throw_Exception(ENV(f), "java/lang/IncompatibleClassChangeError", NULL);
      return;
    }

  set_instance_field(casted_object, field, value);
}

OPCODE(getfield, 180, 2, 1, -1)
{
  u2 index;
  jobject objectref;
  japhar_obj casted_object;
  FieldStruct *field;
  jvalue value;

  JAVARLOG0(MYLOG, 1, "in op_getfield()\n");

  index = get_next_u2(f);

  field = ResolveFieldRef(ENV(f), METHOD(f)->clazz,
			  get_constant(METHOD(f)->clazz,index));

  initialize_class(ENV(f), field->clazz);

  JAVARLOG3(MYLOG, 2, "   getting %s.%s(%s)\n", 
	    getClassName(ENV(f), field->clazz), field->name, field->sig_str);

  if (field->access_flags & ACC_STATIC)
    {
      throw_Exception(ENV(f), "java/lang/IncompatibleClassChangeError", NULL);
      return;
    }

  op_stack_pop_object (ENV(f), OPSTACK(f), &objectref);

  if (objectref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  casted_object = cast_obj ((japhar_obj) objectref, field->clazz);

  if (!casted_object)
    {
      throw_Exception(ENV(f), "java/lang/IncompatibleClassChangeError", NULL);
      return;
    }

  JAVARLOG2(MYLOG, 2, "        index=%d, objectref=%d\n", index, objectref);

  if ( UNRESOLVED ( field->field_offset )
       || UNRESOLVED ( field->java_type ))
    {
      printf ("CALLING GETFIELD ON NON_NEW'ED OBJECT!!!!\n");
      throw_Exception(ENV(f), "java/lang/RuntimeException", NULL);
      return;
    }

  get_instance_field(casted_object, field, &value);
  op_stack_push_value(ENV(f), OPSTACK(f),
		      field->java_type,
		      &value);
}

OPCODE(putstatic, 179, 2, -1, 0)
{
  u2 index;
  jvalue value;
  FieldStruct *field;

  JAVARLOG0(MYLOG, 1, "in op_putstatic()\n");

  index = get_next_u2(f);
  
  field = ResolveFieldRef(ENV(f), METHOD(f)->clazz,
			  get_constant(METHOD(f)->clazz, index));
  initialize_class(ENV(f), field->clazz);

  if (!(field->access_flags & ACC_STATIC))
    {
      throw_Exception(ENV(f), "java/lang/IncompatibleClassChangeError", NULL);
      return;
    }

  op_stack_pop_value(ENV(f), OPSTACK(f),
		     field->java_type,
		     &value);
  set_static_field(field->clazz, field, value);
}

OPCODE(getstatic, 178, 2, 0, -1)
{
  u2 index;
  FieldStruct *field;
  jvalue value;

  JAVARLOG0(MYLOG, 1, "in op_getstatic()\n");

  index = get_next_u2(f);

  JAVARLOG1(MYLOG, 2, "        index=%d\n", index);

  field = ResolveFieldRef(ENV(f), METHOD(f)->clazz,
			  get_constant(METHOD(f)->clazz, index));
  initialize_class(ENV(f), field->clazz);

  if (!(field->access_flags & ACC_STATIC))
    {
      throw_Exception(ENV(f), "java/lang/IncompatibleClassChangeError", NULL);
      return;
    }

  if (UNRESOLVED( field->field_offset )
      || UNRESOLVED( field->java_type ))
    {
      printf ("CALLING GETSTATIC ON NON_RESOLVED CLASS!!!!\n");
      throw_Exception(ENV(f), "java/lang/RuntimeException", NULL);
      return;
    }

  get_static_field(field->clazz, field, &value);
  op_stack_push_value(ENV(f), OPSTACK(f),
		      field->java_type,
		      &value);
}

OPCODE(new, 187, 1, 0, 1)
{
  u2 index;
  ClazzFile *cf;
  jobject object_reference;
  japhar_object *jobj;

  JAVARLOG0(MYLOG, 1, "in op_new()\n");

  index = get_next_u2(f);

  cf = ResolveClass(ENV(f), METHOD(f)->clazz,
		    get_constant(METHOD(f)->clazz, index));
  JAVARLOG1(MYLOG, 2, 
	    "name of class to new: '%s'\n", getClassName(ENV(f), cf));
  object_reference = new_object (ENV(f), cf);

  if (object_reference == NULL)
    {
      throw_Exception(ENV(f), OutOfMemoryError, "object allocation failed.");
      return;
    }

  op_stack_push_object (ENV(f), OPSTACK(f), (void*) object_reference);

  obj_to_object(object_reference, jobj);
#if 0
  GC_addReference((JavaVM*)((HungryJNIEnv*)ENV(f))->_vm, (GC_obj*)jobj);
#endif
}

OPCODE(checkcast, 192, 2, 1, 1)
{
  u2 index;
  japhar_obj object_ref;
  ClazzFile *cf;

  JAVARLOG0(MYLOG, 1, "in op_checkcast()\n");

  index = get_next_u2(f);

  cf = ResolveClass(ENV(f), METHOD(f)->clazz,
		    get_constant(METHOD(f)->clazz, index));

  op_stack_pop_object(ENV(f), OPSTACK(f), (jobject*)&object_ref);

  /* trivial case -- thunk is NULL, which is castable to anything */
  if (!object_ref)
    {
      op_stack_push_object(ENV(f), OPSTACK(f), object_ref);
      return;
    }
  else
    {
      japhar_object *jobj;
      obj_to_object(object_ref, jobj);

      if (is_instance_of(ENV(f), &jobj->_static, cf))
	{
	  op_stack_push_object(ENV(f), OPSTACK(f), object_ref);
	  return;
	}
      else
	{
	  char buffer[200];
	  snprintf(buffer, sizeof(buffer), "can't cast '%s' to '%s'",
		   getClassName(ENV(f), jobj->_static),
		   getClassName(ENV(f), cf));
	  throw_Exception(ENV(f), "java/lang/ClassCastException", buffer);
	  return;
	}
    }
}

OPCODE(instanceof, 193, 2, 1, 1)
{
  u2 index;
  jobject objectref;

  JAVARLOG0(MYLOG, 1, "in op_instanceof()\n");

  index = get_next_u2(f);

  op_stack_pop_object (ENV(f), OPSTACK(f), &objectref);

  /* null object is not instance of anything */
  if (objectref == 0)
    {
      op_stack_push_int (ENV(f), OPSTACK(f), JNI_FALSE);
    }
  else
    {
      ClazzFile *cf = ResolveClass(ENV(f), METHOD(f)->clazz,
				   get_constant(METHOD(f)->clazz, index));

      op_stack_push_int (ENV(f), OPSTACK(f), 
			 is_instance_of(ENV(f), objectref, cf));
    }
}

OPCODE(pop, 87, 0, 1, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_pop()\n");

  OPSTACK(f)->stack_top -= 1;
}

OPCODE(pop2, 88, 0, 2, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_pop2()\n");

  OPSTACK(f)->stack_top -= 2;
}

OPCODE(dup, 89, 0, 1, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_dup()\n");

  op_stack_push_any(ENV(f), OPSTACK(f), OPSTACK(f)->stack_top - 1);
}

OPCODE(dupx1, 90, 0, 2, 3)
{
  void *any1, *any2;

  JAVARLOG0(MYLOG, 1, "in op_dupx1()\n");

  op_stack_pop_any(ENV(f), OPSTACK(f), &any1);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any2);

  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
  op_stack_push_any(ENV(f), OPSTACK(f), &any2);

  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
}

OPCODE(dupx2, 91, 0, 3, 4)
{
  void *any1, *any2, *any3;

  JAVARLOG0(MYLOG, 1, "in op_dupx2()\n");

  op_stack_pop_any(ENV(f), OPSTACK(f), &any1);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any2);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any3);

  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
  op_stack_push_any(ENV(f), OPSTACK(f), &any3);
  op_stack_push_any(ENV(f), OPSTACK(f), &any2);

  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
}

OPCODE(dup2, 92, 0, 2, 4)
{
  void *any1, *any2;

  JAVARLOG0(MYLOG, 1, "in op_dup2()\n");
  
  op_stack_pop_any(ENV(f), OPSTACK(f), &any1);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any2);

  op_stack_push_any(ENV(f), OPSTACK(f), &any2);
  op_stack_push_any(ENV(f), OPSTACK(f), &any1);

  op_stack_push_any(ENV(f), OPSTACK(f), &any2);
  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
}

OPCODE(dup2x1, 93, 0, 3, 5)
{
  void *any1, *any2, *any3;

  JAVARLOG0(MYLOG, 1, "in op_dup2x1()\n");

  op_stack_pop_any(ENV(f), OPSTACK(f), &any1);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any2);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any3);

  op_stack_push_any(ENV(f), OPSTACK(f), &any2);
  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
  op_stack_push_any(ENV(f), OPSTACK(f), &any3);

  op_stack_push_any(ENV(f), OPSTACK(f), &any2);
  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
}

OPCODE(dup2x2, 94, 0, 4, 6)
{
  void *any1, *any2, *any3, *any4;

  JAVARLOG0(MYLOG, 1, "in op_dup2x2()\n");

  op_stack_pop_any(ENV(f), OPSTACK(f), &any1);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any2);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any3);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any4);

  op_stack_push_any(ENV(f), OPSTACK(f), &any2);
  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
  op_stack_push_any(ENV(f), OPSTACK(f), &any4);
  op_stack_push_any(ENV(f), OPSTACK(f), &any3);

  op_stack_push_any(ENV(f), OPSTACK(f), &any2);
  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
}

OPCODE(swap, 95, 0, 2, 2)
{
  void *any1, *any2;

  JAVARLOG0(MYLOG, 1, "in op_swap()\n");

  op_stack_pop_any(ENV(f), OPSTACK(f), &any1);
  op_stack_pop_any(ENV(f), OPSTACK(f), &any2);

  op_stack_push_any(ENV(f), OPSTACK(f), &any1);
  op_stack_push_any(ENV(f), OPSTACK(f), &any2);
}

OPCODE(invokevirtual, 182, 2, -1, 0)
{
  u2 index;
  ClazzFile *cf;
  MethodStruct *method = NULL;
  jboolean not_found = JNI_FALSE;
  char *class_name = NULL;
  char *method_name;
  japhar_obj objectref;
  char *sig_str;
  JNIEnv *env = ENV(f);
  Signature *sig;
  int num_param_words;
  int i;

  JAVARLOG0(MYLOG, 1, "in op_invokevirtual()\n");

  index = get_next_u2(f);

  ResolveMethod(env, METHOD(f)->clazz, &METHOD(f)->clazz->constants[index],
		&method_name, &sig_str);

  sig = SIG_parseFromJavaSig(env, sig_str);

  num_param_words = 0;
  for (i = 0; i < SIG_numParams(env, sig); i ++)
    num_param_words += SIG_sizeInWords(env, sig->method.params[i]);

  SIG_free(env, sig);

  objectref = *(OPSTACK(f)->stack_top - num_param_words - 1);

  if (objectref == 0)
    {
      char msg[110];
#ifndef DEBUG
      snprintf(msg, sizeof(msg), "objectref == null in call to virtual method '%s'",
	       method_name);
#else
      /* CLASSNAME and METHODNAME is only defined when DEBUG is defined */
      snprintf(msg, sizeof(msg), "objectref == null"
	       " in call to virtual method '%s' from %s.%s()",
	       method_name,
	       CLASSNAME(f),
	       METHODNAME(f));
#endif
      throw_Exception(ENV(f), "java/lang/NullPointerException", msg);
      return;
    }

  while (*objectref)
    objectref--;

  objectref++;

  while (*objectref
	 && !(method = GetMethodByNameAndSig(env,
					     *objectref,
					     method_name, sig_str)))
    {
      if ((*objectref)->nesting_level == 0)
	{
	  not_found = JNI_TRUE;
	  break;
	}
      else
	objectref ++;
    }

  if (not_found)
    {
      fprintf(stderr, "method=%s, ref=%p\n", method_name, objectref);
      assert(0 == "IS_POST(objectref)"); /* XXX Hack to get decent assert msg */
      return;
    }
  
  cf = (ClazzFile*)*objectref;
  class_name = getClassName(env, cf);
  
  JAVARLOG2(MYLOG, 1, "    Method is %s.%s\n", class_name, method_name);
  
  do_method_call (f, method);
}

OPCODE(invokenonvirtual, 183, 2, -1, 0)
{
  u2 index;
  ClazzFile *cf;
  MethodStruct *method;

  JAVARLOG0(MYLOG, 1, "in op_invokenonvirtual()\n");

  index = get_next_u2(f);

  method = ResolveNonVirtualMethodRef(ENV(f), METHOD(f)->clazz,
				      get_constant(METHOD(f)->clazz, index));

  if (NULL == method)
    {
      char buf[500];

      snprintf(buf, 500, "unknown method '%s' in invokenonvirtual", method->name);
      /* XXX Is this the correct exception? [pere 1998-05-09] */
      throw_Exception(ENV(f), "java/lang/RuntimeException", buf);
      return;
    }

  cf = method->clazz;

  if (cf == NULL)
    {
      throw_Exception(ENV(f), "java/lang/RuntimeException", NULL);
      return;
    }

  do_method_call (f, method);
}

OPCODE(invokestatic, 184, 2, -1, 0)
{
  u2 index;
  ClazzFile *cf;
  MethodStruct *method;

  JAVARLOG0(MYLOG, 1, "in op_invokestatic()\n");

  index = get_next_u2(f);

  method = ResolveStaticMethodRef(ENV(f), METHOD(f)->clazz,
				  get_constant(METHOD(f)->clazz, index));

  if (NULL == method)
    {
      char buf[500];

      snprintf(buf, 500, "unknown method '%s' in invokestatic", method->name);
      /* XXX Is this the correct exception? [pere 1998-05-09] */
      throw_Exception(ENV(f), "java/lang/RuntimeException", buf);
      return;
    }

  cf = method->clazz;
  if (cf == NULL)
    {
      throw_Exception(ENV(f), "java/lang/RuntimeException", NULL);
      return;
    }

  do_method_call(f, method);
}

OPCODE(invokeinterface, 185, 4, -1, 0)
{
  u2 index;
  u4 nargs;
  u4 reserved;
  jobject objectref;
  char *interface_methodname;
  char *interface_methodsig_str;
  MethodStruct *method;
  ClazzFile *clazz;

  JAVARLOG0(MYLOG, 1, "in op_invokeinterface()\n");

  index = get_next_u2(f);

  nargs = get_next_u1(f);
  reserved = get_next_u1(f);

  ResolveInterfaceMethod(ENV(f), METHOD(f)->clazz,
			 get_constant(METHOD(f)->clazz, index),
			 &interface_methodname,
			 &interface_methodsig_str);

  op_stack_check_bottomspace(ENV(f), OPSTACK(f), nargs);

  objectref = *(OPSTACK(f)->stack_top - nargs);

  method = get_interface_method_info(ENV(f),
				     objectref,
				     &clazz,
				     interface_methodname,
				     interface_methodsig_str);

  method = GetMethodByNameAndSig(ENV(f), clazz, interface_methodname, interface_methodsig_str);

  do_method_call(f, method);
}

OPCODE(ireturn, 172, 0, 1, 0)
{
  jint v;

  JAVARLOG0(MYLOG, 1, "in op_ireturn ()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &v);
  
  THREAD_INFO(f)->return_value.tag = SIG_JINT;
  THREAD_INFO(f)->return_value.value.i = v;

  maybe_push_return_value(f);

  pop_frame(THREAD_INFO(f));
}

OPCODE(lreturn, 173, 0, 2, 0)
{
  jlong ret_val;

  JAVARLOG0(MYLOG, 1, "in op_lreturn ()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f), &ret_val);
  
  THREAD_INFO(f)->return_value.tag = SIG_JLONG;
  THREAD_INFO(f)->return_value.value.j = ret_val;

  maybe_push_return_value(f);

  pop_frame (THREAD_INFO(f));
}

OPCODE(freturn, 174, 0, 1, 0)
{
  jfloat v;

  JAVARLOG0(MYLOG, 1, "in op_freturn ()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &v);
  
  THREAD_INFO(f)->return_value.tag = SIG_JFLOAT;
  THREAD_INFO(f)->return_value.value.f = v;

  maybe_push_return_value(f);

  pop_frame (THREAD_INFO(f));
}

OPCODE(dreturn, 175, 0, 2, 0)
{
  jdouble ret_val;

  JAVARLOG0(MYLOG, 1, "in op_dreturn ()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &ret_val);
  
  THREAD_INFO(f)->return_value.tag = SIG_JDOUBLE;
  THREAD_INFO(f)->return_value.value.d = ret_val;

  maybe_push_return_value(f);

  pop_frame (THREAD_INFO(f));
}

OPCODE(areturn, 176, 0, 1, 0)
{
  u4 v;

  JAVARLOG0(MYLOG, 1, "in op_areturn ()\n");

  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&v);
  
  THREAD_INFO(f)->return_value.tag = SIG_JOBJECT;
  THREAD_INFO(f)->return_value.value.i = v;

  maybe_push_return_value(f);

  pop_frame (THREAD_INFO(f));
}

OPCODE(return, 177, 0, 0, 0)
{
  JAVARLOG0(MYLOG, 1, "in op_return ()\n");

  THREAD_INFO(f)->return_value.tag = SIG_JVOID;

  maybe_push_return_value(f);

  pop_frame (THREAD_INFO(f));
}

OPCODE(ifeq, 153, 2, 1, 0)
{
  jshort branch_add;
  jint value;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_ifeq()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value);

  if (value == 0)
    PC(f) = current_pc + branch_add;
}

OPCODE(ifnull, 198, 2, 1, 1)
{
  jshort branch_add;
  jobject value;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_ifnull()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_object(ENV(f), OPSTACK(f), &value);

  if (value == NULL)
    PC(f) = current_pc + branch_add;
}

OPCODE(iflt, 155, 2, 1, 0)
{
  jshort branch_add;
  jint value;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_iflt()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value);

  if (value < 0)
    PC(f) = current_pc + branch_add;
}

OPCODE(ifle, 158, 2, 1, 0)
{
  jshort branch_add;
  jint value;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_ifle()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value);

  if (value <= 0)
    PC(f) = current_pc + branch_add;
}

OPCODE(ifne, 154, 2, 1, 0)
{
  jshort branch_add;
  jint value;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_ifne()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value);

  if (value != 0)
    PC(f) = current_pc + branch_add;
}

OPCODE(ifnonnull, 199, 2, 1, 1)
{
  jshort branch_add;
  jobject value;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_ifnonnull()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_object(ENV(f), OPSTACK(f), &value);

  if (value != NULL)
    PC(f) = current_pc + branch_add;
}

OPCODE(ifgt, 157, 2, 1, 0)
{
  jshort branch_add;
  jint value;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_ifgt()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value);

  if (value > 0)
    PC(f) = current_pc + branch_add;
}

OPCODE(ifge, 156, 2, 1, 0)
{
  jshort branch_add;
  jint value;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_ifge()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value);

  if (value >= 0)
    PC(f) = current_pc + branch_add;
}

OPCODE(if_icmpeq, 159, 2, 2, 0)
{
  jshort branch_add;
  jint value1, value2;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_if_icmpeq()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  if (value1 == value2)
    PC(f) = current_pc + branch_add;
}

OPCODE(if_icmpne, 160, 2, 2, 0)
{
  jshort branch_add;
  jint value1, value2;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_if_icmpne()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  if (value1 != value2)
    PC(f) = current_pc + branch_add;
}

OPCODE(if_icmplt, 161, 2, 2, 0)
{
  jshort branch_add;
  jint value1, value2;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_if_icmplt()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  if (value1 < value2)
    PC(f) = current_pc + branch_add;
}

OPCODE(if_icmpgt, 163, 2, 2, 0)
{
  jshort branch_add;
  jint value1, value2;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_if_icmpgt()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  if (value1 > value2)
    PC(f) = current_pc + branch_add;
}

OPCODE(if_icmple, 164, 2, 2, 0)
{
  jshort branch_add;
  jint value1, value2;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_if_icmple()\n");

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  if (value1 <= value2)
    PC(f) = current_pc + branch_add;
}

OPCODE(if_icmpge, 162, 2, 2, 0)
{
  jshort branch_add;
  jint value1, value2;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_if_icmpge()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  if (value1 >= value2)
    PC(f) = current_pc + branch_add;
}

OPCODE(lcmp, 148, 0, 4, 1)
{
  jlong value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_lcmp()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_long(ENV(f), OPSTACK(f), &value1);

  if (value1 > value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 1);
  else if (value1 == value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 0);
  else
    op_stack_push_int(ENV(f), OPSTACK(f), -1);
}

OPCODE(fcmpl, 149, 0, 2, 1)
{
  jfloat value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_fcmpl()\n");  

  op_stack_pop_float(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_float(ENV(f), OPSTACK(f), &value1);

  if (isnan(value1) || isnan(value2))
    op_stack_push_int(ENV(f), OPSTACK(f), -1);
  else if (value1 > value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 1);
  else if (value1 == value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 0);
  else /* (value1 < value2) */
    op_stack_push_int(ENV(f), OPSTACK(f), -1);
}

OPCODE(fcmpg, 150, 0, 2, 1)
{
  jfloat value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_fcmpg()\n");  

  op_stack_pop_float(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_float(ENV(f), OPSTACK(f), &value1);

#ifdef isnan /* assume C99 style macro */
  if (isnan(value1) || isnan(value2))
#else
  if (isnanf(value1) || isnanf(value2))
#endif
    op_stack_push_int(ENV(f), OPSTACK(f), 1);
  else if (value1 > value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 1);
  else if (value1 == value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 0);
  else /* (value1 < value2) */
    op_stack_push_int(ENV(f), OPSTACK(f), -1);
}

OPCODE(dcmpl, 151, 0, 4, 1)
{
  jdouble value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_dcmpl()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_double(ENV(f), OPSTACK(f), &value1);

  if (isnan(value1) || isnan(value2))
    op_stack_push_int(ENV(f), OPSTACK(f), -1);
  else if (value1 > value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 1);
  else if (value1 == value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 0);
  else /* (value1 < value2) */
    op_stack_push_int(ENV(f), OPSTACK(f), -1);
}

OPCODE(dcmpg, 152, 0, 4, 1)
{
  jdouble value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_dcmpg()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_double(ENV(f), OPSTACK(f), &value1);

  if (isnan(value1) || isnan(value2))
    op_stack_push_int(ENV(f), OPSTACK(f), 1);
  else if (value1 > value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 1);
  else if (value1 == value2)
    op_stack_push_int(ENV(f), OPSTACK(f), 0);
  else /* (value1 < value2) */
    op_stack_push_int(ENV(f), OPSTACK(f), -1);
}

OPCODE(if_acmpeq, 165, 2, 2, 0)
{
  jshort branch_add;
  japhar_obj value1, value2;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_if_acmpeq()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_object(ENV(f), OPSTACK(f), (jobject*)&value2);
  op_stack_pop_object(ENV(f), OPSTACK(f), (jobject*)&value1);

  while (value1 && *value1) value1--;
  while (value2 && *value2) value2--;

  if (value1 == value2)
    PC(f) = current_pc + branch_add;
}

OPCODE(if_acmpne, 166, 2, 2, 0)
{
  jshort branch_add;
  japhar_obj value1, value2;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_if_acmpne()\n");  

  branch_add = (jshort) get_next_u2(f);
  op_stack_pop_object(ENV(f), OPSTACK(f), (jobject*)&value2);
  op_stack_pop_object(ENV(f), OPSTACK(f), (jobject*)&value1);

  while (value1 && *value1) value1--;
  while (value2 && *value2) value2--;

  if (value1 != value2)
    PC(f) = current_pc + branch_add;
}

OPCODE(goto, 167, 2, 0, 0)
{
  jshort branch_add;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_goto()\n");  

  branch_add = (jshort) get_next_u2(f);

  PC(f) = current_pc + branch_add;
}

OPCODE(goto_w, 200, 4, 0, 0)
{
  jint branch_add;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_goto_w()\n");  

  branch_add = (jint)get_next_u4(f);

  PC(f) = current_pc + branch_add;
}

OPCODE(jsr, 168, 2, 0, 1)
{
  jshort branch_add;
  int current_pc = PC(f) - 1;

  JAVARLOG0(MYLOG, 1, "in op_jsr()\n");  

  branch_add = (jshort) get_next_u2(f);

  op_stack_push_int(ENV(f), OPSTACK(f), PC(f));

  PC(f) = current_pc + branch_add;
}

OPCODE(jsr_w, 201, 4, 0, 1)
{
  JAVARLOG0(MYLOG, 1, "in op_jsr_w()\n");  

  throw_Exception(ENV(f), "java/lang/RuntimeException", "unfinished opcode:  jsr_w");
}

OPCODE(ret, 169, 1, 0, 0)
{
  u2 vindex;

  JAVARLOG1(MYLOG, 1, "in op_ret() wide=%d\n", WIDE(f));  

  if (WIDE(f))
    {
      vindex = get_next_u2(f);
      WIDE(f) = JNI_FALSE;
    }
  else
    vindex = get_next_u1(f);

  PC(f) = (int)VARS(f)[vindex].value.i;
}

OPCODE(iadd, 96, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_iadd()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  op_stack_push_int(ENV(f), OPSTACK(f), value1 + value2);
}

OPCODE(ladd, 97, 0, 4, 2)
{
  jlong value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_ladd()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f),  &value1);
  op_stack_pop_long(ENV(f), OPSTACK(f), &value2);

  op_stack_push_long(ENV(f), OPSTACK(f), value1 + value2);
}

OPCODE(fadd, 98, 0, 2, 1)
{
  jfloat value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_fadd()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_float(ENV(f), OPSTACK(f), &value1);

  op_stack_push_float(ENV(f), OPSTACK(f), value1 + value2);
}

OPCODE(dadd, 99, 0, 4, 2)
{
  jdouble value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_dadd()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_double(ENV(f), OPSTACK(f), &value1);

  op_stack_push_double(ENV(f), OPSTACK(f), value1 + value2);
}

OPCODE(isub, 100, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_isub()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  op_stack_push_int(ENV(f), OPSTACK(f), value1 - value2);
}

OPCODE(lsub, 101, 0, 4, 2)
{
  jlong value1, value2;
  
  JAVARLOG0(MYLOG, 1, "in op_lsub()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_long(ENV(f), OPSTACK(f), &value1);

  op_stack_push_long(ENV(f), OPSTACK(f), value1 - value2);
}

OPCODE(fsub, 102, 0, 2, 1)
{
  jfloat value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_fsub()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_float(ENV(f), OPSTACK(f), &value1);

  op_stack_push_float(ENV(f), OPSTACK(f), value1 - value2);
}

OPCODE(dsub, 103, 0, 4, 2)
{
  jdouble value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_dsub()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_double(ENV(f), OPSTACK(f), &value1);

  op_stack_push_double(ENV(f), OPSTACK(f), value1 - value2);
}

OPCODE(imul, 104, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_imul()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);
 
  op_stack_push_int(ENV(f), OPSTACK(f), value1 * value2);
}

OPCODE(lmul, 105, 0, 4, 2)
{
  jlong value1, value2;
  
  JAVARLOG0(MYLOG, 1, "in op_lmul()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f),  &value2);
  op_stack_pop_long(ENV(f), OPSTACK(f), &value1);

  op_stack_push_long(ENV(f), OPSTACK(f), value1 * value2);
}

OPCODE(fmul, 106, 0, 2, 1)
{
  jfloat value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_fmul()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_float(ENV(f), OPSTACK(f), &value1);

  op_stack_push_float(ENV(f), OPSTACK(f), value1 * value2);
}

OPCODE(dmul, 107, 0, 4, 2)
{ 
  jdouble value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_dmul()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_double(ENV(f), OPSTACK(f), &value1);

  op_stack_push_double(ENV(f), OPSTACK(f), value1 * value2);
}

OPCODE(idiv, 108, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_idiv()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  if (value2 == 0)
    {
      throw_Exception(ENV(f), "java/lang/ArithmeticException", "divisor is 0 in integer division.");
      return;
    }
  else
    op_stack_push_int(ENV(f), OPSTACK(f), value1 / value2);
}

OPCODE(ldiv, 109, 0, 4, 2)
{
  jlong value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_ldiv()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_long(ENV(f), OPSTACK(f), &value1);

  if (value2 == 0)
    {
      throw_Exception(ENV(f), "java/lang/ArithmeticException", "divisor is 0 in long division.");
      return;
    }
  else
    op_stack_push_long(ENV(f), OPSTACK(f), value1 / value2);
}

OPCODE(fdiv, 110, 0, 2, 1)
{
  jfloat value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_fdiv()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_float(ENV(f), OPSTACK(f), &value1);

  op_stack_push_float(ENV(f), OPSTACK(f), value1 / value2);
}

OPCODE(ddiv, 111, 0, 4, 2)
{
  jdouble value1, value2;
  
  JAVARLOG0(MYLOG, 1, "in op_ddiv()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_double(ENV(f), OPSTACK(f), &value1);

  op_stack_push_double(ENV(f), OPSTACK(f), value1 / value2);
}

OPCODE(irem, 112, 0, 2, 1)
{
  jint value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_irem()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_int(ENV(f), OPSTACK(f), &value1);

  if (value2 == 0)
    {
      throw_Exception(ENV(f), "java/lang/ArithmeticException", "divisor is 0 in integer remainder.");
      return;
    }
  else
    op_stack_push_int(ENV(f), OPSTACK(f), value1 % value2);
}

OPCODE(lrem, 113, 0, 4, 2)
{
  jlong value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_lrem()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_long(ENV(f), OPSTACK(f), &value1);

  if (value2 == 0)
    {
      throw_Exception(ENV(f), "java/lang/ArithmeticException", "divisor is 0 in long remainder.");
      return;
    }
  else
    op_stack_push_long(ENV(f), OPSTACK(f), value1 % value2);
}

OPCODE(frem, 114, 0, 2, 1)
{
  jfloat value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_frem()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_float(ENV(f), OPSTACK(f), &value1);

  op_stack_push_float(ENV(f), OPSTACK(f), fmodf(value1,value2));
}

OPCODE(drem, 115, 0, 4, 2)
{
  jdouble value1, value2;

  JAVARLOG0(MYLOG, 1, "in op_drem()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &value2);
  op_stack_pop_double(ENV(f), OPSTACK(f), &value1);

  op_stack_push_double(ENV(f), OPSTACK(f), fmod(value1,value2));
}

OPCODE(ineg, 116, 0, 1, 1)
{
  jint value;

  JAVARLOG0(MYLOG, 1, "in op_ineg()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &value);

  op_stack_push_int(ENV(f), OPSTACK(f), -1 * value);
}

OPCODE(lneg, 117, 0, 2, 2)
{
  jlong value;

  JAVARLOG0(MYLOG, 1, "in op_lneg()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f), &value);

  op_stack_push_long(ENV(f), OPSTACK(f), -1 * value);
}

OPCODE(fneg, 118, 0, 1, 1)
{
  jfloat value;

  JAVARLOG0(MYLOG, 1, "in op_fneg()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &value);
  op_stack_push_float(ENV(f), OPSTACK(f), -1.0 * value);
}

OPCODE(dneg, 119, 0, 2, 2)
{
  jdouble value;

  JAVARLOG0(MYLOG, 1, "in op_dneg()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &value);
  op_stack_push_double(ENV(f), OPSTACK(f), -1.0 * value);
}

OPCODE(iinc, 132, 0, 0, 0)
{
  /* should typecheck the variable... */

  JAVARLOG1(MYLOG, 1, "in op_iinc() wide=%d\n", WIDE(f));

  /* These are handlet separatly to get then signed constant correct */
  if (WIDE(f))
    {
      u2 vindex = get_next_u2(f);
      jshort c = (jshort)get_next_u2(f);
      jint ivalue;
      WIDE(f) = JNI_FALSE;

      ivalue = VARS(f)[vindex].value.i += c;
    }
  else
    {
      u1 vindex = get_next_u1(f);
      jbyte c = (jbyte)get_next_u1(f);
      jint ivalue;

      ivalue = VARS(f)[vindex].value.i += c;
    }
}

OPCODE(i2l, 133, 0, 1, 2)
{
  jint ivalue;

  JAVARLOG0(MYLOG, 1, "in op_i2l()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &ivalue);
  op_stack_push_long (ENV(f), OPSTACK(f), (jlong)ivalue); 
}

OPCODE(i2f, 134, 0, 1, 1)
{
  jint ivalue;

  JAVARLOG0(MYLOG, 1, "in op_i2f()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &ivalue);
  op_stack_push_float (ENV(f), OPSTACK(f), (jfloat)ivalue);
}

OPCODE(i2d, 135, 0, 1, 2)
{
  jint ivalue;

  JAVARLOG0(MYLOG, 1, "in op_i2d()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &ivalue);
  op_stack_push_double (ENV(f), OPSTACK(f), (jdouble)ivalue);
}

OPCODE(f2i, 139, 0, 1, 1)
{
  jfloat fvalue;

  JAVARLOG0(MYLOG, 1, "in op_f2i()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &fvalue);
  op_stack_push_int(ENV(f), OPSTACK(f), (jint)fvalue);
}

OPCODE(f2d, 141, 0, 1, 2)
{
  jfloat fvalue;

  JAVARLOG0(MYLOG, 1, "in op_f2d()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &fvalue);
  op_stack_push_double(ENV(f), OPSTACK(f), (jdouble)fvalue);
}

OPCODE(int2byte, 145, 0, 1, 1)
{
  jint ivalue;
  jbyte bvalue;

  JAVARLOG0(MYLOG, 1, "in op_int2byte()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &ivalue);
  bvalue = (jbyte) (ivalue & 0xFF);
  op_stack_push_int(ENV(f), OPSTACK(f), (jint)bvalue);
}

OPCODE(int2char, 146, 0, 1, 1)
{
  jint ivalue;

  JAVARLOG0(MYLOG, 1, "in op_int2char()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &ivalue);
  op_stack_push_char(ENV(f), OPSTACK(f), (jchar)(ivalue & 0xFFFF));
}

OPCODE(l2i, 136, 0, 2, 1)
{
  jlong lvalue;

  JAVARLOG0(MYLOG, 1, "in op_l2i()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f), &lvalue);
  op_stack_push_int(ENV(f), OPSTACK(f), (jint)(lvalue & 0xFFFFFFFF));
}

OPCODE(l2f, 137, 0, 2, 1)
{
  jlong lvalue;

  JAVARLOG0(MYLOG, 1, "in op_l2f()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f), &lvalue);
  op_stack_push_float(ENV(f), OPSTACK(f), (jfloat)lvalue);
}

OPCODE(l2d, 138, 0, 2, 2)
{
  jlong lvalue;

  JAVARLOG0(MYLOG, 1, "in op_l2d()\n");

  op_stack_pop_long(ENV(f), OPSTACK(f), &lvalue);
  op_stack_push_double(ENV(f), OPSTACK(f), (jdouble)lvalue);
}

OPCODE(f2l, 140, 0, 1, 2)
{
  jfloat fvalue;

  JAVARLOG0(MYLOG, 1, "in op_f2l()\n");

  op_stack_pop_float(ENV(f), OPSTACK(f), &fvalue);
  op_stack_push_long(ENV(f), OPSTACK(f), (jlong)fvalue);
}

OPCODE(d2i, 142, 0, 2, 1)
{
  jdouble dvalue;

  JAVARLOG0(MYLOG, 1, "in op_d2i()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &dvalue);
  op_stack_push_int(ENV(f), OPSTACK(f), (jint)dvalue);
}

OPCODE(d2l, 143, 0, 2, 2)
{
  jdouble dvalue;

  JAVARLOG0(MYLOG, 1, "in op_d2l()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &dvalue);
  op_stack_push_long(ENV(f), OPSTACK(f), (jlong)dvalue);
}

OPCODE(d2f, 144, 0, 2, 1)
{
  jdouble dvalue;

  JAVARLOG0(MYLOG, 1, "in op_d2f()\n");

  op_stack_pop_double(ENV(f), OPSTACK(f), &dvalue);
  op_stack_push_float(ENV(f), OPSTACK(f), (jfloat)dvalue);
}

OPCODE(int2short, 147, 0, 1, 1)
{
  jint ivalue;

  JAVARLOG0(MYLOG, 1, "in op_i2l()\n");

  op_stack_pop_int(ENV(f), OPSTACK(f), &ivalue);
  op_stack_push_short(ENV(f), OPSTACK(f), (jshort)ivalue);
}

OPCODE(newarray, 188, 1, 1, 1)
{
  u1 atype;
  jint size;
  japhar_obj array_reference;
  japhar_object *jobj;
  char *array_classname = NULL;

  JAVARLOG0(MYLOG, 1, "in op_newarray()\n");

  atype = get_next_u1 (f);
  op_stack_pop_int (ENV(f), OPSTACK(f), &size);

  switch (atype)
    {
    case 4: /*T_BOOLEAN*/
      array_classname = "[Z";
      break;
    case 5: /*T_CHAR*/
      array_classname = "[C";
      break;
    case 6: /*T_FLOAT*/
      array_classname = "[F";
      break;
    case 7: /*T_DOUBLE*/
      array_classname = "[D";
      break;
    case 8: /*T_BYTE*/
      array_classname = "[B";
      break;
    case 9: /*T_SHORT*/
      array_classname = "[S";
      break;
    case 10: /*T_INT*/
      array_classname = "[I";
      break;
    case 11: /*T_LONG*/
      array_classname = "[J";
      break;
    default:
      assert(0);
    }
  
  array_reference = new_array (ENV(f), size, createFakeArrayClass(ENV(f), array_classname));

  if (array_reference == NULL)
    {
      throw_Exception(ENV(f), OutOfMemoryError, "array allocation failed.");
      return;
    }

  obj_to_object(array_reference, jobj);

#if 0
  GC_addReference((JavaVM*)((HungryJNIEnv*)ENV(f))->_vm, (GC_obj*)jobj);
#endif

  op_stack_push_object (ENV(f), OPSTACK(f), array_reference);
}

OPCODE(anewarray, 189, 2, 1, 1)
{
  u2 ob_type;
  jint length;
  japhar_obj array_reference;
  char *element_classname;
  japhar_object *jobj;

  JAVARLOG0(MYLOG, 1, "in op_anewarray()\n");

  ob_type = get_next_u2(f);

  element_classname = ResolveClassName(ENV(f), METHOD(f)->clazz,
				       get_constant(METHOD(f)->clazz,ob_type));

  op_stack_pop_int (ENV(f), OPSTACK(f), &length);

  array_reference = create_array(ENV(f), length, element_classname);

  if (array_reference == NULL)
    {
      throw_Exception(ENV(f), OutOfMemoryError, "array allocation failed.");
      return;
    }

  obj_to_object(array_reference, jobj);
#if 0
  GC_addReference((JavaVM*)((HungryJNIEnv*)ENV(f))->_vm, (GC_obj*)jobj);
#endif

  op_stack_push_object (ENV(f), OPSTACK(f), array_reference);
}

OPCODE(multianewarray, 197, 3, -1, 1)
{
  jint *sizes = NULL;
  int i;
  u2 index;
  u1 dimensions;
  japhar_obj array_reference;
  japhar_object *jobj;
  char *array_classname;

  JAVARLOG0(MYLOG, 1, "in op_multianewarray()\n");

  index = get_next_u2(f);

  dimensions = get_next_u1 (f);

  /* get space to store the list of array dimensions */

  sizes = (jint *) malloc (sizeof (u4) * dimensions);
  
  if (sizes == NULL)
    {
      throw_Exception(ENV(f), OutOfMemoryError,
		      "array allocation failed.");
      return;
    }

  /* pop the array sizes from the operand stack */

  for (i=0; i<dimensions; i++)
    op_stack_pop_int (ENV(f), OPSTACK(f), sizes + dimensions - i - 1);

  array_classname = ResolveClassName(ENV(f), METHOD(f)->clazz,
				     get_constant(METHOD(f)->clazz, index));

  array_reference = multi_new_array (ENV(f),
				     sizes,
				     dimensions,
				     createFakeArrayClass(ENV(f),
							  array_classname));

  if (array_reference == NULL)
    {
      throw_Exception(ENV(f), OutOfMemoryError, "array allocation failed.");
      return;
    }

  obj_to_object(array_reference, jobj);

#if 0
  GC_addReference((JavaVM*)((HungryJNIEnv*)ENV(f))->_vm, (GC_obj*)jobj);
#endif
  op_stack_push_object (ENV(f), OPSTACK(f), array_reference);
}

OPCODE(arraylength, 190, 0, 1, 1)
{
  japhar_obj arrayref;
  jint val;

  JAVARLOG0(MYLOG, 1, "in op_arraylength ()\n");

  op_stack_pop_object(ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  val = get_array_length(arrayref);

  JAVARLOG1(MYLOG, 2, "   length=%d\n", val);

  op_stack_push_int (ENV(f), OPSTACK(f), val);
}

OPCODE(iaload, 46, 0, 2, 1)
{
  japhar_obj arrayref;
  jint index;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_iaload ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", "op_iaload");
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException",
		      "op_iaload");
      return;
    }

  body_val = get_array_body(arrayref);

  op_stack_push_int(ENV(f), OPSTACK(f),
		    ((jint*)body_val)[ index ]);
}

OPCODE(laload, 47, 0, 2, 2)
{
  japhar_obj arrayref;
  jint index;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_laload ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  op_stack_push_long(ENV(f), OPSTACK(f),
		     ((jlong*)body_val)[ index ]);
}

OPCODE(faload, 48, 0, 2, 1)
{
  japhar_obj arrayref;
  jint index;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_faload ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  op_stack_push_float(ENV(f), OPSTACK(f),
		      ((jfloat*)body_val)[ index ]);
}

OPCODE(daload, 49, 0, 2, 2)
{
  japhar_obj arrayref;
  jint index;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_daload ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  op_stack_push_double(ENV(f), OPSTACK(f),
		       ((jdouble*)body_val)[ index ]);
}

OPCODE(aaload, 50, 0, 2, 1)
{
  japhar_obj arrayref;
  jint index;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_aaload ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  op_stack_push_object(ENV(f), OPSTACK(f),
		       ((jobject*)body_val)[ index ]);
}

OPCODE(baload, 51, 0, 2, 1)
{
  japhar_obj arrayref;
  jint index;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_baload ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  op_stack_push_byte(ENV(f), OPSTACK(f),
		     ((jbyte*)body_val)[ index ]);
}

OPCODE(caload, 52, 0, 2, 1)
{
  japhar_obj arrayref;
  jint index;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_caload ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  op_stack_push_char(ENV(f), OPSTACK(f),
		     ((jchar*)body_val)[ index ]);
}

OPCODE(saload, 53, 0, 2, 1)
{
  japhar_obj arrayref;
  jint index;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_saload ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  op_stack_push_int(ENV(f), OPSTACK(f),
		    (jint)((jshort*)body_val)[ index ]);
}

OPCODE(iastore, 79, 0, 3, 0)
{
  japhar_obj arrayref;
  jint index;
  jint value;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_iastore ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value);
  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  ((jint*)body_val)[ index ] = value;
}

OPCODE(lastore, 80, 0, 4, 0)
{
  japhar_obj arrayref;
  jint index;
  jlong value;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_lastore ()\n");

  op_stack_pop_long (ENV(f), OPSTACK(f), &value);
  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  ((jlong*)body_val)[ index ] = value;
}

OPCODE(fastore, 81, 0, 3, 0)
{
  japhar_obj arrayref;
  jint index;
  jfloat value;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_fastore ()\n");

  op_stack_pop_float (ENV(f), OPSTACK(f), &value);
  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  ((jfloat*)body_val)[ index ] = value;
}

OPCODE(dastore, 82, 0, 4, 0)
{
  japhar_obj arrayref;
  jint index;
  jdouble value;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_dastore ()\n");

  op_stack_pop_double (ENV(f), OPSTACK(f), &value);
  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  ((jdouble*)body_val)[ index ] = value;
}

OPCODE(aastore, 83, 0, 3, 0)
{
  japhar_obj arrayref;
  jint index;
  jobject value;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_aastore ()\n");

  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&value);
  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  ((jobject*)body_val)[ index ] = value;
}

/*
 * "bastore stores into byte or boolean array", and expects 1)
 * arrayref, 2) index, and 3) value on the operand stack, where both
 * index and value are of type int.
 */
OPCODE(bastore, 84, 0, 3, 0)
{
  japhar_obj arrayref;
  jint index;
  jint value;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_bastore ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value);
  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  ((jbyte*)body_val)[ index ] = (jbyte)value;
}

OPCODE(castore, 85, 0, 3, 0)
{
  japhar_obj arrayref;
  jint index;
  jint value;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_castore ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value);
  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  ((jchar*)body_val)[ index ] = (jchar)value;
}

OPCODE(sastore, 86, 0, 3, 0)
{
  japhar_obj arrayref;
  jint index;
  jint value;
  jint length_val;
  void* body_val;

  JAVARLOG0(MYLOG, 1, "in op_sastore ()\n");

  op_stack_pop_int (ENV(f), OPSTACK(f), &value);
  op_stack_pop_int (ENV(f), OPSTACK(f), &index);
  op_stack_pop_object (ENV(f), OPSTACK(f), (jobject*)&arrayref);

  if (arrayref == 0)
    {
      throw_Exception(ENV(f), "java/lang/NullPointerException", NULL);
      return;
    }

  length_val = get_array_length(arrayref);

  if (index >= length_val)
    {
      throw_Exception(ENV(f), "java/lang/ArrayIndexOutOfBoundsException", NULL);
      return;
    }

  body_val = get_array_body(arrayref);

  ((jshort*)body_val)[ index ] = (jshort)value;
}

OPCODE(monitorenter, 194, 0, 1, 0)
{
  jobject objectref;

  JAVARLOG0(MYLOG, 1, "in op_monitorenter ()\n");

  op_stack_pop_object(ENV(f), OPSTACK(f), &objectref);

  MONITOR_enter(MONITOR_getForObject(objectref));
}

OPCODE(monitorexit, 195, 0, 1, 0)
{
  jobject objectref;

  JAVARLOG0(MYLOG, 1, "in op_monitorexit ()\n");

  op_stack_pop_object(ENV(f), OPSTACK(f), &objectref);

  if ( ! MONITOR_exit(MONITOR_getForObject(objectref)) )
    {
      throw_Exception(ENV(f), "java/lang/IllegalMonitorStateException",
		      "not monitor owner!");
      return;
    }      
}

OPCODE(lookupswitch, 171, -1, 1, 0)
{
  jint address_of_this_instruction = PC(f) - 1 ;
  jint numpairs;
  int padding;
  jint the_offset;
  jboolean found;
  jint i;
  jint key;

  JAVARLOG0(MYLOG, 1, "in op_lookupswitch()\n");

  /* eat up the padding -- the interesting stuff is aligned
     to a 4 byte boundary. */
  padding = 3 - (address_of_this_instruction % 4);

  JAVARLOG1(MYLOG, 2, "  lookupswitch:  data padded with %d 0 bytes\n", padding);
  
  for (i = 0; i < padding; i ++)
    {
      (void)get_next_u1(f);
    }

  op_stack_pop_int(ENV(f), OPSTACK(f), &key);

  /* get the default offset. */
  the_offset = (jint)get_next_u4(f);

  JAVARLOG1(MYLOG, 2, "  lookupswitch:  default offset is %ld\n", the_offset);

  /* get the number of pairs. */
  numpairs = get_next_u4(f);

  JAVARLOG1(MYLOG, 2, "  lookupswitch:  there are %ld pairs\n", numpairs);

  found = JNI_FALSE;
  for (i = 0; i < numpairs; i ++)
    {
      jint match = get_next_u4(f);
      jint offset = get_next_u4(f);

      if (!found && key == match)
	{
	  the_offset = offset;
	  found = JNI_TRUE;
	}
    }

  PC(f) = address_of_this_instruction + the_offset;
}

OPCODE(tableswitch, 170, -1, 1, 0)
{
  jint index;
  jint high, low, default_off;
  jint offset_to_use, i;
  jint address_of_this_instruction = PC(f) - 1 ;
  jint padding;

  JAVARLOG0(MYLOG, 1, "in op_tableswitch()\n");

  /* eat up the padding -- the interesting stuff is aligned
     to a 4 byte boundary. */
  padding = 3 - (address_of_this_instruction % 4);

  JAVARLOG1(MYLOG, 1, "  tableswitch:  data padded with %d 0 bytes\n", padding);

  for (i = 0; i < padding; i ++)
    {
      (void)get_next_u1(f);
    }

  op_stack_pop_int(ENV(f), OPSTACK(f), &index);

  /* get the default offset. */
  default_off = get_next_u4(f);

  JAVARLOG1(MYLOG, 2, "  tableswitch:  default offset is %ld\n", default_off);

  /* get the low index. */
  low = get_next_u4(f);

  JAVARLOG1(MYLOG, 2, "  tableswitch:  low index is %ld\n", low);

  /* get the high index. */
  high = get_next_u4(f);

  JAVARLOG1(MYLOG, 2, "  tableswitch:  high index is %ld\n", high);

  offset_to_use = default_off;

  for (i = 0 ; i < high - low + 1; i ++)
    {
      jint jump_offset = get_next_u4(f);

      /* just consume all the jump_offsets */
      if (index > high || index < low) continue;
      
      if (index - low == i)
	offset_to_use = jump_offset;
    }

  JAVARLOG2(MYLOG, 2, 
	    "  tableswitch:  index = %ld, offset = %ld\n", index, offset_to_use);

  PC(f) = address_of_this_instruction + offset_to_use;
}

OPCODE(athrow, 191, 0, 1, 1)
{
  jobject throwable_ref;
  JNIEnv *env = ENV(f);

  JAVARLOG0(MYLOG, 1, "in interp_athrow()\n");  

    
  /* get the object reference */
  op_stack_pop_object(env, OPSTACK(f), &throwable_ref);

#if fixme
  JAVARLOG1("Exceptions", 1, "throwing exception '%s' from java code\n",
	    getClassName(env, (ClazzFile*)STATIC_DATA(throwable_ref)));
#endif
  (*env)->Throw(env, throwable_ref);
}

OPCODE(notimplemented, 186, 0, 0, 0)
{
  JNIEnv *env = ENV(f);
  
  printf ("Instruction %d not implemented yet :)\n", 
	  CODE(f)[ PC(f)-1 ]);
  
  (*env)->FatalError(env, "Instruction not implemented\n");
}
