diff --git a/src/array.c b/src/array.c index 2c61ce8ccdb2d295d8ef5788e3c666219d9e869e..7e2afa65e93ed167fa4b894e34cd2586119c80d4 100644 --- a/src/array.c +++ b/src/array.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: array.c,v 1.205 2008/05/02 04:15:09 mast Exp $ +|| $Id: array.c,v 1.206 2008/05/11 02:35:21 mast Exp $ */ #include "global.h" @@ -2595,6 +2595,31 @@ void check_all_arrays(void) #endif /* PIKE_DEBUG */ +void visit_array (struct array *a, int action) +{ + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + case VISIT_COMPLEX_ONLY: + break; +#endif + case VISIT_COUNT_BYTES: + mc_counted_bytes += sizeof (struct array) + + (a->malloced_size - 1) * sizeof (struct svalue); + break; + } + + if (a->type_field & + (action & VISIT_COMPLEX_ONLY ? BIT_COMPLEX : BIT_REF_TYPES)) { + size_t e, s = a->size; + int ref_type = a->flags & ARRAY_WEAK_FLAG ? REF_TYPE_WEAK : REF_TYPE_NORMAL; + for (e = 0; e < s; e++) + visit_svalue (ITEM (a) + e, ref_type); + } +} + static void gc_check_array(struct array *a) { GC_ENTER (a, T_ARRAY) { @@ -2614,12 +2639,6 @@ void gc_mark_array_as_referenced(struct array *a) { if(gc_mark(a)) GC_ENTER (a, T_ARRAY) { - if (Pike_in_gc == GC_PASS_COUNT_MEMORY) { - gc_counted_bytes += sizeof (struct array) + - (a->malloced_size - 1) * sizeof (struct svalue); - gc_check_array (a); - } - if (a == gc_mark_array_pos) gc_mark_array_pos = a->next; if (a == gc_internal_array) diff --git a/src/array.h b/src/array.h index 46d277ae597294726c9309946357113599116556..745fc7726a8928a0dcfcf0db4fbddb8c8b5457d5 100644 --- a/src/array.h +++ b/src/array.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: array.h,v 1.73 2008/05/01 21:44:32 mast Exp $ +|| $Id: array.h,v 1.74 2008/05/11 02:35:21 mast Exp $ */ #ifndef ARRAY_H @@ -192,6 +192,7 @@ void array_replace(struct array *a, PMOD_EXPORT void check_array(struct array *a); void check_all_arrays(void); #endif +void visit_array (struct array *a, int action); void gc_mark_array_as_referenced(struct array *a); void real_gc_cycle_check_array(struct array *a, int weak); unsigned gc_touch_all_arrays(void); @@ -211,6 +212,9 @@ PMOD_EXPORT struct array *implode_array(struct array *a, struct array *b); #define array_get_flags(a) ((a)->flags) +#define visit_array_ref(A, REF_TYPE) \ + visit_ref (pass_array (A), (REF_TYPE), \ + (visit_thing_fn *) &visit_array, NULL) #define gc_cycle_check_array(X, WEAK) \ gc_cycle_enqueue((gc_cycle_check_cb *) real_gc_cycle_check_array, (X), (WEAK)) diff --git a/src/constants.c b/src/constants.c index 72c862b927cbc375caf6041a8a0bbc9ada0e486c..811c8b04411e3db537d2c97683b7a0b4712b5d91 100644 --- a/src/constants.c +++ b/src/constants.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: constants.c,v 1.58 2008/04/26 16:07:39 grubba Exp $ +|| $Id: constants.c,v 1.59 2008/05/11 02:35:22 mast Exp $ */ #include "global.h" @@ -16,6 +16,8 @@ #include "mapping.h" #include "pike_error.h" #include "pike_security.h" +#include "gc.h" + #include "block_alloc.h" struct mapping *builtin_constants = 0; @@ -188,6 +190,30 @@ PMOD_EXPORT struct callable *quick_add_efun(const char *name, ptrdiff_t name_len return ret; } +void visit_callable (struct callable *c, int action) +{ + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + case VISIT_COMPLEX_ONLY: + break; +#endif + case VISIT_COUNT_BYTES: + mc_counted_bytes += sizeof (struct callable); + break; + } + + if (!(action & VISIT_COMPLEX_ONLY)) { + visit_type_ref (c->type, REF_TYPE_NORMAL); + visit_string_ref (c->name, REF_TYPE_NORMAL); + } + + /* Looks like the c->prog isn't refcounted..? */ + /* visit_program_ref (c->prog, REF_TYPE_NORMAL); */ +} + #ifdef PIKE_DEBUG void present_constant_profiling(void) { diff --git a/src/constants.h b/src/constants.h index ae5cb016d7e3b5eb52c5dbbf84d21f48db861ee7..f0c03be31ff55475e2da43917086321f0a7d7ab9 100644 --- a/src/constants.h +++ b/src/constants.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: constants.h,v 1.35 2008/04/26 16:07:39 grubba Exp $ +|| $Id: constants.h,v 1.36 2008/05/11 02:35:22 mast Exp $ */ #ifndef ADD_EFUN_H @@ -75,10 +75,14 @@ PMOD_EXPORT struct callable *quick_add_efun(const char *name, ptrdiff_t name_len int flags, optimize_fun optimize, docode_fun docode); +void visit_callable (struct callable *c, int action); void init_builtin_constants(void); void exit_builtin_constants(void); /* Prototypes end here */ +#define visit_callable_ref(C, REF_TYPE) \ + visit_ref (pass_callable (C), (REF_TYPE), \ + (visit_thing_fn *) &visit_callable, NULL) #include "pike_macros.h" diff --git a/src/mapping.c b/src/mapping.c index be825a4eb4a87ccb5964e8f8950206d298db128a..1b2a9178636668573c5c4448be2b3bddc17bd965 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: mapping.c,v 1.199 2008/05/02 04:15:11 mast Exp $ +|| $Id: mapping.c,v 1.200 2008/05/11 02:35:22 mast Exp $ */ #include "global.h" @@ -277,7 +277,7 @@ PMOD_EXPORT void do_free_mapping(struct mapping *m) inl_free_mapping(m); } -/* This function is used to rehash a mapping without loosing the internal +/* This function is used to rehash a mapping without losing the internal * order in each hash chain. This is to prevent mappings from becoming * inefficient just after being rehashed. */ @@ -2316,14 +2316,62 @@ void check_all_mappings(void) } #endif +static void visit_mapping_data (struct mapping_data *md, int action, + struct mapping *m) +{ + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + case VISIT_COMPLEX_ONLY: + break; +#endif + case VISIT_COUNT_BYTES: + mc_counted_bytes += MAPPING_DATA_SIZE (md->hashsize, md->num_keypairs); + break; + } + + if ((md->ind_types | md->val_types) & + (action & VISIT_COMPLEX_ONLY ? BIT_COMPLEX : BIT_REF_TYPES)) { + int ind_ref_type = + md->flags & MAPPING_WEAK_INDICES ? REF_TYPE_WEAK : REF_TYPE_NORMAL; + int val_ref_type = + md->flags & MAPPING_WEAK_VALUES ? REF_TYPE_WEAK : REF_TYPE_NORMAL; + INT32 e; + struct keypair *k; + NEW_MAPPING_LOOP (md) { + visit_svalue (&k->ind, ind_ref_type); + visit_svalue (&k->val, val_ref_type); + } + } +} + +void visit_mapping (struct mapping *m, int action) +{ + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + case VISIT_COMPLEX_ONLY: + break; +#endif + case VISIT_COUNT_BYTES: + mc_counted_bytes += sizeof (struct mapping); + break; + } + + visit_ref (m->data, REF_TYPE_INTERNAL, + (visit_thing_fn *) &visit_mapping_data, m); +} + #ifdef MAPPING_SIZE_DEBUG #define DO_IF_MAPPING_SIZE_DEBUG(x) x #else #define DO_IF_MAPPING_SIZE_DEBUG(x) #endif -static void gc_check_md (struct mapping_data *md); - #define GC_RECURSE_MD_IN_USE(MD, RECURSE_FN, IND_TYPES, VAL_TYPES) do { \ INT32 e; \ struct keypair *k; \ @@ -2338,7 +2386,7 @@ static void gc_check_md (struct mapping_data *md); } while (0) #ifdef PIKE_MAPPING_KEYPAIR_LOOP -/* NOTE: Broken code below! */ +#error Broken code below! #define GC_RECURSE(M, MD, REC_KEYPAIR, TYPE, IND_TYPES, VAL_TYPES) do { \ int remove; \ struct keypair *k,**prev_; \ @@ -2465,11 +2513,6 @@ void gc_mark_mapping_as_referenced(struct mapping *m) GC_ENTER (m, T_MAPPING) { struct mapping_data *md = m->data; - if (Pike_in_gc == GC_PASS_COUNT_MEMORY) { - gc_counted_bytes += sizeof (struct mapping); - gc_check (md); - } - if (m == gc_mark_mapping_pos) gc_mark_mapping_pos = m->next; if (m == gc_internal_mapping) @@ -2479,52 +2522,44 @@ void gc_mark_mapping_as_referenced(struct mapping *m) DOUBLELINK(first_mapping, m); /* Linked in first. */ } - if(gc_mark(md)) { - if (Pike_in_gc == GC_PASS_COUNT_MEMORY) { - gc_counted_bytes += - MAPPING_DATA_SIZE (md->hashsize, md->num_keypairs); - gc_check_md (md); + if(gc_mark(md) && ((md->ind_types | md->val_types) & BIT_COMPLEX)) { + TYPE_FIELD ind_types = 0, val_types = 0; + if (MAPPING_DATA_IN_USE(md)) { + /* Must leave the mapping data untouched if it's busy. */ + debug_malloc_touch(m); + debug_malloc_touch(md); + GC_RECURSE_MD_IN_USE(md, gc_mark_svalues, ind_types, val_types); + gc_assert_checked_as_nonweak(md); } - - if ((md->ind_types | md->val_types) & BIT_COMPLEX) { - TYPE_FIELD ind_types = 0, val_types = 0; - if (MAPPING_DATA_IN_USE(md)) { - /* Must leave the mapping data untouched if it's busy. */ - debug_malloc_touch(m); - debug_malloc_touch(md); - GC_RECURSE_MD_IN_USE(md, gc_mark_svalues, ind_types, val_types); - gc_assert_checked_as_nonweak(md); + else + switch (md->flags & MAPPING_WEAK) { + case 0: + debug_malloc_touch(m); + debug_malloc_touch(md); + GC_RECURSE(m, md, GC_REC_KP, gc_mark, ind_types, val_types); + gc_assert_checked_as_nonweak(md); + break; + case MAPPING_WEAK_INDICES: + debug_malloc_touch(m); + debug_malloc_touch(md); + GC_RECURSE(m, md, GC_REC_KP_IND, gc_mark, ind_types, val_types); + gc_assert_checked_as_weak(md); + break; + case MAPPING_WEAK_VALUES: + debug_malloc_touch(m); + debug_malloc_touch(md); + GC_RECURSE(m, md, GC_REC_KP_VAL, gc_mark, ind_types, val_types); + gc_assert_checked_as_weak(md); + break; + default: + debug_malloc_touch(m); + debug_malloc_touch(md); + GC_RECURSE(m, md, GC_REC_KP_BOTH, gc_mark, ind_types, val_types); + gc_assert_checked_as_weak(md); + break; } - else - switch (md->flags & MAPPING_WEAK) { - case 0: - debug_malloc_touch(m); - debug_malloc_touch(md); - GC_RECURSE(m, md, GC_REC_KP, gc_mark, ind_types, val_types); - gc_assert_checked_as_nonweak(md); - break; - case MAPPING_WEAK_INDICES: - debug_malloc_touch(m); - debug_malloc_touch(md); - GC_RECURSE(m, md, GC_REC_KP_IND, gc_mark, ind_types, val_types); - gc_assert_checked_as_weak(md); - break; - case MAPPING_WEAK_VALUES: - debug_malloc_touch(m); - debug_malloc_touch(md); - GC_RECURSE(m, md, GC_REC_KP_VAL, gc_mark, ind_types, val_types); - gc_assert_checked_as_weak(md); - break; - default: - debug_malloc_touch(m); - debug_malloc_touch(md); - GC_RECURSE(m, md, GC_REC_KP_BOTH, gc_mark, ind_types,val_types); - gc_assert_checked_as_weak(md); - break; - } - md->val_types = val_types; - md->ind_types = ind_types; - } + md->val_types = val_types; + md->ind_types = ind_types; } } GC_LEAVE; } @@ -2583,45 +2618,52 @@ void real_gc_cycle_check_mapping(struct mapping *m, int weak) } GC_CYCLE_LEAVE; } -static void gc_check_md (struct mapping_data *md) +static void gc_check_mapping(struct mapping *m) { - INT32 e; - struct keypair *k; + struct mapping_data *md = m->data; - if (!(md->flags & MAPPING_WEAK) || MAPPING_DATA_IN_USE(md)) - /* Disregard the weak flag if the mapping data is busy; we must - * leave it untouched in that case anyway. */ - NEW_MAPPING_LOOP(md) - { - debug_gc_check_svalues(&k->ind, 1, " as mapping index"); - debug_gc_check_svalues(&k->val, 1, " as mapping value"); - } - else { - switch (md->flags & MAPPING_WEAK) { - case MAPPING_WEAK_INDICES: - NEW_MAPPING_LOOP(md) - { - debug_gc_check_weak_svalues(&k->ind, 1, " as mapping index"); - debug_gc_check_svalues(&k->val, 1, " as mapping value"); - } - break; - case MAPPING_WEAK_VALUES: - NEW_MAPPING_LOOP(md) - { - debug_gc_check_svalues(&k->ind, 1, " as mapping index"); - debug_gc_check_weak_svalues(&k->val, 1, " as mapping value"); - } - break; - default: - NEW_MAPPING_LOOP(md) - { - debug_gc_check_weak_svalues(&k->ind, 1, " as mapping index"); - debug_gc_check_weak_svalues(&k->val, 1, " as mapping value"); + if((md->ind_types | md->val_types) & BIT_COMPLEX) + GC_ENTER (m, T_MAPPING) { + INT32 e; + struct keypair *k; + + if(!debug_gc_check (md, " as mapping data block of a mapping")) { + if (!(md->flags & MAPPING_WEAK) || MAPPING_DATA_IN_USE(md)) + /* Disregard the weak flag if the mapping data is busy; we must + * leave it untouched in that case anyway. */ + NEW_MAPPING_LOOP(md) + { + debug_gc_check_svalues(&k->ind, 1, " as mapping index"); + debug_gc_check_svalues(&k->val, 1, " as mapping value"); + } + else { + switch (md->flags & MAPPING_WEAK) { + case MAPPING_WEAK_INDICES: + NEW_MAPPING_LOOP(md) + { + debug_gc_check_weak_svalues(&k->ind, 1, " as mapping index"); + debug_gc_check_svalues(&k->val, 1, " as mapping value"); + } + break; + case MAPPING_WEAK_VALUES: + NEW_MAPPING_LOOP(md) + { + debug_gc_check_svalues(&k->ind, 1, " as mapping index"); + debug_gc_check_weak_svalues(&k->val, 1, " as mapping value"); + } + break; + default: + NEW_MAPPING_LOOP(md) + { + debug_gc_check_weak_svalues(&k->ind, 1, " as mapping index"); + debug_gc_check_weak_svalues(&k->val, 1, " as mapping value"); + } + break; + } + gc_checked_as_weak(md); } - break; - } - gc_checked_as_weak(md); - } + } + } GC_LEAVE; } unsigned gc_touch_all_mappings(void) @@ -2645,22 +2687,15 @@ void gc_check_all_mappings(void) for(m=first_mapping;m;m=m->next) { - struct mapping_data *md = m->data; - #ifdef DEBUG_MALLOC - if (((int) PTR_TO_INT (md)) == 0x55555555) { + if (((int) PTR_TO_INT (m->data)) == 0x55555555) { fprintf(stderr, "** Zapped mapping in list of active mappings!\n"); describe_something(m, T_MAPPING, 0,2,0, NULL); Pike_fatal("Zapped mapping in list of active mappings!\n"); } #endif /* DEBUG_MALLOC */ - if((md->ind_types | md->val_types) & BIT_COMPLEX) - GC_ENTER (m, T_MAPPING) { - if(!debug_gc_check (md, " as mapping data block of a mapping")) - gc_check_md (md); - } GC_LEAVE; - + gc_check_mapping(m); #ifdef PIKE_DEBUG if(d_flag > 1) check_mapping_type_fields(m); #endif diff --git a/src/mapping.h b/src/mapping.h index b3ee2e8d4b6348748ec1194640eeb4ad076b20ef..0f648ff9c82ecbcb3ed4a288225881dcae694f22 100644 --- a/src/mapping.h +++ b/src/mapping.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: mapping.h,v 1.66 2008/01/05 17:58:54 nilsson Exp $ +|| $Id: mapping.h,v 1.67 2008/05/11 02:35:22 mast Exp $ */ #ifndef MAPPING_H @@ -372,6 +372,7 @@ PMOD_EXPORT void mapping_search_no_free(struct svalue *to, void check_mapping(const struct mapping *m); void check_all_mappings(void); #endif +void visit_mapping (struct mapping *m, int action); void gc_mark_mapping_as_referenced(struct mapping *m); void real_gc_cycle_check_mapping(struct mapping *m, int weak); unsigned gc_touch_all_mappings(void); @@ -388,6 +389,9 @@ int mapping_is_constant(struct mapping *m, #define allocate_mapping(X) dmalloc_touch(struct mapping *,debug_allocate_mapping(X)) +#define visit_mapping_ref(M, REF_TYPE) \ + visit_ref (pass_mapping (M), (REF_TYPE), \ + (visit_thing_fn *) &visit_mapping, NULL) #define gc_cycle_check_mapping(X, WEAK) \ gc_cycle_enqueue((gc_cycle_check_cb *) real_gc_cycle_check_mapping, (X), (WEAK)) diff --git a/src/multiset.c b/src/multiset.c index fbb0dac45bc6d449a119f0b43f60e56762009b77..1e192cef81ddf331505ab4e88da2cf6a09b991dc 100644 --- a/src/multiset.c +++ b/src/multiset.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: multiset.c,v 1.109 2008/05/06 19:19:10 mast Exp $ +|| $Id: multiset.c,v 1.110 2008/05/11 02:35:22 mast Exp $ */ #include "global.h" @@ -3800,10 +3800,72 @@ PMOD_EXPORT ptrdiff_t multiset_get_nth (struct multiset *l, size_t n) return MSNODE2OFF (l->msd, RBNODE (rb_get_nth (HDR (l->msd->root), n))); } + #define GC_MSD_VISITED GC_USER_1 #define GC_MSD_GOT_EXT_REFS GC_USER_2 #define GC_MSD_GOT_NODE_REFS GC_USER_3 +static void visit_multiset_data (struct multiset_data *msd, int action, + struct multiset *l) +{ + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + case VISIT_COMPLEX_ONLY: + break; +#endif + case VISIT_COUNT_BYTES: + mc_counted_bytes += (msd->flags & MULTISET_INDVAL ? + NODE_OFFSET (msnode_indval, msd->allocsize) : + NODE_OFFSET (msnode_ind, msd->allocsize)); + break; + } + + if (msd->root && + ((msd->ind_types | msd->val_types) & + (action & VISIT_COMPLEX_ONLY ? BIT_COMPLEX : BIT_REF_TYPES))) { + int ind_ref_type = + msd->flags & MULTISET_WEAK_INDICES ? REF_TYPE_WEAK : REF_TYPE_NORMAL; + union msnode *node = low_multiset_first (msd); + struct svalue ind; + if (msd->flags & MULTISET_INDVAL) { + int val_ref_type = + msd->flags & MULTISET_WEAK_VALUES ? REF_TYPE_WEAK : REF_TYPE_NORMAL; + do { + low_use_multiset_index (node, ind); + visit_svalue (&ind, ind_ref_type); + visit_svalue (&node->iv.val, val_ref_type); + } while ((node = low_multiset_next (node))); + } + else + do { + low_use_multiset_index (node, ind); + visit_svalue (&ind, ind_ref_type); + } while ((node = low_multiset_next (node))); + } +} + +void visit_multiset (struct multiset *l, int action) +{ + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + case VISIT_COMPLEX_ONLY: + break; +#endif + case VISIT_COUNT_BYTES: + mc_counted_bytes += sizeof (struct multiset); + break; + } + + visit_ref (l->msd, REF_TYPE_INTERNAL, + (visit_thing_fn *) &visit_multiset_data, l); +} + unsigned gc_touch_all_multisets (void) { unsigned n = 0; @@ -3819,8 +3881,6 @@ unsigned gc_touch_all_multisets (void) return n; } -static void gc_check_msd (struct multiset *l); - void gc_check_all_multisets (void) { struct multiset *l; @@ -3849,76 +3909,69 @@ void gc_check_all_multisets (void) } GC_LEAVE; } - for (l = first_multiset; l; l = l->next) - gc_check_msd (l); -} - -static void gc_check_msd (struct multiset *l) -{ - struct multiset_data *msd = l->msd; - struct marker *m = get_marker (msd); - - /* m->refs doesn't have any useful value here when called for - * GC_PASS_COUNT_MEMORY. It doesn't matter since we're making no - * difference between normal and weak refs anyway in that mode. */ + for (l = first_multiset; l; l = l->next) { + struct multiset_data *msd = l->msd; + struct marker *m = get_marker (msd); - if (!(m->flags & GC_MSD_VISITED)) - GC_ENTER (l, T_MULTISET) { - if (m->refs < msd->refs) m->flags |= GC_MSD_GOT_EXT_REFS; + if (!(m->flags & GC_MSD_VISITED)) + GC_ENTER (l, T_MULTISET) { + if (m->refs < msd->refs) m->flags |= GC_MSD_GOT_EXT_REFS; - if (msd->root) { - union msnode *node = low_multiset_first (msd); - struct svalue ind; + if (msd->root) { + union msnode *node = low_multiset_first (msd); + struct svalue ind; #define WITH_NODES_BLOCK(TYPE, OTHERTYPE, IND, INDVAL) \ - if (!(msd->flags & MULTISET_WEAK) || (m->flags & GC_MSD_GOT_EXT_REFS)) \ - do { \ - low_use_multiset_index (node, ind); \ - debug_gc_check_svalues (&ind, 1, " as multiset index"); \ - INDVAL (debug_gc_check_svalues (&node->iv.val, 1, \ - " as multiset value")); \ - } while ((node = low_multiset_next (node))); \ + if (!(msd->flags & MULTISET_WEAK) || \ + (m->flags & GC_MSD_GOT_EXT_REFS)) \ + do { \ + low_use_multiset_index (node, ind); \ + debug_gc_check_svalues (&ind, 1, " as multiset index"); \ + INDVAL (debug_gc_check_svalues (&node->iv.val, 1, \ + " as multiset value")); \ + } while ((node = low_multiset_next (node))); \ \ - else { \ - switch (msd->flags & MULTISET_WEAK) { \ - case MULTISET_WEAK_INDICES: \ - do { \ - low_use_multiset_index (node, ind); \ - debug_gc_check_weak_svalues (&ind, 1, " as multiset index"); \ - INDVAL (debug_gc_check_svalues (&node->iv.val, 1, \ - " as multiset value")); \ - } while ((node = low_multiset_next (node))); \ - break; \ + else { \ + switch (msd->flags & MULTISET_WEAK) { \ + case MULTISET_WEAK_INDICES: \ + do { \ + low_use_multiset_index (node, ind); \ + debug_gc_check_weak_svalues (&ind, 1, " as multiset index"); \ + INDVAL (debug_gc_check_svalues (&node->iv.val, 1, \ + " as multiset value")); \ + } while ((node = low_multiset_next (node))); \ + break; \ \ - case MULTISET_WEAK_VALUES: \ - do { \ - low_use_multiset_index (node, ind); \ - debug_gc_check_svalues (&ind, 1, " as multiset index"); \ - INDVAL (debug_gc_check_weak_svalues (&node->iv.val, 1, \ - " as multiset value")); \ - } while ((node = low_multiset_next (node))); \ - break; \ + case MULTISET_WEAK_VALUES: \ + do { \ + low_use_multiset_index (node, ind); \ + debug_gc_check_svalues (&ind, 1, " as multiset index"); \ + INDVAL (debug_gc_check_weak_svalues (&node->iv.val, 1, \ + " as multiset value")); \ + } while ((node = low_multiset_next (node))); \ + break; \ \ - default: \ - do { \ - low_use_multiset_index (node, ind); \ - debug_gc_check_weak_svalues (&ind, 1, " as multiset index"); \ - INDVAL (debug_gc_check_weak_svalues (&node->iv.val, 1, \ - " as multiset value")); \ - } while ((node = low_multiset_next (node))); \ - break; \ - } \ - gc_checked_as_weak (msd); \ - } + default: \ + do { \ + low_use_multiset_index (node, ind); \ + debug_gc_check_weak_svalues (&ind, 1, " as multiset index"); \ + INDVAL (debug_gc_check_weak_svalues (&node->iv.val, 1, \ + " as multiset value")); \ + } while ((node = low_multiset_next (node))); \ + break; \ + } \ + gc_checked_as_weak (msd); \ + } - DO_WITH_NODES (msd); + DO_WITH_NODES (msd); #undef WITH_NODES_BLOCK - } + } - if (l->node_refs) m->flags |= GC_MSD_GOT_NODE_REFS | GC_MSD_VISITED; - else m->flags |= GC_MSD_VISITED; - } GC_LEAVE; + if (l->node_refs) m->flags |= GC_MSD_GOT_NODE_REFS | GC_MSD_VISITED; + else m->flags |= GC_MSD_VISITED; + } GC_LEAVE; + } } static void gc_unlink_msnode_shared (struct multiset_data *msd, @@ -4081,11 +4134,6 @@ void gc_mark_multiset_as_referenced (struct multiset *l) GC_ENTER (l, T_MULTISET) { struct multiset_data *msd = l->msd; - if (Pike_in_gc == GC_PASS_COUNT_MEMORY) { - gc_counted_bytes += sizeof (struct multiset); - gc_check (msd); - } - if (l == gc_mark_multiset_pos) gc_mark_multiset_pos = l->next; if (l == gc_internal_multiset) @@ -4095,67 +4143,59 @@ void gc_mark_multiset_as_referenced (struct multiset *l) DOUBLELINK (first_multiset, l); /* Linked in first. */ } - if (gc_mark (msd)) { - if (Pike_in_gc == GC_PASS_COUNT_MEMORY) { - gc_counted_bytes += (msd->flags & MULTISET_INDVAL ? - NODE_OFFSET (msnode_indval, msd->allocsize) : - NODE_OFFSET (msnode_ind, msd->allocsize)); - gc_check_msd (l); - } + if (gc_mark (msd) && msd->root && + ((msd->ind_types | msd->val_types) & BIT_COMPLEX)) { + struct marker *m = get_marker (msd); + TYPE_FIELD ind_types = 0, val_types = 0; - if (msd->root && ((msd->ind_types | msd->val_types) & BIT_COMPLEX)) { - struct marker *m = get_marker (msd); - TYPE_FIELD ind_types = 0, val_types = 0; + if (m->flags & GC_MSD_GOT_EXT_REFS) { + /* Must leave the multiset data untouched if there are direct + * external refs to it. */ + GC_RECURSE_MSD_IN_USE (msd, gc_mark_svalues, ind_types, val_types); + gc_assert_checked_as_nonweak (msd); + } - if (m->flags & GC_MSD_GOT_EXT_REFS) { - /* Must leave the multiset data untouched if there are direct - * external refs to it. */ - GC_RECURSE_MSD_IN_USE (msd, gc_mark_svalues, ind_types, val_types); - gc_assert_checked_as_nonweak (msd); + else { + switch (msd->flags & MULTISET_WEAK) { + case 0: + GC_RECURSE (msd, m->flags & GC_MSD_GOT_NODE_REFS, + GC_REC_I_WEAK_NONE, GC_REC_IV_WEAK_NONE, + gc_mark, ind_types, val_types); + gc_assert_checked_as_nonweak (msd); + break; + case MULTISET_WEAK_INDICES: + GC_RECURSE (msd, m->flags & GC_MSD_GOT_NODE_REFS, + GC_REC_I_WEAK_IND, GC_REC_IV_WEAK_IND, + gc_mark, ind_types, val_types); + gc_assert_checked_as_weak (msd); + break; + case MULTISET_WEAK_VALUES: + GC_RECURSE (msd, m->flags & GC_MSD_GOT_NODE_REFS, + GC_REC_I_WEAK_NONE, GC_REC_IV_WEAK_VAL, + gc_mark, ind_types, val_types); + gc_assert_checked_as_weak (msd); + break; + default: + GC_RECURSE (msd, m->flags & GC_MSD_GOT_NODE_REFS, + GC_REC_I_WEAK_IND, GC_REC_IV_WEAK_BOTH, + gc_mark, ind_types, val_types); + gc_assert_checked_as_weak (msd); + break; } - else { - switch (msd->flags & MULTISET_WEAK) { - case 0: - GC_RECURSE (msd, m->flags & GC_MSD_GOT_NODE_REFS, - GC_REC_I_WEAK_NONE, GC_REC_IV_WEAK_NONE, - gc_mark, ind_types, val_types); - gc_assert_checked_as_nonweak (msd); - break; - case MULTISET_WEAK_INDICES: - GC_RECURSE (msd, m->flags & GC_MSD_GOT_NODE_REFS, - GC_REC_I_WEAK_IND, GC_REC_IV_WEAK_IND, - gc_mark, ind_types, val_types); - gc_assert_checked_as_weak (msd); - break; - case MULTISET_WEAK_VALUES: - GC_RECURSE (msd, m->flags & GC_MSD_GOT_NODE_REFS, - GC_REC_I_WEAK_NONE, GC_REC_IV_WEAK_VAL, - gc_mark, ind_types, val_types); - gc_assert_checked_as_weak (msd); - break; - default: - GC_RECURSE (msd, m->flags & GC_MSD_GOT_NODE_REFS, - GC_REC_I_WEAK_IND, GC_REC_IV_WEAK_BOTH, - gc_mark, ind_types, val_types); - gc_assert_checked_as_weak (msd); - break; - } - - if (msd->refs == 1 && DO_SHRINK (msd, 0)) { - /* Only shrink the multiset if it isn't shared, or else we - * can end up with larger memory consumption since the - * shrunk data blocks won't be shared. */ - debug_malloc_touch (msd); - l->msd = resize_multiset_data (msd, ALLOC_SIZE (msd->size), 0); - debug_malloc_touch (l->msd); - msd = l->msd; - } + if (msd->refs == 1 && DO_SHRINK (msd, 0)) { + /* Only shrink the multiset if it isn't shared, or else we + * can end up with larger memory consumption since the + * shrunk data blocks won't be shared. */ + debug_malloc_touch (msd); + l->msd = resize_multiset_data (msd, ALLOC_SIZE (msd->size), 0); + debug_malloc_touch (l->msd); + msd = l->msd; } - - msd->ind_types = ind_types; - if (msd->flags & MULTISET_INDVAL) msd->val_types = val_types; } + + msd->ind_types = ind_types; + if (msd->flags & MULTISET_INDVAL) msd->val_types = val_types; } } GC_LEAVE; } diff --git a/src/multiset.h b/src/multiset.h index 8080489acd60005f80683e238c6d24ea4797a814..71ac914e9c2727080884aa5727b4e535548cfd39 100644 --- a/src/multiset.h +++ b/src/multiset.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: multiset.h,v 1.42 2008/05/01 21:44:33 mast Exp $ +|| $Id: multiset.h,v 1.43 2008/05/11 02:35:22 mast Exp $ */ #ifndef MULTISET_H @@ -429,6 +429,7 @@ struct multiset *copy_multiset_recursively (struct multiset *l, struct mapping *p); PMOD_EXPORT ptrdiff_t multiset_get_nth (struct multiset *l, size_t n); +void visit_multiset (struct multiset *l, int action); unsigned gc_touch_all_multisets (void); void gc_check_all_multisets (void); void gc_mark_multiset_as_referenced (struct multiset *l); @@ -437,6 +438,10 @@ void gc_zap_ext_weak_refs_in_multisets (void); void real_gc_cycle_check_multiset (struct multiset *l, int weak); void gc_cycle_check_all_multisets (void); size_t gc_free_all_unreferenced_multisets (void); + +#define visit_multiset_ref(L, REF_TYPE) \ + visit_ref (pass_multiset (L), (REF_TYPE), \ + (visit_thing_fn *) &visit_multiset, NULL) #define gc_cycle_check_multiset(X, WEAK) \ gc_cycle_enqueue ((gc_cycle_check_cb *) real_gc_cycle_check_multiset, (X), (WEAK)) diff --git a/src/object.c b/src/object.c index 7a7eca2f1421ebd3f51d5ae8498d68453f06ca1e..1b74da3f844d4f0018715e8631791b6781c7f283 100644 --- a/src/object.c +++ b/src/object.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: object.c,v 1.289 2008/05/03 13:08:05 mast Exp $ +|| $Id: object.c,v 1.290 2008/05/11 02:35:22 mast Exp $ */ #include "global.h" @@ -27,6 +27,7 @@ #include "module_support.h" #include "fdlib.h" #include "mapping.h" +#include "multiset.h" #include "constants.h" #include "encode.h" #include "pike_types.h" @@ -1820,6 +1821,151 @@ PMOD_EXPORT struct array *object_values(struct object *o) return a; } + +void visit_object (struct object *o, int action) +{ + struct program *p = o->prog; + + if (o->next == o) return; /* Fake object used by compiler */ + + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + case VISIT_COMPLEX_ONLY: + break; +#endif + case VISIT_COUNT_BYTES: + mc_counted_bytes += sizeof (struct object); + if (p) mc_counted_bytes += p->storage_needed; + break; + } + + if (PIKE_OBJ_INITED (o)) { + struct pike_frame *pike_frame = NULL; + struct inherit *inh = p->inherits; + char *storage = o->storage; + int e; + + debug_malloc_touch (p); + debug_malloc_touch (o); + debug_malloc_touch (storage); + + visit_program_ref (p, REF_TYPE_NORMAL); + + for (e = p->num_inherits - 1; e >= 0; e--) { + struct program *inh_prog = inh[e].prog; + unsigned INT16 *inh_prog_var_idxs = inh_prog->variable_index; + struct identifier *inh_prog_ids = inh_prog->identifiers; + char *inh_storage = storage + inh[e].storage_offset; + + int q, num_vars = (int) inh_prog->num_variable_index; + + for (q = 0; q < num_vars; q++) { + int d = inh_prog_var_idxs[q]; + struct identifier *id = inh_prog_ids + d; + int id_flags = id->identifier_flags; + int rtt = id->run_time_type; + void *var; + union anything *u; + + if (IDENTIFIER_IS_ALIAS (id_flags)) + continue; + + var = inh_storage + id->func.offset; + u = (union anything *) var; +#ifdef DEBUG_MALLOC + if (rtt <= MAX_REF_TYPE) + debug_malloc_touch (u->ptr); +#endif + + switch (rtt) { + case T_MIXED: { + struct svalue *s = (struct svalue *) var; + dmalloc_touch_svalue (s); + if ((s->type != T_OBJECT && s->type != T_FUNCTION) || + s->u.object != o || + !(id_flags & IDENTIFIER_NO_THIS_REF)) + visit_svalue (s, REF_TYPE_NORMAL); + break; + } + + case T_ARRAY: + if (u->array) + visit_array_ref (u->array, REF_TYPE_NORMAL); + break; + case T_MAPPING: + if (u->mapping) + visit_mapping_ref (u->mapping, REF_TYPE_NORMAL); + break; + case T_MULTISET: + if (u->multiset) + visit_multiset_ref (u->multiset, REF_TYPE_NORMAL); + break; + case T_PROGRAM: + if (u->program) + visit_program_ref (u->program, REF_TYPE_NORMAL); + break; + + case T_OBJECT: + if (u->object && (u->object != o || + !(id_flags & IDENTIFIER_NO_THIS_REF))) + visit_object_ref (u->object, REF_TYPE_NORMAL); + break; + + case T_STRING: + if (u->string && !(action & VISIT_COMPLEX_ONLY)) + visit_string_ref (u->string, REF_TYPE_NORMAL); + break; + case T_TYPE: + if (u->type && !(action & VISIT_COMPLEX_ONLY)) + visit_type_ref (u->type, REF_TYPE_NORMAL); + break; + +#ifdef PIKE_DEBUG + case PIKE_T_GET_SET: + case T_INT: + case T_FLOAT: + break; + default: + Pike_fatal ("Invalid runtime type %d.\n", rtt); +#endif + } + } + + if (inh_prog->event_handler) { + if (!pike_frame) PUSH_FRAME2 (o, p); + SET_FRAME_CONTEXT (inh + e); + inh_prog->event_handler (PROG_EVENT_GC_RECURSE); + } + } + + if (pike_frame) POP_FRAME2(); + + /* Strong ref follows. It must be last. */ + if (p->flags & PROGRAM_USES_PARENT) + if (PARENT_INFO (o)->parent) + visit_object_ref (PARENT_INFO (o)->parent, REF_TYPE_STRONG); + } +} + +PMOD_EXPORT void visit_function (struct svalue *s, int ref_type) +{ +#ifdef PIKE_DEBUG + if (s->type != T_FUNCTION) + Pike_fatal ("Should only be called for a function svalue.\n"); +#endif + + if (s->subtype == FUNCTION_BUILTIN) + /* Could avoid this if we had access to the action from the caller + * and check if it's VISIT_COMPLEX_ONLY. However, visit_callable + * will only return first thing. */ + visit_callable_ref (s->u.efun, ref_type); + else + visit_object_ref (s->u.object, ref_type); +} + static void gc_check_object(struct object *o); PMOD_EXPORT void gc_mark_object_as_referenced(struct object *o) @@ -1834,11 +1980,6 @@ PMOD_EXPORT void gc_mark_object_as_referenced(struct object *o) int e; struct program *p = o->prog; - if (Pike_in_gc == GC_PASS_COUNT_MEMORY) { - if (p) gc_counted_bytes += p->storage_needed + sizeof (struct object); - gc_check_object (o); - } - if (o == gc_mark_object_pos) gc_mark_object_pos = o->next; if (o == gc_internal_object) diff --git a/src/object.h b/src/object.h index 2692a32cffc355aecf575fdda14ab4594b7da46e..ec8b589e29bf369b63c5f1f1333af4e966252a1d 100644 --- a/src/object.h +++ b/src/object.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: object.h,v 1.94 2008/04/18 19:45:42 grubba Exp $ +|| $Id: object.h,v 1.95 2008/05/11 02:35:22 mast Exp $ */ #ifndef OBJECT_H @@ -123,6 +123,8 @@ union anything *object_get_item_ptr(struct object *o, PMOD_EXPORT int object_equal_p(struct object *a, struct object *b, struct processing *p); PMOD_EXPORT struct array *object_indices(struct object *o); PMOD_EXPORT struct array *object_values(struct object *o); +void visit_object (struct object *o, int action); +PMOD_EXPORT void visit_function (struct svalue *s, int ref_type); PMOD_EXPORT void gc_mark_object_as_referenced(struct object *o); PMOD_EXPORT void real_gc_cycle_check_object(struct object *o, int weak); unsigned gc_touch_all_objects(void); @@ -155,6 +157,9 @@ void check_all_objects(void); #define master() debug_master() #endif +#define visit_object_ref(O, REF_TYPE) \ + visit_ref (pass_object (O), (REF_TYPE), \ + (visit_thing_fn *) &visit_object, NULL) #define gc_cycle_check_object(X, WEAK) \ gc_cycle_enqueue((gc_cycle_check_cb *) real_gc_cycle_check_object, (X), (WEAK)) diff --git a/src/pike_types.c b/src/pike_types.c index d082eb690ec56afa0af0678258cbdfe8f1f5cf9f..6a6c2eed88dcd8eb52f82abfdd9ba2d2a80b89c8 100644 --- a/src/pike_types.c +++ b/src/pike_types.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: pike_types.c,v 1.330 2008/05/10 11:53:41 grubba Exp $ +|| $Id: pike_types.c,v 1.331 2008/05/11 02:35:22 mast Exp $ */ #include "global.h" @@ -7837,77 +7837,85 @@ void cleanup_pike_type_table(void) #endif /* DO_PIKE_CLEANUP */ } -/* This is only enough gc stuff to detect leaking pike_type structs - * and to get _locate_references and Pike.count_memory working. More - * is needed if types are extended to contain pointers to other memory - * objects or if they might contain cycles. */ - -void gc_check_type (struct pike_type *t) +void visit_type (struct pike_type *t, int action) { - debug_malloc_touch (t); + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + break; +#endif + case VISIT_COMPLEX_ONLY: + return; + case VISIT_COUNT_BYTES: + mc_counted_bytes += sizeof (struct pike_type); + break; + } - GC_ENTER (t, T_TYPE) { - switch (t->type) { - case T_FUNCTION: - case T_MANY: - case T_TUPLE: - case T_MAPPING: - case T_OR: - case T_AND: - case PIKE_T_RING: - case PIKE_T_ATTRIBUTE: - case PIKE_T_NAME: - debug_gc_check (t->car, " as car in a type"); - debug_gc_check (t->cdr, " as cdr in a type"); - break; - case T_ARRAY: - case T_MULTISET: - case T_NOT: - case T_TYPE: - case T_PROGRAM: - case T_STRING: - debug_gc_check (t->car, " as car in a type"); - break; - case T_SCOPE: - case T_ASSIGN: - debug_gc_check (t->cdr, " as cdr in a type"); - break; + switch (t->type) { + case T_FUNCTION: + case T_MANY: + case T_TUPLE: + case T_MAPPING: + case T_OR: + case T_AND: + case PIKE_T_RING: + visit_type_ref (t->car, REF_TYPE_INTERNAL); + /* FALL_THROUGH */ + case T_SCOPE: + case T_ASSIGN: + visit_type_ref (t->cdr, REF_TYPE_INTERNAL); + break; + case T_ARRAY: + case T_MULTISET: + case T_NOT: + case T_TYPE: + case T_PROGRAM: + case T_STRING: + visit_type_ref (t->car, REF_TYPE_INTERNAL); + break; + case PIKE_T_ATTRIBUTE: + case PIKE_T_NAME: + visit_string_ref ((struct pike_string *) t->car, REF_TYPE_INTERNAL); + visit_type_ref (t->cdr, REF_TYPE_INTERNAL); + break; #ifdef PIKE_DEBUG - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case T_FLOAT: - case T_MIXED: - case T_VOID: - case T_ZERO: - case PIKE_T_UNKNOWN: - case T_INT: - case T_OBJECT: - break; - default: - Pike_fatal("gc_check_type: " - "Unhandled type-node: %d\n", t->type); - break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case T_FLOAT: + case T_MIXED: + case T_VOID: + case T_ZERO: + case PIKE_T_UNKNOWN: + case T_INT: + case T_OBJECT: + break; + default: + Pike_fatal("visit_type: Unhandled type-node: %d\n", t->type); + break; #endif /* PIKE_DEBUG */ - } - } GC_LEAVE; + } } +#if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) + +/* This is only enough gc stuff to detect leaking pike_type structs + * and to locate references to them. More is needed if types are + * extended to contain pointers to other memory objects or if they + * might contain cycles. */ + void gc_mark_type_as_referenced(struct pike_type *t) { if (gc_mark(t)) { - if (Pike_in_gc == GC_PASS_COUNT_MEMORY) { - gc_counted_bytes += sizeof (struct pike_type); - gc_check_type (t); - } - GC_ENTER(t, PIKE_T_TYPE) { switch(t->type) { case PIKE_T_SCOPE: @@ -7937,8 +7945,6 @@ void gc_mark_type_as_referenced(struct pike_type *t) } } -#if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) - #ifdef PIKE_DEBUG static void gc_mark_external_types(struct callback *cb, void *a, void *b) { @@ -7995,6 +8001,64 @@ static void gc_mark_external_types(struct callback *cb, void *a, void *b) } #endif +void gc_check_type (struct pike_type *t) +{ + debug_malloc_touch (t); + + GC_ENTER (t, T_TYPE) { + switch (t->type) { + case T_FUNCTION: + case T_MANY: + case T_TUPLE: + case T_MAPPING: + case T_OR: + case T_AND: + case PIKE_T_RING: + case PIKE_T_ATTRIBUTE: + case PIKE_T_NAME: + debug_gc_check (t->car, " as car in a type"); + debug_gc_check (t->cdr, " as cdr in a type"); + break; + case T_ARRAY: + case T_MULTISET: + case T_NOT: + case T_TYPE: + case T_PROGRAM: + case T_STRING: + debug_gc_check (t->car, " as car in a type"); + break; + case T_SCOPE: + case T_ASSIGN: + debug_gc_check (t->cdr, " as cdr in a type"); + break; +#ifdef PIKE_DEBUG + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case T_FLOAT: + case T_MIXED: + case T_VOID: + case T_ZERO: + case PIKE_T_UNKNOWN: + case T_INT: + case T_OBJECT: + break; + default: + Pike_fatal("gc_check_type: " + "Unhandled type-node: %d\n", t->type); + break; +#endif /* PIKE_DEBUG */ + } + } GC_LEAVE; +} + void gc_check_all_types (void) { unsigned INT32 e; diff --git a/src/pike_types.h b/src/pike_types.h index 2023d5785fe6c70894ca1db5168ca1cc57adb339..74663359de977d812f2816cb2581344d42fbc7c9 100644 --- a/src/pike_types.h +++ b/src/pike_types.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: pike_types.h,v 1.113 2008/04/25 13:45:22 grubba Exp $ +|| $Id: pike_types.h,v 1.114 2008/05/11 02:35:22 mast Exp $ */ #ifndef PIKE_TYPES_H @@ -275,6 +275,7 @@ struct pike_type *object_type_to_program_type(struct pike_type *obj_t); PMOD_EXPORT char *get_name_of_type(TYPE_T t); void cleanup_pike_types(void); void cleanup_pike_type_table(void); +void visit_type (struct pike_type *t, int action); void gc_mark_type_as_referenced(struct pike_type *t); void gc_check_type (struct pike_type *t); void gc_check_all_types (void); @@ -289,6 +290,10 @@ void register_attribute_handler(struct pike_string *attr, struct svalue *handler); /* Prototypes end here */ +#define visit_type_ref(T, REF_TYPE) \ + visit_ref (pass_type (T), (REF_TYPE), \ + (visit_thing_fn *) &visit_type, NULL) + #if 0 /* FIXME: Not supported under USE_PIKE_TYPE yet. */ /* "Dynamic types" - use with ADD_FUNCTION_DTYPE */ #define dtStore(TYPE) {int e; for (e=0; e<CONSTANT_STRLEN(TYPE); e++) unsafe_push_type((TYPE)[e]);} diff --git a/src/program.c b/src/program.c index fb98ccd946c72a7fb0ed5417b4115d2a9030f52b..406a25a4877837605cc49890fccc5ec8e5500412 100644 --- a/src/program.c +++ b/src/program.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: program.c,v 1.690 2008/05/10 20:43:25 mast Exp $ +|| $Id: program.c,v 1.691 2008/05/11 02:35:22 mast Exp $ */ #include "global.h" @@ -3758,17 +3758,16 @@ PMOD_EXPORT void set_exit_callback(void (*exit)(struct object *)) * The callback is called after any mapped variables on the object * have been recursed (and possibly freed). * - * If there are unmapped pointers to allocated memory then you should - * add something like this to the recurse callback so that - * Pike.count_memory remains accurate: + * If there are pointers to allocated memory that you keep track of on + * the C level then you should add something like this to the recurse + * callback so that Pike.count_memory remains accurate: * - * if (Pike_in_gc == GC_PASS_COUNT_MEMORY) - * gc_counted_bytes += <size of the allocated memory block(s)> + * if (mc_count_bytes (Pike_fp->current_storage)) + * mc_counted_bytes += <size of the allocated memory block(s)> * * If the allocated memory is shared between objects then it gets more - * complicated and you should insert calls to the gc check callback - * too. See e.g. multiset.c or mapping.c for how to handle that - * correctly. + * complicated and you need to write visit_thing_fn callbacks. See + * e.g. visit_mapping and visit_mapping_data for how to do that. * * This function is obsolete; see pike_set_prog_event_callback for * details. @@ -9416,6 +9415,63 @@ void cleanup_program(void) } } + +void visit_program (struct program *p, int action) +{ + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + case VISIT_COMPLEX_ONLY: + break; +#endif + case VISIT_COUNT_BYTES: + mc_counted_bytes += p->total_size; + break; + } + + if (!(p->flags & PROGRAM_AVOID_CHECK)) { + int e; + struct program_constant *consts = p->constants; + struct inherit *inh = p->inherits; + + for (e = p->num_constants - 1; e >= 0; e--) + visit_svalue (&consts[e].sval, REF_TYPE_NORMAL); + + for (e = p->num_inherits - 1; e >= 0; e--) { + if (inh[e].parent) + visit_object_ref (inh[e].parent, REF_TYPE_NORMAL); + + if (e && inh[e].prog) + visit_program_ref (inh[e].prog, REF_TYPE_NORMAL); + } + + if (!(action & VISIT_COMPLEX_ONLY)) { + struct identifier *ids = p->identifiers; + struct pike_string **strs = p->strings; + + for (e = p->num_inherits - 1; e >= 0; e--) { + if (inh[e].name) + visit_string_ref (inh[e].name, REF_TYPE_NORMAL); + } + + for (e = p->num_identifiers - 1; e >= 0; e--) { + struct identifier *id = ids + e; + visit_string_ref (id->name, REF_TYPE_NORMAL); + visit_type_ref (id->type, REF_TYPE_NORMAL); + } + + for (e = p->num_strings - 1; e >= 0; e--) + visit_string_ref (strs[e], REF_TYPE_NORMAL); + } + + /* Strong ref follows. It must be last. */ + if (p->parent) + visit_program_ref (p->parent, REF_TYPE_STRONG); + } +} + static void gc_check_program(struct program *p); void gc_mark_program_as_referenced(struct program *p) @@ -9446,11 +9502,6 @@ void gc_mark_program_as_referenced(struct program *p) GC_ENTER (p, T_PROGRAM) { int e; - if (Pike_in_gc == GC_PASS_COUNT_MEMORY) { - gc_counted_bytes += p->total_size; - gc_check_program (p); - } - if (p == gc_mark_program_pos) gc_mark_program_pos = p->next; if (p == gc_internal_program) diff --git a/src/program.h b/src/program.h index 82c0d537b6a3b166f78af9b8383d4c36fb56b9ca..52c7dda909f62999d272058156d31c988f66989a 100644 --- a/src/program.h +++ b/src/program.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: program.h,v 1.241 2008/05/01 21:44:33 mast Exp $ +|| $Id: program.h,v 1.242 2008/05/11 02:35:23 mast Exp $ */ #ifndef PROGRAM_H @@ -905,6 +905,7 @@ void check_all_programs(void); void placeholder_index(INT32 args); void init_program(void); void cleanup_program(void); +void visit_program (struct program *p, int action); void gc_mark_program_as_referenced(struct program *p); void real_gc_cycle_check_program(struct program *p, int weak); unsigned gc_touch_all_programs(void); @@ -1009,6 +1010,9 @@ void count_memory_in_programs(size_t *, size_t *); #define start_new_program() debug_start_new_program(__LINE__,__FILE__) +#define visit_program_ref(P, REF_TYPE) \ + visit_ref (pass_program (P), (REF_TYPE), \ + (visit_thing_fn *) &visit_program, NULL) #define gc_cycle_check_program(X, WEAK) \ gc_cycle_enqueue((gc_cycle_check_cb *) real_gc_cycle_check_program, (X), (WEAK)) diff --git a/src/stralloc.c b/src/stralloc.c index 8cd3c9c4cfaceabf2d86fe7892cd96824bf01a0e..497a1692c55288a727e25d4b605b12f96500e773 100644 --- a/src/stralloc.c +++ b/src/stralloc.c @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: stralloc.c,v 1.217 2008/05/03 15:29:26 nilsson Exp $ +|| $Id: stralloc.c,v 1.218 2008/05/11 02:36:00 mast Exp $ */ #include "global.h" @@ -2134,11 +2134,20 @@ void count_memory_in_strings(size_t *num, size_t *size) size[0]=size_; } -void gc_mark_string_as_referenced (struct pike_string *s) +void visit_string (struct pike_string *s, int action) { - if (gc_mark (s)) - if (Pike_in_gc == GC_PASS_COUNT_MEMORY) - gc_counted_bytes += memory_in_string (s); + switch (action) { +#ifdef PIKE_DEBUG + default: + Pike_fatal ("Unknown visit action %d.\n", action); + case VISIT_NORMAL: + case VISIT_COMPLEX_ONLY: + break; +#endif + case VISIT_COUNT_BYTES: + mc_counted_bytes += memory_in_string (s); + break; + } } #ifdef PIKE_DEBUG @@ -2162,8 +2171,7 @@ void gc_mark_all_strings(void) for(e=0;e<htable_size;e++) { struct pike_string *p; - for(p=base_table[e];p;p=p->next) - gc_mark_string_as_referenced(p); + for(p=base_table[e];p;p=p->next) gc_is_referenced(p); } } #endif diff --git a/src/stralloc.h b/src/stralloc.h index 6bb771158bd09c9f647e10922c81b43423b99157..36e638a71ae041a922c363bc7b88599add22e94e 100644 --- a/src/stralloc.h +++ b/src/stralloc.h @@ -2,7 +2,7 @@ || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. -|| $Id: stralloc.h,v 1.102 2008/05/02 04:15:18 mast Exp $ +|| $Id: stralloc.h,v 1.103 2008/05/11 02:36:00 mast Exp $ */ #ifndef STRALLOC_H @@ -330,6 +330,7 @@ PMOD_EXPORT struct pike_string *string_replace(struct pike_string *str, void init_shared_string_table(void); void cleanup_shared_string_table(void); void count_memory_in_strings(size_t *num, size_t *size); +void visit_string (struct pike_string *s, int action); void gc_mark_string_as_referenced (struct pike_string *s); unsigned gc_touch_all_strings(void); void gc_mark_all_strings(void); @@ -415,6 +416,10 @@ static INLINE void string_builder_binary_strcat(struct string_builder *s, #define ISCONSTSTR(X,Y) c_compare_string((X),Y,sizeof(Y)-sizeof("")) +#define visit_string_ref(S, REF_TYPE) \ + visit_ref (pass_string (S), (REF_TYPE), \ + (visit_thing_fn *) &visit_string, NULL) + #ifdef DEBUG_MALLOC #define make_shared_string(X) \ ((struct pike_string *)debug_malloc_pass(debug_make_shared_string(X)))