sima/autoconf/
sima/hosts/i386/
sima/mudlib/
sima/mudlib/kernel/
sima/mudlib/obj/
sima/mudlib/sys/
sima/synhash/mips/
#ifndef ALLOC_H
#define ALLOC_H

#include "port.h"

#define AL_PREV_FREE	0x80
#define AL_MALLOC	0x40
#define AL_NOREF	0x20

#define T_STRING	 0
#define T_LSTRING	 1
#define SV_IS_UNSHARED_STRING(sv) \
	((*(int16*)((sv).p - 1) & C2I16(0xfe, 0xff) == C2I16(T_STRING, 1))
#define SV_IS_2REF_STRING(sv) \
	((*(int16*)((sv).p - 1) & C2I16(0xfe, 0xff)) == C2I16(T_STRING, 2))
#define T_GSTRING	 2
#define T_GLSTRING	 3
#define T_ISTRING	 4
#define T_ILSTRING	 5
#define T_MAPPING	 6
#define T_SPACE 	 7
#define T_ARRAY		 8
#define T_LARRAY	 9
#define T_OBJECT	10
#define T_DESTRUCTED	11
#define SV_STRONG_EQUALITY(type) ( (type) <= T_DESTRUCTED )
#define T_CLOSURE	12
#define T_QUOTED	13	/* symbols and quoted arrays */
#define T_FLOAT 	14
#define T_REGEXP	16
#define T_TERM		17
#define T_LONG		18
#define T_STRUCT	19
#define T_LVALUE	20	/* lvalue created by pass by reference */
#define T_RAW_LVALUE	21	/* range lvalues or char lvalues from pbr */
#define IS_ALLOCED_LVALUE(sv) ( ((sv).p[-1] & T_MASK & ~1) == T_LVALUE )
#define T_CHAR_LVALUE	22	/* a fresh char lvalue */
#define T_CBR_CHAR_LVALUE 23
#define IS_LVALUE(sv) ( ((sv).p[-1] & T_MASK & ~3) == T_LVALUE )
#define T_INVALID	22
#define T_INTERNAL	22	/* internal types with a subtype member where
				 * real svalues have the minor ref count.    */
#define T_VARARGS	24	/* could be expended if varargs functions get
				 * extra return code.			     */
#define T_CONDENSED_MAP	29	/* svalue vectors with a 24 bit size field.
				 * The type is only seen by the garbage
				 * collector. 				     */
#define T_SMALLFREE	30
#define T_LARGEFREE	31

#define T_MASK		31

/*
 * T_SMALLFREE has a size byte in the second and last-but-two byte. These
 * are the same adresses in case of a T_SMALLFREE block of total size 4.
 * T_LARGEFREE has a 32 bit size in the second and last-but one quadbyte,
 * and contains a struct free_block that is part of the global free_tree;
 * the size field of its struct free_block is actually the one in the
 * second quadbyte. The last-but-two byte is zeroed to distingiush from
 * T_SMALLFREE.
 */

#define IT_X_OBJ	 0 /* bits 0 and 1 may be ORed on top for flags */
#define IT_X_UID	 4 /* bits 0 and 1 need be zero */
#define IT_X_ARRAY	 5
#define IT_X_MAP	 6 /* bit 0 may be ORed on top as flag */
#define IT_X_HMAP	IT_X_MAP + 1
#define IT_IDENTIFIER	 8
#define IT_PROGRAM	 9
#define IT_NAMETABLE	10 /* used for program->function_name, up to 128 KB */
#define IT_GENERIC	11 /* internal data structures up to 64 KB */
#define IT_X_ALLOCED	12
#define IT_HEAPEND      13

#define M_X_DIRTY 1
#define M_X_FLAGS(m) ((m).x.p[-3])

#define ALLOC_USER   0
#define ALLOC_MASTER 1
#define ALLOC_SYSTEM 2

typedef union svalue {
    p_int i;
    p_uint u;
    union svalue *lvalue;
    uint8 *p;
    struct generic_svalue *generic;
} svalue __attribute__ ((transparent_union));

struct generic_svalue { int8 ref; };

struct array {
    uint8 type, ref;
    uint16 len;
    union {
	struct uid *uid;
	struct array_x *x;
	struct varargs_x *var;
	uint8 *p;
    } x;
    svalue member[1];
};

#define MAX_SMALL_ARRAY 0xffff

/* T_INTERNAL, IT_X_ARRAY, 2 byte padding */
struct array_x {
    struct uid *uid; /* must be first */
    p_int len;
};

/* T_INTERNAL, IT_X_MAP, major ref */
struct map_x {
    struct uid *uid;
};

/* T_INTERNAL, IT_X_HMAP, major ref */
struct hmap_x {
    struct uid *uid;
    p_int mask;
    p_int used;
    p_int condensed_deleted;
    p_int ref;		/* for lvalue locking */
    struct map_chain *deleted;
    svalue next_dirty;
    struct map_chain *chains[1];
};

#define MAP_HAS_X(m) ((m)->x.p[-sizeof(char *)+1] != IT_X_UID)
#define MAP_X_TYPE(m) ((m)->x.p[-sizeof(char *)+1])
#define MAPX_TYPE(x) (((uint8 *)(x))[-sizeof(char *)+1])
#define MAP_REF(m) ((m)->x.p16[-1])
#define MAPX_REF(x) (((uint16*)(x))[-1])

extern p_int empty_cmap[];
#define EMPTY_CMAP ((svalue *)&empty_cmap[1])

struct mapping {
    uint8 type, ref;
    uint16 num_values;
    union {
	struct uid *uid;
	struct map_x *x;
	struct hmap_x *hash;
	uint8 *p;
	uint16 *p16;
    } x;
    svalue *condensed; /* 24 bit size in front of the svalues */
};

#define CMAP_SIZE(cm) HI24(((p_int *)(cm))[-1])
#define CMAP_HEADER(size) COMBINE8_24(T_CONDENSED_MAP, size)

struct map_chain {
    struct map_chain *next;
    svalue key;
    svalue data[1]; /* data == &key+1 is used in some places */
};

#define MAP_CHAIN_SIZE(n) offsetof(struct map_chain, data[(n)])

struct short_string {
    uint8 type, ref;
    uint8 majref, len;
    struct searchstr *next;
    char contents[1]; /* allows to patch a terminating 0 */
};

/*
 * If we want to make wholesale array assignments on varargs arrays affect
 * parameters passed by reference, we can redefine the array member to be an
 * lvalue. E.g.: t(varags a) { a = ({1}); } t2() { int b; t(&b); return b; }
 * will return 0 now. With an lvalue for array, it would be 1.
 * The allocated size is often larger than needed, because allocation is done
 * as soon as the first lvalue is found, without counting first.
 */
struct s_varargs {
    uint8 type, ref;
    uint8 padding[2];
    p_int alloced_size;
    svalue array;
    struct varargs_lv_field {
	p_int index;
	svalue lvalue;
    } lvalues[0];
};

struct efun_closure {
    uint8 type, ref;
    int16 closure_type;
    svalue ob;
};

struct lfun_closure {
    uint8 type, ref;
    int16 closure_type;
    svalue ob;
    uint16 major_ref;
    uint16 index;
};

struct alien_closure {
    uint8 type, ref;
    int16 closure_type;
    svalue ob; /* object */
    uint16 major_ref;
    uint16 index;
    svalue alien; /* object */
};

struct lambda_closure {
    uint8 type, ref;
    int16 closure_type;
    svalue ob;
    uint16 shared_start;
    uint8 num_shared, num_arg, num_local, code[5];
    uint32 big_size; /* only used for big closures */
    svalue big_shared_start[1];
};

/* The num_shared holds the number of items in the shared table.
 * If it overflows, this byte is 255, and the 255th item in the table holds
 * the actual number.
 * If the code is too large for shared_start to point after it, an F_XLBRANCH
 * is put at the start (after an optional F_VARARGS), followed by
 * alignment padding, a 32 bit total_size field and the shared table.
 */


struct bound_closure {
    uint8 type, ref;
    int16 closure_type;
    struct object *ob;
    struct lambda_closure *lambda;
};

union closure {
    struct efun_closure efun, g; /* g == generic */
    struct lfun_closure lfun, var;
    struct alien_closure alien;
    struct lambda_closure lambda;
    struct bound_closure bound;
};

struct lvalue {
    uint8 type, ref, lvalue_type, pad;
    svalue *lvalue;
    svalue parent;
    svalue index1, index2;
};

#define VEC_SIZE(a) ( (a)->type & 1 ? (a)->x.x->len : (a)->len )

#define ALLOC(type, ref, size) alloc(C2PI(type,ref,0,0), size)
#define ALLOC_TTS(type, subtype, short, size) \
	alloc(COMBINE8_8_16(type, subtype, short), size)

#define MAX_SMALL_STRING 255
#define SMALL_STRING_OVERHEAD (sizeof(char*)*2)
#define LARGE_STRING_OVERHEAD (sizeof(char*)*3)
#define ALLOC_STRING(len) \
  ALLOC(T_STRING, 1, \
    (len) + SMALL_STRING_OVERHEAD + sizeof (char*) - 1 & -sizeof(char *))
#define ALLOC_LSTRING(len) \
  ALLOC(T_LSTRING, 1, \
    (len) + LARGE_STRING_OVERHEAD + sizeof (char*) - 1 & -sizeof(char *))

#define SV_TYPE(sv) ((sv).p[-1] & ~(AL_PREV_FREE|AL_NOREF|AL_MALLOC))
#define SV_TYPE_LOC(sv) ((sv).p[-1])
#define SV_GEN_TYPE(sv) ((sv).p[-1] & ~(AL_PREV_FREE|AL_NOREF|AL_MALLOC|1))
#define SV_REF(sv) ((sv).generic->ref)
#define SV_STRREF(sv) ((sv).p[1])
#define SV_STRLEN(sv) ((sv).p[2])
#define SV_STRNXT(sv) (*(struct searchstr **)(void *)((sv).p+3))
#define SV_STRING(sv) ((sv).p+7)
#define SV_LSTRREF(sv) (*(unsigned short *)(void *)((sv).p+1))
#define SV_LSTRLEN(sv) (*(int32 *)(void *)((sv).p+7))
#define SV_LSTRNXT(sv) (*(struct searchlstr **)(void *)((sv).p+3))
#define SV_LSTRING(sv) ((sv).p+11)
#define SV_ISTRING(sv) (*(svalue*)(uint8 **)&SV_STRNXT(sv))
#define SV_ILSTRING(sv) (*(svalue*)(uint8 **)&SV_LSTRNXT(sv))
#define SV_GENERIC_ISTRING(sv) SV_ISTRING(sv)
#define SV_STRING_IS_LONG(sv) ((sv).p[-1] & 1)
#define SV_ANYSTRLEN(sv) (SV_STRING_IS_LONG(sv)?SV_LSTRLEN(sv):SV_STRLEN(sv))
#define SV_OBJECTP(sv) ((struct object *)(void *)&(sv).p[-1])
#define SV_OBJECT(sv) (*(struct object *)(void *)&(sv).p[-1])
#define SV_ARRAY(sv) (*(struct array *)(void *)&(sv).p[-1])
#define SV_MAPPING(sv) (*(struct mapping *)(void *)&(sv).p[-1])
#define SV_CLOSURE(sv) (*(union closure *)(void *)&(sv).p[-1])
#define SV_VARARGS(sv) (*(struct s_varargs *)(void *)&(sv).p[-1])
#define SV_FLOAT(sv) (*(double *)(void *)((sv).p+3))
#define SV_LONG(sv) (*(long *)(void *)((sv).p+3))
#define SV_ARRAY_LEN(sv) (SV_ARRAY(sv).len)
#define SV_LARRAY_LEN(sv) (SV_ARRAY(sv).x.x->len)
#define SV_LARRAY_REF(sv) (SV_ARRAY(sv).len)
#define SV_GENLEN(sv) (*(uint16*)(void *)((sv).p+1))
#define GEN_ALLOCED_LEN(p) (*(uint16 *)((char *)p - sizeof(char *) + 2))
#define SV_GENBULK(sv) ((sv).p+3)
#define SV_QUOTES(sv) (*(unsigned short *)(void *)((sv).p+1))
#define SV_QUOTED(sv) (*(svalue *)(void *)((sv).p-1+sizeof(char *)))
#define SV_KEY(sv) ((p_int *)(void *)((sv).p-1))
#define SV_LVALUE(sv) (*(struct lvalue *)(void *)&(sv).p[-1])
#define SV_LVALUE_INDEX(sv)  (SV_LVALUE(sv).index1)
#define SV_LVALUE_INDEX1(sv) (SV_LVALUE(sv).index1)
#define SV_LVALUE_INDEX2(sv) (SV_LVALUE(sv).index2)
#define SV_IS_NUMBER(sv) ( !((sv).i & 1) )
#define SV_IS_STRING(sv) (SV_TYPE(sv) <= T_ILSTRING)
#define SV_STR_IS_LONG(sv) ((sv).p[-1] & 1)
#define SVTYPE_IS_FREE(type) (type >= T_SMALLFREE)
#define O_DESTRUCTED(ob) ((ob)->type & 1)
#define TO_SVALUE(x) ((svalue)&(x)->ref)
#define INT_SVALUE(n) ((svalue)(p_int)((n) << 1))
#define ALLOC_FLOAT ALLOC(T_FLOAT, 1, sizeof (double))

/* If an [l]string becomes an i[l]string, the old fields are still acessible
 * till the ref count reaches zero */

#define CLOSURE_OPERATOR        (-0x1800)
#define CLOSURE_EFUN            (-0x1000)
#define CLOSURE_SIMUL_EFUN      (-0x0800)
#define CLOSURE_MALLOCED(c) 1 /* ((c) >= 0) */
#define CLOSURE_LFUN            0
#define CLOSURE_INHERITED_LFUN	1
#define CLOSURE_ALIEN_LFUN      2
#define CLOSURE_IDENTIFIER      3
#define CLOSURE_REFERENCES_CODE(c) ((c) >= CLOSURE_BOUND_LAMBDA)
#define CLOSURE_BOUND_LAMBDA    4
#define CLOSURE_HAS_CODE(c) ((c) >= CLOSURE_LAMBDA)
#define CLOSURE_LAMBDA          5
#define CLOSURE_UNBOUND_LAMBDA  6
#define CLOSURE_PROTO_LFUN	7
#define CLOSURE_PROTO_INHERITED_LFUN 8
#define CLOSURE_BOGUS_LFUN	9
#define CLOSURE_BOGUS_ALIEN	10
#define CLOSURE_BOGUS_LAMBDA	11
#define CLOSURE_CALLABLE(c) ((c) >= CLOSURE_EFUN && (c) <= CLOSURE_LAMBDA)

#define CLOSURE_IDENTIFIER_OFFS 0xe800
#define CLOSURE_OPERATOR_OFFS   (CLOSURE_OPERATOR & 0xffff)
#define CLOSURE_EFUN_OFFS       (CLOSURE_EFUN & 0xffff)
#define CLOSURE_SIMUL_EFUN_OFFS (CLOSURE_SIMUL_EFUN & 0xffff)

/*
 * The RESWORD macros depend on 0x800 being left free from TYPE_ stuff
 * that appears as value of a keyword ( see lex.c::reswords[] )
 */
#define RESWORD_CLOSURE(f_code)	(CLOSURE_OPERATOR+(f_code))
#define IS_RESWORD_CLOSURE(resword_value) ((resword_value) & 0x800)
#define RESWORD_TO_CLOSURE(resword_value) (resword_value)


#define SV_NULL ((svalue)(p_int)0)
#define SV_NULLP ((svalue)(uint8 *)0)

extern unsigned char const_invalid[2];
#define CONST_INVALID ((svalue)(const_invalid + 1))

#define REF_BASE	1
#define SV_REF_CYCLELEN	192 /* values in the range 128..255 make sense */
#define SV_REFINC(sv)	(!++SV_REF(sv))
#define SV_REFDEC(sv)	(!--SV_REF(sv))

#ifdef __GNUC__
#ifdef sparc
#define _FREE_ALLOCED_SVALUE(sv) (({asm(\
        "ldub [%0],%%o0\n\
	addcc %%o0,-1,%%o0\n\
	bne 0f\n\
	stb %%o0,[%0]\n\
	call _free_svalue,0\n\
	mov %0,%%o0\n\
	0:"\
\
	: /* no outputs */ \
	: "r" (sv)\
	: "cc","%o0", "%g2", "%g3");}),0)
