diff --git a/src/array.c b/src/array.c index e75094065934000c5790fbd880d97c8f6deef877..8cea9ac70c9a42dfcdf0364724133e9a58e0738f 100644 --- a/src/array.c +++ b/src/array.c @@ -2797,6 +2797,7 @@ void check_all_arrays(void) PMOD_EXPORT void visit_array (struct array *a, int action, void *extra) { + visit_enter(a, T_ARRAY, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -2818,6 +2819,7 @@ PMOD_EXPORT void visit_array (struct array *a, int action, void *extra) for (e = 0; e < s; e++) visit_svalue (ITEM (a) + e, ref_type, extra); } + visit_leave(a, T_ARRAY, extra); } static void gc_check_array(struct array *a) diff --git a/src/constants.c b/src/constants.c index 6071d0c9996af8314814f499bfa69605029c1ca8..7cf807dff13fce36666fc708d1d6ab0ac2efcab2 100644 --- a/src/constants.c +++ b/src/constants.c @@ -196,6 +196,7 @@ PMOD_EXPORT void quick_add_efun(const char *name, ptrdiff_t name_length, PMOD_EXPORT void visit_callable (struct callable *c, int action, void *extra) { + visit_enter(c, T_STRUCT_CALLABLE, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -216,6 +217,7 @@ PMOD_EXPORT void visit_callable (struct callable *c, int action, void *extra) /* Looks like the c->prog isn't refcounted..? */ /* visit_program_ref (c->prog, REF_TYPE_NORMAL); */ + visit_leave(c, T_STRUCT_CALLABLE, extra); } #ifdef PIKE_DEBUG diff --git a/src/gc.c b/src/gc.c index 6918c27de4aeb68de521332ce89a3da6e54cd4af..a03b55592752fd2530bcc71c7892834fc065e562 100644 --- a/src/gc.c +++ b/src/gc.c @@ -4399,6 +4399,8 @@ void cleanup_gc(void) /* Visit things API */ PMOD_EXPORT visit_ref_cb *visit_ref = NULL; +PMOD_EXPORT visit_enter_cb *visit_enter = NULL; +PMOD_EXPORT visit_leave_cb *visit_leave = NULL; /* Be careful if extending this with internal types like * T_MAPPING_DATA and T_MULTISET_DATA; there's code that assumes @@ -5283,6 +5285,14 @@ static void current_only_visit_ref (void *thing, int ref_type, } } +static void ignore_visit_enter(void *thing, int type, void *extra) +{ +} + +static void ignore_visit_leave(void *thing, int type, void *extra) +{ +} + PMOD_EXPORT int mc_count_bytes (void *thing) { if (mc_pass == MC_PASS_LOOKAHEAD) { @@ -5608,7 +5618,9 @@ void f_count_memory (INT32 args) mc_wq_used = 1; assert (!mc_pass); + assert (visit_enter == NULL); assert (visit_ref == NULL); + assert (visit_leave == NULL); free_svalue (&throw_value); mark_free_svalue (&throw_value); @@ -5693,8 +5705,10 @@ void f_count_memory (INT32 args) count_internal = count_cyclic = count_visited = 0; count_visits = count_revisits = count_rounds = 0; + visit_enter = ignore_visit_enter; visit_ref = mc_lookahead < 0 ? current_only_visit_ref : pass_lookahead_visit_ref; + visit_leave = ignore_visit_leave; do { count_rounds++; @@ -6014,7 +6028,9 @@ void f_count_memory (INT32 args) } mc_pass = 0; + visit_enter = NULL; visit_ref = NULL; + visit_leave = NULL; DL_MAKE_EMPTY (mc_incomplete); DL_MAKE_EMPTY (mc_indirect); diff --git a/src/gc.h b/src/gc.h index 1697503f0461f09fb441c4d210cae4ed618ba7aa..f9786cfd3acc816972ddc4bf3f05ff5561569d2f 100644 --- a/src/gc.h +++ b/src/gc.h @@ -627,12 +627,17 @@ extern int gc_in_cycle_check; * use thread local storage when the time comes. */ /* A visit_thing_fn is made for every type of refcounted block. An - * INT32 refcounter is assumed to be first in every block. The + * INT32 refcounter is assumed to be first in every block. + * The visit_thing_fn should start by calling the visit_enter function + * with src_thing, the base type and extra as arguments. Then * visit_thing_fn should call visit_ref exactly once for every * refcounted ref inside src_thing, in a stable order. dst_thing is * then the target of the ref, ref_type describes the type of the ref * itself (REF_TYPE_*), visit_dst is the visit_thing_fn for the target * block, and extra is an arbitrary value passed along to visit_dst. + * After visit_ref has been called for all refcounted things, visit_leave + * should be called with the same arguments as the initial call of + * visit_enter. * * action identifies some action that the visit_thing_fn should take * (VISIT_*). Also, visit_ref_cb is likely to get a return value that @@ -642,9 +647,13 @@ extern int gc_in_cycle_check; * immediately, queued and called later, or not called at all. */ typedef void visit_thing_fn (void *src_thing, int action, void *extra); +typedef void visit_enter_cb (void *thing, int type, void *extra); typedef void visit_ref_cb (void *dst_thing, int ref_type, visit_thing_fn *visit_dst, void *extra); +typedef void visit_leave_cb (void *thing, int type, void *extra); +PMOD_EXPORT extern visit_enter_cb *visit_enter; PMOD_EXPORT extern visit_ref_cb *visit_ref; +PMOD_EXPORT extern visit_leave_cb *visit_leave; #define REF_TYPE_STRENGTH 0x03 /* Bits for normal/weak/strong. */ #define REF_TYPE_NORMAL 0x00 /* Normal (nonweak and nonstrong) ref. */ diff --git a/src/mapping.c b/src/mapping.c index d8a4ec48e161e6b855ac69ae665d05959d01ddeb..6ff88dd47fededc725e145d123c8a0ea1851819b 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -2472,6 +2472,7 @@ void check_all_mappings(void) static void visit_mapping_data (struct mapping_data *md, int action, void *extra) { + visit_enter(md, T_MAPPING_DATA, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -2498,10 +2499,12 @@ static void visit_mapping_data (struct mapping_data *md, int action, visit_svalue (&k->val, val_ref_type, extra); } } + visit_leave(md, T_MAPPING_DATA, extra); } PMOD_EXPORT void visit_mapping (struct mapping *m, int action, void *extra) { + visit_enter(m, T_MAPPING, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -2517,6 +2520,7 @@ PMOD_EXPORT void visit_mapping (struct mapping *m, int action, void *extra) visit_ref (m->data, REF_TYPE_INTERNAL, (visit_thing_fn *) &visit_mapping_data, extra); + visit_leave(m, T_MAPPING, extra); } #ifdef MAPPING_SIZE_DEBUG diff --git a/src/multiset.c b/src/multiset.c index abfdd86b3013edc1830cc66408231b97bd09c5ca..f1fd4d25a722da4d28a963edba5edf33bf45738a 100644 --- a/src/multiset.c +++ b/src/multiset.c @@ -3485,6 +3485,7 @@ PMOD_EXPORT ptrdiff_t multiset_get_nth (struct multiset *l, size_t n) static void visit_multiset_data (struct multiset_data *msd, int action, void *extra) { + visit_enter(msd, T_MULTISET_DATA, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -3522,10 +3523,12 @@ static void visit_multiset_data (struct multiset_data *msd, int action, visit_svalue (&ind, ind_ref_type, extra); } while ((node = low_multiset_next (node))); } + visit_leave(msd, T_MULTISET_DATA, extra); } PMOD_EXPORT void visit_multiset (struct multiset *l, int action, void *extra) { + visit_enter(l, T_MULTISET, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -3541,6 +3544,7 @@ PMOD_EXPORT void visit_multiset (struct multiset *l, int action, void *extra) visit_ref (l->msd, REF_TYPE_INTERNAL, (visit_thing_fn *) &visit_multiset_data, extra); + visit_leave(l, T_MULTISET, extra); } unsigned gc_touch_all_multisets (void) diff --git a/src/object.c b/src/object.c index 7ed36edabf3dcd4f8086f68a47b5b4dd9b115e09..9af58ab75fdbda31eccf6e68c08daa953e5154fb 100644 --- a/src/object.c +++ b/src/object.c @@ -2089,6 +2089,7 @@ PMOD_EXPORT void visit_object (struct object *o, int action, void *extra) if (o->next == o) return; /* Fake object used by compiler */ + visit_enter(o, T_OBJECT, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -2210,6 +2211,7 @@ PMOD_EXPORT void visit_object (struct object *o, int action, void *extra) if (PARENT_INFO (o)->parent) visit_object_ref (PARENT_INFO (o)->parent, REF_TYPE_STRONG, extra); } + visit_leave(o, T_OBJECT, extra); } PMOD_EXPORT void visit_function (const struct svalue *s, int ref_type, diff --git a/src/pike_types.c b/src/pike_types.c index b1d9f90ab02be34a3d0713f95aac94bde7aa7856..db79db7d3e928178d7ae70431f00960eaf6fa5ce 100644 --- a/src/pike_types.c +++ b/src/pike_types.c @@ -8913,6 +8913,7 @@ PMOD_EXPORT void *find_type(struct pike_type *t, PMOD_EXPORT void visit_type (struct pike_type *t, int action, void *extra) { + visit_enter(t, PIKE_T_TYPE, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -8921,6 +8922,7 @@ PMOD_EXPORT void visit_type (struct pike_type *t, int action, void *extra) break; #endif case VISIT_COMPLEX_ONLY: + visit_leave(t, PIKE_T_TYPE, extra); return; case VISIT_COUNT_BYTES: mc_counted_bytes += sizeof (struct pike_type); @@ -8979,6 +8981,7 @@ PMOD_EXPORT void visit_type (struct pike_type *t, int action, void *extra) break; #endif /* PIKE_DEBUG */ } + visit_leave(t, PIKE_T_TYPE, extra); } #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) diff --git a/src/program.c b/src/program.c index d932b94dacf89dcdc209a2ab6ce51698851716f7..95e65e3be6125ee46b36cc2e64892f1bec04ce73 100644 --- a/src/program.c +++ b/src/program.c @@ -11029,6 +11029,7 @@ void cleanup_program(void) PMOD_EXPORT void visit_program (struct program *p, int action, void *extra) { + visit_enter(p, T_PROGRAM, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -11081,6 +11082,7 @@ PMOD_EXPORT void visit_program (struct program *p, int action, void *extra) if (p->parent) visit_program_ref (p->parent, REF_TYPE_STRONG, extra); } + visit_leave(p, T_PROGRAM, extra); } static void gc_check_program(struct program *p); diff --git a/src/stralloc.c b/src/stralloc.c index f6f28de660d205f596a2190db5dbceb68d262c94..067c56844f79061606799e8690841a3e83ab169c 100644 --- a/src/stralloc.c +++ b/src/stralloc.c @@ -2273,6 +2273,7 @@ void count_memory_in_strings(size_t *num, size_t *size) PMOD_EXPORT void visit_string (struct pike_string *s, int action, void *extra) { + visit_enter(s, T_STRING, extra); switch (action) { #ifdef PIKE_DEBUG default: @@ -2285,6 +2286,7 @@ PMOD_EXPORT void visit_string (struct pike_string *s, int action, void *extra) mc_counted_bytes += memory_in_string (s); break; } + visit_leave(s, T_STRING, extra); } #ifdef PIKE_DEBUG