mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-11 11:42:51 -08:00
932 lines
21 KiB
D
932 lines
21 KiB
D
|
|
/*
|
|
alloc.c -- Memory allocation.
|
|
*/
|
|
/*
|
|
Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
|
|
Copyright (c) 1990, Giuseppe Attardi.
|
|
Copyright (c) 2001, Juan Jose Garcia Ripoll.
|
|
|
|
ECL is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
See file '../Copyright' for full details.
|
|
*/
|
|
|
|
|
|
/*
|
|
Heap and Relocatable Area
|
|
|
|
heap_end data_end
|
|
+------+--------------------+ - - - + - - --------+
|
|
| text | heap | hole | stack |
|
|
+------+--------------------+ - - - + - - --------+
|
|
|
|
The type_map array covers all pages of memory: those not used for objects
|
|
are marked as type t_other.
|
|
|
|
The tm_table array holds a struct typemanager for each type, which contains
|
|
the first element of the free list for the type, and other bookkeeping
|
|
information.
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include "ecl.h"
|
|
#include "page.h"
|
|
|
|
#undef USE_MMAP
|
|
#ifdef USE_MMAP
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#endif
|
|
|
|
#ifdef BSD
|
|
#include <sys/resource.h>
|
|
#endif
|
|
#ifdef SYSV
|
|
#include <ulimit.h>
|
|
#endif
|
|
|
|
/******************************* EXPORTS ******************************/
|
|
|
|
cl_index real_maxpage;
|
|
cl_index new_holepage;
|
|
char type_map[MAXPAGE];
|
|
struct typemanager tm_table[(int)t_end];
|
|
struct contblock *cb_pointer = NULL;
|
|
|
|
cl_index ncb; /* number of contblocks */
|
|
cl_index ncbpage; /* number of contblock pages */
|
|
cl_index maxcbpage; /* maximum number of contblock pages */
|
|
cl_index cbgccount; /* contblock gc count */
|
|
cl_index holepage; /* hole pages */
|
|
|
|
cl_ptr heap_end; /* heap end */
|
|
cl_ptr heap_start; /* heap start */
|
|
cl_ptr data_end; /* end of data space */
|
|
|
|
/******************************* ------- ******************************/
|
|
|
|
static bool ignore_maximum_pages = TRUE;
|
|
|
|
#ifdef NEED_MALLOC
|
|
static cl_object malloc_list;
|
|
#endif
|
|
|
|
/*
|
|
Ensure that the hole is at least "n" pages large. If it is not,
|
|
allocate space from the operating system.
|
|
*/
|
|
|
|
#if defined(USE_MMAP)
|
|
void
|
|
cl_resize_hole(cl_index n)
|
|
{
|
|
cl_index m, bytes;
|
|
cl_ptr result, last_addr;
|
|
if (heap_start == NULL) {
|
|
/* First time use. We allocate the memory and keep the first
|
|
* address in heap_start.
|
|
*/
|
|
bytes = n * LISP_PAGESIZE;
|
|
result = mmap(NULL, bytes, PROT_READ | PROT_WRITE,
|
|
MAP_ANON | MAP_PRIVATE, -1 ,0);
|
|
if (result == MAP_FAILED)
|
|
error("Cannot allocate memory. Good-bye!");
|
|
data_end = heap_end = heap_start = result;
|
|
last_addr = heap_start + bytes;
|
|
holepage = n;
|
|
} else {
|
|
/* Next time use. We extend the region of memory that we had
|
|
* mapped before.
|
|
*/
|
|
m = (data_end - heap_end)/LISP_PAGESIZE;
|
|
if (n <= m)
|
|
return;
|
|
bytes = n * LISP_PAGESIZE;
|
|
result = mmap(data_end, bytes, PROT_READ | PROT_WRITE,
|
|
MAP_ANON | MAP_PRIVATE, -1, 0);
|
|
if (result == MAP_FAILED)
|
|
error("Cannot resize memory pool. Good-bye!");
|
|
last_addr = result + bytes;
|
|
if (result != data_end) {
|
|
cl_dealloc(heap_end, data_end - heap_end);
|
|
while (heap_end < result) {
|
|
cl_index p = page(heap_end);
|
|
if (p > real_maxpage)
|
|
error("Memory limit exceeded.");
|
|
type_map[p] = t_other;
|
|
heap_end += LISP_PAGESIZE;
|
|
}
|
|
}
|
|
holepage = (last_addr - heap_end) / LISP_PAGESIZE;
|
|
}
|
|
while (data_end < last_addr) {
|
|
type_map[page(data_end)] = t_other;
|
|
data_end += LISP_PAGESIZE;
|
|
}
|
|
}
|
|
#else
|
|
void
|
|
cl_resize_hole(cl_index n)
|
|
{
|
|
cl_ptr e;
|
|
cl_index m;
|
|
m = (data_end - heap_end)/LISP_PAGESIZE;
|
|
if (n <= m)
|
|
return;
|
|
|
|
/* Create the hole */
|
|
e = sbrk(0);
|
|
if (data_end == e)
|
|
n -= m;
|
|
else {
|
|
cl_dealloc(heap_end, data_end - heap_end);
|
|
/* FIXME! Horrible hack! */
|
|
/* mark as t_other pages not allocated by us */
|
|
heap_end = e;
|
|
while (data_end < heap_end) {
|
|
type_map[page(data_end)] = t_other;
|
|
data_end += LISP_PAGESIZE;
|
|
}
|
|
holepage = 0;
|
|
}
|
|
if ((int)sbrk(LISP_PAGESIZE * n) < 0)
|
|
error("Can't allocate. Good-bye!");
|
|
data_end += LISP_PAGESIZE*(n);
|
|
holepage += n;
|
|
}
|
|
#endif
|
|
|
|
/* Allocates n pages from the hole. */
|
|
static void *
|
|
alloc_page(cl_index n)
|
|
{
|
|
cl_ptr e = heap_end;
|
|
if (n >= holepage) {
|
|
ecl_gc(t_contiguous);
|
|
cl_resize_hole(new_holepage+n);
|
|
}
|
|
holepage -= n;
|
|
heap_end += LISP_PAGESIZE*n;
|
|
return e;
|
|
}
|
|
|
|
static void
|
|
add_page_to_freelist(cl_ptr p, struct typemanager *tm)
|
|
{ cl_type t;
|
|
cl_object x, f;
|
|
cl_index i;
|
|
t = tm->tm_type;
|
|
type_map[page(p)] = t;
|
|
f = tm->tm_free;
|
|
for (i = tm->tm_nppage; i > 0; --i, p += tm->tm_size) {
|
|
x = (cl_object)p;
|
|
((struct freelist *)x)->t = (short)t;
|
|
((struct freelist *)x)->m = FREE;
|
|
((struct freelist *)x)->f_link = f;
|
|
f = x;
|
|
}
|
|
tm->tm_free = f;
|
|
tm->tm_nfree += tm->tm_nppage;
|
|
tm->tm_npage++;
|
|
}
|
|
|
|
cl_object
|
|
cl_alloc_object(cl_type t)
|
|
{
|
|
register cl_object obj;
|
|
register struct typemanager *tm;
|
|
register cl_ptr p;
|
|
|
|
switch (t) {
|
|
case t_fixnum:
|
|
return MAKE_FIXNUM(0); /* Immediate fixnum */
|
|
case t_character:
|
|
return CODE_CHAR('\0'); /* Immediate character */
|
|
}
|
|
|
|
start_critical_section();
|
|
tm = tm_of(t);
|
|
ONCE_MORE:
|
|
if (interrupt_flag) {
|
|
interrupt_flag = FALSE;
|
|
#ifdef unix
|
|
alarm(0);
|
|
#endif
|
|
terminal_interrupt(TRUE);
|
|
}
|
|
|
|
obj = tm->tm_free;
|
|
if (obj == OBJNULL) {
|
|
cl_index available = available_pages();
|
|
if (tm->tm_npage >= tm->tm_maxpage)
|
|
goto CALL_GC;
|
|
if (available < 1) {
|
|
ignore_maximum_pages = FALSE;
|
|
goto CALL_GC;
|
|
}
|
|
p = alloc_page(1);
|
|
add_page_to_freelist(p, tm);
|
|
obj = tm->tm_free;
|
|
/* why this? Beppe
|
|
if (tm->tm_npage >= tm->tm_maxpage)
|
|
goto CALL_GC; */
|
|
}
|
|
tm->tm_free = ((struct freelist *)obj)->f_link;
|
|
--(tm->tm_nfree);
|
|
(tm->tm_nused)++;
|
|
obj->d.t = (short)t;
|
|
obj->d.m = FALSE;
|
|
/* Now initialize the object so that it can be correctly marked
|
|
* by the GC
|
|
*/
|
|
switch (t) {
|
|
case t_bignum:
|
|
obj->big.big_dim = obj->big.big_size = 0;
|
|
obj->big.big_limbs = NULL;
|
|
break;
|
|
case t_ratio:
|
|
obj->ratio.num = OBJNULL;
|
|
obj->ratio.den = OBJNULL;
|
|
break;
|
|
case t_shortfloat:
|
|
case t_longfloat:
|
|
break;
|
|
case t_complex:
|
|
obj->complex.imag = OBJNULL;
|
|
obj->complex.real = OBJNULL;
|
|
break;
|
|
case t_symbol:
|
|
obj->symbol.plist = OBJNULL;
|
|
SYM_FUN(obj) = OBJNULL;
|
|
SYM_VAL(obj) = OBJNULL;
|
|
obj->symbol.name = OBJNULL;
|
|
break;
|
|
case t_package:
|
|
obj->pack.name = OBJNULL;
|
|
obj->pack.nicknames = OBJNULL;
|
|
obj->pack.shadowings = OBJNULL;
|
|
obj->pack.uses = OBJNULL;
|
|
obj->pack.usedby = OBJNULL;
|
|
obj->pack.internal = OBJNULL;
|
|
obj->pack.external = OBJNULL;
|
|
break;
|
|
case t_cons:
|
|
CAR(obj) = OBJNULL;
|
|
CDR(obj) = OBJNULL;
|
|
break;
|
|
case t_hashtable:
|
|
obj->hash.rehash_size = OBJNULL;
|
|
obj->hash.threshold = OBJNULL;
|
|
obj->hash.data = NULL;
|
|
break;
|
|
case t_array:
|
|
obj->array.displaced = Cnil;
|
|
obj->array.elttype = (short)aet_object;
|
|
obj->array.self.t = NULL;
|
|
break;
|
|
case t_vector:
|
|
obj->array.displaced = Cnil;
|
|
obj->array.elttype = (short)aet_object;
|
|
obj->array.self.t = NULL;
|
|
break;
|
|
case t_string:
|
|
obj->string.displaced = Cnil;
|
|
obj->string.self = NULL;
|
|
break;
|
|
case t_bitvector:
|
|
obj->vector.displaced = Cnil;
|
|
obj->vector.self.bit = NULL;
|
|
break;
|
|
#ifndef CLOS
|
|
case t_structure:
|
|
obj->str.name = OBJNULL;
|
|
obj->str.self = NULL;
|
|
break;
|
|
#endif /* CLOS */
|
|
case t_stream:
|
|
obj->stream.mode = (short)smm_closed;
|
|
obj->stream.file = NULL;
|
|
obj->stream.object0 = OBJNULL;
|
|
obj->stream.object1 = OBJNULL;
|
|
obj->stream.buffer = NULL;
|
|
break;
|
|
case t_random:
|
|
break;
|
|
case t_readtable:
|
|
obj->readtable.table = NULL;
|
|
break;
|
|
case t_pathname:
|
|
obj->pathname.host = OBJNULL;
|
|
obj->pathname.device = OBJNULL;
|
|
obj->pathname.directory = OBJNULL;
|
|
obj->pathname.name = OBJNULL;
|
|
obj->pathname.type = OBJNULL;
|
|
obj->pathname.version = OBJNULL;
|
|
break;
|
|
case t_bytecodes:
|
|
obj->bytecodes.lex = Cnil;
|
|
obj->bytecodes.size = 0;
|
|
obj->bytecodes.data = NULL;
|
|
break;
|
|
case t_cfun:
|
|
obj->cfun.name = OBJNULL;
|
|
obj->cfun.block = NULL;
|
|
break;
|
|
case t_cclosure:
|
|
obj->cclosure.env = OBJNULL;
|
|
obj->cclosure.block = NULL;
|
|
break;
|
|
/*
|
|
case t_spice:
|
|
break;
|
|
*/
|
|
#ifdef THREADS
|
|
case t_cont:
|
|
obj->cn.cn_thread = OBJNULL;
|
|
break;
|
|
case t_thread:
|
|
obj->thread.entry = OBJNULL;
|
|
break;
|
|
#endif
|
|
#ifdef CLOS
|
|
case t_instance:
|
|
CLASS_OF(obj) = OBJNULL;
|
|
obj->instance.slots = NULL;
|
|
break;
|
|
case t_gfun:
|
|
obj->gfun.name = OBJNULL;
|
|
obj->gfun.method_hash = OBJNULL;
|
|
obj->gfun.instance = OBJNULL;
|
|
obj->gfun.specializers = NULL;
|
|
break;
|
|
#endif /* CLOS */
|
|
case t_codeblock:
|
|
obj->cblock.name = Cnil;
|
|
obj->cblock.handle = NULL;
|
|
obj->cblock.entry = NULL;
|
|
obj->cblock.data = NULL;
|
|
obj->cblock.data_size = 0;
|
|
obj->cblock.data_text = NULL;
|
|
obj->cblock.data_text_size = 0;
|
|
break;
|
|
default:
|
|
printf("\ttype = %d\n", t);
|
|
error("alloc botch.");
|
|
}
|
|
#ifdef THREADS
|
|
clwp->lwp_alloc_temporary = obj;
|
|
#endif
|
|
end_critical_section();
|
|
return(obj);
|
|
CALL_GC:
|
|
ecl_gc(tm->tm_type);
|
|
if (tm->tm_nfree != 0 &&
|
|
(float)tm->tm_nfree * 10.0 >= (float)tm->tm_nused)
|
|
goto ONCE_MORE;
|
|
|
|
/* EXHAUSTED: */
|
|
if (ignore_maximum_pages) {
|
|
if (tm->tm_maxpage/2 <= 0)
|
|
tm->tm_maxpage += 1;
|
|
else
|
|
tm->tm_maxpage += tm->tm_maxpage/2;
|
|
goto ONCE_MORE;
|
|
}
|
|
GC_disable();
|
|
{ cl_object s = make_simple_string(tm_table[(int)t].tm_name+1);
|
|
GC_enable();
|
|
CEerror("The storage for ~A is exhausted.~%\
|
|
Currently, ~D pages are allocated.~%\
|
|
Use ALLOCATE to expand the space.",
|
|
2, s, MAKE_FIXNUM(tm->tm_npage));
|
|
}
|
|
goto ONCE_MORE;
|
|
}
|
|
|
|
cl_object
|
|
make_cons(cl_object a, cl_object d)
|
|
{
|
|
register cl_object obj;
|
|
register cl_ptr p;
|
|
struct typemanager *tm=(&tm_table[(int)t_cons]);
|
|
|
|
start_critical_section();
|
|
|
|
ONCE_MORE:
|
|
if (interrupt_flag) {
|
|
interrupt_flag = FALSE;
|
|
#ifdef unix
|
|
alarm(0);
|
|
#endif
|
|
terminal_interrupt(TRUE);
|
|
}
|
|
obj = tm->tm_free;
|
|
if (obj == OBJNULL) {
|
|
if (tm->tm_npage >= tm->tm_maxpage)
|
|
goto CALL_GC;
|
|
if (available_pages() < 1) {
|
|
ignore_maximum_pages = FALSE;
|
|
goto CALL_GC;
|
|
}
|
|
p = alloc_page(1);
|
|
add_page_to_freelist(p,tm);
|
|
obj = tm->tm_free;
|
|
if (tm->tm_npage >= tm->tm_maxpage)
|
|
goto CALL_GC;
|
|
}
|
|
tm->tm_free = ((struct freelist *)obj)->f_link;
|
|
--(tm->tm_nfree);
|
|
(tm->tm_nused)++;
|
|
obj->d.t = (short)t_cons;
|
|
obj->d.m = FALSE;
|
|
CAR(obj) = a;
|
|
CDR(obj) = d;
|
|
|
|
end_critical_section();
|
|
return(obj);
|
|
|
|
CALL_GC:
|
|
ecl_gc(t_cons);
|
|
if ((tm->tm_nfree != 0) && (tm->tm_nfree * 10.0 >= tm->tm_nused))
|
|
goto ONCE_MORE;
|
|
|
|
/* EXHAUSTED: */
|
|
if (ignore_maximum_pages) {
|
|
if (tm->tm_maxpage/2 <= 0)
|
|
tm->tm_maxpage += 1;
|
|
else
|
|
tm->tm_maxpage += tm->tm_maxpage/2;
|
|
goto ONCE_MORE;
|
|
}
|
|
CEerror("The storage for CONS is exhausted.~%\
|
|
Currently, ~D pages are allocated.~%\
|
|
Use ALLOCATE to expand the space.",
|
|
1, MAKE_FIXNUM(tm->tm_npage));
|
|
goto ONCE_MORE;
|
|
#undef tm
|
|
}
|
|
|
|
cl_object
|
|
cl_alloc_instance(cl_index slots)
|
|
{
|
|
cl_object i = cl_alloc_object(t_instance);
|
|
/* INV: slots > 0 */
|
|
i->instance.slots = (cl_object*)cl_alloc(sizeof(cl_object) * slots);
|
|
i->instance.length = slots;
|
|
return i;
|
|
}
|
|
|
|
void *
|
|
cl_alloc(cl_index n)
|
|
{
|
|
volatile cl_ptr p;
|
|
struct contblock **cbpp;
|
|
cl_index i, m;
|
|
bool g, gg;
|
|
|
|
g = FALSE;
|
|
n = round_up(n);
|
|
|
|
start_critical_section();
|
|
|
|
ONCE_MORE:
|
|
if (interrupt_flag) {
|
|
interrupt_flag = FALSE;
|
|
gg = g;
|
|
terminal_interrupt(TRUE);
|
|
g = gg;
|
|
}
|
|
|
|
/* Use extra indirection so that cb_pointer can be updated */
|
|
for (cbpp = &cb_pointer; (*cbpp) != NULL; cbpp = &(*cbpp)->cb_link)
|
|
if ((*cbpp)->cb_size >= n) {
|
|
p = (cl_ptr)(*cbpp);
|
|
i = (*cbpp)->cb_size - n;
|
|
*cbpp = (*cbpp)->cb_link;
|
|
--ncb;
|
|
cl_dealloc(p+n, i);
|
|
|
|
end_critical_section();
|
|
return(p);
|
|
}
|
|
m = round_to_page(n);
|
|
if (ncbpage + m > maxcbpage || available_pages() < m) {
|
|
if (available_pages() < m)
|
|
ignore_maximum_pages = FALSE;
|
|
if (!g) {
|
|
ecl_gc(t_contiguous);
|
|
g = TRUE;
|
|
goto ONCE_MORE;
|
|
}
|
|
if (ignore_maximum_pages) {
|
|
if (maxcbpage/2 <= 0)
|
|
maxcbpage += 1;
|
|
else
|
|
maxcbpage += maxcbpage/2;
|
|
g = FALSE;
|
|
goto ONCE_MORE;
|
|
}
|
|
CEerror("Contiguous blocks exhausted.~%\
|
|
Currently, ~D pages are allocated.~%\
|
|
Use ALLOCATE-CONTIGUOUS-PAGES to expand the space.",
|
|
1, MAKE_FIXNUM(ncbpage));
|
|
g = FALSE;
|
|
goto ONCE_MORE;
|
|
}
|
|
p = alloc_page(m);
|
|
|
|
for (i = 0; i < m; i++)
|
|
type_map[page(p) + i] = (char)t_contiguous;
|
|
ncbpage += m;
|
|
cl_dealloc(p+n, LISP_PAGESIZE*m - n);
|
|
|
|
end_critical_section();
|
|
return(p);
|
|
}
|
|
|
|
/*
|
|
* adds a contblock to the list of available ones, pointed by cb_pointer,
|
|
* sorted by increasing size.
|
|
*/
|
|
void
|
|
cl_dealloc(void *p, cl_index s)
|
|
{
|
|
struct contblock **cbpp, *cbp;
|
|
|
|
if (s < CBMINSIZE)
|
|
return;
|
|
ncb++;
|
|
cbp = (struct contblock *)p;
|
|
cbp->cb_size = s;
|
|
for (cbpp = &cb_pointer; *cbpp != NULL; cbpp = &((*cbpp)->cb_link))
|
|
if ((*cbpp)->cb_size >= s) {
|
|
cbp->cb_link = *cbpp;
|
|
*cbpp = cbp;
|
|
return;
|
|
}
|
|
cbp->cb_link = NULL;
|
|
*cbpp = cbp;
|
|
}
|
|
|
|
/*
|
|
* align must be a power of 2 representing the alignment boundary
|
|
* required for the block.
|
|
*/
|
|
void *
|
|
cl_alloc_align(cl_index size, cl_index align)
|
|
{
|
|
void *output;
|
|
start_critical_section();
|
|
align--;
|
|
output = (void*)(((cl_index)cl_alloc(size + align) + align - 1) & ~align)
|
|
end_critical_section();
|
|
return output;
|
|
}
|
|
|
|
static void
|
|
init_tm(cl_type t, char *name, cl_index elsize, cl_index maxpage)
|
|
{
|
|
int i, j;
|
|
struct typemanager *tm = &tm_table[(int)t];
|
|
|
|
tm->tm_name = name;
|
|
for (i = (int)t_start, j = i-1; i < (int)t_end; i++)
|
|
if (tm_table[i].tm_size >= elsize &&
|
|
(j < (int)t_start || tm_table[j].tm_size > tm_table[i].tm_size))
|
|
j = i;
|
|
if (j >= (int)t_start) {
|
|
tm->tm_type = (cl_type)j;
|
|
tm_table[j].tm_maxpage += maxpage;
|
|
return;
|
|
}
|
|
tm->tm_type = t;
|
|
tm->tm_size = round_up(elsize);
|
|
tm->tm_nppage = LISP_PAGESIZE/round_up(elsize);
|
|
tm->tm_free = OBJNULL;
|
|
tm->tm_nfree = 0;
|
|
tm->tm_nused = 0;
|
|
tm->tm_npage = 0;
|
|
tm->tm_maxpage = maxpage;
|
|
tm->tm_gccount = 0;
|
|
}
|
|
|
|
static int alloc_initialized = FALSE;
|
|
|
|
void
|
|
init_alloc(void)
|
|
{
|
|
cl_index i;
|
|
|
|
if (alloc_initialized) return;
|
|
alloc_initialized = TRUE;
|
|
|
|
holepage = 0;
|
|
new_holepage = HOLEPAGE;
|
|
|
|
#ifdef USE_MMAP
|
|
real_maxpage = MAXPAGE;
|
|
#elif defined(MSDOS) || defined(__CYGWIN__)
|
|
real_maxpage = MAXPAGE;
|
|
#elif defined(BSD)
|
|
{
|
|
struct rlimit data_rlimit;
|
|
# ifdef __MACH__
|
|
sbrk(0);
|
|
getrlimit(RLIMIT_DATA, &data_rlimit);
|
|
real_maxpage = ((unsigned)get_etext() +
|
|
(unsigned)data_rlimit.rlim_cur)/LISP_PAGESIZE;
|
|
# else
|
|
extern etext;
|
|
|
|
getrlimit(RLIMIT_DATA, &data_rlimit);
|
|
real_maxpage = ((unsigned int)&etext +
|
|
(unsigned)data_rlimit.rlim_cur)/LISP_PAGESIZE;
|
|
# endif
|
|
if (real_maxpage > MAXPAGE) real_maxpage = MAXPAGE;
|
|
}
|
|
#elif defined(SYSV)
|
|
real_maxpage= ulimit(UL_GMEMLIM)/LISP_PAGESIZE;
|
|
if (real_maxpage > MAXPAGE) real_maxpage = MAXPAGE;
|
|
#endif /* USE_MMAP, MSDOS, BSD or SYSV */
|
|
|
|
#ifdef USE_MMAP
|
|
heap_start = NULL;
|
|
#else
|
|
heap_end = sbrk(0);
|
|
i = (int)heap_end & (LISP_PAGESIZE - 1);
|
|
if (i)
|
|
sbrk(LISP_PAGESIZE - i);
|
|
heap_end = heap_start = data_end = sbrk(0);
|
|
#endif
|
|
cl_resize_hole(INIT_HOLEPAGE);
|
|
for (i = 0; i < MAXPAGE; i++)
|
|
type_map[i] = (char)t_other;
|
|
|
|
/* Initialization must be done in increasing size order: */
|
|
init_tm(t_shortfloat, "FSHORT-FLOAT", /* 8 */
|
|
sizeof(struct shortfloat_struct), 1);
|
|
init_tm(t_cons, ".CONS", sizeof(struct cons), 384); /* 12 */
|
|
init_tm(t_longfloat, "LLONG-FLOAT", /* 16 */
|
|
sizeof(struct longfloat_struct), 1);
|
|
init_tm(t_bytecodes, "bBYTECODES", sizeof(struct bytecodes), 64);
|
|
init_tm(t_string, "\"STRING", sizeof(struct string), 64); /* 20 */
|
|
init_tm(t_array, "aARRAY", sizeof(struct array), 64); /* 24 */
|
|
init_tm(t_pathname, "pPATHNAME", sizeof(struct pathname), 1); /* 28 */
|
|
init_tm(t_symbol, "|SYMBOL", sizeof(struct symbol), 64); /* 32 */
|
|
init_tm(t_package, ":PACKAGE", sizeof(struct package), 1); /* 36 */
|
|
init_tm(t_codeblock, "#CODEBLOCK", sizeof(struct codeblock), 1);
|
|
init_tm(t_bignum, "BBIGNUM", sizeof(struct bignum), 16);
|
|
init_tm(t_ratio, "RRATIO", sizeof(struct ratio), 1);
|
|
init_tm(t_complex, "CCOMPLEX", sizeof(struct complex), 1);
|
|
init_tm(t_hashtable, "hHASH-TABLE", sizeof(struct hashtable), 1);
|
|
init_tm(t_vector, "vVECTOR", sizeof(struct vector), 2);
|
|
init_tm(t_bitvector, "bBIT-VECTOR", sizeof(struct vector), 1);
|
|
init_tm(t_stream, "sSTREAM", sizeof(struct stream), 1);
|
|
init_tm(t_random, "$RANDOM-STATE", sizeof(struct random), 1);
|
|
init_tm(t_readtable, "rREADTABLE", sizeof(struct readtable), 1);
|
|
init_tm(t_cfun, "fCFUN", sizeof(struct cfun), 32);
|
|
init_tm(t_cclosure, "cCCLOSURE", sizeof(struct cclosure), 1);
|
|
#ifndef CLOS
|
|
init_tm(t_structure, "SSTRUCTURE", sizeof(struct structure), 32);
|
|
#else
|
|
init_tm(t_instance, "IINSTANCE", sizeof(struct instance), 32);
|
|
init_tm(t_gfun, "GGFUN", sizeof(struct gfun), 32);
|
|
#endif /* CLOS */
|
|
#ifdef THREADS
|
|
init_tm(t_cont, "?CONT", sizeof(struct cont), 2);
|
|
init_tm(t_thread, "tTHREAD", sizeof(struct thread), 2);
|
|
#endif /* THREADS */
|
|
|
|
ncb = 0;
|
|
ncbpage = 0;
|
|
#ifdef THREADS
|
|
maxcbpage = 2048;
|
|
#else
|
|
maxcbpage = 512;
|
|
#endif /* THREADS */
|
|
|
|
#ifdef NEED_MALLOC
|
|
malloc_list = Cnil;
|
|
ecl_register_static_root(&malloc_list);
|
|
#endif
|
|
}
|
|
|
|
static int
|
|
t_from_type(cl_object type)
|
|
{ int t;
|
|
|
|
type = cl_string(type);
|
|
for (t = (int)t_start ; t < (int)t_end ; t++) {
|
|
struct typemanager *tm = &tm_table[t];
|
|
if (tm->tm_name &&
|
|
strncmp((tm->tm_name)+1, type->string.self, type->string.fillp) == 0)
|
|
return(t);
|
|
}
|
|
FEerror("Unrecognized type", 0);
|
|
}
|
|
|
|
@(defun si::allocate (type qty &optional (now Cnil))
|
|
struct typemanager *tm;
|
|
cl_ptr pp;
|
|
cl_index i;
|
|
@
|
|
tm = tm_of(t_from_type(type));
|
|
i = fixnnint(qty);
|
|
if (tm->tm_npage > i) i = tm->tm_npage;
|
|
tm->tm_maxpage = i;
|
|
if (now == Cnil || tm->tm_maxpage <= tm->tm_npage)
|
|
@(return Ct)
|
|
if (available_pages() < tm->tm_maxpage - tm->tm_npage ||
|
|
(pp = alloc_page(tm->tm_maxpage - tm->tm_npage)) == NULL)
|
|
FEerror("Can't allocate ~D pages for ~A.", 2, type,
|
|
make_simple_string(tm->tm_name+1));
|
|
for (; tm->tm_npage < tm->tm_maxpage; pp += LISP_PAGESIZE)
|
|
add_page_to_freelist(pp, tm);
|
|
@(return Ct)
|
|
@)
|
|
|
|
@(defun si::maximum-allocatable-pages (type)
|
|
@
|
|
@(return MAKE_FIXNUM(tm_of(t_from_type(type))->tm_maxpage))
|
|
@)
|
|
|
|
@(defun si::allocated-pages (type)
|
|
@
|
|
@(return MAKE_FIXNUM(tm_of(t_from_type(type))->tm_npage))
|
|
@)
|
|
|
|
@(defun si::allocate-contiguous-pages (qty &optional (now Cnil))
|
|
cl_index i, m;
|
|
cl_ptr p;
|
|
@
|
|
i = fixnnint(qty);
|
|
if (ncbpage > i)
|
|
FEerror("Can't set the limit for contiguous blocks to ~D,~%\
|
|
since ~D pages are already allocated.",
|
|
2, qty, MAKE_FIXNUM(ncbpage));
|
|
maxcbpage = i;
|
|
if (Null(now))
|
|
@(return Ct)
|
|
m = maxcbpage - ncbpage;
|
|
if (available_pages() < m || (p = alloc_page(m)) == NULL)
|
|
FEerror("Can't allocate ~D pages for contiguous blocks.",
|
|
1, qty);
|
|
for (i = 0; i < m; i++)
|
|
type_map[page(p + LISP_PAGESIZE*i)] = (char)t_contiguous;
|
|
ncbpage += m;
|
|
cl_dealloc(p, LISP_PAGESIZE*m);
|
|
@(return Ct)
|
|
@)
|
|
|
|
@(defun si::allocated-contiguous-pages ()
|
|
@
|
|
@(return MAKE_FIXNUM(ncbpage))
|
|
@)
|
|
|
|
@(defun si::maximum-contiguous-pages ()
|
|
@
|
|
@(return MAKE_FIXNUM(maxcbpage))
|
|
@)
|
|
|
|
@(defun si::get_hole_size ()
|
|
@
|
|
@(return MAKE_FIXNUM(new_holepage))
|
|
@)
|
|
|
|
@(defun si::set_hole_size (size)
|
|
cl_index i;
|
|
@
|
|
i = fixnnint(size);
|
|
if (i == 0 || i > available_pages() + new_holepage)
|
|
FEerror("Illegal value for the hole size.", 0);
|
|
new_holepage = i;
|
|
@(return size)
|
|
@)
|
|
|
|
@(defun si::ignore_maximum_pages (&optional (flag OBJNULL))
|
|
@
|
|
if (flag == OBJNULL)
|
|
@(return (ignore_maximum_pages? Ct : Cnil))
|
|
ignore_maximum_pages = Null(flag);
|
|
@(return flag)
|
|
@)
|
|
|
|
void
|
|
init_alloc_function(void)
|
|
{
|
|
ignore_maximum_pages = TRUE;
|
|
}
|
|
|
|
#ifdef NEED_MALLOC
|
|
/*
|
|
UNIX malloc simulator.
|
|
|
|
Used by
|
|
getwd, popen, etc.
|
|
*/
|
|
|
|
#undef malloc
|
|
#undef calloc
|
|
#undef free
|
|
#undef cfree
|
|
#undef realloc
|
|
|
|
void *
|
|
malloc(size_t size)
|
|
{
|
|
cl_object x;
|
|
|
|
if (!GC_enabled() && !alloc_initialized)
|
|
init_alloc();
|
|
|
|
x = alloc_simple_string(size-1);
|
|
x->string.self = (char *)cl_alloc(size);
|
|
malloc_list = make_cons(x, malloc_list);
|
|
return(x->string.self);
|
|
}
|
|
|
|
void
|
|
free(void *ptr)
|
|
{
|
|
cl_object *p;
|
|
|
|
if (ptr) {
|
|
for (p = &malloc_list; !endp(*p); p = &(CDR((*p))))
|
|
if ((CAR((*p)))->string.self == ptr) {
|
|
cl_dealloc(CAR((*p))->string.self, CAR((*p))->string.dim+1);
|
|
CAR((*p))->string.self = NULL;
|
|
*p = CDR((*p));
|
|
return;
|
|
}
|
|
FEerror("free(3) error.", 0);
|
|
}
|
|
}
|
|
|
|
void *
|
|
realloc(void *ptr, size_t size)
|
|
{
|
|
cl_object x;
|
|
size_t i, j;
|
|
|
|
if (ptr == NULL)
|
|
return malloc(size);
|
|
for (x = malloc_list; !endp(x); x = CDR(x))
|
|
if (CAR(x)->string.self == ptr) {
|
|
x = CAR(x);
|
|
if (x->string.dim >= size) {
|
|
x->string.fillp = size;
|
|
return(ptr);
|
|
} else {
|
|
j = x->string.dim;
|
|
x->string.self = (char *)cl_alloc(size);
|
|
x->string.fillp = x->string.dim = size;
|
|
memcpy(x->string.self, ptr, j);
|
|
cl_dealloc(ptr, j);
|
|
return(x->string.self);
|
|
}
|
|
}
|
|
FEerror("realloc(3) error.", 0);
|
|
}
|
|
|
|
void *
|
|
calloc(size_t nelem, size_t elsize)
|
|
{
|
|
char *ptr;
|
|
size_t i = nelem*elsize;
|
|
ptr = malloc(i);
|
|
memset(ptr, 0 , i);
|
|
return(ptr);
|
|
}
|
|
|
|
void cfree(void *ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
/* make f allocate enough extra, so that we can round
|
|
up, the address given to an even multiple. Special
|
|
case of size == 0 , in which case we just want an aligned
|
|
number in the address range
|
|
*/
|
|
|
|
#define ALLOC_ALIGNED(f, size, align) \
|
|
((align) <= 4 ? (int)(f)(size) : \
|
|
((align) * (((unsigned)(f)(size + (size ? (align) - 1 : 0)) + (align) - 1)/(align))))
|
|
|
|
void *
|
|
memalign(size_t align, size_t size)
|
|
{ cl_object x = alloc_simple_string(size);
|
|
malloc_list = make_cons(x, malloc_list);
|
|
return x->string.self;
|
|
}
|
|
|
|
# ifdef WANT_VALLOC
|
|
char *
|
|
valloc(size_t size)
|
|
{ return memalign(getpagesize(), size);}
|
|
# endif /* WANT_VALLOC */
|
|
#endif /* NEED_MALLOC */
|