From 71a1c07fe32d2da69400aa9b630291342ce70bca Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Tue, 20 Jul 2021 23:26:38 -0700 Subject: parse/eval: use weak-both hash tables. This addresses the problem that 89059a932cbfc030abc3ebf63582766b177300b2 tried to fix. * eval.c (eval_init): Make all the top-level binding tables, top_fb, top_vb, top_mb, top_smb, special and builtin, weak-both tables: keys and values are weak. This way, the entries disappear if both key and value are unreachable, even if they refer to each other. (eval_compat_fixup): In 266 or earlier compat mode, weak-both tables don't have the right semantics, so we tweak the tables to weak-key tables. * parser.c (parse_init): Same treatment for stream_parser_hash. We want an entry to disappear from the hash if neither the parser nor the stream are reachable. (parse_compat_fixup): New function. * parser.h (parse_compat_function): Declared. * hash.c, hash.h (tweak_hash): New function. * lib.c (compat_fixup): Call parse_compat_fixup. --- eval.c | 21 +++++++++++++++------ hash.c | 9 +++++++++ hash.h | 1 + lib.c | 1 + parser.c | 8 +++++++- parser.h | 1 + 6 files changed, 34 insertions(+), 7 deletions(-) diff --git a/eval.c b/eval.c index d51eb5d3..6ed4a7d1 100644 --- a/eval.c +++ b/eval.c @@ -6488,12 +6488,12 @@ void eval_init(void) &call_f, &iter_begin_f, &iter_from_binding_f, &iter_more_f, &iter_item_f, &iter_step_f, &unbound_s, &origin_hash, &const_foldable_hash, convert(val *, 0)); - top_fb = make_hash(t, nil, nil); - top_vb = make_hash(t, nil, nil); - top_mb = make_hash(t, nil, nil); - top_smb = make_hash(t, nil, nil); - special = make_hash(t, nil, nil); - builtin = make_hash(t, nil, nil); + top_fb = make_hash(t, t, nil); + top_vb = make_hash(t, t, nil); + top_mb = make_hash(t, t, nil); + top_smb = make_hash(t, t, nil); + special = make_hash(t, t, nil); + builtin = make_hash(t, t, nil); op_table = make_hash(nil, nil, nil); pm_table = make_hash(nil, nil, nil); @@ -7342,6 +7342,15 @@ void eval_init(void) void eval_compat_fixup(int compat_ver) { + if (compat_ver <= 266) { + tweak_hash(top_fb, t, nil); + tweak_hash(top_vb, t, nil); + tweak_hash(top_mb, t, nil); + tweak_hash(top_smb, t, nil); + tweak_hash(special, t, nil); + tweak_hash(builtin, t, nil); + } + if (compat_ver <= 107) reg_fun(intern(lit("flip"), user_package), func_n1(swap_12_21)); } diff --git a/hash.c b/hash.c index 3434b026..6caa7397 100644 --- a/hash.c +++ b/hash.c @@ -826,6 +826,15 @@ static val do_make_hash(val weak_keys, val weak_vals, } } +val tweak_hash(val hash, val weak_keys, val weak_vals) +{ + val self = lit("tweak-hash"); + struct hash *h = coerce(struct hash *, cobj_handle(self, hash, hash_cls)); + int flags = ((weak_vals != nil) << 1) | (weak_keys != nil); + h->flags = convert(hash_flags_t, flags); + return hash; +} + val make_seeded_hash(val weak_keys, val weak_vals, val equal_based, val seed) { return do_make_hash(weak_keys, weak_vals, diff --git a/hash.h b/hash.h index 8792b609..3b773a6b 100644 --- a/hash.h +++ b/hash.h @@ -39,6 +39,7 @@ extern struct cobj_class *hash_cls; ucnum equal_hash(val obj, int *count, ucnum); val make_seeded_hash(val weak_keys, val weak_vals, val equal_based, val seed); +val tweak_hash(val hash, val weak_keys, val weak_vals); val make_hash(val weak_keys, val weak_vals, val equal_based); val make_eq_hash(val weak_keys, val weak_vals); val make_similar_hash(val existing); diff --git a/lib.c b/lib.c index 0e8bbbb1..274d3956 100644 --- a/lib.c +++ b/lib.c @@ -14052,6 +14052,7 @@ int compat_fixup(int compat_ver) eval_compat_fixup(compat_ver); rand_compat_fixup(compat_ver); + parse_compat_fixup(compat_ver); return 0; } diff --git a/parser.c b/parser.c index 0deb3867..169b58b0 100644 --- a/parser.c +++ b/parser.c @@ -1878,7 +1878,7 @@ void parse_init(void) parser_cls = cobj_register(parser_s); protect(&stream_parser_hash, &unique_s, &catch_all, convert(val *, 0)); - stream_parser_hash = make_hash(t, nil, nil); + stream_parser_hash = make_hash(t, t, nil); catch_all = cons(t, nil); parser_l_init(); @@ -1897,3 +1897,9 @@ void parse_init(void) reg_fun(intern(lit("repl"), system_package), func_n4(repl)); reg_mac(json_s, func_n2(me_json)); } + +void parse_compat_fixup(int compat_ver) +{ + if (compat_ver <= 266) + tweak_hash(stream_parser_hash, t, nil); +} diff --git a/parser.h b/parser.h index 3d682daa..b504b083 100644 --- a/parser.h +++ b/parser.h @@ -148,3 +148,4 @@ val parser_set_lineno(val self, val stream, val lineno); val parser_errors(val parser); val parse_errors(val stream); void parse_init(void); +void parse_compat_fixup(int compat_ver); -- cgit v1.2.3