/*  toba.h -- general definitions  */

#ifndef _toba_h_
#define _toba_h_

#ifdef SCOUT
/* If we're running in scout, surely we're using scout threads */
#define SCOUT_THREADS (1)
#endif /* SCOUT */

#if defined(SCOUT) && defined(IN_LIBRUNTIME)
/* Scout needs some basic definitions, including its own Class structure,
 * before we go around redefining things. */
#include <scout/path.h>
#include <scout/fsfattr.h>
#endif /* SCOUT && IN_LIBRUNTIME */

#include <setjmp.h>	/* used by generated code for try/catch */

#ifdef SCOUT
/* Scout doesn't define the convenience names that we generate.  Tsk. */
#define setjmp _setjmp
#define longjmp _longjmp

/*
 * BIIIIG hack, since both Scout and Toba define Class
 */
#define Class JavaClass
#endif /* SCOUT */

/* Java types are capitalized. Sometimes they match C types. */
typedef void			Void;
typedef unsigned char		Boolean;
typedef unsigned short		Char;
typedef signed char		Byte;
typedef signed short		Short;
typedef signed int		Int;
typedef unsigned int		UInt;	/* only for >>>; not Java primitive */

#if (0x40000000lu << 2) == 0		/* if long is just 32 bits wide */
    typedef signed long long	Long;
    typedef unsigned long long	ULong;	/* only for >>>; not Java primitive */
#else
    typedef signed long		Long;
    typedef unsigned long	ULong;	/* only for >>>; not Java primitive */
#endif

typedef float			Float;
typedef double			Double;
typedef void *			Object;
typedef struct class *    	Class;
typedef struct monitor *        Monitor;


/* generic object instance struct */
struct in_generic { Class class; Monitor monitor; };

/* interface method hash entry */
struct ihash { int n; void *mt; }; 

/* class struct header */
/* note: any changes here also require mods to code generator and structs.c.
 * We use TOBA_CLASSSTRUCT_VERSION in the structures to detect that this
 * has occurred. */
#define TOBA_CLASSSTRUCT_VERSION (43)
struct class {			
    /* Many things assume needinit is first; don't move it. */
    int needinit;		/* does class need to be initialized? */
    int flags;			/* isInterface, isArray, isPrimitive, etc. */
    Object name;		/* class name (a String) */
    struct in_generic classclass; /* instance of class Class */
    int instsize;		/* size of an instance or element */
    int nimethods;		/* number of instance methods */
    int nsmethods;		/* number of static methods */
    int nivars;                 /* number of instance variables */
    int ncvars;			/* number of static   variables */
    int nsupers;		/* number of superclasses incl self */
    const Class *supers;	/* list of superclasses incl self */
    int ninters;		/* number of interfaces implemented */
    int ndinters;		/* number of directly implemented interfaces */
    const Class *inters;	/* list of interfaces */
    int hashmask;		/* hash value mask for indexing hash table */
    const struct ihash *htable;	/* interface hash table */
    int nothers;		/* number of other known classes */
    const Class *others;	/* list of other known classes */
    Class arrayclass;		/* array of this class, when needed */
    Class elemclass;		/* class of contained elements, if array */
    const Char *strpool;	/* string pool */
    const void **strlist;	/* list of strings */
    void (*initializer)();	/* class initializer (<clinit>), if any */
    void (*constructor)();	/* no-arg instance initializer */
    void (*finalizer)();	/* instance finalizer function */
    void (*sfiinitializer)();   /* initializer of static-final fields */
    Object classloader;         /* The loader responsible for this class */
    int clsformat;              /* Class format tag */
    int access;                 /* Class access flags */
    struct in_toba_classfile_ClassData * cldata; /* The classfile of the class */
    struct in_toba_classfile_ClassRef * clref; /* The canonical reference to the class */
    struct vt_generic *ivars;   /* table of instance variable info */
    struct vt_generic *cvars;   /* table of class variable info */
    struct mt_generic *smethods;/* table of static method info */
};

