I've got a patch for copy_svalues_recursively_no_free() that I'd like to commit. The biggest gain is that the temporary mapping is only allocated when recursing into arrays/mappings/multisets with complex elements, and we now avoid placing simple elements in the mapping where they serve no purpose. Comments welcome on any breakage that this would lead to.
(Two small bonus changes; Grubba's fix to real_allocate_array() wasn't that memory-friendly, and there was an odd add-ref/sub-ref/add-ref sequence when copying empty arrays.)
Index: svalue.c =================================================================== RCS file: /pike/data/cvsroot/Pike/7.8/src/svalue.c,v retrieving revision 1.260 diff -u -w -r1.260 svalue.c --- svalue.c 27 May 2010 23:17:09 -0000 1.260 +++ svalue.c 8 Jul 2010 00:19:42 -0000 @@ -1896,49 +1896,53 @@ { ONERROR err; int allocated_here = 0; - if (!m) { - m = allocate_mapping(num); - allocated_here = 1; - SET_ONERROR(err, do_free_mapping, m); - } while(num--) { struct svalue *tmp; + int from_type = from->type;
check_svalue_type (from); check_refs(from);
- if ((tmp = low_mapping_lookup(m, from))) { + if (from_type == T_ARRAY || + from_type == T_MAPPING || + from_type == T_MULTISET) { + /* Recursive data */ + if (m && (tmp = low_mapping_lookup(m, from))) { *to = *tmp; if (tmp->type <= MAX_REF_TYPE) add_ref(tmp->u.dummy); - to++; - from++; - continue; + } else { +#define ALLOC_DUPL_MAPPING(type_hint) \ + do if (!m && (type_hint) & BIT_COMPLEX) { \ + m = allocate_mapping(num && 1); \ + allocated_here = 1; \ + SET_ONERROR(err, do_free_mapping, m); \ + } while (0) + + if (from_type == T_ARRAY) { + struct array *ar = from->u.array; + ALLOC_DUPL_MAPPING(ar->type_field); + to->u.array = copy_array_recursively(ar, m); + } else if (from_type == T_MAPPING) { + struct mapping *ma = from->u.mapping; + ALLOC_DUPL_MAPPING(m_ind_types(ma) | m_val_types(ma)); + to->u.mapping = copy_mapping_recursively(ma, m); + } else { + struct multiset *mu = from->u.multiset; + ALLOC_DUPL_MAPPING(multiset_ind_types(mu) | multiset_val_types(mu)); + to->u.multiset = copy_multiset_recursively(mu, m); } + to->type = from_type;
- switch(from->type) - { - default: + /* Only store pair if there's a chance we'll look at it later */ + if (m && (!allocated_here || num)) + mapping_insert(m, from, to); + } + } else { *to=*from; - if(from->type <= MAX_REF_TYPE) add_ref(from->u.array); - break; - - case T_ARRAY: - to->u.array=copy_array_recursively(from->u.array,m); - to->type=T_ARRAY; - break; - - case T_MAPPING: - to->u.mapping=copy_mapping_recursively(from->u.mapping,m); - to->type=T_MAPPING; - break; - - case T_MULTISET: - to->u.multiset=copy_multiset_recursively(from->u.multiset,m); - to->type=T_MULTISET; - break; + if (from_type <= MAX_REF_TYPE) add_ref(from->u.array); } - mapping_insert(m, from, to); + to++; from++; } Index: array.c =================================================================== RCS file: /pike/data/cvsroot/Pike/7.8/src/array.c,v retrieving revision 1.227 diff -u -w -r1.227 array.c --- array.c 1 Jul 2010 09:16:05 -0000 1.227 +++ array.c 8 Jul 2010 00:19:43 -0000 @@ -80,7 +80,6 @@ ptrdiff_t extra_space) { struct array *v; - ptrdiff_t e;
if(size+extra_space == 0) { @@ -116,9 +115,11 @@ INIT_PIKE_MEMOBJ(v); DOUBLELINK (first_array, v);
- MEMSET(v->real_item, 0, sizeof(struct svalue) * size); - for(e=0;e<size;e++) { - v->item[e].type=T_INT; + { + struct svalue *item = ITEM(v); + struct svalue *item_end = item + v->size; + while (item < item_end) + *item++ = svalue_int_zero; }
return v; @@ -2432,12 +2433,14 @@ #endif
if (!a->size) { - add_ref(&empty_array); - return array_set_flags(&empty_array, a->flags); + ret = (a->flags & ARRAY_WEAK_FLAG) ? &weak_empty_array : &empty_array; + add_ref(ret); + return ret; }
ret=allocate_array_no_init(a->size,0);
+ if (m) { aa.type = T_ARRAY; aa.subtype = 0; aa.u.array = a; @@ -2445,6 +2448,7 @@ bb.subtype = 0; bb.u.array = ret; low_mapping_insert(m, &aa, &bb, 1); + }
ret->flags = a->flags & ~ARRAY_LVALUE;
Index: mapping.c =================================================================== RCS file: /pike/data/cvsroot/Pike/7.8/src/mapping.c,v retrieving revision 1.216 diff -u -w -r1.216 mapping.c --- mapping.c 31 May 2010 10:18:26 -0000 1.216 +++ mapping.c 8 Jul 2010 00:19:43 -0000 @@ -2153,6 +2153,7 @@
ret=allocate_mapping(MAP_SLOTS(m->data->size));
+ if (p) { aa.type = T_MAPPING; aa.subtype = 0; aa.u.mapping = m; @@ -2160,6 +2161,7 @@ bb.subtype = 0; bb.u.mapping = ret; mapping_insert(p, &aa, &bb); + }
ret->data->flags = m->data->flags;
Index: multiset.c =================================================================== RCS file: /pike/data/cvsroot/Pike/7.8/src/multiset.c,v retrieving revision 1.119 diff -u -w -r1.119 multiset.c --- multiset.c 28 Nov 2009 13:36:20 -0000 1.119 +++ multiset.c 8 Jul 2010 00:19:44 -0000 @@ -3745,6 +3745,7 @@ add_ref (new.msd2 = msd); SET_ONERROR (uwp, free_tree_build_data, &new);
+ if (p) { aa.type = T_MULTISET; aa.subtype = 0; aa.u.multiset = l; @@ -3752,6 +3753,7 @@ bb.subtype = 0; bb.u.multiset = new.l; mapping_insert(p, &aa, &bb); + }
node = low_multiset_first (msd); pos = 0;