#else
/* don't strip REGPARAM */
#define _FREE_ALLOCED_SVALUE(sv) (SV_REFDEC(sv) ? (_free_svalue(sv),0) : 0)
#endif
#else
/* don't 'use' void value */
#define _FREE_ALLOCED_SVALUE(sv) \
	(SV_REFDEC(sv) && (*(int(*)())_free_svalue)(sv))
#endif
#define FREE_ALLOCED_SVALUE(sv) ((void)_FREE_ALLOCED_SVALUE(sv))

#define _FREE_SVALUE(sv) ( (void)(((sv).i & 1) && _FREE_ALLOCED_SVALUE(sv)))
#define FREE_SVALUE(sv) ((void)_FREE_SVALUE(sv))

/* at least gcc 2.5.8 and 2.7.0 make bad code for sv = REF_INC(sv) */
#if defined(__GNUC__) && defined(sparc)

#define REF_INC(sv) ({svalue out = sv; REF_INC_IN_VAR(out); out;})
#define _REF_INC_IN_VAR(sv) (({__asm__ __volatile__ (\
        "ldub [%0],%%o0\n\
	addcc %%o0,1,%%o0\n\
	bne 0f\n\
	stb %%o0,[%0]\n\
	call _ref_inc,0\n\
	mov %0,%%o0\n\
	mov %%o0,%0\n\
	0:"\
