#include <string.h>#include <stdlib.h>#include "mlvalues.h"#include "debugger.h"#include "fail.h"#include "freelist.h"#include "gc.h"#include "gc_ctrl.h"#include "major_gc.h"#include "memory.h"#include "minor_gc.h"#include "misc.h"value *c_roots_head;/* Allocate more memory from malloc for the heap. Return a block of at least the requested size (in words). Return NULL when out of memory.*/static char *expand_heap (mlsize_t request){ char *mem; char *new_page_table = NULL; asize_t new_page_table_size = 0; asize_t malloc_request; asize_t i, more_pages; malloc_request = round_heap_chunk_size (Bhsize_wosize (request)); gc_message ("Growing heap to %ldk\n", (stat_heap_size + malloc_request) / 1024); mem = aligned_malloc (malloc_request + sizeof (heap_chunk_head), sizeof (heap_chunk_head)); if (mem == NULL){ gc_message ("No room for growing heap\n", 0); return NULL; } mem += sizeof (heap_chunk_head); (((heap_chunk_head *) mem) [-1]).size = malloc_request; Assert (Wosize_bhsize (malloc_request) >= request); Hd_hp (mem) = Make_header (Wosize_bhsize (malloc_request), 0, Blue);#ifndef SIXTEEN if (mem < heap_start){ more_pages = -Page (mem); }else if (Page (mem + malloc_request) > page_table_size){ Assert (mem >= heap_end); more_pages = Page (mem + malloc_request) - page_table_size; }else{ more_pages = 0; } if (more_pages != 0){ new_page_table_size = page_table_size + more_pages; new_page_table = (char *) malloc (new_page_table_size); if (new_page_table == NULL){ gc_message ("No room for growing page table\n", 0); free (mem); return NULL; } } if (mem < heap_start){ Assert (more_pages != 0); for (i = 0; i < more_pages; i++){ new_page_table [i] = Not_in_heap; } bcopy (page_table, new_page_table + more_pages, page_table_size); (((heap_chunk_head *) mem) [-1]).next = heap_start; heap_start = mem; }else{ char **last; char *cur; if (mem >= heap_end) heap_end = mem + malloc_request; if (more_pages != 0){ for (i = page_table_size; i < new_page_table_size; i++){ new_page_table [i] = Not_in_heap; } bcopy (page_table, new_page_table, page_table_size); } last = &heap_start; cur = *last; while (cur != NULL && cur < mem){ last = &((((heap_chunk_head *) cur) [-1]).next); cur = *last; } (((heap_chunk_head *) mem) [-1]).next = cur; *last = mem; } if (more_pages != 0){ free (page_table); page_table = new_page_table; page_table_size = new_page_table_size; }#else /* Simplified version for the 8086 */ { char **last; char *cur; last = &heap_start; cur = *last; while (cur != NULL && (char huge *) cur < (char huge *) mem){ last = &((((heap_chunk_head *) cur) [-1]).next); cur = *last; } (((heap_chunk_head *) mem) [-1]).next = cur; *last = mem; }#endif for (i = Page (mem); i < Page (mem + malloc_request); i++){ page_table [i] = In_heap; } stat_heap_size += malloc_request; return Bp_hp (mem);}EXTERN value alloc_shr (mlsize_t wosize, tag_t tag){ char *hp, *new_block; hp = fl_allocate (wosize); if (hp == NULL){ new_block = expand_heap (wosize); if (new_block == NULL) raise_out_of_memory (); fl_add_block (new_block); hp = fl_allocate (wosize); if (hp == NULL) fatal_error ("alloc_shr: expand heap failed\n"); } Assert (Is_in_heap (Val_hp (hp))); if (gc_phase == Phase_mark || (addr)hp >= (addr)gc_sweep_hp){ Hd_hp (hp) = Make_header (wosize, tag, Black); }else{ Hd_hp (hp) = Make_header (wosize, tag, White); } allocated_words += Whsize_wosize (wosize); if (allocated_words > Wsize_bsize (minor_heap_size)) force_minor_gc (); return Val_hp (hp);}/* Use this function to tell the major GC to speed up when you use finalized objects to automatically deallocate extra-heap objects. The GC will do at least one cycle every [max] allocated words; [mem] is the number of words allocated this time. Note that only [mem/max] is relevant. You can use numbers of bytes (or kilobytes, ...) instead of words. You can change units between calls to [adjust_collector_speed].*/void adjust_gc_speed (mlsize_t mem, mlsize_t max){ if (max == 0) max = 1; if (mem > max) mem = max; extra_heap_memory += ((float) mem / max) * stat_heap_size; if (extra_heap_memory > stat_heap_size){ extra_heap_memory = stat_heap_size; } if (extra_heap_memory > Wsize_bsize (minor_heap_size) / 2) force_minor_gc ();}/* You must use [initialize] to store the initial value in a field of a shared block, unless you are sure the value is not a young block. A block value [v] is a shared block if and only if [Is_in_heap (v)] is true.*//* [initialize] never calls the GC, so you may call it while an object is unfinished (i.e. just after a call to [alloc_shr].) */void initialize (value * fp, value val){ *fp = val; Assert (Is_in_heap (fp)); if (Is_block (val) && Is_young (val)){ *ref_table_ptr++ = fp; if (ref_table_ptr >= ref_table_limit){ realloc_ref_table (); } }}/* You must use [modify] to change a field of an existing shared block, unless you are sure the value being overwritten is not a shared block and the value being written is not a young block. *//* Never calls the GC. */EXTERN void modify (value * fp, value val){ Modify (fp, val);}char *stat_alloc(asize_t sz){ char *result = (char *) malloc (sz); if (result == NULL) raise_out_of_memory (); return result;}void stat_free(char * blk){ free (blk);}char *stat_resize (char * blk, asize_t sz){ char *result = (char *) realloc (blk, sz); if (result == NULL) raise_out_of_memory (); return result;}void init_c_roots (void){ c_roots_head = NULL;}
#include <string.h>
#include <stdlib.h>
#include "mlvalues.h"
#include "debugger.h"
#include "fail.h"
#include "freelist.h"
#include "gc.h"
#include "gc_ctrl.h"
#include "major_gc.h"
#include "memory.h"
#include "minor_gc.h"
#include "misc.h"
value *c_roots_head;
/* Allocate more memory from malloc for the heap.
Return a block of at least the requested size (in words).
Return NULL when out of memory.
*/
static char *expand_heap (mlsize_t request)
{
char *mem;
char *new_page_table = NULL;
asize_t new_page_table_size = 0;
asize_t malloc_request;
asize_t i, more_pages;
malloc_request = round_heap_chunk_size (Bhsize_wosize (request));
gc_message ("Growing heap to %ldk\n",
(stat_heap_size + malloc_request) / 1024);
mem = aligned_malloc (malloc_request + sizeof (heap_chunk_head),
sizeof (heap_chunk_head));
if (mem == NULL){
gc_message ("No room for growing heap\n", 0);
return NULL;
}
mem += sizeof (heap_chunk_head);
(((heap_chunk_head *) mem) [-1]).size = malloc_request;
Assert (Wosize_bhsize (malloc_request) >= request);
Hd_hp (mem) = Make_header (Wosize_bhsize (malloc_request), 0, Blue);
#ifndef SIXTEEN
if (mem < heap_start){
more_pages = -Page (mem);
}else if (Page (mem + malloc_request) > page_table_size){
Assert (mem >= heap_end);
more_pages = Page (mem + malloc_request) - page_table_size;
}else{
more_pages = 0;
}
if (more_pages != 0){
new_page_table_size = page_table_size + more_pages;
new_page_table = (char *) malloc (new_page_table_size);
if (new_page_table == NULL){
gc_message ("No room for growing page table\n", 0);
free (mem);
return NULL;
}
}
if (mem < heap_start){
Assert (more_pages != 0);
for (i = 0; i < more_pages; i++){
new_page_table [i] = Not_in_heap;
}
bcopy (page_table, new_page_table + more_pages, page_table_size);
(((heap_chunk_head *) mem) [-1]).next = heap_start;
heap_start = mem;
}else{
char **last;
char *cur;
if (mem >= heap_end) heap_end = mem + malloc_request;
if (more_pages != 0){
for (i = page_table_size; i < new_page_table_size; i++){
new_page_table [i] = Not_in_heap;
}
bcopy (page_table, new_page_table, page_table_size);
}
last = &heap_start;
cur = *last;
while (cur != NULL && cur < mem){
last = &((((heap_chunk_head *) cur) [-1]).next);
cur = *last;
}
(((heap_chunk_head *) mem) [-1]).next = cur;
*last = mem;
}
if (more_pages != 0){
free (page_table);
page_table = new_page_table;
page_table_size = new_page_table_size;
}
#else /* Simplified version for the 8086 */
{
char **last;
char *cur;
last = &heap_start;
cur = *last;
while (cur != NULL && (char huge *) cur < (char huge *) mem){
last = &((((heap_chunk_head *) cur) [-1]).next);
cur = *last;
}
(((heap_chunk_head *) mem) [-1]).next = cur;
*last = mem;
}
#endif
for (i = Page (mem); i < Page (mem + malloc_request); i++){
page_table [i] = In_heap;
}
stat_heap_size += malloc_request;
return Bp_hp (mem);
}
EXTERN value alloc_shr (mlsize_t wosize, tag_t tag)
{
char *hp, *new_block;
hp = fl_allocate (wosize);
if (hp == NULL){
new_block = expand_heap (wosize);
if (new_block == NULL) raise_out_of_memory ();
fl_add_block (new_block);
hp = fl_allocate (wosize);
if (hp == NULL) fatal_error ("alloc_shr: expand heap failed\n");
}
Assert (Is_in_heap (Val_hp (hp)));
if (gc_phase == Phase_mark || (addr)hp >= (addr)gc_sweep_hp){
Hd_hp (hp) = Make_header (wosize, tag, Black);
}else{
Hd_hp (hp) = Make_header (wosize, tag, White);
}
allocated_words += Whsize_wosize (wosize);
if (allocated_words > Wsize_bsize (minor_heap_size)) force_minor_gc ();
return Val_hp (hp);
}
/* Use this function to tell the major GC to speed up when you use
finalized objects to automatically deallocate extra-heap objects.
The GC will do at least one cycle every [max] allocated words;
[mem] is the number of words allocated this time.
Note that only [mem/max] is relevant. You can use numbers of bytes
(or kilobytes, ...) instead of words. You can change units between
calls to [adjust_collector_speed].
*/
void adjust_gc_speed (mlsize_t mem, mlsize_t max)
{
if (max == 0) max = 1;
if (mem > max) mem = max;
extra_heap_memory += ((float) mem / max) * stat_heap_size;
if (extra_heap_memory > stat_heap_size){
extra_heap_memory = stat_heap_size;
}
if (extra_heap_memory > Wsize_bsize (minor_heap_size) / 2) force_minor_gc ();
}
/* You must use [initialize] to store the initial value in a field of
a shared block, unless you are sure the value is not a young block.
A block value [v] is a shared block if and only if [Is_in_heap (v)]
is true.
*/
/* [initialize] never calls the GC, so you may call it while an object is
unfinished (i.e. just after a call to [alloc_shr].) */
void initialize (value * fp, value val)
{
*fp = val;
Assert (Is_in_heap (fp));
if (Is_block (val) && Is_young (val)){
*ref_table_ptr++ = fp;
if (ref_table_ptr >= ref_table_limit){
realloc_ref_table ();
}
}
}
/* You must use [modify] to change a field of an existing shared block,
unless you are sure the value being overwritten is not a shared block and
the value being written is not a young block. */
/* Never calls the GC. */
EXTERN void modify (value * fp, value val)
{
Modify (fp, val);
}
char *stat_alloc(asize_t sz)
{
char *result = (char *) malloc (sz);
if (result == NULL) raise_out_of_memory ();
return result;
}
void stat_free(char * blk)
{
free (blk);
}
char *stat_resize (char * blk, asize_t sz)
{
char *result = (char *) realloc (blk, sz);
if (result == NULL) raise_out_of_memory ();
return result;
}
void init_c_roots (void)
{
c_roots_head = NULL;
}