summaryrefslogtreecommitdiffstats
path: root/filter.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-03-29 11:44:52 -0700
committerKaz Kylheku <kaz@kylheku.com>2014-03-29 22:55:55 -0700
commitc61ccd9769c9c83dcdf5f7693af2ca0a605b6e19 (patch)
tree6e9cfead5209cc2c591f472d8c884bf5fe9563ce /filter.c
parentc20c994098c12f499fd24a89305ff37c7a2bcf76 (diff)
downloadtxr-c61ccd9769c9c83dcdf5f7693af2ca0a605b6e19.tar.gz
txr-c61ccd9769c9c83dcdf5f7693af2ca0a605b6e19.tar.bz2
txr-c61ccd9769c9c83dcdf5f7693af2ca0a605b6e19.zip
Change to how locations are passed around, for the sake of generational
GC. The issue being solved here is the accuracy of the gc_set function. The existing impelmentation is too conservative. It has no generation information about the memory location being stored, and so it assumes the worst: that it is a location in the middle of a gen 1 object. This is sub-optimal, creating unacceptable pressure against the checkobj array and, worse, as a consequence causing unreachable gen 0 objects to be tenured into gen 1. To solve this problem, we replace "val *" pointers with a structure of type "loc" which keeps track of the object too, which lets us discover the generation. I tried another approach: using just a pointer with a bitfield indicating the generation. This turned out to have a serious issue: such a bitfield goes stale when the object is moved to a different generation. The object holding the memory location is in gen 1, but the annotated pointer still indicates gen 0. The gc_set function then makes the wrong decision, and premature reclamation takes place. * combi.c (perm_init_common, comb_gen_fun_common, rcomb_gen_fun_common, rcomb_list_gen_fun): Update to new interfaces for managing mutation. * debug.c (debug): Update to new interfaces for managing mutation. Avoid loc variable name. * eval.c (env_fbind, env_fbind): Update to new interfaces for managing mutation. (lookup_var_l, dwim_loc): Return loc type and update to new interfaces. (apply_frob_args, op_modplace, op_dohash, transform_op, mapcarv, mappendv, repeat_infinite_func, repeat_times_func): Update to new interfaces for managing mutation. * eval.h (lookup_var_l): Declaration updated. * filter.c (trie_add, trie_compress, trie_compress_intrinsic, * build_filter, built_filter_from_list, filter_init): Update to new * interfaces. * gc.c (gc_set): Rewritten to use loc type which provides the exact generation. We do not need the in_malloc_range hack any more, since we have the backpointer to the object. (gc_push): Take loc rather than raw pointer. * gc.h (gc_set, gc_push): Declarations updated. * hash.c (struct hash): The acons* functions use loc instead of val * now. (hash_equal_op, copy_hash, gethash_c, inhash, gethash_n, pushhash, Change to how locations are passed around, for the sake of generational GC. The issue being solved here is the accuracy of the gc_set function. The existing impelmentation is too conservative. It has no generation information about the memory location being stored, and so it assumes the worst: that it is a location in the middle of a gen 1 object. This is sub-optimal, creating unacceptable pressure against the checkobj array and, worse, as a consequence causing unreachable gen 0 objects to be tenured into gen 1. To solve this problem, we replace "val *" pointers with a structure of type "loc" which keeps track of the object too, which lets us discover the generation. I tried another approach: using just a pointer with a bitfield indicating the generation. This turned out to have a serious issue: such a bitfield goes stale when the object is moved to a different generation. The object holding the memory location is in gen 1, but the annotated pointer still indicates gen 0. The gc_set function then makes the wrong decision, and premature reclamation takes place. * combi.c (perm_init_common, comb_gen_fun_common, rcomb_gen_fun_common, rcomb_list_gen_fun): Update to new interfaces for managing mutation. * debug.c (debug): Update to new interfaces for managing mutation. Avoid loc variable name. * eval.c (env_fbind, env_fbind): Update to new interfaces for managing mutation. (lookup_var_l, dwim_loc): Return loc type and update to new interfaces. (apply_frob_args, op_modplace, op_dohash, transform_op, mapcarv, mappendv, repeat_infinite_func, repeat_times_func): Update to new interfaces for managing mutation. * eval.h (lookup_var_l): Declaration updated. * filter.c (trie_add, trie_compress, trie_compress_intrinsic, * build_filter, built_filter_from_list, filter_init): Update to new * interfaces. * gc.c (gc_set): Rewritten to use loc type which provides the exact generation. We do not need the in_malloc_range hack any more, since we have the backpointer to the object. (gc_push): Take loc rather than raw pointer. * gc.h (gc_set, gc_push): Declarations updated. * hash.c (struct hash): The acons* functions use loc instead of val * now. (hash_equal_op, copy_hash, gethash_c, inhash, gethash_n, pushhash,
Diffstat (limited to 'filter.c')
-rw-r--r--filter.c26
1 files changed, 13 insertions, 13 deletions
diff --git a/filter.c b/filter.c
index 4ac65f17..646c4d28 100644
--- a/filter.c
+++ b/filter.c
@@ -62,10 +62,10 @@ static val trie_add(val trie, val key, val value)
for (node = trie, i = zero; lt(i, len); i = plus(i, one)) {
val ch = chr_str(key, i);
val newnode_p;
- val *loc = gethash_l(node, ch, &newnode_p);
+ loc place = gethash_l(node, ch, mkcloc(newnode_p));
if (newnode_p)
- set(*loc, make_hash(nil, nil, nil));
- node = *loc;
+ set(place, make_hash(nil, nil, nil));
+ node = deref(place);
}
set_hash_userdata(node, value);
@@ -84,21 +84,21 @@ static val trie_add(val trie, val key, val value)
* character, and whose CDR is the transition.
*/
-static void trie_compress(val *ptrie)
+static void trie_compress(loc ptrie)
{
- val trie = *ptrie;
+ val trie = deref(ptrie);
if (hashp(trie)) {
val count = hash_count(trie);
val value = get_hash_userdata(trie);
if (zerop(count)) {
- set(*ptrie, value);
+ set(ptrie, value);
} else if (count == one && nilp(value)) {
val iter = hash_begin(trie);
val cell = hash_next(iter);
- set(*ptrie, cons(car(cell), cdr(cell)));
- trie_compress(cdr_l(*ptrie));
+ set(ptrie, cons(car(cell), cdr(cell)));
+ trie_compress(cdr_l(deref(ptrie)));
} else {
val cell, iter = hash_begin(trie);
@@ -107,12 +107,12 @@ static void trie_compress(val *ptrie)
}
} else if (consp(trie)) {
trie_compress(cdr_l(trie));
- }
+ }
}
static val trie_compress_intrinsic(val ptrie)
{
- trie_compress(&ptrie);
+ trie_compress(mkcloc(ptrie));
return ptrie;
}
@@ -184,7 +184,7 @@ static val build_filter(struct filter_pair *pair, val compress_p)
trie_add(trie, static_str(pair[i].key), static_str(pair[i].value));
if (compress_p)
- trie_compress(&trie);
+ trie_compress(mkcloc(trie));
return trie;
}
@@ -198,7 +198,7 @@ static val build_filter_from_list(val list)
mapcar(curry_123_2(func_n3(trie_add), trie, first(tuple)), rest(tuple));
}
- trie_compress(&trie);
+ trie_compress(mkcloc(trie));
return trie;
}
@@ -706,7 +706,7 @@ void filter_init(void)
{
val trie = build_filter(from_html_table, nil);
trie_add(trie, lit("&#"), func_n1(html_numeric_handler));
- trie_compress(&trie);
+ trie_compress(mkcloc(trie));
sethash(filters, from_html_k, trie);
}
sethash(filters, upcase_k, func_n1(upcase_str));