/***********************************************************************/ /* */ /* Objective Caml */ /* */ /* Damien Doligez, projet Para, INRIA Rocquencourt */ /* */ /* Copyright 1996 Institut National de Recherche en Informatique et */ /* Automatique. Distributed only by permission. */ /* */ /***********************************************************************/ /* $Id$ */ /* Allocation macros and functions */ #ifndef _memory_ #define _memory_ #include "config.h" #include "gc.h" #include "major_gc.h" #include "minor_gc.h" #include "misc.h" #include "mlvalues.h" value alloc_shr P((mlsize_t, tag_t)); void adjust_gc_speed P((mlsize_t, mlsize_t)); void modify P((value *, value)); void initialize P((value *, value)); value check_urgent_gc P((value)); char * stat_alloc P((asize_t)); /* Size in bytes. */ void stat_free P((char *)); char * stat_resize P((char *, asize_t)); /* Size in bytes. */ /* void shrink_heap P((char *)); Only used in compact.c */ #ifdef NATIVE_CODE #define Garbage_collection_function garbage_collection #else #define Garbage_collection_function minor_collection #endif #define Alloc_small(result, wosize, tag) { Assert (wosize >= 1); \ young_ptr -= Bhsize_wosize (wosize); \ if (young_ptr < young_limit){ \ Setup_for_gc; \ Garbage_collection_function (); \ Restore_after_gc; \ young_ptr -= Bhsize_wosize (wosize); \ } \ Hd_hp (young_ptr) = Make_header ((wosize), (tag), Black); \ (result) = Val_hp (young_ptr); \ } /* 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. */ /* [Modify] never calls the GC. */ #define Modify(fp, val) { \ value _old_ = *(fp); \ *(fp) = (val); \ if (Is_in_heap (fp)){ \ if (gc_phase == Phase_mark) darken (_old_, NULL); \ if (Is_block (val) && Is_young (val) \ && ! (Is_block (_old_) && Is_young (_old_))){ \ *ref_table_ptr++ = (fp); \ if (ref_table_ptr >= ref_table_limit){ \ Assert (ref_table_ptr == ref_table_limit); \ realloc_ref_table (); \ } \ } \ } \ } \ /* [Begin_roots] and [End_roots] are used for C variables that are GC roots. It must contain all values in C local variables and function parameters at the time the minor GC is called. Usage: After initialising your local variables to legal Caml values, but before calling allocation functions, insert [Begin_roots_n(v1, ... vn)], where v1 ... vn are your variables of type [value] that you want to be updated across allocations. At the end, insert [End_roots()]. Note that [Begin_roots] opens a new block, and [End_roots] closes it. Thus they must occur in matching pairs at the same brace nesting level. You can use [Val_unit] as a dummy initial value for your variables. */ struct caml__roots_block { struct caml__roots_block *next; long ntables; long nitems; value *tables [5]; }; extern struct caml__roots_block *local_roots; /* defined in roots.h */ #define Begin_root Begin_roots1 #define Begin_roots1(r0) { \ struct caml__roots_block caml__roots_block; \ caml__roots_block.next = local_roots; \ local_roots = &caml__roots_block; \ caml__roots_block.nitems = 1; \ caml__roots_block.ntables = 1; \ caml__roots_block.tables[0] = &(r0); #define Begin_roots2(r0, r1) { \ struct caml__roots_block caml__roots_block; \ caml__roots_block.next = local_roots; \ local_roots = &caml__roots_block; \ caml__roots_block.nitems = 1; \ caml__roots_block.ntables = 2; \ caml__roots_block.tables[0] = &(r0); \ caml__roots_block.tables[1] = &(r1); #define Begin_roots3(r0, r1, r2) { \ struct caml__roots_block caml__roots_block; \ caml__roots_block.next = local_roots; \ local_roots = &caml__roots_block; \ caml__roots_block.nitems = 1; \ caml__roots_block.ntables = 3; \ caml__roots_block.tables[0] = &(r0); \ caml__roots_block.tables[1] = &(r1); \ caml__roots_block.tables[2] = &(r2); #define Begin_roots4(r0, r1, r2, r3) { \ struct caml__roots_block caml__roots_block; \ caml__roots_block.next = local_roots; \ local_roots = &caml__roots_block; \ caml__roots_block.nitems = 1; \ caml__roots_block.ntables = 4; \ caml__roots_block.tables[0] = &(r0); \ caml__roots_block.tables[1] = &(r1); \ caml__roots_block.tables[2] = &(r2); \ caml__roots_block.tables[3] = &(r3); #define Begin_roots5(r0, r1, r2, r3, r4) { \ struct caml__roots_block caml__roots_block; \ caml__roots_block.next = local_roots; \ local_roots = &caml__roots_block; \ caml__roots_block.nitems = 1; \ caml__roots_block.ntables = 5; \ caml__roots_block.tables[0] = &(r0); \ caml__roots_block.tables[1] = &(r1); \ caml__roots_block.tables[2] = &(r2); \ caml__roots_block.tables[3] = &(r3); \ caml__roots_block.tables[4] = &(r4); #define Begin_roots_block(table, size) { \ struct caml__roots_block caml__roots_block; \ caml__roots_block.next = local_roots; \ local_roots = &caml__roots_block; \ caml__roots_block.nitems = (size); \ caml__roots_block.ntables = 1; \ caml__roots_block.tables[0] = (table); #define End_roots() local_roots = caml__roots_block.next; } /* [Push_roots] and [Pop_roots] are obsolete. Use [Begin_roots] and [End_roots] instead. */ /* [Push_roots] and [Pop_roots] are used for C variables that are GC roots. * It must contain all values in C local variables at the time the minor GC is * called. * Usage: * At the end of the declarations of your C local variables, add * [ Push_roots (variable_name, size); ] * The size is the number of declared roots. They are accessed as * [ variable_name [0] ... variable_name [size - 1] ]. * The [variable_name] and the [size] must not be [ _ ]. * Just before the function return, add a call to [Pop_roots]. */ #define Push_roots(name, size) \ value name [(size)]; \ struct caml__roots_block caml__roots_block; \ { long _; for (_ = 0; _ < (size); name [_++] = Val_unit); } \ caml__roots_block.next = local_roots; \ local_roots = &caml__roots_block; \ caml__roots_block.nitems = (size); \ caml__roots_block.ntables = 1; \ caml__roots_block.tables[0] = name; #define Pop_roots() local_roots = caml__roots_block.next; /* [register_global_root] registers a global C variable as a memory root for the duration of the program, or until [remove_global_root] is called. */ void register_global_root P((value *)); /* [remove_global_root] removes a memory root registered on a global C variable with [register_global_root]. */ void remove_global_root P((value *)); #endif /* _memory_ */