/***********************************************************************
 * Bdbj 1.1 (by Jon Cook August 2001)
 *
 * reverse.def 
 * 
 * Reversals for instructions not reversed in the default way.
 * 
 ***********************************************************************/

/* START JJC */

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

        push( 1 ); /* we do have to push and pop separately because of loadstack */
        loadstack( 1 );
	swap_any( local( idx ), stack( 0 ) );
	if( opsobjs ) lvtobjs[ idx ] = *opsobjs;
	marknotobj_int;		  
}

define_insn(LSTORE)
{
	/*
	 * ..., long var <- ...
	 */
	check_pc (0);
	idx = (uint8)getpc(0);
  
        push( 2 );
        loadstack( 2 );
	swap_long( local_long( idx ), stack_long( 0 ) );
	if( opsobjs ) lvtobjs[ idx + 1 ] = lvtobjs[ idx ] = *opsobjs;
	marknotobj2_long;
}

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

 	push( 1 );
	loadstack( 1 );
	swap_any( local_float( idx ), stack( 0 ) );
	if( opsobjs ) lvtobjs[ idx ] = *opsobjs;
	marknotobj_float;
}

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

	push( 2 );
	loadstack( 2 );
	swap_long( local_double( idx ), stack_double( 0 ) ); 
	if( opsobjs ) lvtobjs[ idx + 1 ] = lvtobjs[ idx ] = *opsobjs;
	marknotobj2_double;
}

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

	push( 1 );
	loadstack( 1 );
        swap_any( local( idx ), stack( 0 ) ); 
	if( opsobjs ) lvtobjs[ idx ] = *opsobjs;
	if( stack( 0 )[ 0 ].v.tint <= 0xFFFF )
		marknotobj_int
	else
		markisobj
}

define_insn(ISTORE_0)
define_insn_alias(ISTORE_1)
define_insn_alias(ISTORE_2)
define_insn_alias(ISTORE_3)
{
	/*
	 * ..., val <- ...
	 */
	
	push( 1 );
	loadstack( 1 );
        swap_any(local(getopcode() - ISTORE_0), stack(0));
	if( opsobjs ) lvtobjs[ getopcode() - ISTORE_0 ] = *opsobjs;
	marknotobj_int;
}

define_insn(LSTORE_0)
define_insn_alias(LSTORE_1)
define_insn_alias(LSTORE_2)
define_insn_alias(LSTORE_3)
{
	/*
	 * ..., long val <- ...
	 */
	
	push( 2 );
	loadstack( 2 );
	swap_long(local_long(getopcode() - LSTORE_0), stack_long(0)); 
	if( opsobjs ) lvtobjs[ getopcode() - LSTORE_0 + 1 ] = lvtobjs[ getopcode() - LSTORE_0 ] = *opsobjs;
	marknotobj2_long;
}

define_insn(FSTORE_0)
define_insn_alias(FSTORE_1)
define_insn_alias(FSTORE_2)
define_insn_alias(FSTORE_3)
{
	/*
	 * ..., val <- ...
	 */

	push( 1 );
	loadstack( 1 );
	swap_any(local_float(getopcode() - FSTORE_0), stack(0)); 
	if( opsobjs ) lvtobjs[ getopcode() - FSTORE_0 ] = *opsobjs;
	marknotobj_float;
}

define_insn(DSTORE_0)
define_insn_alias(DSTORE_1)
define_insn_alias(DSTORE_2)
define_insn_alias(DSTORE_3)
{
	/*
	 * ..., double val <- ...
	 */

	push( 2 );
	loadstack( 2 );
	swap_long(local_double(getopcode() - DSTORE_0), stack_double(0)); 
	if( opsobjs ) lvtobjs[ getopcode() - DSTORE_0 + 1 ] = lvtobjs[ getopcode() - DSTORE_0 ] = *opsobjs;
	marknotobj2_double;
}

define_insn(ASTORE_0)
define_insn_alias(ASTORE_1)
define_insn_alias(ASTORE_2)
define_insn_alias(ASTORE_3)
{
	/*
	 * ..., val <- ...
	 */

	push( 1 );
	loadstack( 1 );
	swap_any(local(getopcode() - ASTORE_0), stack(0)); 
	if( opsobjs ) lvtobjs[ getopcode() - ASTORE_0 ] = *opsobjs;
	if( stack( 0 )[ 0 ].v.tint <= 0xFFFF )
		marknotobj_int
	else
		markisobj
}

define_insn(IASTORE)
{
	/*
	 * ..., array ref, index, val -> ...
	 */

	push( 3 );
	loadstack( 3 );
        load_offset_scaled_int( tmp, stack( 2 ), stack( 1 ), object_array_offset );
	store_offset_scaled_int(rstack(2), rstack(1), object_array_offset, rstack(0));
        move_int( stack( 0 ), tmp ); 
}

