diff --git a/src/mapping.c b/src/mapping.c index dba67d5d1769a5a61d79dcfabd35366af52251b2..1da6a0f4d19ded3a9e9aabe0ceab2998a368fd07 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: mapping.c,v 1.98 2000/08/11 13:20:44 grubba Exp $"); +RCSID("$Id: mapping.c,v 1.99 2000/09/03 23:18:46 mast Exp $"); #include "main.h" #include "object.h" #include "mapping.h" @@ -110,7 +110,7 @@ static void check_mapping_type_fields(struct mapping *m) } #endif -static struct mapping_data empty_data = { 1, 1, 0,0,0,0,0 }; +static struct mapping_data empty_data = { 1, 1, 0,0,0,0,0,0 }; /* This function allocates the hash table and svalue space for a mapping * struct. The size is the max number of indices that can fit in the @@ -125,6 +125,8 @@ static void init_mapping(struct mapping *m, INT32 size) debug_malloc_touch(m); #ifdef PIKE_DEBUG + if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_ZAP_WEAK) + fatal("Can't allocate a new mapping_data inside gc.\n"); if(size < 0) fatal("init_mapping with negative value.\n"); #endif if(size) @@ -153,6 +155,7 @@ static void init_mapping(struct mapping *m, INT32 size) md->free_list[e-1].val.type=T_INT; md->ind_types = 0; md->val_types = 0; + md->flags = 0; md->size = 0; md->refs=0; md->valrefs=0; @@ -163,7 +166,7 @@ static void init_mapping(struct mapping *m, INT32 size) } add_ref(md); m->data=md; -#ifdef PIKE_DEBUG +#ifdef MAPPING_SIZE_DEBUG m->debug_size = md->size; #endif } @@ -182,7 +185,6 @@ PMOD_EXPORT struct mapping *debug_allocate_mapping(int size) init_mapping(m,size); m->refs = 1; - m->flags = 0; DOUBLELINK(first_mapping, m); @@ -330,7 +332,8 @@ static struct mapping *rehash(struct mapping *m, int new_size) #ifdef PIKE_DEBUG if(m->data->size != tmp) fatal("Rehash failed, size not same any more.\n"); - +#endif +#ifdef MAPPING_SIZE_DEBUG m->debug_size = m->data->size; #endif @@ -355,6 +358,11 @@ struct mapping_data *copy_mapping_data(struct mapping_data *md) struct mapping_data *nmd; struct keypair *keypairs; +#ifdef PIKE_DEBUG + if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_ZAP_WEAK) + fatal("Can't allocate a new mapping_data inside gc.\n"); +#endif + debug_malloc_touch(md); size=MAPPING_DATA_SIZE(md->hashsize, md->num_keypairs); @@ -392,6 +400,8 @@ struct mapping_data *copy_mapping_data(struct mapping_data *md) return nmd; } +#define MAPPING_DATA_IN_USE(MD) ((MD)->refs != (MD)->hardlinks + 1) + #define LOW_FIND(FUN, KEY, FOUND, NOT_FOUND) do { \ md=m->data; \ add_ref(md); \ @@ -540,6 +550,17 @@ PMOD_EXPORT void mapping_fix_type_field(struct mapping *m) m->data->ind_types = ind_types; } +PMOD_EXPORT void mapping_set_flags(struct mapping *m, int flags) +{ + struct mapping_data *md = m->data; + if (md->refs > 1) { + struct keypair *k, *prev; + COPYMAP2(); + } + md->flags = flags; +} + + /* This function inserts key:val into the mapping m. * Same as doing m[key]=val; in pike. */ @@ -631,7 +652,7 @@ PMOD_EXPORT void low_mapping_insert(struct mapping *m, assign_svalue_no_free(& k->val, val); k->hval = h2; md->size++; -#ifdef PIKE_DEBUG +#ifdef MAPPING_SIZE_DEBUG if(m->data ==md) m->debug_size++; #endif @@ -742,7 +763,7 @@ PMOD_EXPORT union anything *mapping_get_item_ptr(struct mapping *m, md->ind_types |= 1 << key->type; md->val_types |= BIT_INT; md->size++; -#ifdef PIKE_DEBUG +#ifdef MAPPING_SIZE_DEBUG if(m->data ==md) m->debug_size++; #endif @@ -818,7 +839,7 @@ PMOD_EXPORT void map_delete_no_free(struct mapping *m, k->next=md->free_list; md->free_list=k; md->size--; -#ifdef PIKE_DEBUG +#ifdef MAPPING_SIZE_DEBUG if(m->data ==md) m->debug_size--; #endif @@ -835,6 +856,50 @@ PMOD_EXPORT void map_delete_no_free(struct mapping *m, return; } +static void low_check_mapping_for_destruct( + struct mapping_data *md, int e, struct keypair **prev, + TYPE_FIELD ind_types, TYPE_FIELD val_types) +{ + struct keypair *k; + +#ifdef PIKE_DEBUG + if (MAPPING_DATA_IN_USE(md)) fatal("The mapping data is busy.\n"); +#endif + debug_malloc_touch(md); + + if (prev) { + k = *prev; + goto jump_in; + } + + for(e=0;e<md->hashsize;e++) + { + for(prev= md->hash + e;(k=*prev);) + { + jump_in: + check_destructed(& k->val); + + if((k->ind.type == T_OBJECT || k->ind.type == T_FUNCTION) && + !k->ind.u.object->prog) + { + *prev=k->next; + free_svalue(& k->ind); + free_svalue(& k->val); + k->next=md->free_list; + md->free_list=k; + md->size--; + }else{ + val_types |= 1 << k->val.type; + ind_types |= 1 << k->ind.type; + prev=&k->next; + } + } + } + + md->val_types = val_types; + md->ind_types = ind_types; +} + PMOD_EXPORT void check_mapping_for_destruct(struct mapping *m) { INT32 e; @@ -847,9 +912,6 @@ PMOD_EXPORT void check_mapping_for_destruct(struct mapping *m) fatal("Zero refs in mapping->data\n"); if(d_flag>1) check_mapping(m); debug_malloc_touch(m); - if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_ZAP_WEAK && - Pike_in_gc != GC_PASS_MARK) - fatal("check_mapping_for_destruct called in wrong pass inside gc.\n"); #endif /* no is_eq -> no locking */ @@ -864,49 +926,65 @@ PMOD_EXPORT void check_mapping_for_destruct(struct mapping *m) { for(prev= md->hash + e;(k=*prev);) { - check_destructed(& k->val); - if((k->ind.type == T_OBJECT || k->ind.type == T_FUNCTION) && !k->ind.u.object->prog) { - debug_malloc_touch(md); +#ifdef MAPPING_SIZE_DEBUG + size_t old_size = md->size; +#endif debug_malloc_touch(m); + debug_malloc_touch(md); PREPARE_FOR_INDEX_CHANGE2(); - *prev=k->next; - free_svalue(& k->ind); - free_svalue(& k->val); - k->next=md->free_list; - md->free_list=k; - md->size--; -#ifdef PIKE_DEBUG - if(m->data ==md) - { - m->debug_size++; - debug_malloc_touch(m); - } + low_check_mapping_for_destruct (md, e, prev, ind_types, val_types); +#ifdef MAPPING_SIZE_DEBUG + m->debug_size -= old_size - md->size; #endif - debug_malloc_touch(md); + goto done; }else{ + check_destructed(& k->val); val_types |= 1 << k->val.type; ind_types |= 1 << k->ind.type; prev=&k->next; } } } + + done: if(MAP_SLOTS(md->size) < md->hashsize * MIN_LINK_LENGTH) { debug_malloc_touch(m); rehash(m, MAP_SLOTS(md->size)); } - md->val_types = val_types; - md->ind_types = ind_types; #ifdef PIKE_DEBUG - if(d_flag>1) check_mapping(m); + if(d_flag>1) check_mapping(m); #endif } } +/* This one doesn't copy the mapping data before writing it. Instead + * it does nothing at all if the mapping data is busy. */ +static void stealth_check_mapping_for_destruct(struct mapping *m) +{ + struct mapping_data *md=m->data; + + if (MAPPING_DATA_IN_USE(md)) { + TYPE_FIELD val_types = 0; + INT32 e; + struct keypair *k; + md->val_types |= BIT_INT; + NEW_MAPPING_LOOP(md) { + check_destructed(&k->val); + val_types |= 1 << k->val.type; + } + md->val_types = val_types; + } + + else + if((md->ind_types | md->val_types) & (BIT_OBJECT | BIT_FUNCTION)) + low_check_mapping_for_destruct (md, 0, 0, 0, 0); +} + PMOD_EXPORT struct svalue *low_mapping_lookup(struct mapping *m, struct svalue *key) { @@ -1220,7 +1298,7 @@ PMOD_EXPORT struct mapping *copy_mapping(struct mapping *m) debug_malloc_touch(n->data); free_mapping_data(n->data); n->data=m->data; -#ifdef PIKE_DEBUG +#ifdef MAPPING_SIZE_DEBUG n->debug_size=n->data->size; #endif n->data->refs++; @@ -1404,6 +1482,10 @@ PMOD_EXPORT int mapping_equal_p(struct mapping *a, struct mapping *b, struct pro #endif if(a==b) return 1; + + check_mapping_for_destruct(a); + check_mapping_for_destruct(b); + if(m_sizeof(a) != m_sizeof(b)) return 0; curr.pointer_a = a; @@ -1414,9 +1496,6 @@ PMOD_EXPORT int mapping_equal_p(struct mapping *a, struct mapping *b, struct pro if(p->pointer_a == (void *)a && p->pointer_b == (void *)b) return 1; - check_mapping_for_destruct(a); - check_mapping_for_destruct(b); - md=a->data; md->valrefs++; add_ref(md); @@ -1603,7 +1682,6 @@ PMOD_EXPORT struct mapping *copy_mapping_recursively(struct mapping *m, return copy_mapping(m); ret=allocate_mapping(MAP_SLOTS(m->data->size)); - ret->flags=m->flags; doing.pointer_b=ret; check_stack(2); @@ -1729,6 +1807,7 @@ void check_mapping(struct mapping *m) if(m->next && m->next->prev != m) fatal("Mapping ->next->prev != mapping.\n"); +#ifdef MAPPING_SIZE_DEBUG if(m->debug_size != md->size) { if(Pike_in_gc) @@ -1743,6 +1822,7 @@ void check_mapping(struct mapping *m) describe(md); fatal("Mapping zapping detected (%d != %d)!\n",m->debug_size,md->size); } +#endif if(m->prev) { @@ -1830,8 +1910,9 @@ static void gc_recurse_weak_mapping(struct mapping *m, struct mapping_data *md=m->data; #ifdef PIKE_DEBUG - if(!(m->flags & MAPPING_FLAG_WEAK)) + if(!(md->flags & MAPPING_FLAG_WEAK)) fatal("Mapping is not weak.\n"); + if (MAPPING_DATA_IN_USE(md)) fatal("Mapping data is busy.\n"); #endif /* no locking required (no is_eq) */ @@ -1842,14 +1923,13 @@ static void gc_recurse_weak_mapping(struct mapping *m, int i, v; if((i = recurse_fn(&k->ind, 1)) | (v = recurse_fn(&k->val, 1))) { - PREPARE_FOR_INDEX_CHANGE(); *prev=k->next; if (!i) free_svalue(&k->ind); if (!v) free_svalue(&k->val); k->next=md->free_list; md->free_list=k; md->size--; -#ifdef PIKE_DEBUG +#ifdef MAPPING_SIZE_DEBUG if(m->data ==md) m->debug_size--; #endif @@ -1862,26 +1942,19 @@ static void gc_recurse_weak_mapping(struct mapping *m, } md->val_types = val_types; md->ind_types = ind_types; - - if(MAP_SLOTS(md->size) < md->hashsize * MIN_LINK_LENGTH) - { - debug_malloc_touch(m); - rehash(m, MAP_SLOTS(md->size)); - } } void gc_mark_mapping_as_referenced(struct mapping *m) { - INT32 e; - struct keypair *k; - #ifdef PIKE_DEBUG if(m->data->refs <=0) fatal("Zero refs in mapping->data\n"); #endif if(gc_mark(m)) { - check_mapping_for_destruct(m); + struct mapping_data *md = m->data; + + stealth_check_mapping_for_destruct(m); if (m == gc_mark_mapping_pos) gc_mark_mapping_pos = m->next; if (m == gc_internal_mapping) @@ -1891,22 +1964,30 @@ void gc_mark_mapping_as_referenced(struct mapping *m) DOUBLELINK(first_mapping, m); /* Linked in first. */ } - if(gc_mark(m->data) && - ((m->data->ind_types | m->data->val_types) & BIT_COMPLEX)) + if(gc_mark(md) && ((md->ind_types | md->val_types) & BIT_COMPLEX)) { - if (m->flags & MAPPING_FLAG_WEAK) + INT32 e; + struct keypair *k; + + if (MAPPING_DATA_IN_USE(md)) { + /* Must leave destructed indices intact if the mapping data is busy. */ + NEW_MAPPING_LOOP(md) + if ((!IS_DESTRUCTED(&k->ind) && gc_mark_svalues(&k->ind, 1)) | + gc_mark_svalues(&k->val, 1)) { +#ifdef PIKE_DEBUG + fatal("Didn't expect an svalue zapping now.\n"); +#endif + } + } + else if (md->flags & MAPPING_FLAG_WEAK) gc_recurse_weak_mapping(m, gc_mark_weak_svalues); else - NEW_MAPPING_LOOP(m->data) - { - if (gc_mark_svalues(&k->ind, 1) || - gc_mark_svalues(&k->val, 1)) { + NEW_MAPPING_LOOP(md) + if (gc_mark_svalues(&k->ind, 1) | gc_mark_svalues(&k->val, 1)) { #ifdef PIKE_DEBUG - fatal("Looks like check_mapping_for_destruct " - "didn't do its job properly.\n"); + fatal("stealth_check_mapping_for_destruct didn't do its job properly.\n"); #endif } - } } } } @@ -1914,66 +1995,64 @@ void gc_mark_mapping_as_referenced(struct mapping *m) void real_gc_cycle_check_mapping(struct mapping *m, int weak) { GC_CYCLE_ENTER(m, weak) { + struct mapping_data *md = m->data; + #ifdef PIKE_DEBUG - if(m->data->refs <=0) + if(md->refs <=0) fatal("Zero refs in mapping->data\n"); #endif - if((m->data->ind_types | m->data->val_types) & BIT_COMPLEX) + if((md->ind_types | md->val_types) & BIT_COMPLEX) { INT32 e; struct keypair *k; - if (m->flags & MAPPING_FLAG_WEAK) + if (MAPPING_DATA_IN_USE(md)) { + /* Must leave destructed indices intact if the mapping data is busy. */ + NEW_MAPPING_LOOP(md) + if ((!IS_DESTRUCTED(&k->ind) && gc_cycle_check_svalues(&k->ind, 1)) | + gc_cycle_check_svalues(&k->val, 1)) { +#ifdef PIKE_DEBUG + fatal("Didn't expect an svalue zapping now.\n"); +#endif + } + } + else if (md->flags & MAPPING_FLAG_WEAK) gc_recurse_weak_mapping(m, gc_cycle_check_weak_svalues); else - NEW_MAPPING_LOOP(m->data) - { - if (gc_cycle_check_svalues(&k->ind, 1) || - gc_cycle_check_svalues(&k->val, 1)) { + NEW_MAPPING_LOOP(md) + if (gc_cycle_check_svalues(&k->ind, 1) | gc_cycle_check_svalues(&k->val, 1)) { #ifdef PIKE_DEBUG - fatal("Looks like check_mapping_for_destruct " - "didn't do its job properly.\n"); + fatal("stealth_check_mapping_for_destruct didn't do its job properly.\n"); #endif } - } } } GC_CYCLE_LEAVE; } static void gc_check_mapping(struct mapping *m) { - INT32 e; - struct keypair *k; + struct mapping_data *md = m->data; - if((m->data->ind_types | m->data->val_types) & BIT_COMPLEX) + if((md->ind_types | md->val_types) & BIT_COMPLEX) { - if(debug_gc_check(m->data, T_MAPPING, m)) return; + INT32 e; + struct keypair *k; - if (m->flags & MAPPING_FLAG_WEAK) { - MAPPING_LOOP(m) - { - /* We do not want to count this key:index pair if - * the index is a destructed object or function - */ - if(((1 << k->ind.type) & (BIT_OBJECT | BIT_FUNCTION)) && - !(k->ind.u.object->prog)) - continue; + if(debug_gc_check(md, T_MAPPING, m)) return; + if (md->flags & MAPPING_FLAG_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_weak_svalues(&k->ind, 1, T_MAPPING, m); debug_gc_check_weak_svalues(&k->val, 1, T_MAPPING, m); } } else { - MAPPING_LOOP(m) + NEW_MAPPING_LOOP(md) { - /* We do not want to count this key:index pair if - * the index is a destructed object or function - */ - if(((1 << k->ind.type) & (BIT_OBJECT | BIT_FUNCTION)) && - !(k->ind.u.object->prog)) - continue; - debug_gc_check_svalues(&k->ind, 1, T_MAPPING, m); debug_gc_check_svalues(&k->val, 1, T_MAPPING, m); } @@ -1990,6 +2069,7 @@ unsigned gc_touch_all_mappings(void) fatal("Error in mapping link list.\n"); for (m = first_mapping; m; m = m->next) { debug_gc_touch(m); + debug_gc_touch(m->data); n++; if (m->next && m->next->prev != m) fatal("Error in mapping link list.\n"); @@ -2030,7 +2110,7 @@ void gc_mark_all_mappings(void) else /* Done in gc_mark_mapping_as_referenced() otherwise (and it has * to be done there). */ - check_mapping_for_destruct(m); + stealth_check_mapping_for_destruct(m); } } @@ -2072,7 +2152,7 @@ void gc_free_all_unreferenced_mappings(void) m->data->refs++; unlink_mapping_data(md); -#ifdef PIKE_DEBUG +#ifdef MAPPING_SIZE_DEBUG m->debug_size=0; #endif gc_free_extra_ref(m); @@ -2100,13 +2180,13 @@ void simple_describe_mapping(struct mapping *m) void debug_dump_mapping(struct mapping *m) { - fprintf(stderr, "Refs=%d, flags=0x%x, next=%p, prev=%p", - m->refs, m->flags, m->next, m->prev); + fprintf(stderr, "Refs=%d, next=%p, prev=%p", + m->refs, m->next, m->prev); if (((ptrdiff_t)m->data) & 3) { fprintf(stderr, ", data=%p (unaligned)\n", m->data); } else { - fprintf(stderr, ", size=%d, hashsize=%d\n", - m->data->size, m->data->hashsize); + fprintf(stderr, ", flags=0x%x, size=%d, hashsize=%d\n", + m->data->flags, m->data->size, m->data->hashsize); fprintf(stderr, "Indices type field = "); debug_dump_type_field(m->data->ind_types); fprintf(stderr, "\n"); @@ -2147,7 +2227,7 @@ void zap_all_mappings(void) } } md->size=0; -#ifdef PIKE_DEBUG +#ifdef MAPPING_SIZE_DEBUG if(m->data ==md) m->debug_size=0; #endif