\
	: "=r" (sv)\
	: "0" (sv)\
	: "cc","%o0");}),sv.i)

#else /* !sparc */

/* return value is nonzero if allocation ok */
#define REF_INC(source) (SV_REFINC(source) ? ref_inc(source) : (source))
#define _REF_INC_IN_VAR(sv) ( !SV_REFINC(sv) || ((sv) = ref_inc(sv)).i )

#endif

#define REF_INC_IN_VAR(sv) (void)_REF_INC_IN_VAR(sv)
#define _COPY_SVALUE_IN_VAR(sv) ( SV_IS_NUMBER(sv) || _REF_INC_IN_VAR(sv) )
#define COPY_SVALUE_IN_VAR(sv) ((void)_COPY_SVALUE_IN_VAR(sv))

#ifdef __GNUC__
#define COPY_SVALUE(source) \
({svalue out = source; if (!SV_IS_NUMBER(out)) REF_INC_IN_VAR(out); out;})
#else
#define COPY_SVALUE(source) \
 ( !SV_IS_NUMBER(source) && SV_REFINC(source) ? ref_inc(source) : (source) )
#endif

#define ASSIGN_SVALUE_NO_FREE(dest, source) ((void)( *(dest) =  \
    COPY_SVALUE(source) ))

#define ASSIGN_ALLOCED_SVALUE_NO_FREE(dest, source) ((void)( *(dest) =  \
    REF_INC(source) ))

