generalize finalisation datastructure

master
François Bobot 2016-06-06 00:09:30 +02:00
parent 19fa879eb5
commit 8640fe3ba6
1 changed files with 70 additions and 49 deletions

View File

@ -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;