define_insn(LASTORE)
{
	/*
	 * ..., array ref, index, long val -> ...
	 */

	push( 4 );
	loadstack( 4 );
        load_offset_scaled_long( tmp, stack( 3 ), stack( 2 ), object_array_offset );
	store_offset_scaled_long(stack(3), stack(2), object_array_offset, stack_long(0));
        move_long( stack_long( 0 ), tmp ); 
}

define_insn(FASTORE)
{
	/*
	 * ..., array ref, index, float val -> ...
	 */
	push( 3 );
	loadstack( 3 );       
        load_offset_scaled_float( tmp, stack( 2 ), stack( 1 ), object_array_offset );
	store_offset_scaled_float(stack(2), stack(1), object_array_offset, stack(0));
        move_float( stack( 0 ), tmp ); 
}

define_insn(DASTORE)
{
	/*
	 * ..., array ref, index, double val -> ...
	 */

	push( 4 );
	loadstack( 4 );
        load_offset_scaled_double( tmp, stack( 3 ), stack( 2 ), object_array_offset );
	store_offset_scaled_double(stack(3), stack(2), object_array_offset, stack_double(0));
   	move_double( stack_long( 0 ), tmp ); 
}

define_insn(AASTORE)
{
	/*
	 * ..., array ref, index, val -> ...
	 */
	push( 3 );
	loadstack( 3 );
        load_offset_scaled_ref( tmp, stack( 2 ), stack( 1 ), object_array_offset );
	store_offset_scaled_ref(rstack(2), rstack(1), object_array_offset, rstack(0));
	move_ref( stack( 0 ), tmp ); 
}

define_insn(BASTORE)
{
	/*
	 * ..., array ref, index, byte value  -> ...
	 */
	push( 3 );
	loadstack( 3 );
        load_offset_scaled_byte( tmp, stack( 2 ), stack( 1 ), object_array_offset );
	store_offset_scaled_byte(rstack(2), rstack(1), object_array_offset, rstack(0));
	move_int( stack( 0 ), tmp ); 
}

define_insn(CASTORE)
{
	/*
	 * ..., array ref, index, char value  -> ...
	 */
	push( 3 );
	loadstack( 3 );
        load_offset_scaled_char( tmp, stack( 2 ), stack( 1 ), object_array_offset );
	store_offset_scaled_char(rstack(2), rstack(1), object_array_offset, rstack(0));
	move_int( stack( 0 ), tmp ); 
}

define_insn(SASTORE)
{
	/*
	 * ..., array ref, index, short value  -> ...
	 */
	push( 3 );
	loadstack( 3 );
        load_offset_scaled_short( tmp, stack( 2 ), stack( 1 ), object_array_offset );
	store_offset_scaled_short(rstack(2), rstack(1), object_array_offset, rstack(0));
	move_int( stack( 0 ), tmp ); 
}

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

        check_local_int(idx);

        sub_int_const(local(idx), local(idx), low); /*changed from add to sub*/
}

define_insn(IRETURN)
define_insn_alias(LRETURN)
define_insn_alias(FRETURN)
define_insn_alias(DRETURN)
define_insn_alias(ARETURN)
define_insn_alias(RETURN)
{
  loadlocals;
  loadnandstack;
}

/*
 * 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
	 */
	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)) {
		pop(1);
	}
	else switch (CLASS_PRIM_SIG(FIELD_TYPE(finfo.field))) {
	case 'I': case 'S': case 'B': case 'Z': case 'C': case 'F':
		pop(1);
		break;
	case 'J': case 'D':
		pop(2);
		break;
	default:
		ABORT();
	}
}

