/*
** ObjectiveAmiga: objc.library interface structures and definitions
** See GNU:lib/libobjam/ReadMe for details
*/


#ifndef LIBRARIES_OBJC_H
#define LIBRARIES_OBJC_H

#ifdef __cplusplus
extern "C" {
#endif


/****************************************************************** includes */

#include <stddef.h>

#ifndef EXEC_TYPES_H
#include <exec/types.h>
#endif

#ifndef EXEC_LIBRARIES_H
#include <exec/libraries.h>
#endif


/************************************************************ boolean values */

#define YES   TRUE
#define NO    FALSE


/************************************************** definition of a selector */

/* Selectors themselves are not unique,
   but the sel_id is a unique identifier */

typedef const struct objc_selector 
{
  void *sel_id;
  const char *sel_types;
} *SEL;

inline static BOOL sel_eq (SEL s1, SEL s2)
{
  if (s1 == 0 || s2 == 0) return s1 == s2;
  else return s1->sel_id == s2->sel_id;
}


/********************************************* typedef for untyped instances */

typedef struct objc_object
{
  struct objc_class*  class_pointer;
} *id;


/************************************************* definition of method type */

/* When retrieving the implementation of a method,
   this is the type of the pointer returned */
typedef id (*IMP)(id, SEL, ...); 


/********************************************************* more simple types */

#define nil (id)0         /* id of Nil instance */
#define Nil (OCClass*)0   /* id of Nil class */

typedef char *STR;        /* String alias */


/*********************************************************** class structure */

/*
** The compiler generates one of these structures for each class.  
** 
** This structure is the definition for classes. 
** 
** This structure is generated by the compiler in the executable and used by
** the run-time during normal messaging operations.  Therefore some members
** change type. The compiler generates "char* const" and places a string in
** the following member variables:  super_class. 
*/

typedef struct objc_class MetaClass;
typedef struct objc_class OCClass; /* 'Class' is used by BOOPSI... */
#ifndef	INTUITION_CLASSES_H
typedef OCClass Class; /* ...but we can use it too ;) */
#endif

struct objc_class {     
  MetaClass*          class_pointer;    /* Pointer to the class's meta class */
  struct objc_class*  super_class;      /* Pointer to the super class. NULL for class Object */
  const char*         name;             /* Name of the class */
  long                version;          /* Unknown */
  unsigned long       info;             /* Bit mask.  See class masks defined above */
  long                instance_size;    /* Size in bytes of the class. The sum of the
					   class definition and all super class definitions */
  struct objc_ivar_list *ivars;         /* Pointer to a structure that describes the instance 
                                           variables in the class definition.  NULL indicates
                                           no instance variables.  Does not include super class
                                           variables */
  struct objc_method_list *methods;     /* Linked list of instance methods defined for the class */
  struct sarray *dtable;                /* Pointer to instance method dispatch table */
  struct objc_class *subclass_list;     /* Subclasses */
  struct objc_class *sibling_class;
  struct objc_protocol_list *protocols; /* Protocols conformed to */
};

#ifndef __OBJC__
typedef struct objc_protocol {
  struct objc_class* class_pointer;
  char *protocol_name;
  struct objc_protocol_list *protocol_list;
  struct objc_method_description_list *instance_methods, *class_methods; 
} Protocol; 

#else /* __OBJC__ */
@class Protocol;
#endif 

typedef void* retval_t;		/* return value */
typedef void(*apply_t)(void);	/* function pointer */
typedef union {
  char *arg_ptr;
  char arg_regs[sizeof (char*)];
} *arglist_t;			/* argument frame */


/************************************************************** method stuff */

/* For functions which return Method_t */
#define METHOD_NULL	(Method_t)0

/*
** Method descriptor returned by introspective Object methods.
** This is really just the first part of the more complete objc_method
** structure defined below and used internally by the runtime.
*/
struct objc_method_description
{
    SEL name;			/* this is a selector, not a string */
    char *types;		/* type encoding */
};

/* Filer types used to describe Ivars and Methods.  */
#define _C_ID       '@'
#define _C_CLASS    '#'
#define _C_SEL      ':'
#define _C_CHR      'c'
#define _C_UCHR     'C'
#define _C_SHT      's'
#define _C_USHT     'S'
#define _C_INT      'i'
#define _C_UINT     'I'
#define _C_LNG      'l'
#define _C_ULNG     'L'
#define _C_FLT      'f'
#define _C_DBL      'd'
#define _C_BFLD     'b'
#define _C_VOID     'v'
#define _C_UNDEF    '?'
#define _C_PTR      '^'
#define _C_CHARPTR  '*'
#define _C_ATOM     '%'
#define _C_ARY_B    '['
#define _C_ARY_E    ']'
#define _C_UNION_B  '('
#define _C_UNION_E  ')'
#define _C_STRUCT_B '{'
#define _C_STRUCT_E '}'


/********************************************* compiler-generated structures */

/*
** Whereas a Module (defined further down) is the root (typically) of a file,
** a Symtab is the root of the class and category definitions within the
** module.  
** 
** A Symtab contains a variable length array of pointers to classes and
** categories  defined in the module. 
*/
typedef struct objc_symtab {
  unsigned long sel_ref_cnt;                     /* Unknown. */
  SEL       *refs;                              /* Unknown. */
  unsigned short cls_def_cnt;                   /* Number of classes compiled
                                                  (defined) in the module. */
  unsigned short cat_def_cnt;                   /* Number of categories 
                                                  compiled (defined) in the 
                                                  module. */
  void      *defs[1];                           /* Variable array of pointers.
                                                  cls_def_cnt of type Class* 
                                                  followed by cat_def_cnt of
                                                  type Category_t. */
} Symtab,   *Symtab_t;

/*
** The compiler generates one of these structures for each module that
** composes the executable (eg main.m).  
** 
** This data structure is the root of the definition tree for the module.  
** 
** A collect program runs between ld stages and creates a ObjC ctor array. 
** That array holds a pointer to each module structure of the executable. 
*/
typedef struct objc_module {
  unsigned long version;                        /* Compiler revision. */
  unsigned long size;                           /* sizeof(Module). */
  const char* name;                             /* Name of the file where the 
                                                  module was generated.   The 
                                                  name includes the path. */
  Symtab_t    symtab;                           /* Pointer to the Symtab of
                                                  the module.  The Symtab
                                                  holds an array of pointers to 
                                                  the classes and categories 
                                                  defined in the module. */
} Module, *Module_t;

/*
** The compiler generates one of these structures for a class that has
** instance variables defined in its specification. 
*/
typedef struct objc_ivar* Ivar_t;
typedef struct objc_ivar_list {
  int   ivar_count;                             /* Number of structures (Ivar) 
                                                  contained in the list.  One
                                                  structure per instance 
                                                  variable defined in the
                                                  class. */
  struct objc_ivar {
    const char* ivar_name;                      /* Name of the instance
                                                  variable as entered in the
                                                  class definition. */
    const char* ivar_type;                      /* Description of the Ivar's
                                                  type.  Useful for 
                                                  debuggers. */
    int         ivar_offset;                    /* Byte offset from the base 
                                                  address of the instance 
                                                  structure to the variable. */

  } ivar_list[1];                               /* Variable length 
                                                  structure. */
} IvarList, *IvarList_t;

/*
** The compiler generates one (or more) of these structures for a class that
** has methods defined in its specification. 
** 
** The implementation of a class can be broken into separate pieces in a file
** and categories can break them across modules. To handle this problem is a
** singly linked list of methods. 
*/
typedef struct objc_method Method;
typedef Method* Method_t;
typedef struct objc_method_list {
  struct objc_method_list*  method_next;      /* This variable is used to link 
                                                a method list to another.  It 
                                                is a singly linked list. */
  int             method_count;               /* Number of methods defined in 
                                                this structure. */
  struct objc_method {
    SEL         method_name;                  /* This variable is the method's 
                                                name.  It is a char*. 
                                                  The unique integer passed to 
                                                objc_msg_send is a char* too.  
                                                It is compared against 
                                                method_name using strcmp. */
    const char* method_types;                 /* Description of the method's
                                                parameter list.  Useful for
                                                debuggers. */
    IMP         method_imp;                   /* Address of the method in the 
                                                executable. */
  } method_list[1];                           /* Variable length 
                                                structure. */
} MethodList, *MethodList_t;

struct objc_protocol_list {
  struct objc_protocol_list *next;
  int count;
  Protocol *list[1];
};


/****************************************************** introspection macros */

/*
** This is used to assure consistent access to the info field of 
** classes
*/
#ifndef HOST_BITS_PER_LONG
#define HOST_BITS_PER_LONG  (sizeof(long)*8)
#endif 

#define __CLS_INFO(cls) ((cls)->info)
#define __CLS_ISINFO(cls, mask) ((__CLS_INFO(cls)&mask)==mask)
#define __CLS_SETINFO(cls, mask) (__CLS_INFO(cls) |= mask)

/* The structure is of type MetaClass* */
#define _CLS_META 0x2L
#define CLS_ISMETA(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_META))


/* The structure is of type Class* */
#define _CLS_CLASS 0x1L
#define CLS_ISCLASS(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_CLASS))

/*
** The class is initialized within the runtime.  This means that 
** it has had correct super and sublinks assigned
*/
#define _CLS_RESOLV 0x8L
#define CLS_ISRESOLV(cls) __CLS_ISINFO(cls, _CLS_RESOLV)
#define CLS_SETRESOLV(cls) __CLS_SETINFO(cls, _CLS_RESOLV)

/*
** The class has been send a +initialize message or a such is not 
** defined for this class
*/
#define _CLS_INITIALIZED 0x04L
#define CLS_ISINITIALIZED(cls) __CLS_ISINFO(cls, _CLS_INITIALIZED)
#define CLS_SETINITIALIZED(cls) __CLS_SETINFO(cls, _CLS_INITIALIZED)

/*
** The class number of this class.  This must be the same for both the 
** class and it's meta class object
*/
#define CLS_GETNUMBER(cls) (__CLS_INFO(cls) >> (HOST_BITS_PER_LONG/2))
#define CLS_SETNUMBER(cls, num) \
  ({ (cls)->info <<= (HOST_BITS_PER_LONG/2); \
     (cls)->info >>= (HOST_BITS_PER_LONG/2); \
     __CLS_SETINFO(cls, (((unsigned long)num) << (HOST_BITS_PER_LONG/2))); })


/***************************************************** more compiler structs */

/*
** The compiler generates one of these structures for each category.  A class
** may have many categories and contain both instance and factory methods.  
*/
typedef struct objc_category {
  const char*   category_name;                /* Name of the category.  Name
                                                contained in the () of the
                                                category definition. */
  const char*   class_name;                   /* Name of the class to which
                                                the category belongs. */
  MethodList_t  instance_methods;             /* Linked list of instance
                                                methods defined in the 
                                                category. NULL indicates no
                                                instance methods defined. */
  MethodList_t  class_methods;                /* Linked list of factory 
                                                methods defined in the
                                                category.  NULL indicates no
                                                class methods defined. */
  struct objc_protocol_list *protocols;	      /* List of Protocols 
					         conformed to */
} Category, *Category_t;

/*
** Structure used when a message is send to a class's super class.  The
** compiler generates one of these structures and passes it to
** objc_msg_super.
*/
typedef struct objc_super {
  id      self;                           /* Id of the object sending
                                             the message. */
  OCClass* class;                         /* Object's super class. */
} Super, *Super_t;

IMP objc_msg_lookup_super(Super_t super, SEL sel);

retval_t objc_msg_sendv(id, SEL, arglist_t);


/********************************************************* encoding of types */

#define _C_CONST    'r'
#define _C_IN       'n'
#define _C_INOUT    'N'
#define _C_OUT      'o'
#define _C_BYCOPY   'O'
#define _C_ONEWAY   'V'

#define _F_CONST    0x01
#define _F_IN       0x01
#define _F_OUT      0x02
#define _F_INOUT    0x03
#define _F_BYCOPY   0x04
#define _F_ONEWAY   0x08


/************************************************************** library base */

#define OBJCNAME "objc-5-2-3.library"
#define OBJCVERSION 0

struct ObjcBase
{
  struct Library lb_LibNode;
};


/********************************************************* memory management */

typedef void NXZone; /* No introspection allowed */

#define vm_page_size  4096            /* The standard page size of an MC68040 MMU */
#define NX_NOZONE     ((NXZone *)0)   /* No zone */

/* Redefine standard memory functions */
#define malloc(size) NXZoneMalloc(NXDefaultMallocZone(),size)
#define calloc(num,size) NXZoneCalloc(NXDefaultMallocZone(),num,size)
#define realloc(block,size) NXZoneRealloc(NXDefaultMallocZone(),block,size)
#define free(block) NXZoneFree(NXZoneFromPtr(block),block)

/* NX memory functions with integrated typecasting */
#define NX_MALLOC(VAR,TYPE,NUM) ((VAR)=(TYPE*)malloc((unsigned)(NUM)*sizeof(TYPE)))
#define NX_REALLOC(VAR,TYPE,NUM) ((VAR)=(TYPE*)realloc((VAR),(unsigned)(NUM)*sizeof(TYPE)))
#define NX_FREE(PTR) free((PTR));


/************************************************************* sparse arrays */

#define OBJC_SPARSE2		/* 2-level sparse array */
/* #define OBJC_SPARSE3 */      /* 3-level sparse array */

#ifdef OBJC_SPARSE2
extern const char* __objc_sparse2_id;
#endif

#ifdef OBJC_SPARSE3
extern const char* __objc_sparse3_id;
#endif


extern int nbuckets;		/* for stats */
extern int nindices;
extern int narrays;
extern int idxsize;


/* An unsigned integer of same size as a pointer */
#define SIZET_BITS (sizeof(size_t)*8)

#if defined(sparc) || defined(OBJC_SPARSE2)
#define PRECOMPUTE_SELECTORS
#endif

#ifdef OBJC_SPARSE3

/* Buckets are 8 words each */
#define BUCKET_BITS 3
#define BUCKET_SIZE (1<<BUCKET_BITS)
#define BUCKET_MASK (BUCKET_SIZE-1)

/* Indices are 16 words each */
#define INDEX_BITS 4
#define INDEX_SIZE (1<<INDEX_BITS)
#define INDEX_MASK (INDEX_SIZE-1)

#define INDEX_CAPACITY (BUCKET_SIZE*INDEX_SIZE)

#else /* OBJC_SPARSE2 */

/* Buckets are 32 words each */
#define BUCKET_BITS 5
#define BUCKET_SIZE (1<<BUCKET_BITS)
#define BUCKET_MASK (BUCKET_SIZE-1)

#endif /* OBJC_SPARSE2 */

typedef size_t sidx;

#ifdef PRECOMPUTE_SELECTORS

struct soffset {
#ifdef OBJC_SPARSE3
  unsigned int unused : SIZET_BITS/4;
  unsigned int eoffset : SIZET_BITS/4;
  unsigned int boffset : SIZET_BITS/4;
  unsigned int ioffset : SIZET_BITS/4;
#else /* OBJC_SPARSE2 */
#ifdef sparc
  unsigned int boffset : (SIZET_BITS - 2) - BUCKET_BITS;
  unsigned int eoffset : BUCKET_BITS;
  unsigned int unused  : 2;
#else
  unsigned int boffset : SIZET_BITS/2;
  unsigned int eoffset : SIZET_BITS/2;
#endif
#endif /* OBJC_SPARSE2 */
};

union sofftype {
  struct soffset off;
  sidx idx;
};

#endif /* not PRECOMPUTE_SELECTORS */

struct sbucket {
  void* elems[BUCKET_SIZE];	/* elements stored in array */
  short version;			/* used for copy-on-write */
};

#ifdef OBJC_SPARSE3

struct sindex {
  struct sbucket* buckets[INDEX_SIZE];
  short version;
};

#endif /* OBJC_SPARSE3 */

struct sarray {
#ifdef OBJC_SPARSE3
  struct sindex** indices;
  struct sindex* empty_index;
#else /* OBJC_SPARSE2 */
  struct sbucket** buckets;
#endif  /* OBJC_SPARSE2 */
  struct sbucket* empty_bucket;
  short version;
  short ref_count;
  struct sarray* is_copy_of;
  int capacity;
};


#ifdef PRECOMPUTE_SELECTORS
/* Transform soffset values to ints and vica verca */
static inline unsigned int
soffset_decode(sidx index)
{
  union sofftype x;
  x.idx = index;
#ifdef OBJC_SPARSE3
  return x.off.eoffset
    + (x.off.boffset*BUCKET_SIZE)
      + (x.off.ioffset*INDEX_CAPACITY);
#else /* OBJC_SPARSE2 */
  return x.off.eoffset + (x.off.boffset*BUCKET_SIZE);
#endif /* OBJC_SPARSE2 */
}

static inline sidx
soffset_encode(size_t offset)
{
  union sofftype x;
  x.off.eoffset = offset%BUCKET_SIZE;
#ifdef OBJC_SPARSE3
  x.off.boffset = (offset/BUCKET_SIZE)%INDEX_SIZE;
  x.off.ioffset = offset/INDEX_CAPACITY;
#else /* OBJC_SPARSE2 */
  x.off.boffset = offset/BUCKET_SIZE;
#endif
  return (sidx)x.idx;
}

#else /* not PRECOMPUTE_SELECTORS */

static inline size_t
soffset_decode(sidx index)
{
  return index;
}

static inline sidx
soffset_encode(size_t offset)
{
  return offset;
}
#endif /* not PRECOMPUTE_SELECTORS */

/* Get element from the Sparse array `array' at offset `index' */

static inline void* sarray_get(struct sarray* array, sidx index)
{
#ifdef PRECOMPUTE_SELECTORS
  union sofftype x;
  x.idx = index;
#ifdef OBJC_SPARSE3
  return 
    array->
      indices[x.off.ioffset]->
	buckets[x.off.boffset]->
	  elems[x.off.eoffset];
#else /* OBJC_SPARSE2 */
  return array->buckets[x.off.boffset]->elems[x.off.eoffset];
#endif /* OBJC_SPARSE2 */
#else /* not PRECOMPUTE_SELECTORS */
#ifdef OBJC_SPARSE3
  return array->
    indices[index/INDEX_CAPACITY]->
      buckets[(index/BUCKET_SIZE)%INDEX_SIZE]->
	elems[index%BUCKET_SIZE];
#else /* OBJC_SPARSE2 */
  return array->buckets[index/BUCKET_SIZE]->elems[index%BUCKET_SIZE];
#endif /* not OBJC_SPARSE3 */
#endif /* not PRECOMPUTE_SELECTORS */
}

static inline void* sarray_get_safe(struct sarray* array, sidx index)
{
  if(soffset_decode(index) < array->capacity)
    return sarray_get(array, index);
  else
    return (array->empty_bucket->elems[0]);
}


/************************************************************ atom emulation */

typedef const char *NXAtom; /* A unique string */


/*************************************************** private data structures */

struct __objclib_init_data
{
  void *globaldata;
  void (*abort)(void);
};


/******************************************************************* the end */

#ifdef __cplusplus
}
#endif

#endif	/* LIBRARIES_OBJC_H */
