#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "toba.h"

#include "runtime.h"

#ifndef OPTION_JIT

/** Initialize a basic ClassData structure from the data in the toba Class
  * structure at claddr.  This cannot be called without JIT support.
  * @param cdobj raw ClassData instance to be filled in
  * @param clobj existing java.lang.Class that we're reading from
  * Toba hash code: _CC_a8RIy
  */
Void
ClassDataInternal_CC_a8RIy (Object cdobj,
                            Object clobj)
{
   throwInternalError ("Unexpected invocation of toba.classfile.ClassData.ClassDataInternal");
   /*NOTREACHED*/
}

#else /* OPTION_JIT */
#include "toba_classfile_ClassData.h"
#include "toba_classfile_Field.h"
#include "toba_classfile_FieldRef.h"
#include "toba_classfile_ClassRef.h"

/** Given a vt_generic structure and the table slot it holds, create a Field
  * class instance with its variable information. */
static struct in_toba_classfile_Field *
setVTfield (struct vt_generic * vgp, /* Generic variable structure */
            int tslot)          /* Its slot, in instance or class table */
{
   struct in_toba_classfile_Field * fp; /* Field we're creating */

   fp = (struct in_toba_classfile_Field *) new (&cl_toba_classfile_Field.C);
   fp->name = (Object) arraystring (vgp->name_chars, vgp->name_len);
   fp->signature = (Object) arraystring (vgp->sig_chars, vgp->sig_len);
   fp->access = vgp->access;
   fp->tableslot = tslot;
   finishField__c1FeX (fp);
   return fp;
}

/** Given a mt_generic structure and the table slot it holds, create a Field
  * class instance with its method information. */
static struct in_toba_classfile_Field *
setMTfield (struct mt_generic * mgp, /* Generic method structure */
            int tslot)          /* Its slot, in instance or static table */
{
   struct in_toba_classfile_Field * fp; /* Field we're creating */

   fp = (struct in_toba_classfile_Field *) new (&cl_toba_classfile_Field.C);
   fp->name = (Object) arraystring (mgp->name_chars, mgp->name_len);
   fp->signature = (Object) arraystring (mgp->sig_chars, mgp->sig_len);
   fp->access = mgp->access;
   fp->tableslot = tslot;
   finishField__c1FeX (fp);
   return fp;
}

static int
countLocalMethods (struct mt_generic * mgp,
                   int nm)
{
   int nlm;

   nlm = 0;
   while (0 < nm--) {
      if (mgp->localp) {
         ++nlm;
      }
      ++mgp;
   }
   return nlm;
}

static int
countLocalFields (struct vt_generic * vgp,
                  int nm)
{
   int nlm;

   nlm = 0;
   while (0 < nm--) {
      if (vgp->localp) {
         ++nlm;
      }
      ++vgp;
   }
   return nlm;
}


/** Initialize a basic ClassData structure from the data in the toba Class
  * structure at claddr.
  * @param cdobj raw ClassData instance to be filled in
  * @param clobj existing java.lang.Class that we're reading from
  * Toba hash code: _CC_a8RIy
  */
