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