/* generic variable, method, and class structs */
struct vt_generic {
   int offset;                  /* If nonzero, is offset of field from instance start */
   void *addr;                  /* If nonnull, is address of class variable */
   const Char * name_chars;     /* Name of the field */
   int name_len;                /* Length of field name */
   const Char * sig_chars;      /* Signature of the field */
   int sig_len;                 /* Length of field signature */
   int localp;                  /* Nonzero iff field is declared in this class (not superclass) */
   int access;                  /* Access flags for field */
};

/* Encode in method tables where the thing came from (native Toba code,
 * compiled JIT code, etc.).  Calling conventions may differ depending on
 * the source for the caller and callee.  Yes, "InvokeType" is misleading.
 * The values here should be matched in toba.classfile.MethodCode, and
 * put into toba.classfile.Names as reserved words. */
typedef enum TobaMethodInvokeType {
   TMIT_undefined = 0,          /* Unknown method */
   TMIT_native_code = 1,        /* Native code invocation */
   TMIT_interpreter = 2,        /* Call interpreter to execute */
   TMIT_uninstalled_jit = 3,    /* Need to compile this */
   TMIT_abstract = 4,           /* Unreachable abstract method */
   TMIT_LAST_ENUM
} TobaMethodInvokeType;

/* NOTE: If you modify this structure, you must modify the code in
 * toba.translator.HFile that emits anonymous structures with prototyped
 * function entry points. */
struct mt_generic {
   TobaMethodInvokeType itype;  /* Type/source of method */
   Void (*f) ();                /* Function entry point */
   const Char * name_chars;     /* Name of the method */
   int name_len;                /* Length of method name */
   const Char * sig_chars;      /* Signature of the method */
   int sig_len;                 /* Length of method signature */
   int localp;                  /* Nonzero iff method is declared in this class (not superclass) */
   int access;                  /* Access flags for method */
};

struct cl_generic { struct class C; struct mt_generic M[1];};

/* array instance structs */
struct carray
    { Class class; Monitor monitor; int length; int pad; Char   data[1]; };
struct barray 
    { Class class; Monitor monitor; int length; int pad; Byte   data[1]; };
struct sarray 
    { Class class; Monitor monitor; int length; int pad; Short  data[1]; };
struct iarray 
    { Class class; Monitor monitor; int length; int pad; Int    data[1]; };
struct larray 
    { Class class; Monitor monitor; int length; int pad; Long   data[1]; };
struct farray 
    { Class class; Monitor monitor; int length; int pad; Float  data[1]; };
struct darray 
    { Class class; Monitor monitor; int length; int pad; Double data[1]; };
struct aarray 
    { Class class; Monitor monitor; int length; int pad; Object data[1]; };

/* character array macro */
#define CARRAY(len) struct { void *c; Monitor m; int n; int pad; Char d[len]; }

/* primitive "classes" */
extern struct class cl_boolean;
extern struct class cl_char;
extern struct class cl_byte;
extern struct class cl_short;
extern struct class cl_int;
extern struct class cl_long;
extern struct class cl_float;
extern struct class cl_double;

/* array-of-primitive classes */
extern struct cl_java_lang_Object acl_boolean;
extern struct cl_java_lang_Object acl_char;
extern struct cl_java_lang_Object acl_byte;
extern struct cl_java_lang_Object acl_short;
extern struct cl_java_lang_Object acl_int;
extern struct cl_java_lang_Object acl_long;
extern struct cl_java_lang_Object acl_float;
extern struct cl_java_lang_Object acl_double;

/* These are assigned to the translated C file name and line of where
 * a null-pointer-exception is thrown, since those are generated by jumping
 * to a block at the end of the function, and there's no other way to tell
 * where they came from.  Definitions are in helpers.c. */
extern char * npe_file_name;    /* Name of file throwing NPE */
extern int npe_file_line;       /* Line where threw NPE */

#ifdef NDEBUG
#define SetNPESource()  ((void)0)
#else /* NDEBUG */
#define SetNPESource()  { npe_file_name = __FILE__; npe_file_line = __LINE__; }
#endif /* NDEBUG */

/* exception handling table */
/* WARNING: Modifying this requires modifying toba.jit.CodeBlock where
 * the exception handler table is created. */