#define STR_REFINC(p)  ((void)(SV_REF(p)++ || SV_STRREF(p)++))
#define LSTR_REFINC(p) ((void)(SV_REF(p)++ || SV_LSTRREF(p)++))

#define NIL_STRING	TO_SVALUE(&nil_string)
#define NIL_ARRAY	TO_SVALUE(&nil_array)

#define SHS_SEARCH	 0
#define SHS_REORDER	 1
#define SHS_HEADMATCH	 2
#define SHS_FAIL	 3
#define SHS_FREE	 4
#define SHS_LSEARCH	 5
#define SHS_LREORDER	 6
#define SHS_LHEADMATCH	 7
#define SHS_LFAIL	 8
#define SHS_LFREE	 9
#define SHS_UNSHARE	10
#define ALLOC_FREE1	11
#define ALLOC_FREE9	19
#define ALLOC_ALLOC1	20
#define ALLOC_ALLOC9	28
#define ALLOC_LALLOC	29
#define ALLOC_LALLOC_TOTAL 30
#define ALLOC_LFREE	31
#define ALLOC_LFREE_TOTAL 32
#define ADDMESS_CALLS	33
#define ADDMESS_TOTAL	34
#define COMM_COMMANDS	35
#define COMM_IN_TOTAL	36
#define COMM_OUTPACKETS	37
#define COMM_OUTTOTAL	38
#define ADTSTAT_SIZE	39

