/***************************************************************************
*
* Copyright (c) 1998-1999 Niels Möller
* Copyright (c) 1999 BalaBit Computing
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: xalloc.c,v 1.10 2003/04/30 21:58:12 bazsi Exp $
*
***************************************************************************/
#include "objects.h"
#include "list.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
/* There are two sets of allocation functions: Low level allocation *
* that can allocate memory for any purpose, and object allocators
* that assume that the allocated object begins with a type field. */
/* NOTE: This doesn't work if there are types that require other
* alignment than int boundaries. But it doesn't matter much if the
* optional debug code isn't fully portable. */
#ifdef DEBUG_ALLOC
/* This is a very dirty malloc debugger, because I couldn't find a leaked
* block otherwise
*/
struct malloc_entry *first_malloc = NULL;
#define SIZE_IN_INTS(x) (((x) + sizeof(int)-1) / sizeof(int))
/* #define REALLY_DEBUG_ALLOC 1 */
#if REALLY_DEBUG_ALLOC
UINT32 strcount = 0;
#endif
static void *debug_malloc(size_t real_size)
{
static int count = 4711;
int *res;
int size = SIZE_IN_INTS(real_size);
res = malloc((size + 3)*sizeof(int));
if (!res)
return NULL;
res += 2;
res[-2] = count;
res[-1] = real_size;
res[size] = ~count;
count++;
#if REALLY_DEBUG_ALLOC
strcount++;
{
struct malloc_entry *p = malloc(sizeof(struct malloc_entry));
p->ptr = res;
p->size = real_size;
p->next = first_malloc;
first_malloc = p;
}
#endif
return (void *) res;
}
void debug_free(void *m)
{
if (m)
{
int *p = (int *) m;
int real_size = p[-1];
int size = SIZE_IN_INTS(real_size);
if (~p[-2] != p[size])
fatal("Memory corrupted!\n");
p[-2] = 0;
p[size] = 1;
free(p-2);
#if REALLY_DEBUG_ALLOC
strcount--;
{
struct malloc_entry *e, *ep;
for (ep = NULL, e = first_malloc; e; ep = e, e = e->next) {
if (e->ptr == p) {
if (ep)
ep->next = e->next;
else
first_malloc = e->next;
break;
}
}
if (e) free(e);
}
#endif
}
}
#endif /* !DEBUG_ALLOC */
void *xalloc(size_t size)
{
void *res = ol_malloc(size);
if (!res)
fatal("Virtual memory exhausted");
/* FIXME: The gc can't handle uninitialized pointers. The simple way
* is to zero-fill all memory as it is allocated. But initialization
* is only necessary for objects, strings need no initialization. By
* moving initializing to some higher level, we could avoid
* unnecessary clearing, and also initialize mpz objects
* automatically. */
memset(res, 0, size);
return res;
}
struct ol_object *ol_object_alloc(struct ol_class *class)
{
struct ol_object *instance = xalloc(class->size);
instance->isa = class;
instance->alloc_method = OL_ALLOC_HEAP;
gc_register(instance);
return instance;
}
struct ol_object *ol_object_clone(struct ol_object *o)
{
struct ol_object *i = xalloc(o->isa->size);
/* Copy header and all instance variables. Note that the header is
* now invalid, as the next pointer can't be copied directly. This
* is fixed by the gc_register call below. */
memcpy(i, o, o->isa->size);
i->alloc_method = OL_ALLOC_HEAP;
gc_register(i);
return i;
}
struct list_header *ol_list_alloc(struct ol_class *class,
unsigned length, size_t element_size)
{
struct list_header *list = xalloc(class->size
+ element_size * length
- element_size);
assert(element_size < 1024);
/* assert(length < 65536); */
list->super.isa = class;
list->super.alloc_method = OL_ALLOC_HEAP;
list->allocated = length;
gc_register(&list->super);
return list;
}
/* Should be called *only* by the gc */
void ol_object_free(struct ol_object *o)
{
if (!o)
return;
if (o->alloc_method != OL_ALLOC_HEAP)
fatal("ol_object_free: Object not allocated on the heap!\n");
#if 0
if (o->isa->free_instance)
o->isa->free_instance(o);
#endif
ol_free(o);
}
struct ol_string *ol_string_use(struct ol_string *str)
{
str->use_cnt++;
return str;
}
struct ol_string *ol_string_alloc(UINT32 length)
{
struct ol_string *s
= xalloc(sizeof(struct ol_string) - 1 + length);
#ifdef DEBUG_ALLOC
s->magic = -1717;
#endif
s->length = length;
s->use_cnt = 1;
return s;
}
void ol_string_free(struct ol_string *s)
{
if (!s)
return;
#if 0
debug("ol_string_free: freeing %xi.\n", (void *) s);
#endif
assert(s->use_cnt);
if (--s->use_cnt == 0) {
#ifdef DEBUG_ALLOC
if (s->magic != -1717)
fatal("ol_string_free: Not string!\n");
s->magic = 9999;
#endif
ol_free(s);
}
}
#ifdef DEBUG_ALLOC
struct ol_object *ol_object_check(struct ol_class *class,
struct ol_object *instance)
{
if (!instance)
return instance;
if (instance->marked)
fatal("ol_object_check: Unexpected marked object!\n");
if (instance->dead)
fatal("ol_object_check: Reference to dead object!\n");
if ( (instance->alloc_method == OL_ALLOC_HEAP)
&& (instance->isa != class))
fatal("ol_object_check: Type error!\n");
return instance;
}
struct ol_object *ol_object_check_subtype(struct ol_class *class,
struct ol_object *instance)
{
struct ol_class *type;
if (!instance)
return instance;
if (instance->marked)
fatal("ol_object_check: Unexpected marked object!\n");
if (instance->dead)
fatal("ol_object_check: Reference to dead object!\n");
/* Only heap allocated objects have a valid isa-pointer */
switch (instance->alloc_method)
{
case OL_ALLOC_STATIC:
case OL_ALLOC_STACK:
return instance;
case OL_ALLOC_HEAP:
break;
default:
fatal("ol_object_check_subtype: Memory corrupted!\n");
}
for (type = instance->isa; type; type=type->super_class)
if (type == class)
return instance;
fatal("ol_object_check_subtype: Type error!\n");
return 0;
}
#endif /* DEBUG_ALLOC */
#ifdef DEBUG_ALLOC
void *ol_space_alloc(size_t size)
{
int * p = xalloc(size + sizeof(int));
*p = -1919;
return (void *) (p + 1);
}
void ol_space_free(void *p)
{
int *m;
if (!p)
return;
m = ((int *) p) - 1;
if (*m != -1919)
fatal("ol_free_space: Type error!\n");
ol_free(m);
}
#else /* !DEBUG_ALLOC */
void *ol_space_alloc(size_t size)
{
return xalloc(size);
}
void ol_space_free(void *p)
{
ol_free(p);
}
#endif /* !DEBUG_ALLOC */
syntax highlighted by Code2HTML, v. 0.9.1