#ifndef _INTERPRETER_DEFS_
#define _INTERPRETER_DEFS_

#include "util.h"
#include "yesno.h"
/**
 * OVM Interpreter (c) 2001-2002 S3 Lab, Purdue University
 *
 * This header contains some function declarations and macros
 * needed to compile the C source code generated by the
 * interpreter generator.
 *
 * @file interpreter_defs.h
 * @author Krzysztof Palacz
 * @author James Liang
 */

#include "jtypes.h"
#include "frame.h"
#include "types.h"
#include "eventmanager.h"
#include "jvm_constants/throwables.h"

#define AFMT "0x%08X"
/* this should always be set to 'yes', I don't know why it is
   even an option (CG) */
#if defined(OVM_PPC)
#define CONVERT_ENDIAN NO
#else
#define CONVERT_ENDIAN YES
#endif
/** Note that _blueprint_ above is a dependency on the object header format. **/

#define INCPC(i) (pc)+=(i)
#define GETPC() (pc)
#define SETPC(i) (pc) = (i)

#define DEREF(pointer) (*(pointer))
/*
#define DEREF(pointer) (checkPointer((byte *)pointer) ? *(pointer) : *(0))
*/

#define PUSHFRAME(codeFragment) createAndPushFrame \
(current_context,&local_vars,&stack_top, &pc)


#if CONVERT_ENDIAN
#define ntohll(n) ((((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32))
#else
#define ntohll(n) (n)
#endif

#if CONVERT_ENDIAN
#define htonll(n) ((((unsigned long long)htonl(n)) << 32) + htonl(n >> 32))
#else
#define htonll(n) (n)
#endif

jdouble dmod(jdouble, jdouble);

#define INSTR_BREAKPOINT 0xCA

#define INVOKE_SYSTEM   0xe5

#include "jvm_constants/invoke_system_arguments.h"
#include "jvm_constants/word_ops.h"
#include "jvm_constants/dereference_ops.h"

#define ISTREAM_GET_UBYTE_AT(i) (*((unsigned char *)(pc+i)))
#define ISTREAM_GET_SBYTE_AT(i) (*((signed char *)(pc+i)))
#define ISTREAM_GET_SINT_ADDRESS_AT(i)  ((signed int *)(pc+i))

float ntohf(float f);
double ntohd(double d);

#if CONVERT_ENDIAN
#define ISTREAM_GET_SSHORT_AT(i) get_stream_signed_short(pc, i)
#define ISTREAM_GET_USHORT_AT(i) ntohs(*((unsigned short *)(pc+i)))
#define ISTREAM_GET_SINT_AT(i) get_stream_signed_int(pc, i) 
#define ISTREAM_GET_LONG_AT(i) ntohll(*((long long*)(pc+i)))
#define ISTREAM_GET_FLOAT_AT(i) ntohf(*((float*)(pc+i)))
#define ISTREAM_GET_DOUBLE_AT(i) ntohd(*((double*)(pc+i)))
#else
#define ISTREAM_GET_SSHORT_AT(i) (*((signed short *)(pc+i)))
#define ISTREAM_GET_USHORT_AT(i) (*((unsigned short *)(pc+i)))
#define ISTREAM_GET_SINT_AT(i) (*(ISTREAM_GET_SINT_ADDRESS_AT(i)))
#define ISTREAM_GET_LONG_AT(i) (*(long long*)(pc+i))
#define ISTREAM_GET_FLOAT_AT(i) (*(float*)(pc+i))
#define ISTREAM_GET_DOUBLE_AT(i) (*(double*)(pc+i))
#endif /* CONVERT_ENDIAN */

#define ISTREAM_SET_UBYTE_AT(i,val) {(*((unsigned char*)(pc+i)))=val;}

#define PAD4(i) ((((int)i) % 4) > 0 ? 4 - (((int)i) % 4) : 0)

/* #define PAD4(i) (((i) + 0x3) & ~0x3) */

#define POLLCHECK() \
    EVENT_POLLCHECK()

/* this is the usual event manager hook */
#if EXECUTE_POLLING_HOOK == YES
#define EVENT_POLLCHECK() {						\
  if (eventPollcheck()) {                                               \
    if ( 0 && current_context->processing_stack_overflow == YES)       	\
       printf("ACTIVE POLLCHECK DURING STACK OVERFLOW PROCESSING\n");   \
    PUSH_R((struct java_lang_Object *)csaTHIS);				\
    UNCHECKED_INVOKE_CSA(pollingEventHook, 1);				\
  }									\
}
#else
#define EVENT_POLLCHECK()
#endif

