/* $Id: jit_JITCodeGen.c,v 1.6 1998/02/25 18:05:22 pab Exp $
 * Created: Thu Jun 19 12:10:27 1997
 * Peter A. Bigot (pab@baskerville.CS.Arizona.EDU)
 *
 * Description: 
 * 
 */

/* ------------- */
/* Include Files */

#include <stdio.h>              /* Standard input/output routines */
#include <stdlib.h>             /* Standard library routines */
#include <assert.h>             /* Debugging assertion macro */
#include <stdarg.h>
#include <stddef.h>
#include <alloca.h>
#include <setjmp.h>

#include "toba.h"

#include "java_lang_Class.h"
#include "java_lang_Object.h"
#include "toba_runtime_CodeGen.h"
#include "toba_classfile_Method.h"
#include "toba_classfile_MethodRef.h"
#include "java_lang_String.h"

#include "classfile_ClassData.h"
#include "runtime.h"
#include "md.h"
#include "sthreads.h"

/* ------------------------------- */
/* Constant and Macro Declarations */

/* ----------------- */
/* Type Declarations */

/* -------------------- */
/* Variable Definitions */

/* -------------------- */
/* Function Definitions */

static void *longToAddress(Long l)
{
    return (void *)(long)l;
}
static Long addressToLong(void *v)
{
    return (Long)(long)v;
}

/* Given a reference to an array instance, return the length of the
 * array. */
static int
getarraylen (struct carray * ap)
{
   return ap->length;
}

static Long
longmul (Long a,
         Long b)
{
   return (a * b);
}

static Long
longdiv (Long a,
         Long b)
{
   if (0 == b) {
      throwDivisionByZeroException ();
   }
   return (a / b);
}

static Long
longrem (Long a,
         Long b)
{
   if (0 == b) {
      throwDivisionByZeroException ();
   }
   return (a % b);
}

static Long
longshift (Long a,
           int sv,
           int stype)
{
   Long res = 0;
   
   /* Truncate to no more than 63-bit shift.  Yes, this means shifts of
    * positive multiples of 64 become no-ops; that's what the book wants. */
   sv &= 0x3F;
   /* I'm really not convinced this is right, in terms of sign extension
    * in the right shifts. */
   switch (stype) {
      case 121: /* LSHL */
         res = (a << sv);
         break;
      case 123: /* LSHR */
         res = (a >> sv);
         break;
      case 125: /* LUSHR */
         res = (((ULong) a) >> sv);
         break;
      default:
         assert (0);
   }
   return res;
}

static int
longcmp (Long a,
         Long b)
{
   if (a < b) {
      return -1;
   }
   return (a > b);
}

static float
long2f (Long a)
{
   return (float) a;
}

static double
long2d (Long a)
{
   return (double) a;
}

static int
intdiv (int a,
         int b)
{
   if (0 == b) {
      throwDivisionByZeroException ();
   }
   return (a / b);
}

static int
intrem (int a,
         int b)
{
   if (0 == b) {
      throwDivisionByZeroException ();
   }
   return (a % b);
}

static void *
geteltoffs (struct barray * ap,
            int esz,
            int idx)
{
   if (NULL == ap) {
      throwNullPointerException (0);
   }
   if ((0 > idx) || (ap->length <= idx)) {
      throwArrayIndexOutOfBoundsException (ap, idx);
   }
   return (void *) ((idx * esz) + (char *) ap->data);
}

#ifdef SCOUT
/* TODO -- Scout doesn't have puts? */
static int
puts (char * s)
{
   printf ("%s\n", s);
   return 0;
}
#endif /* SCOUT */