/*
 * adtstat is indexed by free_block() like an array of pointers, thus it
 * needs to have an int type of matching size.
 */
extern p_int adtstat[ADTSTAT_SIZE];
extern double xadtstat[ADTSTAT_SIZE];

struct counted_string { char *start; p_uint len; } ALIGN8;

void _free_svalue(svalue) REGPARM(1);
void _free_object(svalue ob);
void free_varargs(svalue); /* free a varargs value and assign via lvalues */
void _free_lambda_closure(svalue);
void _free_mapping(svalue);
void assign_svalue_no_free(svalue *dest, svalue source);
void assign_svalue(svalue *dest, svalue source);
char *sv_string(svalue, mp_uint *);
struct counted_string sv_string2(svalue);
p_int sv_strcmp(svalue, svalue);
/*
 * 2-member structs are nice for returning values, but data flow analisys is
 * disturbed when you calculate with them.
 */
#define SV_COUNT_STRING(sv, str, length) { \
    struct counted_string __tmp = sv_string2(sv); \
    (str) = __tmp.start; \
    (length) = __tmp.len; \
}
svalue make_global_string(char *, mp_int);
/* shared identifiers *must* have long strings so they can trust the string
 * type.
 */
extern svalue make_string(char *, mp_int);
#define make_astring(str, len) make_string(str, len) /* 4-byte aligned start */
extern svalue make_lstring(char *, mp_int);
extern svalue make_string_global(svalue);
extern svalue findstring(svalue);
extern void free_string(svalue);
extern void free_lstring(svalue);
extern svalue unshare_string(svalue);
extern svalue add_string(svalue, svalue);
extern void push_svalue(svalue);
extern void transfer_svalue(svalue *, svalue);
extern p_int _privilege_violation(p_int, svalue, svalue *);
extern void call_lambda(svalue, int);
extern svalue ref_inc(svalue) REGPARM(1);
/* free_block takes pointer with and size without overhead */
extern void free_block(uint8 *, mp_int);
extern svalue *get_map_lvalue(svalue map, svalue index, int need_lvalue);
extern svalue subtract_array(svalue, svalue);
extern svalue subtract_mapping(svalue, svalue, svalue);
extern struct lambda_closure
  *lambda(struct array *, svalue, svalue object);
extern void free_array(svalue);
extern void free_closure(svalue);
extern svalue allocate_mapping(mp_int, int, svalue ob);
extern void add_to_mapping(svalue m1, svalue m2);
extern svalue *cook_lvalue(svalue);
extern svalue allocate_array(p_int, struct uid *);
extern void remove_mapping(svalue, svalue);

extern svalue *inter_sp, apply_return_value;
extern struct array nil_array;
extern struct short_string nil_string;
extern int out_of_memory;
extern int malloc_privilege;

#define MALLOC_USER   (0)
#define MALLOC_MASTER (1)
#define MALLOC_SYSTEM (2)

#endif /* ALLOC_H */