#if DEBUGGING
#define DEBUG_OPCODE() debug_opcode(current_context, pc, local_vars, stack_top)
#else 
#define DEBUG_OPCODE()
#endif

#define NEXT_INSTRUCTION_WITH_POLL_CHECK \
 do { POLLCHECK(); DEBUG_OPCODE(); } while(0); goto *instruction_dispatch[*pc];
#define NEXT_INSTRUCTION DEBUG_OPCODE(); goto *instruction_dispatch[*pc];
#define DO_WIDE DEBUG_OPCODE(); goto *instruction_dispatch[256 + *(++pc)]; 

#define INVOKE(obj, f, bp, paramCount, adjustment) {			\
  current_context->current_frame->pc_adjustment = (adjustment);		\
  if ( (MIN_FREE_FRAMES > create_frame(CONTEXT_CACHE_INOUT(),		\
				       (ByteCode*)(f),			\
				       (Blueprint*)bp,			\
				       (paramCount))) &&		\
       (current_context->processing_stack_overflow == NO) ) {		\
    if(0)printf("GENERATING STACK OVERFLOW\n");                              \
    current_context->processing_stack_overflow = YES;			\
    POPFRAME();								\
    PUSH_R((jref)csaTHIS);						\
    PUSH_P(STACK_OVERFLOW_ERROR);					\
    PUSH_P(0);								\
    UNCHECKED_INVOKE_CSA(generateThrowable, 3);				\
    NEXT_INSTRUCTION;           					\
    ASSERT(0, "not reached");						\
  } else {								\
    if (f == (ByteCode*)csavtbl->Java_ovm_core_execution_CoreServicesAccess_processThrowable) {  /* ATHROW */\
        current_context->processing_stack_overflow = YES;		\
        if(0)printf("ATHROW marking overflow processing\n");                 \
    }                                                                   \
    if (((ByteCode*)(f))->isSynchronized_) {				\
      CALL_MONITORENTER(obj);						\
     }									\
    NEXT_INSTRUCTION;					\
  }									\
}

#define CALL_MONITORENTER(lock) {					\
 PUSH_R((struct java_lang_Object *)csaTHIS);				\
 PUSH_R((jref)(lock));							\
 UNCHECKED_INVOKE_CSA(monitorEnter, 2);					\
}

#define CALL_MONITOREXIT(lock) {					\
 PUSH_R((struct java_lang_Object *)csaTHIS);				\
 PUSH_R((jref)(lock));							\
 UNCHECKED_INVOKE_CSA(monitorExit, 2);					\
}



jlong get_constant_wide(NativeContext* ctx, int index);

signed short get_stream_signed_short(byte* pc, int offset);

signed int get_stream_signed_int(byte* pc, int offset);

Blueprint* get_current_blueprint(NativeContext* ctx);

jref get_constant(NativeContext* ctx, int index);

jref get_constant_bp_resolved_instance_methodref(NativeContext* ctx, int index);

jref get_constant_shst_resolved_static_methodref(NativeContext* ctx, int index);

jref get_constant_shst_resolved_static_fieldref(NativeContext* ctx, int index);

#define GET_CONSTANT_BP_RESOLVED_INSTANCE_METHODREF(index) \
    get_constant_bp_resolved_instance_methodref(current_context, index)

#define GET_CONSTANT_SHST_RESOLVED_STATIC_METHODREF(index) \
    get_constant_shst_resolved_static_methodref(current_context, index)

#define GET_CONSTANT_SHST_RESOLVED_STATIC_FIELDREF(index) \
    get_constant_shst_resolved_static_fieldref(current_context, index)

jbyte get_constant_tag(NativeContext* ctx, int index);

inline Blueprint* get_linkset_entry(NativeContext* ctx, int index);


#define UNCHECKED_INVOKE_CSA(methname__, args)			 	 \
{									 \
  create_frame(CONTEXT_CACHE_INOUT(),					 \
	       (ByteCode*)csavtbl->Java_ovm_core_execution_CoreServicesAccess_##methname__, \
	       HEADER_BLUEPRINT(csaTHIS),				 \
	       (args));						 	 \
}


#define INVOKE_CSA(methname__, args, adjustment)			   \
{									   \
  INVOKE(csaTHIS,							   \
	 (ByteCode*)csavtbl->Java_ovm_core_execution_CoreServicesAccess_##methname__, \
	 HEADER_BLUEPRINT(csaTHIS),					   \
	 (args), (adjustment));						   \
}

#endif