/* These are generated by genFID */
#define FID_new (1)
#define FID_anewarray (2)
#define FID_initclass (3)
#define FID_vmnewarray (4)
#define FID_getarraylen (5)
#define FID_geteltoffs (6)
#define FID_intdiv (7)
#define FID_intrem (8)
#define FID_longdiv (9)
#define FID_longrem (10)
#define FID_longmul (11)
#define FID_remdr (12)
#define FID_dtoi (13)
#define FID_dtol (14)
#define FID_longshift (15)
#define FID_long2f (16)
#define FID_long2d (17)
#define FID_longcmp (18)
#define FID_puts (19)
#define FID_throwNPE (20)
#define FID_mythread (21)
#define FID_sthread_got_exc (22)
#define FID_setjmp (23)
#define FID_longjmp (24)
#define FID_findhandler (25)
#define FID_athrow (26)
#define FID_monitorenter (27)
#define FID_monitorexit (28)
#define FID_throwCCE (29)
#define FID_instanceof (30)
#define FID_findinterface (31)
#define FID_throwNASE (32)
#define FID_enterclass (33)
#define FID_exitclass (34)
#define FID_backjumpfn (35)
#define FID_timeNow (36)
#define FID_timeSliceEnd (37)

Long
getFuncAddr_i_m3SYh (int fid)
{
   switch (fid) {
      case FID_new:
         return addressToLong (new);
      case FID_anewarray:
         return addressToLong (anewarray);
      case FID_initclass:
         return addressToLong (initclass);
      case FID_vmnewarray:
         return addressToLong (vmnewarray);
      case FID_getarraylen:
         return addressToLong (getarraylen);
      case FID_geteltoffs:
         return addressToLong (geteltoffs);
      case FID_intdiv:
         return addressToLong (intdiv);
      case FID_intrem:
         return addressToLong (intrem);
      case FID_longdiv:
         return addressToLong (longdiv);
      case FID_longrem:
         return addressToLong (longrem);
      case FID_longmul:
         return addressToLong (longmul);
      case FID_remdr:
         return addressToLong (remdr);
      case FID_dtoi:
         return addressToLong (dtoi);
      case FID_dtol:
         return addressToLong (dtol);
      case FID_longshift:
         return addressToLong (longshift);
      case FID_long2f:
         return addressToLong (long2f);
      case FID_long2d:
         return addressToLong (long2d);
      case FID_longcmp:
         return addressToLong (longcmp);
      case FID_puts:
         return addressToLong (puts);
      case FID_throwNPE:
         return addressToLong (throwNullPointerException);
      case FID_mythread:
         return addressToLong (mythread);
      case FID_sthread_got_exc:
         return addressToLong (sthread_got_exception);
      case FID_setjmp:
         return addressToLong (SETJMP_FNAME);
      case FID_longjmp:
         return addressToLong (longjmp);
      case FID_findhandler:
         return addressToLong (findhandler);
      case FID_athrow:
         return addressToLong (athrow);
      case FID_monitorenter:
         return addressToLong (monitorenter);
      case FID_monitorexit:
         return addressToLong (monitorexit);
      case FID_throwCCE:
         return addressToLong (throwClassCastException);
      case FID_instanceof:
         return addressToLong (instanceof);
      case FID_findinterface:
         return addressToLong (findinterface);
      case FID_throwNASE:
         return addressToLong (throwNegativeArraySizeException);
      case FID_enterclass:
         return addressToLong (enterclass);
      case FID_exitclass:
         return addressToLong (exitclass);
      case FID_backjumpfn:
         return addressToLong (YIELD_FN);
      case FID_timeNow:
         return addressToLong (&timeNow);
      case FID_timeSliceEnd:
         return addressToLong (&timeSliceEnd);
      default:
         assert (0);
   }
   return 0L;
}

/* Typecodes for primitive types, as used by newarray */
#define T_BOOLEAN         4
#define T_CHAR            5
#define T_FLOAT           6
#define T_DOUBLE          7
#define T_BYTE            8
#define T_SHORT           9
#define T_INT            10
#define T_LONG           11

