1995-08-09 08:06:35 -07:00
|
|
|
/***********************************************************************/
|
|
|
|
/* */
|
2011-07-27 07:17:02 -07:00
|
|
|
/* OCaml */
|
1995-08-09 08:06:35 -07:00
|
|
|
/* */
|
|
|
|
/* Damien Doligez, projet Para, INRIA Rocquencourt */
|
|
|
|
/* */
|
1996-04-30 07:53:58 -07:00
|
|
|
/* Copyright 1996 Institut National de Recherche en Informatique et */
|
1999-11-17 10:59:06 -08:00
|
|
|
/* en Automatique. All rights reserved. This file is distributed */
|
2001-12-07 05:41:02 -08:00
|
|
|
/* under the terms of the GNU Library General Public License, with */
|
|
|
|
/* the special exception on linking described in file ../LICENSE. */
|
1995-08-09 08:06:35 -07:00
|
|
|
/* */
|
|
|
|
/***********************************************************************/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
2008-12-03 10:09:09 -08:00
|
|
|
#define FREELIST_DEBUG 0
|
|
|
|
#if FREELIST_DEBUG
|
|
|
|
#include <stdio.h>
|
|
|
|
#endif
|
|
|
|
|
2008-02-29 04:56:15 -08:00
|
|
|
#include <string.h>
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
#include "config.h"
|
|
|
|
#include "freelist.h"
|
|
|
|
#include "gc.h"
|
|
|
|
#include "gc_ctrl.h"
|
2008-01-03 01:37:10 -08:00
|
|
|
#include "memory.h"
|
1995-05-04 03:15:53 -07:00
|
|
|
#include "major_gc.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "mlvalues.h"
|
|
|
|
|
|
|
|
/* The free-list is kept sorted by increasing addresses.
|
|
|
|
This makes the merging of adjacent free blocks possible.
|
2004-01-02 11:23:29 -08:00
|
|
|
(See [caml_fl_merge_block].)
|
1995-05-04 03:15:53 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
char *next_bp; /* Pointer to the first byte of the next block. */
|
|
|
|
} block;
|
|
|
|
|
|
|
|
/* The sentinel can be located anywhere in memory, but it must not be
|
|
|
|
adjacent to any heap object. */
|
|
|
|
static struct {
|
|
|
|
value filler1; /* Make sure the sentinel is never adjacent to any block. */
|
|
|
|
header_t h;
|
|
|
|
value first_bp;
|
|
|
|
value filler2; /* Make sure the sentinel is never adjacent to any block. */
|
2000-01-02 08:10:00 -08:00
|
|
|
} sentinel = {0, Make_header (0, 0, Caml_blue), 0, 0};
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
#define Fl_head ((char *) (&(sentinel.first_bp)))
|
2008-12-03 10:09:09 -08:00
|
|
|
static char *fl_prev = Fl_head; /* Current allocation pointer. */
|
1995-05-04 03:15:53 -07:00
|
|
|
static char *fl_last = NULL; /* Last block in the list. Only valid
|
2004-01-02 11:23:29 -08:00
|
|
|
just after [caml_fl_allocate] returns NULL. */
|
|
|
|
char *caml_fl_merge = Fl_head; /* Current insertion pointer. Managed
|
1995-05-04 03:15:53 -07:00
|
|
|
jointly with [sweep_slice]. */
|
2004-01-02 11:23:29 -08:00
|
|
|
asize_t caml_fl_cur_size = 0; /* Number of words in the free list,
|
2002-05-28 09:57:31 -07:00
|
|
|
including headers but not fragments. */
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2008-02-29 04:56:15 -08:00
|
|
|
#define FLP_MAX 1000
|
|
|
|
static char *flp [FLP_MAX];
|
|
|
|
static int flp_size = 0;
|
|
|
|
static char *beyond = NULL;
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
#define Next(b) (((block *) (b))->next_bp)
|
|
|
|
|
2008-12-03 10:09:09 -08:00
|
|
|
#define Policy_next_fit 0
|
|
|
|
#define Policy_first_fit 1
|
|
|
|
uintnat caml_allocation_policy = Policy_next_fit;
|
|
|
|
#define policy caml_allocation_policy
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
#ifdef DEBUG
|
2004-01-02 11:23:29 -08:00
|
|
|
static void fl_check (void)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
char *cur, *prev;
|
2008-12-03 10:09:09 -08:00
|
|
|
int prev_found = 0, flp_found = 0, merge_found = 0;
|
2005-09-22 07:21:50 -07:00
|
|
|
uintnat size_found = 0;
|
2008-02-29 04:56:15 -08:00
|
|
|
int sz = 0;
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
prev = Fl_head;
|
|
|
|
cur = Next (prev);
|
|
|
|
while (cur != NULL){
|
2002-05-28 09:57:31 -07:00
|
|
|
size_found += Whsize_bp (cur);
|
1995-05-04 03:15:53 -07:00
|
|
|
Assert (Is_in_heap (cur));
|
2008-12-03 10:09:09 -08:00
|
|
|
if (cur == fl_prev) prev_found = 1;
|
|
|
|
if (policy == Policy_first_fit && Wosize_bp (cur) > sz){
|
2008-02-29 04:56:15 -08:00
|
|
|
sz = Wosize_bp (cur);
|
|
|
|
if (flp_found < flp_size){
|
|
|
|
Assert (Next (flp[flp_found]) == cur);
|
|
|
|
++ flp_found;
|
|
|
|
}else{
|
|
|
|
Assert (beyond == NULL || cur >= Next (beyond));
|
|
|
|
}
|
|
|
|
}
|
2004-01-02 11:23:29 -08:00
|
|
|
if (cur == caml_fl_merge) merge_found = 1;
|
1995-05-04 03:15:53 -07:00
|
|
|
prev = cur;
|
|
|
|
cur = Next (prev);
|
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
if (policy == Policy_next_fit) Assert (prev_found || fl_prev == Fl_head);
|
|
|
|
if (policy == Policy_first_fit) Assert (flp_found == flp_size);
|
2004-01-02 11:23:29 -08:00
|
|
|
Assert (merge_found || caml_fl_merge == Fl_head);
|
|
|
|
Assert (size_found == caml_fl_cur_size);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
2008-02-29 06:21:22 -08:00
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
#endif
|
|
|
|
|
2004-01-02 11:23:29 -08:00
|
|
|
/* [allocate_block] is called by [caml_fl_allocate]. Given a suitable free
|
1995-05-04 03:15:53 -07:00
|
|
|
block and the desired size, it allocates a new block from the free
|
|
|
|
block. There are three cases:
|
|
|
|
0. The free block has the desired size. Detach the block from the
|
|
|
|
free-list and return it.
|
|
|
|
1. The free block is 1 word longer than the desired size. Detach
|
|
|
|
the block from the free list. The remaining word cannot be linked:
|
|
|
|
turn it into an empty block (header only), and return the rest.
|
|
|
|
2. The free block is big enough. Split it in two and return the right
|
|
|
|
block.
|
|
|
|
In all cases, the allocated block is right-justified in the free block:
|
|
|
|
it is located in the high-address words of the free block. This way,
|
|
|
|
the linking of the free-list does not change in case 2.
|
|
|
|
*/
|
2008-02-29 04:56:15 -08:00
|
|
|
static char *allocate_block (mlsize_t wh_sz, int flpi, char *prev, char *cur)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
header_t h = Hd_bp (cur);
|
|
|
|
Assert (Whsize_hd (h) >= wh_sz);
|
|
|
|
if (Wosize_hd (h) < wh_sz + 1){ /* Cases 0 and 1. */
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_fl_cur_size -= Whsize_hd (h);
|
1995-05-04 03:15:53 -07:00
|
|
|
Next (prev) = Next (cur);
|
|
|
|
Assert (Is_in_heap (Next (prev)) || Next (prev) == NULL);
|
2004-01-02 11:23:29 -08:00
|
|
|
if (caml_fl_merge == cur) caml_fl_merge = prev;
|
1995-05-04 03:15:53 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
fl_last = NULL;
|
|
|
|
#endif
|
|
|
|
/* In case 1, the following creates the empty block correctly.
|
|
|
|
In case 0, it gives an invalid header to the block. The function
|
2004-01-02 11:23:29 -08:00
|
|
|
calling [caml_fl_allocate] will overwrite it. */
|
2000-01-02 08:10:00 -08:00
|
|
|
Hd_op (cur) = Make_header (0, 0, Caml_white);
|
2008-12-03 10:09:09 -08:00
|
|
|
if (policy == Policy_first_fit){
|
|
|
|
if (flpi + 1 < flp_size && flp[flpi + 1] == cur){
|
|
|
|
flp[flpi + 1] = prev;
|
|
|
|
}else if (flpi == flp_size - 1){
|
|
|
|
beyond = (prev == Fl_head) ? NULL : prev;
|
|
|
|
-- flp_size;
|
|
|
|
}
|
2008-02-29 04:56:15 -08:00
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
}else{ /* Case 2. */
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_fl_cur_size -= wh_sz;
|
2000-01-02 08:10:00 -08:00
|
|
|
Hd_op (cur) = Make_header (Wosize_hd (h) - wh_sz, 0, Caml_blue);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
if (policy == Policy_next_fit) fl_prev = prev;
|
1995-05-04 03:15:53 -07:00
|
|
|
return cur + Bosize_hd (h) - Bsize_wsize (wh_sz);
|
2008-02-29 04:56:15 -08:00
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2004-01-02 11:23:29 -08:00
|
|
|
/* [caml_fl_allocate] does not set the header of the newly allocated block.
|
1995-05-04 03:15:53 -07:00
|
|
|
The calling function must do it before any GC function gets called.
|
2004-01-02 11:23:29 -08:00
|
|
|
[caml_fl_allocate] returns a head pointer.
|
1995-05-04 03:15:53 -07:00
|
|
|
*/
|
2004-01-02 11:23:29 -08:00
|
|
|
char *caml_fl_allocate (mlsize_t wo_sz)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
2008-02-29 04:56:15 -08:00
|
|
|
char *cur = NULL, *prev, *result;
|
|
|
|
int i;
|
|
|
|
mlsize_t sz, prevsz;
|
1995-05-04 03:15:53 -07:00
|
|
|
Assert (sizeof (char *) == sizeof (value));
|
|
|
|
Assert (wo_sz >= 1);
|
2008-12-03 10:09:09 -08:00
|
|
|
switch (policy){
|
|
|
|
case Policy_next_fit:
|
|
|
|
Assert (fl_prev != NULL);
|
|
|
|
/* Search from [fl_prev] to the end of the list. */
|
|
|
|
prev = fl_prev;
|
|
|
|
cur = Next (prev);
|
|
|
|
while (cur != NULL){ Assert (Is_in_heap (cur));
|
|
|
|
if (Wosize_bp (cur) >= wo_sz){
|
|
|
|
return allocate_block (Whsize_wosize (wo_sz), 0, prev, cur);
|
|
|
|
}
|
|
|
|
prev = cur;
|
|
|
|
cur = Next (prev);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
fl_last = prev;
|
|
|
|
/* Search from the start of the list to [fl_prev]. */
|
2008-02-29 04:56:15 -08:00
|
|
|
prev = Fl_head;
|
1995-05-04 03:15:53 -07:00
|
|
|
cur = Next (prev);
|
2008-12-03 10:09:09 -08:00
|
|
|
while (prev != fl_prev){
|
|
|
|
if (Wosize_bp (cur) >= wo_sz){
|
|
|
|
return allocate_block (Whsize_wosize (wo_sz), 0, prev, cur);
|
2008-02-29 04:56:15 -08:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
prev = cur;
|
|
|
|
cur = Next (prev);
|
2008-02-29 04:56:15 -08:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
/* No suitable block was found. */
|
|
|
|
return NULL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Policy_first_fit: {
|
|
|
|
/* Search in the flp array. */
|
|
|
|
for (i = 0; i < flp_size; i++){
|
|
|
|
sz = Wosize_bp (Next (flp[i]));
|
|
|
|
if (sz >= wo_sz){
|
|
|
|
#if FREELIST_DEBUG
|
|
|
|
if (i > 5) fprintf (stderr, "FLP: found at %d size=%d\n", i, wo_sz);
|
|
|
|
#endif
|
|
|
|
result = allocate_block (Whsize_wosize (wo_sz), i, flp[i], Next(flp[i]));
|
|
|
|
goto update_flp;
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
/* Extend the flp array. */
|
|
|
|
if (flp_size == 0){
|
|
|
|
prev = Fl_head;
|
2008-02-29 04:56:15 -08:00
|
|
|
prevsz = 0;
|
2008-12-03 10:09:09 -08:00
|
|
|
}else{
|
|
|
|
prev = Next (flp[flp_size - 1]);
|
|
|
|
prevsz = Wosize_bp (prev);
|
|
|
|
if (beyond != NULL) prev = beyond;
|
2008-02-29 04:56:15 -08:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
while (flp_size < FLP_MAX){
|
|
|
|
cur = Next (prev);
|
|
|
|
if (cur == NULL){
|
|
|
|
fl_last = prev;
|
|
|
|
beyond = (prev == Fl_head) ? NULL : prev;
|
|
|
|
return NULL;
|
2008-02-29 04:56:15 -08:00
|
|
|
}else{
|
|
|
|
sz = Wosize_bp (cur);
|
|
|
|
if (sz > prevsz){
|
2008-12-03 10:09:09 -08:00
|
|
|
flp[flp_size] = prev;
|
|
|
|
++ flp_size;
|
|
|
|
if (sz >= wo_sz){
|
|
|
|
beyond = cur;
|
|
|
|
i = flp_size - 1;
|
|
|
|
#if FREELIST_DEBUG
|
|
|
|
if (flp_size > 5){
|
|
|
|
fprintf (stderr, "FLP: extended to %d\n", flp_size);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
result = allocate_block (Whsize_wosize (wo_sz), flp_size - 1, prev,
|
|
|
|
cur);
|
|
|
|
goto update_flp;
|
2008-02-29 04:56:15 -08:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
prevsz = sz;
|
2008-02-29 04:56:15 -08:00
|
|
|
}
|
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
prev = cur;
|
|
|
|
}
|
|
|
|
beyond = cur;
|
|
|
|
|
|
|
|
/* The flp table is full. Do a slow first-fit search. */
|
|
|
|
#if FREELIST_DEBUG
|
|
|
|
fprintf (stderr, "FLP: table is full -- slow first-fit\n");
|
|
|
|
#endif
|
|
|
|
if (beyond != NULL){
|
|
|
|
prev = beyond;
|
|
|
|
}else{
|
|
|
|
prev = flp[flp_size - 1];
|
|
|
|
}
|
|
|
|
prevsz = Wosize_bp (Next (flp[FLP_MAX-1]));
|
|
|
|
Assert (prevsz < wo_sz);
|
|
|
|
cur = Next (prev);
|
|
|
|
while (cur != NULL){
|
|
|
|
Assert (Is_in_heap (cur));
|
|
|
|
sz = Wosize_bp (cur);
|
|
|
|
if (sz < prevsz){
|
|
|
|
beyond = cur;
|
|
|
|
}else if (sz >= wo_sz){
|
|
|
|
return allocate_block (Whsize_wosize (wo_sz), flp_size, prev, cur);
|
|
|
|
}
|
|
|
|
prev = cur;
|
|
|
|
cur = Next (prev);
|
|
|
|
}
|
|
|
|
fl_last = prev;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
update_flp: /* (i, sz) */
|
|
|
|
/* The block at [i] was removed or reduced. Update the table. */
|
|
|
|
Assert (0 <= i && i < flp_size + 1);
|
|
|
|
if (i < flp_size){
|
|
|
|
if (i > 0){
|
|
|
|
prevsz = Wosize_bp (Next (flp[i-1]));
|
|
|
|
}else{
|
|
|
|
prevsz = 0;
|
|
|
|
}
|
|
|
|
if (i == flp_size - 1){
|
|
|
|
if (Wosize_bp (Next (flp[i])) <= prevsz){
|
|
|
|
beyond = Next (flp[i]);
|
|
|
|
-- flp_size;
|
|
|
|
}else{
|
|
|
|
beyond = NULL;
|
|
|
|
}
|
2008-02-29 04:56:15 -08:00
|
|
|
}else{
|
2008-12-03 10:09:09 -08:00
|
|
|
char *buf [FLP_MAX];
|
|
|
|
int j = 0;
|
|
|
|
mlsize_t oldsz = sz;
|
|
|
|
|
|
|
|
prev = flp[i];
|
|
|
|
while (prev != flp[i+1]){
|
|
|
|
cur = Next (prev);
|
|
|
|
sz = Wosize_bp (cur);
|
|
|
|
if (sz > prevsz){
|
|
|
|
buf[j++] = prev;
|
|
|
|
prevsz = sz;
|
|
|
|
if (sz >= oldsz){
|
|
|
|
Assert (sz == oldsz);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
prev = cur;
|
|
|
|
}
|
|
|
|
#if FREELIST_DEBUG
|
|
|
|
if (j > 2) fprintf (stderr, "FLP: update; buf size = %d\n", j);
|
|
|
|
#endif
|
|
|
|
if (FLP_MAX >= flp_size + j - 1){
|
|
|
|
if (j != 1){
|
|
|
|
memmove (&flp[i+j], &flp[i+1], sizeof (block *) * (flp_size-i-1));
|
|
|
|
}
|
|
|
|
if (j > 0) memmove (&flp[i], &buf[0], sizeof (block *) * j);
|
|
|
|
flp_size += j - 1;
|
2008-02-29 04:56:15 -08:00
|
|
|
}else{
|
2008-12-03 10:09:09 -08:00
|
|
|
if (FLP_MAX > i + j){
|
|
|
|
if (j != 1){
|
|
|
|
memmove (&flp[i+j], &flp[i+1], sizeof (block *) * (FLP_MAX-i-j));
|
|
|
|
}
|
|
|
|
if (j > 0) memmove (&flp[i], &buf[0], sizeof (block *) * j);
|
|
|
|
}else{
|
|
|
|
if (i != FLP_MAX){
|
|
|
|
memmove (&flp[i], &buf[0], sizeof (block *) * (FLP_MAX - i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
flp_size = FLP_MAX - 1;
|
|
|
|
beyond = Next (flp[FLP_MAX - 1]);
|
2008-02-29 04:56:15 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Assert (0); /* unknown policy */
|
|
|
|
break;
|
2008-02-29 04:56:15 -08:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
return NULL; /* NOT REACHED */
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
|
1997-05-21 08:28:15 -07:00
|
|
|
static char *last_fragment;
|
|
|
|
|
2004-01-02 11:23:29 -08:00
|
|
|
void caml_fl_init_merge (void)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
1997-05-21 08:28:15 -07:00
|
|
|
last_fragment = NULL;
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_fl_merge = Fl_head;
|
1995-08-08 06:37:34 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
fl_check ();
|
|
|
|
#endif
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
|
2008-02-29 04:56:15 -08:00
|
|
|
static void truncate_flp (char *changed)
|
|
|
|
{
|
|
|
|
if (changed == Fl_head){
|
|
|
|
flp_size = 0;
|
|
|
|
beyond = NULL;
|
|
|
|
}else{
|
|
|
|
while (flp_size > 0 && Next (flp[flp_size - 1]) >= changed) -- flp_size;
|
|
|
|
if (beyond >= changed) beyond = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-31 06:20:40 -08:00
|
|
|
/* This is called by caml_compact_heap. */
|
2004-01-02 11:23:29 -08:00
|
|
|
void caml_fl_reset (void)
|
1997-05-13 07:45:38 -07:00
|
|
|
{
|
2008-02-29 04:56:15 -08:00
|
|
|
Next (Fl_head) = NULL;
|
2008-12-03 10:09:09 -08:00
|
|
|
switch (policy){
|
|
|
|
case Policy_next_fit:
|
|
|
|
fl_prev = Fl_head;
|
|
|
|
break;
|
|
|
|
case Policy_first_fit:
|
|
|
|
truncate_flp (Fl_head);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Assert (0);
|
|
|
|
break;
|
|
|
|
}
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_fl_cur_size = 0;
|
|
|
|
caml_fl_init_merge ();
|
1997-05-13 07:45:38 -07:00
|
|
|
}
|
|
|
|
|
2004-01-02 11:23:29 -08:00
|
|
|
/* [caml_fl_merge_block] returns the head pointer of the next block after [bp],
|
1995-05-04 03:15:53 -07:00
|
|
|
because merging blocks may change the size of [bp]. */
|
2004-01-02 11:23:29 -08:00
|
|
|
char *caml_fl_merge_block (char *bp)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
char *prev, *cur, *adj;
|
|
|
|
header_t hd = Hd_bp (bp);
|
2002-12-12 10:59:11 -08:00
|
|
|
mlsize_t prev_wosz;
|
1997-05-13 07:45:38 -07:00
|
|
|
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_fl_cur_size += Whsize_hd (hd);
|
2008-02-29 04:56:15 -08:00
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
#ifdef DEBUG
|
2008-02-29 04:56:15 -08:00
|
|
|
caml_set_fields (bp, 0, Debug_free_major);
|
1995-05-04 03:15:53 -07:00
|
|
|
#endif
|
2004-01-02 11:23:29 -08:00
|
|
|
prev = caml_fl_merge;
|
1995-05-04 03:15:53 -07:00
|
|
|
cur = Next (prev);
|
1997-05-21 08:28:15 -07:00
|
|
|
/* The sweep code makes sure that this is the right place to insert
|
|
|
|
this block: */
|
|
|
|
Assert (prev < bp || prev == Fl_head);
|
|
|
|
Assert (cur > bp || cur == NULL);
|
|
|
|
|
2008-12-03 10:09:09 -08:00
|
|
|
if (policy == Policy_first_fit) truncate_flp (prev);
|
2008-02-29 04:56:15 -08:00
|
|
|
|
1997-05-21 08:28:15 -07:00
|
|
|
/* If [last_fragment] and [bp] are adjacent, merge them. */
|
|
|
|
if (last_fragment == Hp_bp (bp)){
|
2002-12-12 10:59:11 -08:00
|
|
|
mlsize_t bp_whsz = Whsize_bp (bp);
|
|
|
|
if (bp_whsz <= Max_wosize){
|
|
|
|
hd = Make_header (bp_whsz, 0, Caml_white);
|
|
|
|
bp = last_fragment;
|
|
|
|
Hd_bp (bp) = hd;
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_fl_cur_size += Whsize_wosize (0);
|
2002-12-12 10:59:11 -08:00
|
|
|
}
|
1997-05-21 08:28:15 -07:00
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
|
1997-05-21 08:28:15 -07:00
|
|
|
/* If [bp] and [cur] are adjacent, remove [cur] from the free-list
|
|
|
|
and merge them. */
|
1995-05-04 03:15:53 -07:00
|
|
|
adj = bp + Bosize_hd (hd);
|
|
|
|
if (adj == Hp_bp (cur)){
|
|
|
|
char *next_cur = Next (cur);
|
2002-12-12 10:59:11 -08:00
|
|
|
mlsize_t cur_whsz = Whsize_bp (cur);
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2002-12-12 10:59:11 -08:00
|
|
|
if (Wosize_hd (hd) + cur_whsz <= Max_wosize){
|
|
|
|
Next (prev) = next_cur;
|
2008-12-03 10:09:09 -08:00
|
|
|
if (policy == Policy_next_fit && fl_prev == cur) fl_prev = prev;
|
2002-12-12 10:59:11 -08:00
|
|
|
hd = Make_header (Wosize_hd (hd) + cur_whsz, 0, Caml_blue);
|
|
|
|
Hd_bp (bp) = hd;
|
|
|
|
adj = bp + Bosize_hd (hd);
|
1995-05-04 03:15:53 -07:00
|
|
|
#ifdef DEBUG
|
2002-12-12 10:59:11 -08:00
|
|
|
fl_last = NULL;
|
|
|
|
Next (cur) = (char *) Debug_free_major;
|
|
|
|
Hd_bp (cur) = Debug_free_major;
|
1995-05-04 03:15:53 -07:00
|
|
|
#endif
|
2002-12-12 10:59:11 -08:00
|
|
|
cur = next_cur;
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
1997-05-21 08:28:15 -07:00
|
|
|
/* If [prev] and [bp] are adjacent merge them, else insert [bp] into
|
|
|
|
the free-list if it is big enough. */
|
2002-12-12 10:59:11 -08:00
|
|
|
prev_wosz = Wosize_bp (prev);
|
|
|
|
if (prev + Bsize_wsize (prev_wosz) == Hp_bp (bp)
|
|
|
|
&& prev_wosz + Whsize_hd (hd) < Max_wosize){
|
|
|
|
Hd_bp (prev) = Make_header (prev_wosz + Whsize_hd (hd), 0,Caml_blue);
|
1995-05-04 03:15:53 -07:00
|
|
|
#ifdef DEBUG
|
2000-04-03 01:34:22 -07:00
|
|
|
Hd_bp (bp) = Debug_free_major;
|
1995-05-04 03:15:53 -07:00
|
|
|
#endif
|
2004-01-02 11:23:29 -08:00
|
|
|
Assert (caml_fl_merge == prev);
|
1995-08-08 06:37:34 -07:00
|
|
|
}else if (Wosize_hd (hd) != 0){
|
1995-05-04 03:15:53 -07:00
|
|
|
Hd_bp (bp) = Bluehd_hd (hd);
|
|
|
|
Next (bp) = cur;
|
|
|
|
Next (prev) = bp;
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_fl_merge = bp;
|
1997-05-21 08:28:15 -07:00
|
|
|
}else{
|
|
|
|
/* This is a fragment. Leave it in white but remember it for eventual
|
|
|
|
merging with the next block. */
|
|
|
|
last_fragment = bp;
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_fl_cur_size -= Whsize_wosize (0);
|
1997-05-21 08:28:15 -07:00
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
return adj;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This is a heap extension. We have to insert it in the right place
|
|
|
|
in the free-list.
|
2008-02-29 04:56:15 -08:00
|
|
|
[caml_fl_add_blocks] can only be called right after a call to
|
2004-01-02 11:23:29 -08:00
|
|
|
[caml_fl_allocate] that returned NULL.
|
1995-05-04 03:15:53 -07:00
|
|
|
Most of the heap extensions are expected to be at the end of the
|
|
|
|
free list. (This depends on the implementation of [malloc].)
|
2008-02-29 04:56:15 -08:00
|
|
|
|
|
|
|
[bp] must point to a list of blocks chained by their field 0,
|
|
|
|
terminated by NULL, and field 1 of the first block must point to
|
|
|
|
the last block.
|
1995-05-04 03:15:53 -07:00
|
|
|
*/
|
2008-02-29 04:56:15 -08:00
|
|
|
void caml_fl_add_blocks (char *bp)
|
1995-05-04 03:15:53 -07:00
|
|
|
{
|
|
|
|
Assert (fl_last != NULL);
|
|
|
|
Assert (Next (fl_last) == NULL);
|
2004-01-02 11:23:29 -08:00
|
|
|
caml_fl_cur_size += Whsize_bp (bp);
|
2002-05-28 09:57:31 -07:00
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
if (bp > fl_last){
|
|
|
|
Next (fl_last) = bp;
|
2008-02-29 04:56:15 -08:00
|
|
|
if (fl_last == caml_fl_merge && bp < caml_gc_sweep_hp){
|
|
|
|
caml_fl_merge = (char *) Field (bp, 1);
|
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
if (policy == Policy_first_fit && flp_size < FLP_MAX){
|
|
|
|
flp [flp_size++] = fl_last;
|
|
|
|
}
|
1995-05-04 03:15:53 -07:00
|
|
|
}else{
|
|
|
|
char *cur, *prev;
|
|
|
|
|
|
|
|
prev = Fl_head;
|
|
|
|
cur = Next (prev);
|
|
|
|
while (cur != NULL && cur < bp){ Assert (prev < bp || prev == Fl_head);
|
2008-02-29 04:56:15 -08:00
|
|
|
/* XXX TODO: extend flp on the fly */
|
1995-05-04 03:15:53 -07:00
|
|
|
prev = cur;
|
|
|
|
cur = Next (prev);
|
|
|
|
} Assert (prev < bp || prev == Fl_head);
|
|
|
|
Assert (cur > bp || cur == NULL);
|
2008-02-29 04:56:15 -08:00
|
|
|
Next (Field (bp, 1)) = cur;
|
1995-05-04 03:15:53 -07:00
|
|
|
Next (prev) = bp;
|
2008-02-29 04:56:15 -08:00
|
|
|
/* When inserting blocks between [caml_fl_merge] and [caml_gc_sweep_hp],
|
2004-01-02 11:23:29 -08:00
|
|
|
we must advance [caml_fl_merge] to the new block, so that [caml_fl_merge]
|
|
|
|
is always the last free-list block before [caml_gc_sweep_hp]. */
|
2008-02-29 04:56:15 -08:00
|
|
|
if (prev == caml_fl_merge && bp < caml_gc_sweep_hp){
|
|
|
|
caml_fl_merge = (char *) Field (bp, 1);
|
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
if (policy == Policy_first_fit) truncate_flp (bp);
|
1995-05-04 03:15:53 -07:00
|
|
|
}
|
|
|
|
}
|
2002-12-12 10:59:11 -08:00
|
|
|
|
|
|
|
/* Cut a block of memory into Max_wosize pieces, give them headers,
|
|
|
|
and optionally merge them into the free list.
|
|
|
|
arguments:
|
|
|
|
p: pointer to the first word of the block
|
|
|
|
size: size of the block (in words)
|
|
|
|
do_merge: 1 -> do merge; 0 -> do not merge
|
|
|
|
*/
|
2004-01-02 11:23:29 -08:00
|
|
|
void caml_make_free_blocks (value *p, mlsize_t size, int do_merge)
|
2002-12-12 10:59:11 -08:00
|
|
|
{
|
|
|
|
mlsize_t sz;
|
|
|
|
|
|
|
|
while (size > 0){
|
|
|
|
if (size > Whsize_wosize (Max_wosize)){
|
|
|
|
sz = Whsize_wosize (Max_wosize);
|
|
|
|
}else{
|
|
|
|
sz = size;
|
|
|
|
}
|
|
|
|
*(header_t *)p = Make_header (Wosize_whsize (sz), 0, Caml_white);
|
2004-01-02 11:23:29 -08:00
|
|
|
if (do_merge) caml_fl_merge_block (Bp_hp (p));
|
2002-12-12 10:59:11 -08:00
|
|
|
size -= sz;
|
|
|
|
p += sz;
|
|
|
|
}
|
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
|
|
|
|
void caml_set_allocation_policy (uintnat p)
|
|
|
|
{
|
|
|
|
switch (p){
|
|
|
|
case Policy_next_fit:
|
|
|
|
fl_prev = Fl_head;
|
|
|
|
break;
|
|
|
|
case Policy_first_fit:
|
|
|
|
flp_size = 0;
|
|
|
|
beyond = NULL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Assert (0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
policy = p;
|
|
|
|
}
|