define_insn(PUTSTATIC)
{
	/*
	 * ..., value  -> ...
	 */
	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)); */
		push( 1 );
		loadstack( 1 );
                load_addr_ref( tmp, FIELD_ADDRESS( finfo.field ) ); 
		store_addr_ref(FIELD_ADDRESS(finfo.field), stack(0));
		move_ref( stack( 0 ), tmp ); 
	}
	else switch (CLASS_PRIM_SIG(FIELD_TYPE(finfo.field))) {
	case 'I':
		push( 1 );
		loadstack( 1 );
		load_addr_int( tmp, FIELD_ADDRESS( finfo.field ) ); 
		store_addr_int(FIELD_ADDRESS(finfo.field), stack(0));
		move_int( stack( 0 ), tmp ); 
		break;
	case 'S':
		push( 1 );
		loadstack( 1 );
		load_addr_short( tmp, FIELD_ADDRESS( finfo.field ) ); 
		store_addr_short(FIELD_ADDRESS(finfo.field), stack(0));
		move_int( stack( 0 ), tmp ); 
		break;
	case 'B':
	case 'Z':
		push( 1 );
		loadstack( 1 );
		load_addr_byte( tmp, FIELD_ADDRESS( finfo.field ) ); 
		store_addr_byte(FIELD_ADDRESS(finfo.field), stack(0));
		move_int( stack( 0 ), tmp ); 
		break;
	case 'C':
		push( 1 );
		loadstack( 1 );
		load_addr_char( tmp, FIELD_ADDRESS( finfo.field ) ); 
		store_addr_char(FIELD_ADDRESS(finfo.field), stack(0));
		move_int( stack( 0 ), tmp ); 
		break;
	case 'F':
		push( 1 );
		loadstack( 1 );
		load_addr_float( tmp, FIELD_ADDRESS( finfo.field ) ); 
		store_addr_float(FIELD_ADDRESS(finfo.field), stack(0));
		move_float( stack( 0 ), tmp ); 
		break;
	case 'J':
		push( 2 );
		loadstack( 2 );
		load_addr_long( tmp, FIELD_ADDRESS( finfo.field ) ); 
		store_addr_long(FIELD_ADDRESS(finfo.field), stack_long(0));
		move_long( stack_long( 0 ), tmp ); 
		break;
	case 'D':
		push( 2 );
		loadstack( 2 );
		load_addr_double( tmp, FIELD_ADDRESS( finfo.field ) ); 
		store_addr_double(FIELD_ADDRESS(finfo.field), stack_double(0));
		move_double( stack_long( 0 ), tmp ); 
		break;
	default:
		ABORT();
	}
}

define_insn(GETFIELD)
{
	/*
	 * ..., obj-ref -> ..., value
	 */

	/* bug fixed: macros are evil */
	int i = rcbuffi( debug );
	pop( i );
	loadstack( 1 );
}

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)) {
		push( 2 );
		loadstack( 2 );

		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 ) ); 
		store_offset_ref(rstack(1), FIELD_BOFFSET(finfo.field), rstack(0));
		move_ref( stack( 0 ), tmp ); 
	}
	else switch (CLASS_PRIM_SIG(FIELD_TYPE(finfo.field))) {
	case 'I':
		push( 2 );
		loadstack( 2 );

		check_stack_ref(1);
		CHECK_NULL(PUTFIELD, stack(1), 36);
		load_offset_int( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) );
		store_offset_int(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
		move_int( stack( 0 ), tmp ); 
		break;
	case 'S':
		push( 2 );
		loadstack( 2 );

		check_stack_ref(1);
		CHECK_NULL(PUTFIELD, stack(1), 37);
		load_offset_short( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) );

		store_offset_short(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
		move_int( stack( 0 ), tmp ); 
		break;
	case 'B':
	case 'Z':
		push( 2 );
		loadstack( 2 );

		check_stack_ref(1);
		CHECK_NULL(PUTFIELD, stack(1), 40);
		load_offset_byte( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) ); 
		store_offset_byte(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
		move_int( stack( 0 ), tmp ); 
		break;
	case 'C':
		push( 2 );
		loadstack( 2 );

		check_stack_ref(1);
		CHECK_NULL(PUTFIELD, stack(1), 41);
		load_offset_char( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) ); 
		store_offset_char(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
		move_int( stack( 0 ), tmp ); 
		break;
	case 'F':
		push( 2 );
		loadstack( 2 );

		check_stack_ref(1);
		CHECK_NULL(PUTFIELD, stack(1), 42);
		load_offset_float( tmp, stack( 1 ), FIELD_BOFFSET( finfo.field ) ); 
		store_offset_float(stack(1), FIELD_BOFFSET(finfo.field), stack(0));
		move_float( stack( 0 ), tmp ); 
		break;
	case 'J':
		push( 3 );
		loadstack( 3 );

		check_stack_ref(2);
		CHECK_NULL(PUTFIELD, stack(2), 38);
		load_offset_long( tmp, stack( 2 ), FIELD_BOFFSET( finfo.field ) );
		store_offset_long(stack(2), FIELD_BOFFSET(finfo.field), stack_long(0));
		move_long( stack_long( 0 ), tmp ); 
		break;
	case 'D':
		push( 3 );
		loadstack( 3 );

		check_stack_ref(2);
		CHECK_NULL(PUTFIELD, stack(2), 39);
		load_offset_double( tmp, stack( 2 ), FIELD_BOFFSET( finfo.field ) ); 
		store_offset_double(stack(2), FIELD_BOFFSET(finfo.field), stack_double(0));
		move_double( stack_long( 0 ), tmp ); 
		break;
	default:
		ABORT();
	}
}