Long
getNPprimclass_ii_QHITB (int tid,
                        int getArray)
{
   Class clt;

   clt = NULL;
   switch (tid) {
      case T_BOOLEAN:
         clt = getArray ? &acl_boolean.C : &cl_boolean;
         break;
      case T_CHAR:
         clt = getArray ? &acl_char.C : &cl_char;
         break;
      case T_FLOAT:
         clt = getArray ? &acl_float.C : &cl_float;
         break;
      case T_DOUBLE:
         clt = getArray ? &acl_double.C : &cl_double;
         break;
      case T_BYTE:
         clt = getArray ? &acl_byte.C : &cl_byte;
         break;
      case T_SHORT:
         clt = getArray ? &acl_short.C : &cl_short;
         break;
      case T_INT:
         clt = getArray ? &acl_int.C : &cl_int;
         break;
      case T_LONG:
         clt = getArray ? &acl_long.C : &cl_long;
         break;
      default:
         assert (0);
   }
   return addressToLong (clt);
}

#define OID_mythread_jmpbuf (1)
#define OID_mythread_exception (2)
#define OID_class_flags (3)
#define OID_class_nsupers (4)
#define OID_class_supers (5)
#define OID_mtgeneric_f (6)
int
getFieldOffset_i_N1XnB (int oid)
{
   switch (oid) {
      case OID_mythread_jmpbuf:
         return offsetof (struct mythread, jmpbuf);
      case OID_mythread_exception:
         return offsetof (struct mythread, exception);
      case OID_class_flags:
         return offsetof (struct class, flags);
      case OID_class_nsupers:
         return offsetof (struct class, nsupers);
      case OID_class_supers:
         return offsetof (struct class, supers);
      case OID_mtgeneric_f:
         return offsetof (struct mt_generic, f);
      default:
         assert (0);
   }
   return -1;
}

Long
allocUncolMemory_i_qYFS3 (int sz)
{
   return addressToLong (allocateuncol (sz));
}

/* Allocate an array for sizes of objects store in AR to support exception
 * handling. */
Object
getOverheadSize__Ds3WL (void)
{
   struct iarray * ia;

   ia = anewarray (&cl_int, 6);
   ia->data[0] = sizeof (jmp_buf); /* jmp_buf newbuf */
   ia->data[1] = sizeof (void *); /* void * oldbuf */
   ia->data[2] = sizeof (int);  /* volatile int pc */
   ia->data[3] = sizeof (struct mythread *); /* struct mythread * tdata */
   ia->data[4] = sizeof (Object); /* Object instref */
   ia->data[5] = sizeof (char *); /* char * method.cname */
   return ia;
}

Long
getStringAddress_S_Z43yi (Object st)
{
   char * cs;                   /* C version of string */
   char * ucs;                  /* C version of string in uncollected memory */

   /* Use the standard conversion routine to get a copy of the string
    * in its normal format, then allocate enough uncollected memory
    * to hold it, and copy it there.  Has to be uncollected, because the
    * address exists only in code-space unless the method is active. */
   cs = cstring (st);
   ucs = allocateuncol (strlen (cs) + 1);
   strcpy (ucs, cs);
   return addressToLong (ucs);
}

/* Given an array of integers, make a copy of the data portion and return
 * the address of the copy. */
Long
intArrToLong_ai_JlUaZ (Object aar)
{
   struct iarray * ia = aar;
   int * ra;

   ra = allocate (4 * ia->length);
   memcpy (ra, ia->data, 4 * ia->length);
   return addressToLong (ra);
}

Long
getNativeString_S_2chg8 (Object s)
{
   return addressToLong (cstring (s));
}

Long
getArrayDataAddress_O_TCJx0 (Object aar)
{
   struct aarray * aa = aar;
   return addressToLong (aa->data);
}

void
startMain_laS_r1YxG (Long addr,
                     Object aargs)
{
   void (*fn)() = longToAddress (addr);
   fn (aargs);
}