Void
ClassDataInternal_CC_a8RIy (Object cdobj,
                            Object clobj)
{
   struct in_toba_classfile_ClassData * cd;
   struct in_java_lang_Class * jcl;
   struct in_toba_classfile_Field ** fpp;
   struct in_toba_classfile_ClassRef ** crpp;
   Class cl;
   int i;
   struct vt_generic * vgp;
   struct mt_generic * mgp;
   int nelts;

   cd = (struct in_toba_classfile_ClassData *) cdobj;
   if (NULL == cd) {
      throwInternalError ("Invalid ClassData object in native ClassData constructor");
   }
   jcl = (struct in_java_lang_Class *) clobj;
   cl = find_class (clobj);
   if (NULL == cl) {
      throwInternalError ("Invalid Class object in native ClassData constructor");
   }
   if (NULL != cl->cldata) {
      throwInternalError ("Redundant ClassData structure in C class");
   }
   /* Make sure we know where things are in this structure */
   if (TOBA_CLASSSTRUCT_VERSION != cl->clsformat) {
      throwInternalError ("ClassData: Internal class structure version mismatch (expect %d, got %d)",
                          TOBA_CLASSSTRUCT_VERSION, cl->clsformat);
   }


   /* Assign whatever fields we can. */
   cd->name = cl->name;
   cd->access = cl->access;
   cd->javaClass = clobj;
   if (1 < cl->nsupers) {
      cd->superclass = cl->supers[1];
      cd->supername = cl->supers[1]->name;
   } else {
      cd->superclass = NULL;
      cd->supername = NULL;
   }
   /* Create fields: instance vars followed by class vars.  We only store the
    * ones local to this class; superclass ones are assigned elsewhere. */
   nelts = countLocalFields (cl->ivars, cl->nivars) 
      + countLocalFields (cl->cvars, cl->ncvars);

   cd->fields = anewarray (&cl_toba_classfile_Field.C, nelts);
   fpp = (struct in_toba_classfile_Field **) ((struct aarray *) cd->fields)->data;
   vgp = cl->ivars;
   for (i = 0; i < cl->nivars; i++) {
      if (0 == vgp->name_chars) {
         throwInternalError ("Invalid instance variable structure");
      }
      if (0 != vgp->addr) {
         throwInternalError ("Unexpected addr in %s/%s instance var vt_generic",
                             cstring (cl->name),
                             cstring (arraystring (vgp->name_chars, vgp->name_len)));
      }
      if (vgp->localp) {
         *fpp = setVTfield (vgp, i);
         ++fpp;
      }
      ++vgp;
   }
   vgp = cl->cvars;
   for (i = 0; i < cl->ncvars; i++) {
      if (0 == vgp->name_chars) {
         throwInternalError ("Invalid instance variable structure");
      }
      if (0 != vgp->offset) {
         throwInternalError ("Unexpected offset in %s/%s class var vt_generic",
                             cstring (cl->name), 
                             cstring (arraystring (vgp->name_chars, vgp->name_len)));
      }
      if (vgp->localp) {
         *fpp = setVTfield (vgp, i);
         ++fpp;
      }
      ++vgp;
   }
   assert ((fpp - (struct in_toba_classfile_Field **) ((struct aarray *) cd->fields)->data) == nelts);

   /* Build the method table.  We need three: imtable contains all instance
    * methods; smtable has all static methods; and methods has all methods
    * defined within this class, which we don't have stored separately. */
   nelts = countLocalMethods (((struct cl_generic *) cl)->M, cl->nimethods)
      + countLocalMethods (cl->smethods, cl->nsmethods);

   /* Now we know how many methods are defined in this class.  Allocate an
    * array of field pointers for them, then walk the instance and static
    * tables again to create the field structures. */
   cd->methods = anewarray (&cl_toba_classfile_Field.C, nelts);
   fpp = (struct in_toba_classfile_Field **) ((struct aarray *) cd->methods)->data;
   mgp = ((struct cl_generic *) cl)->M;
   for (i = 0; i < cl->nimethods; i++) {
      if (mgp->localp) {
         *fpp = setMTfield (mgp, i);
         ++fpp;
      }
      ++mgp;
   }
   mgp = cl->smethods;
   for (i = 0; i < cl->nsmethods; i++) {
      if (mgp->localp) {
         *fpp = setMTfield (mgp, i);
         ++fpp;
      }
      ++mgp;
   }
   assert ((fpp - (struct in_toba_classfile_Field **) ((struct aarray *) cd->methods)->data) == nelts);
   
   /* Interfaces: ndinters is the number of interfaces in this class; ninters
    * is the total number, including superclass interfaces.  We want the first
    * ndinters entries in the interface table; those are ours. */
   cd->interfaces = anewarray (&cl_toba_classfile_ClassRef.C, cl->ndinters);
   crpp = (struct in_toba_classfile_ClassRef **) ((struct aarray *) cd->interfaces)->data;
   for (i = 0; i < cl->ndinters; i++) {
      Class icl = cl->inters [i]; /* Interface class pointer */
      
      *crpp = (struct in_toba_classfile_ClassRef *) new (&cl_toba_classfile_ClassRef.C);
      (*crpp)->name = intern_string (icl->name);
      (*crpp)->refClass = &icl->classclass;
      ++crpp;
   }
   cd->myRef = cl->clref;

   /* Archive this so we don't need to build it again */
   cl->cldata = cd;
   
}

#endif /* OPTION_JIT */
