/* Copyright (C) 1993, 1996, 1997, 1998, 1999 artofcode LLC. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: gsmemory.c,v 1.4.2.1.2.1 2003/01/17 00:49:03 giles Exp $ */ /* Generic allocator support */ #include "memory_.h" #include "gdebug.h" #include "gstypes.h" #include "gsmemory.h" #include "gsmdebug.h" #include "gsrefct.h" /* to check prototype */ #include "gsstruct.h" /* ditto */ /* Define the fill patterns for unallocated memory. */ const byte gs_alloc_fill_alloc = 0xa1; const byte gs_alloc_fill_block = 0xb1; const byte gs_alloc_fill_collected = 0xc1; const byte gs_alloc_fill_deleted = 0xd1; const byte gs_alloc_fill_free = 0xf1; /* A 'structure' type descriptor for free blocks. */ gs_public_st_simple(st_free, byte, "(free)"); /* The 'structure' type descriptor for bytes. */ gs_public_st_simple(st_bytes, byte, "bytes"); /* The structure type descriptor for GC roots. */ public_st_gc_root_t(); /* The descriptors for elements and arrays of const strings. */ private_st_const_string(); public_st_const_string_element(); /* GC procedures for bytestrings */ gs_ptr_type_t enum_bytestring(enum_ptr_t *pep, const gs_bytestring *pbs) { return (pbs->bytes ? ENUM_OBJ(pbs->bytes) : ENUM_STRING(pbs)); } gs_ptr_type_t enum_const_bytestring(enum_ptr_t *pep, const gs_const_bytestring *pbs) { return (pbs->bytes ? ENUM_OBJ(pbs->bytes) : ENUM_CONST_STRING(pbs)); } void reloc_bytestring(gs_bytestring *pbs, gc_state_t *gcst) { if (pbs->bytes) { byte *bytes = pbs->bytes; long offset = pbs->data - bytes; pbs->bytes = bytes = RELOC_OBJ(bytes); pbs->data = bytes + offset; } else RELOC_STRING_VAR(*(gs_string *)pbs); } void reloc_const_bytestring(gs_const_bytestring *pbs, gc_state_t *gcst) { if (pbs->bytes) { const byte *bytes = pbs->bytes; long offset = pbs->data - bytes; pbs->bytes = bytes = RELOC_OBJ(bytes); pbs->data = bytes + offset; } else RELOC_CONST_STRING_VAR(*(gs_const_string *)pbs); } /* Fill an unoccupied block with a pattern. */ /* Note that the block size may be too large for a single memset. */ void gs_alloc_memset(void *ptr, int /*byte */ fill, ulong lsize) { ulong msize = lsize; char *p = ptr; int isize; for (; msize; msize -= isize, p += isize) { isize = min(msize, max_int); memset(p, fill, isize); } } /* * Either allocate (if obj == 0) or resize (if obj != 0) a structure array. * If obj != 0, pstype is used only for checking (in DEBUG configurations). */ void * gs_resize_struct_array(gs_memory_t *mem, void *obj, uint num_elements, gs_memory_type_ptr_t pstype, client_name_t cname) { if (obj == 0) return gs_alloc_struct_array(mem, num_elements, void, pstype, cname); #ifdef DEBUG if (gs_object_type(mem, obj) != pstype) { lprintf3("resize_struct_array 0x%lx, type was 0x%lx, expected 0x%lx!\n", (ulong)obj, (ulong)gs_object_type(mem, obj), (ulong)pstype); return 0; } #endif return gs_resize_object(mem, obj, num_elements, cname); } /* Allocate a structure using a "raw memory" allocator. */ void * gs_raw_alloc_struct_immovable(gs_raw_memory_t * rmem, gs_memory_type_ptr_t pstype, client_name_t cname) { return gs_alloc_bytes_immovable(rmem, gs_struct_type_size(pstype), cname); } /* No-op freeing procedures */ void gs_ignore_free_object(gs_memory_t * mem, void *data, client_name_t cname) { } void gs_ignore_free_string(gs_memory_t * mem, byte * data, uint nbytes, client_name_t cname) { } /* Deconstifying freeing procedures. */ /* These procedures rely on a severely deprecated pun. */ void gs_free_const_object(gs_memory_t * mem, const void *data, client_name_t cname) { union { const void *r; void *w; } u; u.r = data; gs_free_object(mem, u.w, cname); } void gs_free_const_string(gs_memory_t * mem, const byte * data, uint nbytes, client_name_t cname) { union { const byte *r; byte *w; } u; u.r = data; gs_free_string(mem, u.w, nbytes, cname); } /* Free a [const] bytestring. */ void gs_free_bytestring(gs_memory_t *mem, gs_bytestring *pbs, client_name_t cname) { if (pbs->bytes) gs_free_object(mem, pbs->bytes, cname); else gs_free_string(mem, pbs->data, pbs->size, cname); } void gs_free_const_bytestring(gs_memory_t *mem, gs_const_bytestring *pbs, client_name_t cname) { if (pbs->bytes) gs_free_const_object(mem, pbs->bytes, cname); else gs_free_const_string(mem, pbs->data, pbs->size, cname); } /* No-op consolidation procedure */ void gs_ignore_consolidate_free(gs_memory_t *mem) { } /* No-op pointer enumeration procedure */ ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs) { return 0; ENUM_PTRS_END_PROC } /* No-op pointer relocation procedure */ RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs) { } RELOC_PTRS_END /* Get the size of a structure from the descriptor. */ uint gs_struct_type_size(gs_memory_type_ptr_t pstype) { return pstype->ssize; } /* Get the name of a structure from the descriptor. */ struct_name_t gs_struct_type_name(gs_memory_type_ptr_t pstype) { return pstype->sname; } /* Register a structure root. */ int gs_register_struct_root(gs_memory_t *mem, gs_gc_root_t *root, void **pp, client_name_t cname) { return gs_register_root(mem, root, ptr_struct_type, pp, cname); } /* ---------------- Reference counting ---------------- */ #ifdef DEBUG private const char * rc_object_type_name(const void *vp, const rc_header *prc) { gs_memory_type_ptr_t pstype; if (prc->memory == 0) return "(unknown)"; pstype = gs_object_type(prc->memory, vp); if (prc->free != rc_free_struct_only) { /* * This object might be stack-allocated or have other unusual memory * management properties. Make some reasonableness checks. * ****** THIS IS A HACK. ****** */ long dist; dist = (const char *)&dist - (const char *)vp; if (dist < 10000 && dist > -10000) return "(on stack)"; if ((ulong)pstype < 0x10000 || (long)pstype < 0) return "(anomalous)"; } return client_name_string(gs_struct_type_name(pstype)); } /* Trace reference count operations. */ void rc_trace_init_free(const void *vp, const rc_header *prc) { dprintf3("[^]%s 0x%lx init = %ld\n", rc_object_type_name(vp, prc), (ulong)vp, (long)prc->ref_count); } void rc_trace_free_struct(const void *vp, const rc_header *prc, client_name_t cname) { dprintf3("[^]%s 0x%lx => free (%s)\n", rc_object_type_name(vp, prc), (ulong)vp, client_name_string(cname)); } void rc_trace_increment(const void *vp, const rc_header *prc) { dprintf3("[^]%s 0x%lx ++ => %ld\n", rc_object_type_name(vp, prc), (ulong)vp, (long)prc->ref_count); } void rc_trace_adjust(const void *vp, const rc_header *prc, int delta) { dprintf4("[^]%s 0x%lx %+d => %ld\n", rc_object_type_name(vp, prc), (ulong)vp, delta, (long)(prc->ref_count + delta)); } #endif /* DEBUG */ /* Normal freeing routine for reference-counted structures. */ void rc_free_struct_only(gs_memory_t * mem, void *data, client_name_t cname) { if (mem != 0) gs_free_object(mem, data, cname); } /* ---------------- Basic-structure GC procedures ---------------- */ /* Enumerate pointers */ ENUM_PTRS_BEGIN_PROC(basic_enum_ptrs) { const gc_struct_data_t *psd = pstype->proc_data; if (index < psd->num_ptrs) { const gc_ptr_element_t *ppe = &psd->ptrs[index]; EV_CONST char *pptr = (EV_CONST char *)vptr + ppe->offset; switch ((gc_ptr_type_index_t)ppe->type) { case GC_ELT_OBJ: return ENUM_OBJ(*(const void *EV_CONST *)pptr); case GC_ELT_STRING: return ENUM_STRING((const gs_string *)pptr); case GC_ELT_CONST_STRING: return ENUM_CONST_STRING((const gs_const_string *)pptr); } } if (!psd->super_type) return 0; return ENUM_USING(*(psd->super_type), (EV_CONST void *) ((EV_CONST char *)vptr + psd->super_offset), pstype->ssize, index - psd->num_ptrs); } ENUM_PTRS_END_PROC /* Relocate pointers */ RELOC_PTRS_BEGIN(basic_reloc_ptrs) { const gc_struct_data_t *psd = pstype->proc_data; uint i; for (i = 0; i < psd->num_ptrs; ++i) { const gc_ptr_element_t *ppe = &psd->ptrs[i]; char *pptr = (char *)vptr + ppe->offset; switch ((gc_ptr_type_index_t) ppe->type) { case GC_ELT_OBJ: RELOC_OBJ_VAR(*(void **)pptr); break; case GC_ELT_STRING: RELOC_STRING_VAR(*(gs_string *)pptr); break; case GC_ELT_CONST_STRING: RELOC_CONST_STRING_VAR(*(gs_const_string *)pptr); break; } } if (psd->super_type) RELOC_USING(*(psd->super_type), (void *)((char *)vptr + psd->super_offset), pstype->ssize); } RELOC_PTRS_END