struct handler {
    Class class;		/* exception */
    unsigned short start_pc;
    unsigned short end_pc;
    unsigned int handler_pc;    /* JIT requires this to be at least 32bit */
};

/* thread-specific info */
struct mythread {
    void *jmpbuf;		/* current setjmp buffer */
    Object exception;		/* current exception */
    jmp_buf default_jmpbuf;	/* initial jump buffer */
    int exception_count;	/* number of uncaught exceptions */
};



/* structs for floating point constants */
union fconst { UInt b;  Float v;  };	/* float */
union dconst { ULong b; Double v; };	/* double */


/* If we have a non-preemptive threads package, we need to voluntarily
 * yield at regular intervals---e.g., every back jump.  Name the function
 * that executes that; use 0 if we don't have to worry about it:
 *  YIELD_FN : An integral value naming a function to call to yield, 0 if none
 *  YIELD : A macro that expands to C code that invokes YIELD_FN, if non-zero */
#ifndef YIELD
#ifdef SCOUT_THREADS
extern volatile unsigned long timeNow;
extern unsigned long timeSliceEnd;

/* This is the only one we know of so far.  Don't call Scout's threadYield
 * directly, because that's a macro, and we need a function pointer to
 * make the jit happy.  sthread_preemption_point checks for pending
 * exceptions and signals before yielding. */
#define YIELD_FN sthread_preemption_point
#define YIELD \
{ \
    if (timeNow >= timeSliceEnd) \
        YIELD_FN(); \
}
#else /* SCOUT_THREADS */
/* Don't do anything. */
#define YIELD_FN (0)
#define YIELD ((void)0)
#endif /* SCOUT_THREADS */
#endif /* YIELD */

/* macros for control flow changes */
#define GOTO(oldpc,newlbl) goto newlbl
#define GOBACK(oldpc,newlbl) do { YIELD; goto newlbl; } while (0)
#define RETTO(oldpc,lblnum) do { tgt = lblnum; goto TOP; } while (0)

/* Generic function prologue that may change depending on the machine */
#define PROLOGUE YIELD

/* helper functions called by generated code */

/* start main program */
int start(Class c, Void main(Object o), int argc, char *argv[]);

/*
 *  handle class initialization: synchronize, check circularity,
 *     init superclass, call myclass.<clinit>, catch exceptions, etc.
 */
void initclass(Class myclass);

/* get current thread's per-thread structure */
struct mythread *mythread();

/* search exception table to find handler */
int findhandler(struct handler *table, int tsize, Object exception, int oldpc);

/* find interface method for "invokeinterface" */
struct mt_generic * findinterface(Object o, int signaturehash);

/* if not a native method, figure out what to do with it */
void invoker_dispatch (struct mt_generic * mtp);

/* synchronization */
/* Don't redefine these to be (void)0 if threads aren't supported; the
 * JIT doesn't know that, and expects to be able to find function entry
 * points for them.
 * Besides, these things have side effects (storing in *resp) that don't
 * get done if you do that. */
void monitorenter(Object o, struct mythread *thr, int val, volatile int *resp);
void monitorexit(Object o, struct mythread *thr, int val, volatile int *resp);
void enterclass(Class c, struct mythread *thr, int val, volatile int *resp);
void exitclass(Class c, struct mythread *thr, int val, volatile int *resp);

/* throw exception */
void athrow(Object o);
void throwArrayIndexOutOfBoundsException(Object o, int index);
void throwArrayStoreException(char *mesg);
void throwClassCastException(Object o);
void throwDivisionByZeroException(void);
void throwInstantiationException(Object o);
void throwNoSuchMethodError(Object o);
void throwNullPointerException(char *mesg);

/* create object, also creating class structs for arrays as needed */
Object new(Class c);
Object anewarray(Class c, int nelem);
Object vmnewarray(Class c, int arraydim, int ndim, /*d1,d2,*/...);
Object mnewarray(Class c, int arraydim, int ndim, int *dims);

/* check class relationships */
int instanceof(Object o, Class c, int ndim);

/* floating point math operations */
Int dtoi(Double d);
Long dtol(Double d);
Double remdr(Double x, Double y);

#endif /* _toba_h_ */
