summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-07-20 23:26:38 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-07-20 23:26:38 -0700
commit5613a3b0d42a89d061df18cd9ae4e1008696572c (patch)
treecf810df036b366a9f3fab00117db639e2b6c4378
parenta6f0c72306da0c628be9e180288f79fbf29bfa57 (diff)
downloadtxr-5613a3b0d42a89d061df18cd9ae4e1008696572c.tar.gz
txr-5613a3b0d42a89d061df18cd9ae4e1008696572c.tar.bz2
txr-5613a3b0d42a89d061df18cd9ae4e1008696572c.zip
parse/eval: use weak-both hash tables.
This addresses the problem that a4c376979d15323ad729e92e41ba43768e8dc163 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.
-rw-r--r--eval.c21
-rw-r--r--hash.c9
-rw-r--r--hash.h1
-rw-r--r--lib.c1
-rw-r--r--parser.c8
-rw-r--r--parser.h1
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);