#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 */