generalize finalisation datastructure
parent
19fa879eb5
commit
8640fe3ba6
|
@ -29,8 +29,12 @@ struct final {
|
|||
int offset;
|
||||
};
|
||||
|
||||
static struct final *final_table = NULL;
|
||||
static uintnat old = 0, young = 0, size = 0;
|
||||
struct finalisable {
|
||||
struct final *table;
|
||||
uintnat old;
|
||||
uintnat young;
|
||||
uintnat size;
|
||||
};
|
||||
/* [0..old) : finalisable set, the values are in the major heap
|
||||
[old..young) : recent set, the values could be in the minor heap
|
||||
[young..size) : free space
|
||||
|
@ -39,6 +43,8 @@ static uintnat old = 0, young = 0, size = 0;
|
|||
below when the value are unreachable (for the first time).
|
||||
*/
|
||||
|
||||
static struct finalisable finalisable_first = {NULL,0,0,0};
|
||||
|
||||
struct to_do {
|
||||
struct to_do *next;
|
||||
int size;
|
||||
|
@ -76,16 +82,16 @@ static void alloc_to_do (int size)
|
|||
/* Find white finalisable values, move them to the finalising set, and
|
||||
darken them.
|
||||
*/
|
||||
void caml_final_update (void)
|
||||
static void generic_final_update (struct finalisable * final)
|
||||
{
|
||||
uintnat i, j, k;
|
||||
uintnat todo_count = 0;
|
||||
|
||||
Assert (old <= young);
|
||||
for (i = 0; i < old; i++){
|
||||
Assert (Is_block (final_table[i].val));
|
||||
Assert (Is_in_heap (final_table[i].val));
|
||||
if (Is_white_val (final_table[i].val)) ++ todo_count;
|
||||
Assert (final->old <= final->young);
|
||||
for (i = 0; i < final->old; i++){
|
||||
Assert (Is_block (final->table[i].val));
|
||||
Assert (Is_in_heap (final->table[i].val));
|
||||
if (Is_white_val (final->table[i].val)) ++ todo_count;
|
||||
}
|
||||
|
||||
/** invariant:
|
||||
|
@ -100,22 +106,22 @@ void caml_final_update (void)
|
|||
if (todo_count > 0){
|
||||
alloc_to_do (todo_count);
|
||||
j = k = 0;
|
||||
for (i = 0; i < old; i++){
|
||||
Assert (Is_block (final_table[i].val));
|
||||
Assert (Is_in_heap (final_table[i].val));
|
||||
Assert (Tag_val (final_table[i].val) != Forward_tag);
|
||||
if (Is_white_val (final_table[i].val)){
|
||||
to_do_tl->item[k++] = final_table[i];
|
||||
for (i = 0; i < final->old; i++){
|
||||
Assert (Is_block (final->table[i].val));
|
||||
Assert (Is_in_heap (final->table[i].val));
|
||||
Assert (Tag_val (final->table[i].val) != Forward_tag);
|
||||
if (Is_white_val (final->table[i].val)){
|
||||
to_do_tl->item[k++] = final->table[i];
|
||||
}else{
|
||||
final_table[j++] = final_table[i];
|
||||
final->table[j++] = final->table[i];
|
||||
}
|
||||
}
|
||||
CAMLassert (i == old);
|
||||
old = j;
|
||||
for(;i < young; i++){
|
||||
final_table[j++] = final_table[i];
|
||||
CAMLassert (i == final->old);
|
||||
final->old = j;
|
||||
for(;i < final->young; i++){
|
||||
final->table[j++] = final->table[i];
|
||||
}
|
||||
young = j;
|
||||
final->young = j;
|
||||
to_do_tl->size = k;
|
||||
for (i = 0; i < k; i++){
|
||||
/* Note that item may already be dark due to multiple entries in
|
||||
|
@ -125,6 +131,11 @@ void caml_final_update (void)
|
|||
}
|
||||
}
|
||||
|
||||
void caml_final_update (){
|
||||
generic_final_update(&finalisable_first);
|
||||
}
|
||||
|
||||
|
||||
static int running_finalisation_function = 0;
|
||||
|
||||
/* Call the finalisation functions for the finalising set.
|
||||
|
@ -168,13 +179,15 @@ void caml_final_do_calls (void)
|
|||
This is called by the major GC [caml_darken_all_roots]
|
||||
and by the compactor through [caml_do_roots]
|
||||
*/
|
||||
void caml_final_do_roots (scanning_action f)
|
||||
void caml_final_do_roots (scanning_action f, struct finalisable *final)
|
||||
{
|
||||
uintnat i;
|
||||
struct to_do *todo;
|
||||
|
||||
Assert (old <= young);
|
||||
for (i = 0; i < young; i++) Call_action (f, final_table[i].fun);
|
||||
Assert (finalisable_first.old <= finalisable_first.young);
|
||||
for (i = 0; i < finalisable_first.young; i++){
|
||||
Call_action (f, finalisable_first.table[i].fun);
|
||||
};
|
||||
|
||||
for (todo = to_do_hd; todo != NULL; todo = todo->next){
|
||||
for (i = 0; i < todo->size; i++){
|
||||
|
@ -191,9 +204,10 @@ void caml_final_invert_finalisable_values ()
|
|||
{
|
||||
uintnat i;
|
||||
|
||||
CAMLassert (old <= young);
|
||||
for (i = 0; i < young; i++){
|
||||
invert_root(final_table[i].val,&final_table[i].val);
|
||||
CAMLassert (finalisable_first.old <= finalisable_first.young);
|
||||
for (i = 0; i < finalisable_first.young; i++){
|
||||
invert_root(finalisable_first.table[i].val,
|
||||
&finalisable_first.table[i].val);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -204,10 +218,12 @@ void caml_final_do_young_roots ()
|
|||
{
|
||||
uintnat i;
|
||||
|
||||
Assert (old <= young);
|
||||
for (i = old; i < young; i++){
|
||||
caml_oldify_one(final_table[i].fun, &final_table[i].fun);
|
||||
caml_oldify_one(final_table[i].val, &final_table[i].val);
|
||||
Assert (finalisable_first.old <= finalisable_first.young);
|
||||
for (i = finalisable_first.old; i < finalisable_first.young; i++){
|
||||
caml_oldify_one(finalisable_first.table[i].fun,
|
||||
&finalisable_first.table[i].fun);
|
||||
caml_oldify_one(finalisable_first.table[i].val,
|
||||
&finalisable_first.table[i].val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,11 +233,11 @@ void caml_final_do_young_roots ()
|
|||
*/
|
||||
void caml_final_empty_young (void)
|
||||
{
|
||||
old = young;
|
||||
finalisable_first.old = finalisable_first.young;
|
||||
}
|
||||
|
||||
/* Put (f,v) in the recent set. */
|
||||
CAMLprim value caml_final_register (value f, value v)
|
||||
static void generic_final_register (struct finalisable *final, value f, value v)
|
||||
{
|
||||
if (!Is_block (v)
|
||||
|| !Is_in_heap_or_young(v)
|
||||
|
@ -230,36 +246,41 @@ CAMLprim value caml_final_register (value f, value v)
|
|||
|| Tag_val (v) == Forward_tag) {
|
||||
caml_invalid_argument ("Gc.finalise");
|
||||
}
|
||||
Assert (old <= young);
|
||||
Assert (final->old <= final->young);
|
||||
|
||||
if (young >= size){
|
||||
if (final_table == NULL){
|
||||
if (final->young >= final->size){
|
||||
if (final->table == NULL){
|
||||
uintnat new_size = 30;
|
||||
final_table = caml_stat_alloc (new_size * sizeof (struct final));
|
||||
Assert (old == 0);
|
||||
Assert (young == 0);
|
||||
size = new_size;
|
||||
final->table = caml_stat_alloc (new_size * sizeof (struct final));
|
||||
Assert (final->old == 0);
|
||||
Assert (final->young == 0);
|
||||
final->size = new_size;
|
||||
}else{
|
||||
uintnat new_size = size * 2;
|
||||
final_table = caml_stat_resize (final_table,
|
||||
uintnat new_size = final->size * 2;
|
||||
final->table = caml_stat_resize (final->table,
|
||||
new_size * sizeof (struct final));
|
||||
size = new_size;
|
||||
final->size = new_size;
|
||||
}
|
||||
}
|
||||
Assert (young < size);
|
||||
final_table[young].fun = f;
|
||||
Assert (final->young < final->size);
|
||||
final->table[final->young].fun = f;
|
||||
if (Tag_val (v) == Infix_tag){
|
||||
final_table[young].offset = Infix_offset_val (v);
|
||||
final_table[young].val = v - Infix_offset_val (v);
|
||||
final->table[final->young].offset = Infix_offset_val (v);
|
||||
final->table[final->young].val = v - Infix_offset_val (v);
|
||||
}else{
|
||||
final_table[young].offset = 0;
|
||||
final_table[young].val = v;
|
||||
final->table[final->young].offset = 0;
|
||||
final->table[final->young].val = v;
|
||||
}
|
||||
++ young;
|
||||
++ final->young;
|
||||
|
||||
}
|
||||
|
||||
CAMLprim value caml_final_register (value f, value v){
|
||||
generic_final_register(&finalisable_first, f, v);
|
||||
return Val_unit;
|
||||
}
|
||||
|
||||
|
||||
CAMLprim value caml_final_release (value unit)
|
||||
{
|
||||
running_finalisation_function = 0;
|
||||
|
|
Loading…
Reference in New Issue