diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2014-03-29 11:44:52 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2014-03-29 22:55:55 -0700 |
commit | c61ccd9769c9c83dcdf5f7693af2ca0a605b6e19 (patch) | |
tree | 6e9cfead5209cc2c591f472d8c884bf5fe9563ce /filter.c | |
parent | c20c994098c12f499fd24a89305ff37c7a2bcf76 (diff) | |
download | txr-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.c | 26 |
1 files changed, 13 insertions, 13 deletions
@@ -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)); |