#define METHOD_POP_RETVAL()      \
do {                             \
switch( method_returntype() ) {  \
   case 'V': break;              \
   case 'L': case '[': case 'I': case 'Z': case 'S': case 'B': case 'C': case 'F': \
       pop( 1 ); break;          \
   case 'J': case 'D':           \
       pop( 2 ); break;          \
   default: ABORT();             \
   }                             \
} while( 0 )

define_insn(INVOKEVIRTUAL)
{
        idx = (uint16)((getpc(0) << 8) | getpc(1));
        get_method_info(idx);
	METHOD_POP_RETVAL();	
	loadnandstack;
}

define_insn(INVOKESPECIAL)
{
        idx = (uint16)((getpc(0) << 8) | getpc(1));
        get_special_method_info(idx);
	METHOD_POP_RETVAL();
	loadnandstack;
}

define_insn(INVOKESTATIC)
{
        idx = (uint16)((getpc(0) << 8) | getpc(1));
        get_method_info(idx);
	METHOD_POP_RETVAL();
	loadnandstack;
}

define_insn(INVOKEINTERFACE)
{
        idx = (uint16)((getpc(0) << 8) | getpc(1));
        get_interface_method_info(idx);
	METHOD_POP_RETVAL();
	loadnandstack;
}

define_insn(ATHROW)
{
	/*
	 * ..., obj -> undefined
	 */
	fprintf( stderr, "Can't reverse ATHROW\n" );
}

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

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

	define_insn(ILOAD)
	{
		/*
		 * ..., -> ..., local variable
		 */
		pop( 1 );
	}

	define_insn(FLOAD)
	{
		/*
		 * ..., -> ..., local variable
		 */
		pop( 1 );
	}
	define_insn(ALOAD)
	{
		/*
		 * ..., -> ..., local variable
		 */
		pop( 1 );
	}
	define_insn(LLOAD)
	{
		/*      
		 * ..., -> ..., long local variable
		 */
		pop( 2 );
	}
	define_insn(DLOAD)
	{
		/*      
		 * ..., -> ..., double local variable
		 */
		pop( 2 );
	}
	define_insn(ISTORE)
	{
		/*      
		 * ..., var -> ...
		 */
		check_pcidx (0);
		idx = (uint16)((getpc(0) << 8) | getpc(1));

		push( 1 );
		loadstack( 1 );
		swap_any( local( idx ), stack( 0 ) ); 
		if( opsobjs ) lvtobjs[ idx ] = *opsobjs;
		marknotobj_int;
	}
	define_insn(FSTORE)
	{
		/*      
		 * ..., var -> ...
		 */
		check_pcidx (0);
		idx = (uint16)((getpc(0) << 8) | getpc(1));
 
		push( 1 );
		loadstack( 1 );
		swap_any( local_float( idx ), stack( 0 ) ); 
		if( opsobjs ) lvtobjs[ idx ] = *opsobjs;
		marknotobj_float;
	}
	define_insn(ASTORE)
	{
		/*
		 * ..., var -> ...
		 */
		check_pcidx (0);
		idx = (uint16)((getpc(0) << 8) | getpc(1));

		push( 1 );
		loadstack( 1 );
		swap_any( local( idx ), stack( 0 ) ); 
		if( opsobjs ) lvtobjs[ idx ] = *opsobjs;
		if( stack( 0 )[ 0 ].v.tint <= 0xFFFF )
			marknotobj_int
		else
			markisobj
	}
	define_insn(LSTORE)
	{
		/*      
		 * ..., long var -> ...
		 */
		check_pcidx (0);
		idx = (uint16)((getpc(0) << 8) | getpc(1));

		push( 2 );
		loadstack( 2 );
		swap_long( local_long( idx ), stack_long( 0 ) ); 
		if( opsobjs ) lvtobjs[ idx + 1 ] = lvtobjs[ idx ] = *opsobjs;
		marknotobj2_long;
	}
	define_insn(DSTORE)
	{
		/*      
		 * ..., var -> ...
		 */
		check_pcidx (0);
		idx = (uint16)((getpc(0) << 8) | getpc(1));

		push( 2 );
		loadstack( 2 );
		swap_long( local_double( idx ), stack_double( 0 ) );
		if( opsobjs ) lvtobjs[ idx + 1 ] = lvtobjs[ idx ] = *opsobjs;
		marknotobj2_double;
	}
	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);

		sub_int_const(local(idx), local(idx), low);

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

define_insn(MULTIANEWARRAY)
{
	/*
	 * ... size1, size2, ... sizen ->  ..., object ref
	 */
	pop( 1 );
	loadnandstack;
}

/* MONITORENTER and MONITOREXIT are mutual inverses */

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

	check_stack_ref(0);

	softcall_monitorenter(rstack(0));

}

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

	check_stack_ref(0);

	softcall_monitorexit(rstack(0));
}

/* END JJC */
