wingo pushed a commit to branch wip-whippet
in repository guile.

commit 8280c8485fde0d347f0d9fa5c5740b62a8509fe1
Author: Andy Wingo <wi...@pobox.com>
AuthorDate: Tue May 13 14:57:31 2025 +0200

    Move weak table implementation to Scheme
    
    * libguile/weak-table.c:
    * libguile/weak-table.h: Remove.
    
    * libguile.h: Remove weak-table.h include.
    * libguile/Makefile.am (libguile_@GUILE_EFFECTIVE_VERSION@_la_SOURCES):
    (DOT_X_FILES):
    (DOT_DOC_FILES):
    (modinclude_HEADERS): Remove weak-table.[ch].
    
    * libguile/evalext.c:
    * libguile/fluids.c:
    * libguile/hash.c:
    * libguile/init.c:
    * libguile/print.c:
    * libguile/scm.h: Remove uses of weak-table.h and free up the tc7.
    
    * libguile/hashtab.c:
    * libguile/hashtab.h: Add deprecated shims to dispatch to (ice-9
    weak-tables) when working on weak tables.
    
    * module/ice-9/weak-tables.scm: New implementation.  Embeds the hash and
    equality functions in the table itself.
    
    * module/ice-9/object-properties.scm:
    * module/ice-9/poe.scm:
    * module/ice-9/popen.scm:
    * module/ice-9/source-properties.scm:
    * module/language/cps/compile-bytecode.scm:
    * module/language/ecmascript/array.scm:
    * module/language/ecmascript/function.scm:
    * module/oop/goops/save.scm:
    * module/srfi/srfi-18.scm:
    * module/srfi/srfi-69.scm:
    * module/system/base/types.scm:
    * module/system/base/types/internal.scm:
    * module/system/foreign.scm:
    * module/system/vm/assembler.scm:
    * test-suite/tests/gc.test:
    * test-suite/tests/hash.test:
    * test-suite/tests/srfi-69.test:
    * test-suite/tests/types.test:
    * test-suite/tests/weaks.test: Update to use new, non-deprecated weak
    tables API.
---
 libguile.h                               |   1 -
 libguile/Makefile.am                     |  12 +-
 libguile/evalext.c                       |   1 -
 libguile/fluids.c                        |   1 -
 libguile/hash.c                          |   1 -
 libguile/hashtab.c                       | 683 ++++++++++++++++++++++----
 libguile/hashtab.h                       |  11 +-
 libguile/init.c                          |   4 +-
 libguile/print.c                         |   4 -
 libguile/scm.h                           |   2 +-
 libguile/weak-table.c                    | 807 -------------------------------
 libguile/weak-table.h                    |  86 ----
 module/ice-9/object-properties.scm       |   9 +-
 module/ice-9/poe.scm                     |  50 +-
 module/ice-9/popen.scm                   |  12 +-
 module/ice-9/source-properties.scm       |   5 +-
 module/ice-9/weak-tables.scm             | 358 +++++++++++++-
 module/language/cps/compile-bytecode.scm |   1 -
 module/language/ecmascript/array.scm     |   5 +-
 module/language/ecmascript/function.scm  |  10 +-
 module/oop/goops/save.scm                |   8 +-
 module/srfi/srfi-18.scm                  |  11 +-
 module/srfi/srfi-69.scm                  |   5 +
 module/system/base/types.scm             |   2 -
 module/system/base/types/internal.scm    |   3 +-
 module/system/foreign.scm                |   8 +-
 module/system/vm/assembler.scm           |   1 -
 test-suite/tests/gc.test                 |   4 +-
 test-suite/tests/hash.test               |   5 +-
 test-suite/tests/srfi-69.test            |   6 +-
 test-suite/tests/types.test              |   3 -
 test-suite/tests/weaks.test              | 144 +++---
 32 files changed, 1094 insertions(+), 1169 deletions(-)

diff --git a/libguile.h b/libguile.h
index b7211f4f3..9bcc32402 100644
--- a/libguile.h
+++ b/libguile.h
@@ -114,7 +114,6 @@ extern "C" {
 #include "libguile/vm.h"
 #include "libguile/vports.h"
 #include "libguile/weak-set.h"
-#include "libguile/weak-table.h"
 #include "libguile/backtrace.h"
 #include "libguile/debug.h"
 #include "libguile/stacks.h"
diff --git a/libguile/Makefile.am b/libguile/Makefile.am
index 1cc0d34b8..68bda9160 100644
--- a/libguile/Makefile.am
+++ b/libguile/Makefile.am
@@ -237,8 +237,7 @@ libguile_@GUILE_EFFECTIVE_VERSION@_la_SOURCES =             
                \
        version.c                               \
        vm.c                                    \
        vports.c                                \
-       weak-set.c                              \
-       weak-table.c
+       weak-set.c
 
 if ENABLE_JIT
 libguile_@GUILE_EFFECTIVE_VERSION@_la_SOURCES += $(lightening_c_files)
@@ -347,8 +346,7 @@ DOT_X_FILES =                                       \
        vectors.x                               \
        version.x                               \
        vm.x                                    \
-       weak-set.x                              \
-       weak-table.x
+       weak-set.x
 
 EXTRA_DOT_X_FILES = @EXTRA_DOT_X_FILES@
 
@@ -445,8 +443,7 @@ DOT_DOC_FILES =                             \
        vectors.doc                             \
        version.doc                             \
        vports.doc                              \
-       weak-set.doc                            \
-       weak-table.doc
+       weak-set.doc
 
 EXTRA_DOT_DOC_FILES = @EXTRA_DOT_DOC_FILES@
 
@@ -706,8 +703,7 @@ modinclude_HEADERS =                                \
        vm-expand.h                             \
        vm.h                                    \
        vports.h                                \
-       weak-set.h                              \
-       weak-table.h
+       weak-set.h
 
 nodist_modinclude_HEADERS = version.h scmconfig.h
 
diff --git a/libguile/evalext.c b/libguile/evalext.c
index 418b32261..07c9a0239 100644
--- a/libguile/evalext.c
+++ b/libguile/evalext.c
@@ -80,7 +80,6 @@ SCM_DEFINE (scm_self_evaluating_p, "self-evaluating?", 1, 0, 
0,
        case scm_tc7_pointer:
        case scm_tc7_hashtable:
        case scm_tc7_weak_set:
-       case scm_tc7_weak_table:
        case scm_tc7_fluid:
        case scm_tc7_dynamic_state:
         case scm_tc7_frame:
diff --git a/libguile/fluids.c b/libguile/fluids.c
index a2fadbd8a..6de7b83f7 100644
--- a/libguile/fluids.c
+++ b/libguile/fluids.c
@@ -40,7 +40,6 @@
 #include "print.h"
 #include "threads.h"
 #include "variable.h"
-#include "weak-table.h"
 
 #include "fluids.h"
 
diff --git a/libguile/hash.c b/libguile/hash.c
index a076213a2..b30d7750e 100644
--- a/libguile/hash.c
+++ b/libguile/hash.c
@@ -347,7 +347,6 @@ scm_raw_ihash (SCM obj, size_t depth)
     case scm_tc7_program:
     case scm_tc7_vm_cont:
     case scm_tc7_weak_set:
-    case scm_tc7_weak_table:
     case scm_tc7_port:
       return scm_raw_ihashq (SCM_UNPACK (obj));
 
diff --git a/libguile/hashtab.c b/libguile/hashtab.c
index b4f004c1d..09738436c 100644
--- a/libguile/hashtab.c
+++ b/libguile/hashtab.c
@@ -1,4 +1,4 @@
-/* Copyright 1995-1996,1998-2001,2003-2004,2006,2008-2013,2018
+/* Copyright 1995-1996,1998-2001,2003-2004,2006,2008-2013,2018,2025
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -30,23 +30,441 @@
 #include "alist.h"
 #include "bdw-gc.h"
 #include "boolean.h"
+#include "deprecation.h"
 #include "eq.h"
 #include "eval.h"
 #include "gsubr.h"
 #include "hash.h"
 #include "list.h"
+#include "modules.h"
 #include "numbers.h"
 #include "pairs.h"
 #include "ports.h"
 #include "procs.h"
+#include "threads.h"
+#include "variable.h"
 #include "vectors.h"
-#include "weak-table.h"
 
 #include "hashtab.h"
 
 
 
 
+#if (SCM_ENABLE_DEPRECATED == 1)
+
+/* In versions 3.0 and prior, the hash table interface could also access
+   weak tables.  This is now deprecated.  */
+
+static SCM make_weak_key_hash_table_var;
+static SCM weak_key_hash_table_p_var;
+static SCM weak_key_hash_table_ref_var;
+static SCM weak_key_hash_table_set_x_var;
+static SCM weak_key_hash_table_remove_x_var;
+static SCM weak_key_hash_table_clear_x_var;
+static SCM weak_key_hash_table_fold_var;
+static SCM weak_key_hash_table_for_each_var;
+static SCM weak_key_hash_table_map_to_list_var;
+
+static SCM make_weak_value_hash_table_var;
+static SCM weak_value_hash_table_p_var;
+static SCM weak_value_hash_table_ref_var;
+static SCM weak_value_hash_table_set_x_var;
+static SCM weak_value_hash_table_remove_x_var;
+static SCM weak_value_hash_table_clear_x_var;
+static SCM weak_value_hash_table_fold_var;
+static SCM weak_value_hash_table_for_each_var;
+static SCM weak_value_hash_table_map_to_list_var;
+
+static SCM make_doubly_weak_hash_table_var;
+static SCM doubly_weak_hash_table_p_var;
+static SCM doubly_weak_hash_table_ref_var;
+static SCM doubly_weak_hash_table_set_x_var;
+static SCM doubly_weak_hash_table_remove_x_var;
+static SCM doubly_weak_hash_table_clear_x_var;
+static SCM doubly_weak_hash_table_fold_var;
+static SCM doubly_weak_hash_table_for_each_var;
+static SCM doubly_weak_hash_table_map_to_list_var;
+
+static void
+init_weak_hash_table_constructor_vars (void)
+{
+  make_weak_key_hash_table_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "make-weak-key-hash-table");
+  make_weak_value_hash_table_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "make-weak-value-hash-table");
+  make_doubly_weak_hash_table_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "make-doubly-weak-hash-table");
+}
+
+static void
+init_weak_hash_table_predicate_vars (void)
+{
+  weak_key_hash_table_p_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-key-hash-table?");
+  weak_value_hash_table_p_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-value-hash-table?");
+  doubly_weak_hash_table_p_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "doubly-weak-hash-table?");
+}
+
+static void
+init_weak_hash_table_accessor_vars (void)
+{
+  weak_key_hash_table_ref_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-key-hash-table-ref");
+  weak_key_hash_table_set_x_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-key-hash-table-set!");
+  weak_key_hash_table_remove_x_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-key-hash-table-remove!");
+  weak_key_hash_table_clear_x_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-key-hash-table-clear!");
+
+  weak_value_hash_table_ref_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-value-hash-table-ref");
+  weak_value_hash_table_set_x_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-value-hash-table-set!");
+  weak_value_hash_table_remove_x_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-value-hash-table-remove!");
+  weak_value_hash_table_clear_x_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-value-hash-table-clear!");
+
+  doubly_weak_hash_table_ref_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "doubly-weak-hash-table-ref");
+  doubly_weak_hash_table_set_x_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "doubly-weak-hash-table-set!");
+  doubly_weak_hash_table_remove_x_var =
+    scm_c_public_lookup ("ice-9 weak-tables", 
"doubly-weak-hash-table-remove!");
+  doubly_weak_hash_table_clear_x_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "doubly-weak-hash-table-clear!");
+}
+
+static void
+init_weak_hash_table_iteration_vars (void)
+{
+  weak_key_hash_table_fold_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-key-hash-table-fold");
+  weak_key_hash_table_for_each_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-key-hash-table-for-each");
+  weak_key_hash_table_map_to_list_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-key-hash-table-map->list");
+
+  weak_value_hash_table_fold_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "weak-value-hash-table-fold");
+  weak_value_hash_table_for_each_var =
+    scm_c_public_lookup ("ice-9 weak-tables", 
"weak-value-hash-table-for-each");
+  weak_value_hash_table_map_to_list_var =
+    scm_c_public_lookup ("ice-9 weak-tables", 
"weak-value-hash-table-map->list");
+
+  doubly_weak_hash_table_fold_var =
+    scm_c_public_lookup ("ice-9 weak-tables", "doubly-weak-hash-table-fold");
+  doubly_weak_hash_table_for_each_var =
+    scm_c_public_lookup ("ice-9 weak-tables", 
"doubly-weak-hash-table-for-each");
+  doubly_weak_hash_table_map_to_list_var =
+    scm_c_public_lookup ("ice-9 weak-tables", 
"doubly-weak-hash-table-map->list");
+}
+
+static void
+init_weak_table_constructors (void)
+{
+  static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
+  scm_c_issue_deprecation_warning
+    ("Creating weak hash tables from C is deprecated.  Invoke "
+     "make-weak-key-hash-table, etc. from (ice-9 weak-tables) instead.");
+  scm_i_pthread_once (&once, init_weak_hash_table_constructor_vars);
+}
+
+static void
+init_weak_table_predicates (void)
+{
+  static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
+  scm_i_pthread_once (&once, init_weak_hash_table_predicate_vars);
+}
+
+static void
+init_weak_table_accessors (void)
+{
+  static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
+  scm_c_issue_deprecation_warning
+    ("Accessing weak hash tables via hashq-ref, hashq-set!, and so on is "
+     "deprecated.  Invoke the weak-table-specific procedures from (ice-9 "
+     "weak-tables) instead.");
+  scm_i_pthread_once (&once, init_weak_hash_table_accessor_vars);
+}
+
+static void
+init_weak_table_iterators (void)
+{
+  static scm_i_pthread_once_t once = SCM_I_PTHREAD_ONCE_INIT;
+  scm_c_issue_deprecation_warning
+    ("Iterating weak hash tables via hash-fold, hash-for-each, and so on is "
+     "deprecated.  Invoke the weak-table-specific procedures from (ice-9 "
+     "weak-tables) instead.");
+  scm_i_pthread_once (&once, init_weak_hash_table_iteration_vars);
+}
+
+static int
+is_weak_key_hash_table (SCM x)
+{
+  init_weak_table_predicates ();
+  return scm_is_true
+    (scm_call_1 (scm_variable_ref (weak_key_hash_table_p_var), x));
+}
+
+static int
+is_weak_value_hash_table (SCM x)
+{
+  init_weak_table_predicates ();
+  return scm_is_true
+    (scm_call_1 (scm_variable_ref (weak_value_hash_table_p_var), x));
+}
+
+static int
+is_doubly_weak_hash_table (SCM x)
+{
+  init_weak_table_predicates ();
+  return scm_is_true
+    (scm_call_1 (scm_variable_ref (doubly_weak_hash_table_p_var), x));
+}
+
+static SCM
+weak_key_hash_table_ref (SCM table, SCM key, SCM dflt)
+{
+  init_weak_table_accessors ();
+  // FIXME: #:default-value
+  SCM ret = scm_call_2 (scm_variable_ref (weak_key_hash_table_ref_var),
+                        table, key);
+  return scm_is_false (ret) ? dflt : ret;
+}
+
+static SCM
+weak_key_hash_table_set_x (SCM table, SCM key, SCM value)
+{
+  init_weak_table_accessors ();
+  scm_call_3 (scm_variable_ref (weak_key_hash_table_set_x_var),
+              table, key, value);
+  return value;
+}
+
+static SCM
+weak_key_hash_table_remove_x (SCM table, SCM key)
+{
+  init_weak_table_accessors ();
+  scm_call_2 (scm_variable_ref (weak_key_hash_table_remove_x_var),
+              table, key);
+  return SCM_BOOL_F;
+}
+
+static SCM
+weak_key_hash_table_clear_x (SCM table)
+{
+  init_weak_table_accessors ();
+  scm_call_1 (scm_variable_ref (weak_key_hash_table_clear_x_var), table);
+  return SCM_UNSPECIFIED;
+}
+
+static SCM
+weak_key_hash_table_fold (SCM proc, SCM init, SCM table)
+{
+  init_weak_table_iterators ();
+  return scm_call_3 (scm_variable_ref (weak_key_hash_table_fold_var),
+                     proc, init, table);
+}
+
+static SCM
+weak_key_hash_table_for_each (SCM proc, SCM table)
+{
+  init_weak_table_iterators ();
+  scm_call_2 (scm_variable_ref (weak_key_hash_table_for_each_var),
+              proc, table);
+  return SCM_UNSPECIFIED;
+}
+
+static SCM
+weak_key_hash_table_map_to_list (SCM proc, SCM table)
+{
+  init_weak_table_iterators ();
+  return scm_call_2 (scm_variable_ref (weak_key_hash_table_map_to_list_var),
+                     proc, table);
+}
+
+static SCM
+weak_value_hash_table_ref (SCM table, SCM key, SCM dflt)
+{
+  init_weak_table_accessors ();
+  // FIXME: #:default-value
+  SCM ret = scm_call_2 (scm_variable_ref (weak_value_hash_table_ref_var),
+                        table, key);
+  return scm_is_false (ret) ? dflt : ret;
+}
+
+static SCM
+weak_value_hash_table_set_x (SCM table, SCM key, SCM value)
+{
+  init_weak_table_accessors ();
+  scm_call_3 (scm_variable_ref (weak_value_hash_table_set_x_var),
+              table, key, value);
+  return value;
+}
+
+static SCM
+weak_value_hash_table_remove_x (SCM table, SCM key)
+{
+  init_weak_table_accessors ();
+  scm_call_2 (scm_variable_ref (weak_value_hash_table_remove_x_var),
+              table, key);
+  return SCM_BOOL_F;
+}
+
+static SCM
+weak_value_hash_table_clear_x (SCM table)
+{
+  init_weak_table_accessors ();
+  scm_call_1 (scm_variable_ref (weak_value_hash_table_clear_x_var), table);
+  return SCM_UNSPECIFIED;
+}
+
+static SCM
+weak_value_hash_table_fold (SCM proc, SCM init, SCM table)
+{
+  init_weak_table_iterators ();
+  return scm_call_3 (scm_variable_ref (weak_value_hash_table_fold_var),
+                     proc, init, table);
+}
+
+static SCM
+weak_value_hash_table_for_each (SCM proc, SCM table)
+{
+  init_weak_table_iterators ();
+  scm_call_2 (scm_variable_ref (weak_value_hash_table_for_each_var),
+              proc, table);
+  return SCM_UNSPECIFIED;
+}
+
+static SCM
+weak_value_hash_table_map_to_list (SCM proc, SCM table)
+{
+  init_weak_table_iterators ();
+  return scm_call_2 (scm_variable_ref (weak_value_hash_table_map_to_list_var),
+                     proc, table);
+}
+
+static SCM
+doubly_weak_hash_table_ref (SCM table, SCM key, SCM dflt)
+{
+  init_weak_table_accessors ();
+  // FIXME: #:default-value
+  SCM ret = scm_call_2 (scm_variable_ref (doubly_weak_hash_table_ref_var),
+                        table, key);
+  return scm_is_false (ret) ? dflt : ret;
+}
+
+static SCM
+doubly_weak_hash_table_set_x (SCM table, SCM key, SCM value)
+{
+  init_weak_table_accessors ();
+  scm_call_3 (scm_variable_ref (doubly_weak_hash_table_set_x_var),
+              table, key, value);
+  return value;
+}
+
+static SCM
+doubly_weak_hash_table_remove_x (SCM table, SCM key)
+{
+  init_weak_table_accessors ();
+  scm_call_2 (scm_variable_ref (doubly_weak_hash_table_remove_x_var),
+              table, key);
+  return SCM_BOOL_F;
+}
+
+static SCM
+doubly_weak_hash_table_clear_x (SCM table)
+{
+  init_weak_table_accessors ();
+  scm_call_1 (scm_variable_ref (doubly_weak_hash_table_clear_x_var), table);
+  return SCM_UNSPECIFIED;
+}
+
+static SCM
+doubly_weak_hash_table_fold (SCM proc, SCM init, SCM table)
+{
+  init_weak_table_iterators ();
+  return scm_call_3 (scm_variable_ref (doubly_weak_hash_table_fold_var),
+                     proc, init, table);
+}
+
+static SCM
+doubly_weak_hash_table_for_each (SCM proc, SCM table)
+{
+  init_weak_table_iterators ();
+  scm_call_2 (scm_variable_ref (doubly_weak_hash_table_for_each_var),
+              proc, table);
+  return SCM_UNSPECIFIED;
+}
+
+static SCM
+doubly_weak_hash_table_map_to_list (SCM proc, SCM table)
+{
+  init_weak_table_iterators ();
+  return scm_call_2 (scm_variable_ref (doubly_weak_hash_table_map_to_list_var),
+                     proc, table);
+}
+
+SCM
+scm_make_weak_key_hash_table (SCM unused)
+{
+  init_weak_table_constructors ();
+  return scm_call_0 (scm_variable_ref (make_weak_key_hash_table_var));
+}
+
+SCM
+scm_make_weak_value_hash_table (SCM unused)
+{
+  init_weak_table_constructors ();
+  return scm_call_0 (scm_variable_ref (make_weak_value_hash_table_var));
+}
+
+SCM
+scm_make_doubly_weak_hash_table (SCM unused)
+{
+  init_weak_table_constructors ();
+  return scm_call_0 (scm_variable_ref (make_doubly_weak_hash_table_var));
+}
+
+SCM
+scm_weak_key_hash_table_p (SCM x)
+{
+  init_weak_table_predicates ();
+  scm_c_issue_deprecation_warning
+    ("scm_weak_key_hash_table_p is deprecated.  Use weak-key-hash-table? "
+     "from (ice-9 weak-tables) instead.");
+  return scm_from_bool (is_weak_key_hash_table (x));
+}
+
+SCM
+scm_weak_value_hash_table_p (SCM x)
+{
+  init_weak_table_predicates ();
+  scm_c_issue_deprecation_warning
+    ("scm_weak_value_hash_table_p is deprecated.  Use weak-value-hash-table? "
+     "from (ice-9 weak-tables) instead.");
+  return scm_from_bool (is_weak_value_hash_table (x));
+}
+
+SCM
+scm_doubly_weak_hash_table_p (SCM x)
+{
+  init_weak_table_predicates ();
+  scm_c_issue_deprecation_warning
+    ("scm_doubly_weak_hash_table_p is deprecated.  Use doubly-weak-hash-table? 
"
+     "from (ice-9 weak-tables) instead.");
+  return scm_from_bool (is_doubly_weak_hash_table (x));
+}
+
+#endif // SCM_ENABLE_DEPRECATED == 1
+
+
+
+
 /* A hash table is a cell containing a vector of association lists.
  *
  * Growing or shrinking, with following rehashing, is triggered when
@@ -199,14 +617,18 @@ SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 
0,
 }
 #undef FUNC_NAME
 
-#define SCM_WEAK_TABLE_P(x) (scm_is_true (scm_weak_table_p (x)))
-
 SCM_DEFINE (scm_hash_table_p, "hash-table?", 1, 0, 0, 
             (SCM obj),
-           "Return @code{#t} if @var{obj} is an abstract hash table object.")
+           "Return @code{#t} if @var{obj} is an hash table.")
 #define FUNC_NAME s_scm_hash_table_p
 {
-  return scm_from_bool (SCM_HASHTABLE_P (obj) || SCM_WEAK_TABLE_P (obj));
+  return scm_from_bool (SCM_HASHTABLE_P (obj)
+#if (SCM_ENABLE_DEPRECATED == 1)
+                        || is_weak_key_hash_table (obj)
+                        || is_weak_value_hash_table (obj)
+                        || is_doubly_weak_hash_table (obj)
+#endif
+                        );
 }
 #undef FUNC_NAME
 
@@ -361,11 +783,17 @@ SCM_DEFINE (scm_hash_clear_x, "hash-clear!", 1, 0, 0,
            "Remove all items from @var{table} (without triggering a resize).")
 #define FUNC_NAME s_scm_hash_clear_x
 {
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      scm_weak_table_clear_x (table);
-      return SCM_UNSPECIFIED;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_clear_x (table);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_clear_x (table);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_clear_x (table);
     }
+#endif
 
   SCM_VALIDATE_HASHTABLE (SCM_ARG1, table);
 
@@ -420,8 +848,17 @@ SCM_DEFINE (scm_hashq_ref, "hashq-ref", 2, 1, 0,
   if (SCM_UNBNDP (dflt))
     dflt = SCM_BOOL_F;
 
-  if (SCM_WEAK_TABLE_P (table))
-    return scm_weak_table_refq (table, key, dflt);
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
+    {
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_ref (table, key, dflt);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_ref (table, key, dflt);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_ref (table, key, dflt);
+    }
+#endif
 
   return scm_hash_fn_ref (table, key, dflt,
                          (scm_t_hash_fn) scm_ihashq,
@@ -438,11 +875,17 @@ SCM_DEFINE (scm_hashq_set_x, "hashq-set!", 3, 0, 0,
            "store @var{val} there. Uses @code{eq?} for equality testing.")
 #define FUNC_NAME s_scm_hashq_set_x
 {
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      scm_weak_table_putq_x (table, key, val);
-      return val;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_set_x (table, key, val);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_set_x (table, key, val);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_set_x (table, key, val);
     }
+#endif
 
   return scm_hash_fn_set_x (table, key, val,
                            (scm_t_hash_fn) scm_ihashq,
@@ -459,15 +902,17 @@ SCM_DEFINE (scm_hashq_remove_x, "hashq-remove!", 2, 0, 0,
            "@var{table}.  Uses @code{eq?} for equality tests.")
 #define FUNC_NAME s_scm_hashq_remove_x
 {
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      scm_weak_table_remq_x (table, key);
-      /* This return value is for historical compatibility with
-         hash-remove!, which returns either the "handle" corresponding
-         to the entry, or #f.  Since weak tables don't have handles, we
-         have to return #f.  */
-      return SCM_BOOL_F;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_remove_x (table, key);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_remove_x (table, key);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_remove_x (table, key);
     }
+#endif
 
   return scm_hash_fn_remove_x (table, key,
                               (scm_t_hash_fn) scm_ihashq,
@@ -510,12 +955,6 @@ SCM_DEFINE (scm_hashv_create_handle_x, 
"hashv-create-handle!", 3, 0, 0,
 #undef FUNC_NAME
 
 
-static int
-assv_predicate (SCM k, SCM v, void *closure)
-{
-  return scm_is_true (scm_eqv_p (k, SCM_PACK_POINTER (closure)));
-}
-
 SCM_DEFINE (scm_hashv_ref, "hashv-ref", 2, 1, 0,
             (SCM table, SCM key, SCM dflt),
            "Look up @var{key} in the hash table @var{table}, and return the\n"
@@ -527,10 +966,17 @@ SCM_DEFINE (scm_hashv_ref, "hashv-ref", 2, 1, 0,
   if (SCM_UNBNDP (dflt))
     dflt = SCM_BOOL_F;
 
-  if (SCM_WEAK_TABLE_P (table))
-    return scm_c_weak_table_ref (table, scm_ihashv (key, -1),
-                                 assv_predicate,
-                                 (void *) SCM_UNPACK (key), dflt);
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
+    {
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_ref (table, key, dflt);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_ref (table, key, dflt);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_ref (table, key, dflt);
+    }
+#endif
 
   return scm_hash_fn_ref (table, key, dflt,
                          (scm_t_hash_fn) scm_ihashv,
@@ -547,13 +993,17 @@ SCM_DEFINE (scm_hashv_set_x, "hashv-set!", 3, 0, 0,
            "store @var{value} there. Uses @code{eqv?} for equality testing.")
 #define FUNC_NAME s_scm_hashv_set_x
 {
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      scm_c_weak_table_put_x (table, scm_ihashv (key, -1),
-                              assv_predicate, (void *) SCM_UNPACK (key),
-                              key, val);
-      return val;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_set_x (table, key, val);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_set_x (table, key, val);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_set_x (table, key, val);
     }
+#endif
 
   return scm_hash_fn_set_x (table, key, val,
                            (scm_t_hash_fn) scm_ihashv,
@@ -569,13 +1019,17 @@ SCM_DEFINE (scm_hashv_remove_x, "hashv-remove!", 2, 0, 0,
            "@var{table}.  Uses @code{eqv?} for equality tests.")
 #define FUNC_NAME s_scm_hashv_remove_x
 {
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      scm_c_weak_table_remove_x (table, scm_ihashv (key, -1),
-                                 assv_predicate, (void *) SCM_UNPACK (key));
-      /* See note in hashq-remove!.  */
-      return SCM_BOOL_F;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_remove_x (table, key);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_remove_x (table, key);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_remove_x (table, key);
     }
+#endif
 
   return scm_hash_fn_remove_x (table, key,
                               (scm_t_hash_fn) scm_ihashv,
@@ -617,12 +1071,6 @@ SCM_DEFINE (scm_hash_create_handle_x, 
"hash-create-handle!", 3, 0, 0,
 #undef FUNC_NAME
 
 
-static int
-assoc_predicate (SCM k, SCM v, void *closure)
-{
-  return scm_is_true (scm_equal_p (k, SCM_PACK_POINTER (closure)));
-}
-
 SCM_DEFINE (scm_hash_ref, "hash-ref", 2, 1, 0,
             (SCM table, SCM key, SCM dflt),
            "Look up @var{key} in the hash table @var{table}, and return the\n"
@@ -634,10 +1082,17 @@ SCM_DEFINE (scm_hash_ref, "hash-ref", 2, 1, 0,
   if (SCM_UNBNDP (dflt))
     dflt = SCM_BOOL_F;
 
-  if (SCM_WEAK_TABLE_P (table))
-    return scm_c_weak_table_ref (table, scm_ihash (key, -1),
-                                 assoc_predicate,
-                                 (void *) SCM_UNPACK (key), dflt);
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
+    {
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_ref (table, key, dflt);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_ref (table, key, dflt);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_ref (table, key, dflt);
+    }
+#endif
 
   return scm_hash_fn_ref (table, key, dflt,
                          (scm_t_hash_fn) scm_ihash,
@@ -655,13 +1110,17 @@ SCM_DEFINE (scm_hash_set_x, "hash-set!", 3, 0, 0,
            "testing.")
 #define FUNC_NAME s_scm_hash_set_x
 {
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      scm_c_weak_table_put_x (table, scm_ihash (key, -1),
-                              assoc_predicate, (void *) SCM_UNPACK (key),
-                              key, val);
-      return val;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_set_x (table, key, val);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_set_x (table, key, val);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_set_x (table, key, val);
     }
+#endif
 
   return scm_hash_fn_set_x (table, key, val,
                            (scm_t_hash_fn) scm_ihash,
@@ -678,13 +1137,17 @@ SCM_DEFINE (scm_hash_remove_x, "hash-remove!", 2, 0, 0,
            "@var{table}.  Uses @code{equal?} for equality tests.")
 #define FUNC_NAME s_scm_hash_remove_x
 {
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      scm_c_weak_table_remove_x (table, scm_ihash (key, -1),
-                                 assoc_predicate, (void *) SCM_UNPACK (key));
-      /* See note in hashq-remove!.  */
-      return SCM_BOOL_F;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_remove_x (table, key);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_remove_x (table, key);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_remove_x (table, key);
     }
+#endif
 
   return scm_hash_fn_remove_x (table, key,
                               (scm_t_hash_fn) scm_ihash,
@@ -719,21 +1182,6 @@ scm_sloppy_assx (SCM obj, SCM alist, void *arg)
   return scm_call_2 (closure->assoc, obj, alist);
 }
 
-static int
-assx_predicate (SCM k, SCM v, void *closure)
-{
-  scm_t_ihashx_closure *c = (scm_t_ihashx_closure *) closure;
-
-  /* FIXME: The hashx interface is crazy.  Hash tables have nothing to
-     do with alists in principle.  Instead of getting an assoc proc,
-     hashx functions should use an equality predicate.  Perhaps we can
-     change this before 2.2, but until then, add a terrible, terrible
-     hack.  */
-
-  return scm_is_true (scm_call_2 (c->assoc, c->key, scm_acons (k, v, 
SCM_EOL)));
-}
-
-
 SCM_DEFINE (scm_hashx_get_handle, "hashx-get-handle", 4, 0, 0, 
             (SCM hash, SCM assoc, SCM table, SCM key),
            "This behaves the same way as the corresponding\n"
@@ -797,12 +1245,17 @@ SCM_DEFINE (scm_hashx_ref, "hashx-ref", 4, 1, 0,
   closure.assoc = assoc;
   closure.key = key;
 
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      unsigned long h = scm_to_ulong (scm_call_2 (hash, key,
-                                                  scm_from_ulong (-1)));
-      return scm_c_weak_table_ref (table, h, assx_predicate, &closure, dflt);
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_ref (table, key, dflt);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_ref (table, key, dflt);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_ref (table, key, dflt);
     }
+#endif
 
   return scm_hash_fn_ref (table, key, dflt, scm_ihashx, scm_sloppy_assx,
                          (void *)&closure);
@@ -830,13 +1283,17 @@ SCM_DEFINE (scm_hashx_set_x, "hashx-set!", 5, 0, 0,
   closure.assoc = assoc;
   closure.key = key;
 
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      unsigned long h = scm_to_ulong (scm_call_2 (hash, key,
-                                                  scm_from_ulong (-1)));
-      scm_c_weak_table_put_x (table, h, assx_predicate, &closure, key, val);
-      return val;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_set_x (table, key, val);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_set_x (table, key, val);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_set_x (table, key, val);
     }
+#endif
 
   return scm_hash_fn_set_x (table, key, val, scm_ihashx, scm_sloppy_assx,
                            (void *)&closure);
@@ -861,14 +1318,17 @@ SCM_DEFINE (scm_hashx_remove_x, "hashx-remove!", 4, 0, 0,
   closure.assoc = assoc;
   closure.key = obj;
 
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      unsigned long h = scm_to_ulong (scm_call_2 (hash, obj,
-                                                  scm_from_ulong (-1)));
-      scm_c_weak_table_remove_x (table, h, assx_predicate, &closure);
-      /* See note in hashq-remove!.  */
-      return SCM_BOOL_F;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_remove_x (table, obj);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_remove_x (table, obj);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_remove_x (table, obj);
     }
+#endif
 
   return scm_hash_fn_remove_x (table, obj, scm_ihashx, scm_sloppy_assx,
                                (void *) &closure);
@@ -891,8 +1351,17 @@ SCM_DEFINE (scm_hash_fold, "hash-fold", 3, 0, 0,
 {
   SCM_VALIDATE_PROC (1, proc);
 
-  if (SCM_WEAK_TABLE_P (table))
-    return scm_weak_table_fold (proc, init, table);
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
+    {
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_fold (proc, init, table);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_fold (proc, init, table);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_fold (proc, init, table);
+    }
+#endif
 
   SCM_VALIDATE_HASHTABLE (3, table);
   return scm_internal_hash_fold ((scm_t_hash_fold_fn) scm_call_3,
@@ -916,11 +1385,17 @@ SCM_DEFINE (scm_hash_for_each, "hash-for-each", 2, 0, 0,
 {
   SCM_VALIDATE_PROC (1, proc);
 
-  if (SCM_WEAK_TABLE_P (table))
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
     {
-      scm_weak_table_for_each (proc, table);
-      return SCM_UNSPECIFIED;
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_for_each (proc, table);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_for_each (proc, table);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_for_each (proc, table);
     }
+#endif
 
   SCM_VALIDATE_HASHTABLE (2, table);
   
@@ -963,8 +1438,17 @@ SCM_DEFINE (scm_hash_map_to_list, "hash-map->list", 2, 0, 
0,
 {
   SCM_VALIDATE_PROC (1, proc);
 
-  if (SCM_WEAK_TABLE_P (table))
-    return scm_weak_table_map_to_list (proc, table);
+#if (SCM_ENABLE_DEPRECATED == 1)
+  if (!SCM_HASHTABLE_P (table))
+    {
+      if (is_weak_key_hash_table (table))
+        return weak_key_hash_table_map_to_list (proc, table);
+      if (is_weak_value_hash_table (table))
+        return weak_value_hash_table_map_to_list (proc, table);
+      if (is_doubly_weak_hash_table (table))
+        return doubly_weak_hash_table_map_to_list (proc, table);
+    }
+#endif
 
   SCM_VALIDATE_HASHTABLE (2, table);
   return scm_internal_hash_fold (map_proc,
@@ -1011,9 +1495,6 @@ scm_internal_hash_fold (scm_t_hash_fold_fn fn, void 
*closure,
   long i, n;
   SCM buckets, result = init;
   
-  if (SCM_WEAK_TABLE_P (table))
-    return scm_c_weak_table_fold (fn, closure, init, table);
-
   SCM_VALIDATE_HASHTABLE (0, table);
   buckets = SCM_HASHTABLE_VECTOR (table);
   
diff --git a/libguile/hashtab.h b/libguile/hashtab.h
index 61e81b341..8c9e45e25 100644
--- a/libguile/hashtab.h
+++ b/libguile/hashtab.h
@@ -1,7 +1,7 @@
 #ifndef SCM_HASHTAB_H
 #define SCM_HASHTAB_H
 
-/* Copyright 1995-1996,1999-2001,2003-2004,2006,2008-2009,2011,2018
+/* Copyright 1995-1996,1999-2001,2003-2004,2006,2008-2009,2011,2018,2025
      Free Software Foundation, Inc.
 
    This file is part of Guile.
@@ -137,4 +137,13 @@ SCM_API SCM scm_hash_count (SCM hash, SCM pred);
 SCM_INTERNAL void scm_i_hashtable_print (SCM exp, SCM port, scm_print_state 
*pstate);
 SCM_INTERNAL void scm_init_hashtab (void);
 
+#if (SCM_ENABLE_DEPRECATED == 1)
+SCM_DEPRECATED SCM scm_make_weak_key_hash_table (SCM k);
+SCM_DEPRECATED SCM scm_make_weak_value_hash_table (SCM k);
+SCM_DEPRECATED SCM scm_make_doubly_weak_hash_table (SCM k);
+SCM_DEPRECATED SCM scm_weak_key_hash_table_p (SCM h);
+SCM_DEPRECATED SCM scm_weak_value_hash_table_p (SCM h);
+SCM_DEPRECATED SCM scm_doubly_weak_hash_table_p (SCM h);
+#endif
+
 #endif  /* SCM_HASHTAB_H */
diff --git a/libguile/init.c b/libguile/init.c
index fc86a6145..7348a9916 100644
--- a/libguile/init.c
+++ b/libguile/init.c
@@ -146,7 +146,6 @@
 #include "version.h"
 #include "vm.h"
 #include "weak-set.h"
-#include "weak-table.h"
 
 #include "init.h"
 
@@ -354,8 +353,7 @@ scm_i_init_guile (struct gc_stack_addr base)
 
   struct gc_mutator *mut = scm_storage_prehistory (base);
   scm_threads_prehistory (mut, base);  /* requires storage_prehistory */
-  scm_weak_table_prehistory ();        /* requires storage_prehistory */
-  scm_symbols_prehistory ();      /* requires weak_table_prehistory */
+  scm_symbols_prehistory ();
   scm_modules_prehistory ();
   scm_init_array_handle ();
   scm_bootstrap_bytevectors ();   /* Requires array-handle */
diff --git a/libguile/print.c b/libguile/print.c
index cd6e811e5..98150ff8c 100644
--- a/libguile/print.c
+++ b/libguile/print.c
@@ -69,7 +69,6 @@
 #include "vectors.h"
 #include "vm.h"
 #include "weak-set.h"
-#include "weak-table.h"
 
 #include "print.h"
 
@@ -725,9 +724,6 @@ iprin1 (SCM exp, SCM port, scm_print_state *pstate)
        case scm_tc7_weak_set:
          scm_i_weak_set_print (exp, port, pstate);
          break;
-       case scm_tc7_weak_table:
-         scm_i_weak_table_print (exp, port, pstate);
-         break;
        case scm_tc7_fluid:
          scm_i_fluid_print (exp, port, pstate);
          break;
diff --git a/libguile/scm.h b/libguile/scm.h
index 6408bfeb7..fde767174 100644
--- a/libguile/scm.h
+++ b/libguile/scm.h
@@ -495,7 +495,7 @@ typedef uintptr_t scm_t_bits;
 #define scm_tc7_bytevector     0x4d
 #define scm_tc7_thread         0x4f
 #define scm_tc7_weak_set       0x55
-#define scm_tc7_weak_table     0x57
+#define scm_tc7_unused_57      0x57
 #define scm_tc7_array          0x5d
 #define scm_tc7_bitvector      0x5f
 #define scm_tc7_finalizer      0x65
diff --git a/libguile/weak-table.c b/libguile/weak-table.c
deleted file mode 100644
index 06f2cafdd..000000000
--- a/libguile/weak-table.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/* Copyright 2011-2014,2017-2018,2025
-     Free Software Foundation, Inc.
-
-   This file is part of Guile.
-
-   Guile is free software: you can redistribute it and/or modify it
-   under the terms of the GNU Lesser General Public License as published
-   by the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   Guile is distributed in the hope that it will be useful, but WITHOUT
-   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-   License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with Guile.  If not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <assert.h>
-
-#include "alist.h"
-#include "bdw-gc.h"
-#include "eval.h"
-#include "extensions.h"
-#include "finalizers.h"
-#include "gsubr.h"
-#include "hash.h"
-#include "numbers.h"
-#include "pairs.h"
-#include "ports.h"
-#include "procs.h"
-#include "threads.h"
-#include "version.h"
-
-#include "weak-table.h"
-
-#include <gc/gc_typed.h>
-
-
-/* Weak Tables
-
-   This file implements weak hash tables.  Weak hash tables are
-   generally used when you want to augment some object with additional
-   data, but when you don't have space to store the data in the object.
-   For example, procedure properties are implemented with weak tables.
-
-   This is a normal bucket-and-chain hash table, except that the chain
-   entries are allocated in such a way that the GC doesn't trace the
-   weak values.  For doubly-weak tables, this means that the entries are
-   allocated as an "atomic" piece of memory.  Key-weak and value-weak
-   tables use a special GC kind with a custom mark procedure.  When
-   items are added weakly into table, a disappearing link is registered
-   to their locations.  If the referent is collected, then that link
-   will be zeroed out.
-
-   An entry in the table consists of the key and the value, together
-   with the hash code of the key.
-
-   Note that since the weak references are stored in an atomic region
-   with disappearing links, they need to be accessed with the GC alloc
-   lock.  `read_weak_entry' will do that for you.  The hash code itself
-   can be read outside the lock, though.
-  */
-
-
-typedef struct scm_weak_entry scm_t_weak_entry;
-
-struct scm_weak_entry {
-  unsigned long hash;
-  scm_t_weak_entry *next;
-  scm_t_bits key;
-  scm_t_bits value;
-};
-
-
-struct weak_entry_data {
-  scm_t_weak_entry *entry;
-  scm_t_bits key;
-  scm_t_bits value;
-};
-  
-static void*
-do_read_weak_entry (void *data)
-{
-  struct weak_entry_data *e = data;
-
-  e->key = e->entry->key;
-  e->value = e->entry->value;
-
-  return NULL;
-}
-
-static void
-read_weak_entry (scm_t_weak_entry *entry, scm_t_bits *key, scm_t_bits *value)
-{
-  struct weak_entry_data data;
-
-  data.entry = entry;
-  GC_call_with_alloc_lock (do_read_weak_entry, &data);
-
-  *key = data.key;
-  *value = data.value;
-}
-  
-static void
-register_disappearing_links (scm_t_weak_entry *entry,
-                             SCM k, SCM v,
-                             scm_t_weak_table_kind kind)
-{
-  if (SCM_UNPACK (k) && SCM_HEAP_OBJECT_P (k)
-      && (kind == SCM_WEAK_TABLE_KIND_KEY
-          || kind == SCM_WEAK_TABLE_KIND_BOTH))
-    SCM_I_REGISTER_DISAPPEARING_LINK ((void **) &entry->key,
-                                      SCM2PTR (k));
-
-  if (SCM_UNPACK (v) && SCM_HEAP_OBJECT_P (v)
-      && (kind == SCM_WEAK_TABLE_KIND_VALUE
-          || kind == SCM_WEAK_TABLE_KIND_BOTH))
-    SCM_I_REGISTER_DISAPPEARING_LINK ((void **) &entry->value,
-                                      SCM2PTR (v));
-}
-
-static void
-unregister_disappearing_links (scm_t_weak_entry *entry,
-                               scm_t_weak_table_kind kind)
-{
-  if (kind == SCM_WEAK_TABLE_KIND_KEY || kind == SCM_WEAK_TABLE_KIND_BOTH)
-    GC_unregister_disappearing_link ((void **) &entry->key);
-
-  if (kind == SCM_WEAK_TABLE_KIND_VALUE || kind == SCM_WEAK_TABLE_KIND_BOTH)
-    GC_unregister_disappearing_link ((void **) &entry->value);
-}
-
-typedef struct {
-  scm_t_weak_entry **buckets;   /* the data */
-  scm_i_pthread_mutex_t lock;   /* the lock */
-  scm_t_weak_table_kind kind;   /* what kind of table it is */
-  unsigned long n_buckets;     /* total number of buckets. */
-  unsigned long n_items;       /* number of items in table */
-  unsigned long lower;         /* when to shrink */
-  unsigned long upper;         /* when to grow */
-  int size_index;              /* index into hashtable_size */
-  int min_size_index;          /* minimum size_index */
-  GC_word last_gc_no;
-} scm_t_weak_table;
-
-
-#define SCM_WEAK_TABLE_P(x) (SCM_HAS_TYP7 (x, scm_tc7_weak_table))
-#define SCM_VALIDATE_WEAK_TABLE(pos, arg) \
-  SCM_MAKE_VALIDATE_MSG (pos, arg, WEAK_TABLE_P, "weak-table")
-#define SCM_WEAK_TABLE(x) ((scm_t_weak_table *) SCM_CELL_WORD_1 (x))
-
-
-
-
-/* GC descriptors for the various kinds of scm_t_weak_entry.  */
-static GC_descr weak_key_descr;
-static GC_descr weak_value_descr;
-static GC_descr doubly_weak_descr;
-
-static scm_t_weak_entry *
-allocate_entry (scm_t_weak_table_kind kind)
-{
-  scm_t_weak_entry *ret;
-
-  switch (kind)
-    {
-    case SCM_WEAK_TABLE_KIND_KEY:
-      ret = GC_malloc_explicitly_typed (sizeof (*ret), weak_key_descr);
-      break;
-    case SCM_WEAK_TABLE_KIND_VALUE:
-      ret = GC_malloc_explicitly_typed (sizeof (*ret), weak_value_descr);
-      break;
-    case SCM_WEAK_TABLE_KIND_BOTH:
-      ret = GC_malloc_explicitly_typed (sizeof (*ret), doubly_weak_descr);
-      break;
-    default:
-      abort ();
-    }
-
-  return ret;
-}
-
-static void
-add_entry (scm_t_weak_table *table, scm_t_weak_entry *entry)
-{
-  unsigned long bucket = entry->hash % table->n_buckets;
-  entry->next = table->buckets[bucket];
-  table->buckets[bucket] = entry;
-  table->n_items++;
-}
-
-
-
-/* Growing or shrinking is triggered when the load factor
- *
- *   L = N / S    (N: number of items in table, S: bucket vector length)
- *
- * passes an upper limit of 0.9 or a lower limit of 0.25.
- *
- * The implementation stores the upper and lower number of items which
- * trigger a resize in the hashtable object.
- *
- * Possible hash table sizes (primes) are stored in the array
- * hashtable_size.
- */
-
-static unsigned long hashtable_size[] = {
-  31, 61, 113, 223, 443, 883, 1759, 3517, 7027, 14051, 28099, 56197, 112363,
-  224717, 449419, 898823, 1797641, 3595271, 7190537, 14381041, 28762081,
-  57524111, 115048217, 230096423
-};
-
-#define HASHTABLE_SIZE_N (sizeof(hashtable_size)/sizeof(unsigned long))
-
-static void
-resize_table (scm_t_weak_table *table)
-{
-  scm_t_weak_entry **old_buckets, **new_buckets;
-  int new_size_index;
-  unsigned long old_n_buckets, new_n_buckets, old_k;
-
-  new_size_index = table->size_index;
-  if (table->n_items < table->lower)
-    {
-      /* Rehashing is not triggered when i <= min_size.  */
-      do
-       new_size_index -= 1;
-      while (new_size_index > table->min_size_index
-            && table->n_items < hashtable_size[new_size_index] / 4);
-    }
-  else if (table->n_items > table->upper)
-    {
-      new_size_index += 1;
-      if (new_size_index >= HASHTABLE_SIZE_N)
-        /* Limit max bucket count.  */
-        return;
-    }
-  else
-    /* Nothing to do.  */
-    return;
-
-  new_n_buckets = hashtable_size[new_size_index];
-  new_buckets = scm_gc_malloc (sizeof (*new_buckets) * new_n_buckets,
-                               "weak table buckets");
-
-  old_buckets = table->buckets;
-  old_n_buckets = table->n_buckets;
-  
-  table->size_index = new_size_index;
-  table->n_buckets = new_n_buckets;
-  if (new_size_index <= table->min_size_index)
-    table->lower = 0;
-  else
-    table->lower = new_n_buckets / 4;
-  table->upper = 9 * new_n_buckets / 10;
-  table->n_items = 0;
-  table->buckets = new_buckets;
-
-  for (old_k = 0; old_k < old_n_buckets; old_k++)
-    {
-      scm_t_weak_entry *entry = old_buckets[old_k];
-      while (entry)
-        {
-          scm_t_weak_entry *next = entry->next;
-          entry->next = NULL;
-          add_entry (table, entry);
-          entry = next;
-        }
-    }
-}
-
-/* Run after GC via do_vacuum_weak_table, this function runs over the
-   whole table, removing lost weak references, reshuffling the table as it
-   goes.  It might resize the table if it reaps enough buckets.  */
-static void
-vacuum_weak_table (scm_t_weak_table *table)
-{
-  GC_word gc_no = GC_get_gc_no ();
-  unsigned long k;
-
-  if (gc_no == table->last_gc_no)
-    return;
-
-  table->last_gc_no = gc_no;
-
-  for (k = 0; k < table->n_buckets; k++)
-    {
-      scm_t_weak_entry **loc = table->buckets + k;
-      scm_t_weak_entry *entry;
-
-      for (entry = *loc; entry; entry = *loc)
-        {
-          scm_t_bits key, value;
-
-          read_weak_entry (entry, &key, &value);
-          if (!key || !value)
-            /* Lost weak reference; prune entry.  */
-            {
-              *loc = entry->next;
-              table->n_items--;
-              entry->next = NULL;
-              unregister_disappearing_links (entry, table->kind);
-            }
-          else
-            loc = &entry->next;
-        }
-    }
-
-  if (table->n_items < table->lower)
-    resize_table (table);
-}
-
-
-
-
-static SCM
-weak_table_ref (scm_t_weak_table *table, unsigned long hash,
-                scm_t_table_predicate_fn pred, void *closure,
-                SCM dflt)
-{
-  unsigned long bucket = hash % table->n_buckets;
-  scm_t_weak_entry *entry;
-
-  for (entry = table->buckets[bucket]; entry; entry = entry->next)
-    {
-      if (entry->hash == hash)
-        {
-          scm_t_bits key, value;
-
-          read_weak_entry (entry, &key, &value);
-          if (key && value && pred (SCM_PACK (key), SCM_PACK (value), closure))
-            /* Found. */
-            return SCM_PACK (value);
-        }
-    }
-
-  return dflt;
-}
-
-
-static void
-weak_table_put_x (scm_t_weak_table *table, unsigned long hash,
-                  scm_t_table_predicate_fn pred, void *closure,
-                  SCM key, SCM value)
-{
-  unsigned long bucket = hash % table->n_buckets;
-  scm_t_weak_entry *entry;
-
-  for (entry = table->buckets[bucket]; entry; entry = entry->next)
-    {
-      if (entry->hash == hash)
-        {
-          scm_t_bits k, v;
-
-          read_weak_entry (entry, &k, &v);
-          if (k && v && pred (SCM_PACK (k), SCM_PACK (v), closure))
-            {
-              unregister_disappearing_links (entry, table->kind);
-              key = SCM_PACK (k);
-              entry->value = SCM_UNPACK (value);
-              register_disappearing_links (entry, key, value, table->kind);
-              return;
-            }
-        }
-    }
-
-  if (table->n_items > table->upper)
-    /* Full table, time to resize.  */
-    resize_table (table);
-
-  entry = allocate_entry (table->kind);
-  entry->hash = hash;
-  entry->key = SCM_UNPACK (key);
-  entry->value = SCM_UNPACK (value);
-  register_disappearing_links (entry, key, value, table->kind);
-  add_entry (table, entry);
-}
-
-
-static void
-weak_table_remove_x (scm_t_weak_table *table, unsigned long hash,
-                   scm_t_table_predicate_fn pred, void *closure)
-{
-  unsigned long bucket = hash % table->n_buckets;
-  scm_t_weak_entry **loc = table->buckets + bucket;
-  scm_t_weak_entry *entry;
-
-  for (entry = *loc; entry; entry = *loc)
-    {
-      if (entry->hash == hash)
-        {
-          scm_t_bits k, v;
-
-          read_weak_entry (entry, &k, &v);
-          if (k && v && pred (SCM_PACK (k), SCM_PACK (v), closure))
-            {
-              *loc = entry->next;
-              table->n_items--;
-              entry->next = NULL;
-              unregister_disappearing_links (entry, table->kind);
-
-              if (table->n_items < table->lower)
-                resize_table (table);
-
-              return;
-            }
-        }
-      loc = &entry->next;
-    }
-
-  return;
-}
-
-
-
-static SCM
-make_weak_table (unsigned long k, scm_t_weak_table_kind kind)
-{
-  scm_t_weak_table *table;
-
-  int i = 0, n = k ? k : 31;
-  while (i + 1 < HASHTABLE_SIZE_N && n > hashtable_size[i])
-    ++i;
-  n = hashtable_size[i];
-
-  table = scm_gc_malloc (sizeof (*table), "weak-table");
-  table->buckets = scm_gc_malloc (sizeof (*table->buckets) * n,
-                                  "weak table buckets");
-  table->kind = kind;
-  table->n_items = 0;
-  table->n_buckets = n;
-  table->lower = 0;
-  table->upper = 9 * n / 10;
-  table->size_index = i;
-  table->min_size_index = i;
-  table->last_gc_no = GC_get_gc_no ();
-  scm_i_pthread_mutex_init (&table->lock, NULL);
-
-  return scm_cell (scm_tc7_weak_table, (scm_t_bits)table);
-}
-
-void
-scm_i_weak_table_print (SCM exp, SCM port, scm_print_state *pstate)
-{
-  scm_puts ("#<", port);
-  scm_puts ("weak-table ", port);
-  scm_uintprint (SCM_WEAK_TABLE (exp)->n_items, 10, port);
-  scm_putc ('/', port);
-  scm_uintprint (SCM_WEAK_TABLE (exp)->n_buckets, 10, port);
-  scm_puts (">", port);
-}
-
-SCM
-scm_c_make_weak_table (unsigned long k, scm_t_weak_table_kind kind)
-{
-  SCM ret;
-
-  ret = make_weak_table (k, kind);
-
-  return ret;
-}
-
-SCM
-scm_weak_table_p (SCM obj)
-{
-  return scm_from_bool (SCM_WEAK_TABLE_P (obj));
-}
-
-SCM
-scm_c_weak_table_ref (SCM table, unsigned long raw_hash,
-                      scm_t_table_predicate_fn pred,
-                      void *closure, SCM dflt)
-#define FUNC_NAME "weak-table-ref"
-{
-  SCM ret;
-  scm_t_weak_table *t;
-
-  SCM_VALIDATE_WEAK_TABLE (1, table);
-
-  t = SCM_WEAK_TABLE (table);
-
-  scm_i_pthread_mutex_lock (&t->lock);
-
-  vacuum_weak_table (t);
-
-  ret = weak_table_ref (t, raw_hash, pred, closure, dflt);
-
-  scm_i_pthread_mutex_unlock (&t->lock);
-
-  return ret;
-}
-#undef FUNC_NAME
-
-void
-scm_c_weak_table_put_x (SCM table, unsigned long raw_hash,
-                        scm_t_table_predicate_fn pred,
-                        void *closure, SCM key, SCM value)
-#define FUNC_NAME "weak-table-put!"
-{
-  scm_t_weak_table *t;
-
-  SCM_VALIDATE_WEAK_TABLE (1, table);
-
-  t = SCM_WEAK_TABLE (table);
-
-  scm_i_pthread_mutex_lock (&t->lock);
-
-  vacuum_weak_table (t);
-
-  weak_table_put_x (t, raw_hash, pred, closure, key, value);
-
-  scm_i_pthread_mutex_unlock (&t->lock);
-}
-#undef FUNC_NAME
-
-void
-scm_c_weak_table_remove_x (SCM table, unsigned long raw_hash,
-                           scm_t_table_predicate_fn pred,
-                           void *closure)
-#define FUNC_NAME "weak-table-remove!"
-{
-  scm_t_weak_table *t;
-
-  SCM_VALIDATE_WEAK_TABLE (1, table);
-
-  t = SCM_WEAK_TABLE (table);
-
-  scm_i_pthread_mutex_lock (&t->lock);
-
-  vacuum_weak_table (t);
-
-  weak_table_remove_x (t, raw_hash, pred, closure);
-
-  scm_i_pthread_mutex_unlock (&t->lock);
-}
-#undef FUNC_NAME
-
-static int
-assq_predicate (SCM x, SCM y, void *closure)
-{
-  return scm_is_eq (x, SCM_PACK_POINTER (closure));
-}
-
-SCM
-scm_weak_table_refq (SCM table, SCM key, SCM dflt)
-{
-  return scm_c_weak_table_ref (table, scm_ihashq (key, -1),
-                               assq_predicate, SCM_UNPACK_POINTER (key),
-                               dflt);
-}
-
-void
-scm_weak_table_putq_x (SCM table, SCM key, SCM value)
-{
-  scm_c_weak_table_put_x (table, scm_ihashq (key, -1),
-                          assq_predicate, SCM_UNPACK_POINTER (key),
-                          key, value);
-}
-
-void
-scm_weak_table_remq_x (SCM table, SCM key)
-{
-  scm_c_weak_table_remove_x (table, scm_ihashq (key, -1),
-                             assq_predicate, SCM_UNPACK_POINTER (key));
-}
-
-void
-scm_weak_table_clear_x (SCM table)
-#define FUNC_NAME "weak-table-clear!"
-{
-  scm_t_weak_table *t;
-  unsigned long k;
-  scm_t_weak_entry *entry;
-
-  SCM_VALIDATE_WEAK_TABLE (1, table);
-
-  t = SCM_WEAK_TABLE (table);
-
-  scm_i_pthread_mutex_lock (&t->lock);
-
-  t->last_gc_no = GC_get_gc_no ();
-
-  for (k = 0; k < t->n_buckets; k++)
-    {
-      for (entry = t->buckets[k]; entry; entry = entry->next)
-        unregister_disappearing_links (entry, t->kind);
-      t->buckets[k] = NULL;
-    }
-  t->n_items = 0;
-
-  scm_i_pthread_mutex_unlock (&t->lock);
-}
-#undef FUNC_NAME
-
-SCM
-scm_c_weak_table_fold (scm_t_table_fold_fn proc, void *closure,
-                       SCM init, SCM table)
-{
-  scm_t_weak_table *t;
-  unsigned long k;
-  SCM alist = SCM_EOL;
-
-  t = SCM_WEAK_TABLE (table);
-
-  scm_i_pthread_mutex_lock (&t->lock);
-
-  vacuum_weak_table (t);
-
-  for (k = 0; k < t->n_buckets; k++)
-    {
-      scm_t_weak_entry *entry;
-      for (entry = t->buckets[k]; entry; entry = entry->next)
-        {
-          scm_t_bits key, value;
-          read_weak_entry (entry, &key, &value);
-      
-          if (key && value)
-            alist = scm_acons (SCM_PACK (key), SCM_PACK (value), alist);
-        }
-    }
-  
-  scm_i_pthread_mutex_unlock (&t->lock);
-  
-  /* Call the proc outside the lock.  */
-  for (; !scm_is_null (alist); alist = scm_cdr (alist))
-    init = proc (closure, scm_caar (alist), scm_cdar (alist), init);
-
-  return init;
-}
-
-static SCM
-fold_trampoline (void *closure, SCM k, SCM v, SCM init)
-{
-  return scm_call_3 (SCM_PACK_POINTER (closure), k, v, init);
-}
-
-SCM
-scm_weak_table_fold (SCM proc, SCM init, SCM table)
-#define FUNC_NAME "weak-table-fold"
-{
-  SCM_VALIDATE_WEAK_TABLE (3, table);
-  SCM_VALIDATE_PROC (1, proc);
-
-  return scm_c_weak_table_fold (fold_trampoline, SCM_UNPACK_POINTER (proc), 
init, table);
-}
-#undef FUNC_NAME
-
-static SCM
-for_each_trampoline (void *closure, SCM k, SCM v, SCM seed)
-{
-  scm_call_2 (SCM_PACK_POINTER (closure), k, v);
-  return seed;
-}
-
-void
-scm_weak_table_for_each (SCM proc, SCM table)
-#define FUNC_NAME "weak-table-for-each"
-{
-  SCM_VALIDATE_WEAK_TABLE (2, table);
-  SCM_VALIDATE_PROC (1, proc);
-
-  scm_c_weak_table_fold (for_each_trampoline, SCM_UNPACK_POINTER (proc), 
SCM_BOOL_F, table);
-}
-#undef FUNC_NAME
-
-static SCM
-map_trampoline (void *closure, SCM k, SCM v, SCM seed)
-{
-  return scm_cons (scm_call_2 (SCM_PACK_POINTER (closure), k, v), seed);
-}
-
-SCM
-scm_weak_table_map_to_list (SCM proc, SCM table)
-#define FUNC_NAME "weak-table-map->list"
-{
-  SCM_VALIDATE_WEAK_TABLE (2, table);
-  SCM_VALIDATE_PROC (1, proc);
-
-  return scm_c_weak_table_fold (map_trampoline, SCM_UNPACK_POINTER (proc), 
SCM_EOL, table);
-}
-#undef FUNC_NAME
-
-
-
-
-/* Legacy interface.  */
-
-SCM_DEFINE (scm_make_weak_key_hash_table, "make-weak-key-hash-table", 0, 1, 0, 
-           (SCM n),
-           "@deffnx {Scheme Procedure} make-weak-value-hash-table size\n"
-           "@deffnx {Scheme Procedure} make-doubly-weak-hash-table size\n"
-           "Return a weak hash table with @var{size} buckets.\n"
-           "\n"
-           "You can modify weak hash tables in exactly the same way you\n"
-           "would modify regular hash tables. (@pxref{Hash Tables})")
-#define FUNC_NAME s_scm_make_weak_key_hash_table
-{
-  return scm_c_make_weak_table (SCM_UNBNDP (n) ? 0 : scm_to_ulong (n),
-                                SCM_WEAK_TABLE_KIND_KEY);
-}
-#undef FUNC_NAME
-
-
-SCM_DEFINE (scm_make_weak_value_hash_table, "make-weak-value-hash-table", 0, 
1, 0, 
-            (SCM n),
-           "Return a hash table with weak values with @var{size} buckets.\n"
-           "(@pxref{Hash Tables})")
-#define FUNC_NAME s_scm_make_weak_value_hash_table
-{
-  return scm_c_make_weak_table (SCM_UNBNDP (n) ? 0 : scm_to_ulong (n),
-                                SCM_WEAK_TABLE_KIND_VALUE);
-}
-#undef FUNC_NAME
-
-
-SCM_DEFINE (scm_make_doubly_weak_hash_table, "make-doubly-weak-hash-table", 0, 
1, 0, 
-            (SCM n),
-           "Return a hash table with weak keys and values with @var{size}\n"
-           "buckets.  (@pxref{Hash Tables})")
-#define FUNC_NAME s_scm_make_doubly_weak_hash_table
-{
-  return scm_c_make_weak_table (SCM_UNBNDP (n) ? 0 : scm_to_ulong (n),
-                                SCM_WEAK_TABLE_KIND_BOTH);
-}
-#undef FUNC_NAME
-
-
-SCM_DEFINE (scm_weak_key_hash_table_p, "weak-key-hash-table?", 1, 0, 0, 
-           (SCM obj),
-           "@deffnx {Scheme Procedure} weak-value-hash-table? obj\n"
-           "@deffnx {Scheme Procedure} doubly-weak-hash-table? obj\n"
-           "Return @code{#t} if @var{obj} is the specified weak hash\n"
-           "table. Note that a doubly weak hash table is neither a weak key\n"
-           "nor a weak value hash table.")
-#define FUNC_NAME s_scm_weak_key_hash_table_p
-{
-  return scm_from_bool (SCM_WEAK_TABLE_P (obj) &&
-                        SCM_WEAK_TABLE (obj)->kind == SCM_WEAK_TABLE_KIND_KEY);
-}
-#undef FUNC_NAME
-
-
-SCM_DEFINE (scm_weak_value_hash_table_p, "weak-value-hash-table?", 1, 0, 0, 
-            (SCM obj),
-           "Return @code{#t} if @var{obj} is a weak value hash table.")
-#define FUNC_NAME s_scm_weak_value_hash_table_p
-{
-  return scm_from_bool (SCM_WEAK_TABLE_P (obj) &&
-                        SCM_WEAK_TABLE (obj)->kind == 
SCM_WEAK_TABLE_KIND_VALUE);
-}
-#undef FUNC_NAME
-
-
-SCM_DEFINE (scm_doubly_weak_hash_table_p, "doubly-weak-hash-table?", 1, 0, 0, 
-            (SCM obj),
-           "Return @code{#t} if @var{obj} is a doubly weak hash table.")
-#define FUNC_NAME s_scm_doubly_weak_hash_table_p
-{
-  return scm_from_bool (SCM_WEAK_TABLE_P (obj) &&
-                        SCM_WEAK_TABLE (obj)->kind == 
SCM_WEAK_TABLE_KIND_BOTH);
-}
-#undef FUNC_NAME
-
-
-
-
-
-static void
-scm_init_weak_tables (void*)
-{
-#include "weak-table.x"
-}
-
-void
-scm_weak_table_prehistory (void)
-{
-  GC_word weak_key_bitmap[GC_BITMAP_SIZE (scm_t_weak_entry)] = { 0 };
-  GC_word weak_value_bitmap[GC_BITMAP_SIZE (scm_t_weak_entry)] = { 0 };
-  GC_word doubly_weak_bitmap[GC_BITMAP_SIZE (scm_t_weak_entry)] = { 0 };
-
-  GC_set_bit (weak_key_bitmap, GC_WORD_OFFSET (scm_t_weak_entry, next));
-  GC_set_bit (weak_value_bitmap, GC_WORD_OFFSET (scm_t_weak_entry, next));
-  GC_set_bit (doubly_weak_bitmap, GC_WORD_OFFSET (scm_t_weak_entry, next));
-
-  GC_set_bit (weak_key_bitmap, GC_WORD_OFFSET (scm_t_weak_entry, value));
-  GC_set_bit (weak_value_bitmap, GC_WORD_OFFSET (scm_t_weak_entry, key));
-
-  weak_key_descr = GC_make_descriptor (weak_key_bitmap,
-                                       GC_WORD_LEN (scm_t_weak_entry));
-  weak_value_descr = GC_make_descriptor (weak_value_bitmap,
-                                         GC_WORD_LEN (scm_t_weak_entry));
-  doubly_weak_descr = GC_make_descriptor (doubly_weak_bitmap,
-                                          GC_WORD_LEN (scm_t_weak_entry));
-
-  scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
-                            "scm_init_weak_tables", scm_init_weak_tables, 
NULL);
-}
-
diff --git a/libguile/weak-table.h b/libguile/weak-table.h
deleted file mode 100644
index f7e6c7cae..000000000
--- a/libguile/weak-table.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef SCM_WEAK_TABLE_H
-#define SCM_WEAK_TABLE_H
-
-/* Copyright 2011-2012,2018,2025
-     Free Software Foundation, Inc.
-
-   This file is part of Guile.
-
-   Guile is free software: you can redistribute it and/or modify it
-   under the terms of the GNU Lesser General Public License as published
-   by the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   Guile is distributed in the hope that it will be useful, but WITHOUT
-   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-   License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with Guile.  If not, see
-   <https://www.gnu.org/licenses/>.  */
-
-
-
-#include "libguile/scm.h"
-
-
-
-/* The weak table API is currently only used internally.  We could make it
-   public later, after some API review.  */
-
-typedef enum {
-  SCM_WEAK_TABLE_KIND_KEY,
-  SCM_WEAK_TABLE_KIND_VALUE,
-  SCM_WEAK_TABLE_KIND_BOTH,
-} scm_t_weak_table_kind;
-
-/* Function that returns nonzero if the given mapping is the one we are
-   looking for.  */
-typedef int (*scm_t_table_predicate_fn) (SCM k, SCM v, void *closure);
-
-/* Function to fold over the elements of a set.  */
-typedef SCM (*scm_t_table_fold_fn) (void *closure, SCM k, SCM v, SCM result);
-
-SCM_INTERNAL SCM scm_c_make_weak_table (unsigned long k,
-                                        scm_t_weak_table_kind kind);
-SCM_INTERNAL SCM scm_weak_table_p (SCM h);
-
-SCM_INTERNAL SCM scm_c_weak_table_ref (SCM table, unsigned long raw_hash,
-                                       scm_t_table_predicate_fn pred,
-                                       void *closure, SCM dflt);
-SCM_INTERNAL void scm_c_weak_table_put_x (SCM table, unsigned long raw_hash,
-                                          scm_t_table_predicate_fn pred,
-                                          void *closure, SCM key, SCM value);
-SCM_INTERNAL void scm_c_weak_table_remove_x (SCM table, unsigned long raw_hash,
-                                             scm_t_table_predicate_fn pred,
-                                             void *closure);
-
-SCM_INTERNAL SCM scm_weak_table_refq (SCM table, SCM key, SCM dflt);
-SCM_INTERNAL void scm_weak_table_putq_x (SCM table, SCM key, SCM value);
-SCM_INTERNAL void scm_weak_table_remq_x (SCM table, SCM key);
-
-SCM_INTERNAL void scm_weak_table_clear_x (SCM table);
-
-SCM_INTERNAL SCM scm_c_weak_table_fold (scm_t_table_fold_fn proc, void 
*closure,
-                                      SCM init, SCM table);
-SCM_INTERNAL SCM scm_weak_table_fold (SCM proc, SCM init, SCM table);
-SCM_INTERNAL void scm_weak_table_for_each (SCM proc, SCM table);
-SCM_INTERNAL SCM scm_weak_table_map_to_list (SCM proc, SCM table);
-
-
-
-/* Legacy interface.  */
-SCM_API SCM scm_make_weak_key_hash_table (SCM k);
-SCM_API SCM scm_make_weak_value_hash_table (SCM k);
-SCM_API SCM scm_make_doubly_weak_hash_table (SCM k);
-SCM_API SCM scm_weak_key_hash_table_p (SCM h);
-SCM_API SCM scm_weak_value_hash_table_p (SCM h);
-SCM_API SCM scm_doubly_weak_hash_table_p (SCM h);
-
-
-
-SCM_INTERNAL void scm_i_weak_table_print (SCM exp, SCM port, scm_print_state 
*pstate);
-SCM_INTERNAL void scm_weak_table_prehistory (void);
-
-#endif  /* SCM_WEAK_TABLE_H */
diff --git a/module/ice-9/object-properties.scm 
b/module/ice-9/object-properties.scm
index c587262b2..9b40be4dc 100644
--- a/module/ice-9/object-properties.scm
+++ b/module/ice-9/object-properties.scm
@@ -45,17 +45,18 @@
   ;; Weak tables are thread-safe.
   (let ((prop (make-weak-key-hash-table)))
     (make-procedure-with-setter
-     (lambda (obj) (hashq-ref prop obj))
-     (lambda (obj val) (hashq-set! prop obj val)))))
+     (lambda (obj) (weak-key-hash-table-ref prop obj))
+     (lambda (obj val) (weak-key-hash-table-set! prop obj val)))))
 
 ;; FIXME: Deprecate these global properties.
 (define global-properties (make-weak-key-hash-table))
 
 (define (object-properties obj)
-  (hashq-ref global-properties obj '()))
+  (weak-key-hash-table-ref global-properties obj
+                           #:default (lambda (k) '())))
 
 (define (set-object-properties! obj props)
-  (hashq-set! global-properties obj props))
+  (weak-key-hash-table-set! global-properties obj props))
 
 (define (object-property obj key)
   (assq-ref (object-properties obj) key))
diff --git a/module/ice-9/poe.scm b/module/ice-9/poe.scm
index d72a4cafa..76585152c 100644
--- a/module/ice-9/poe.scm
+++ b/module/ice-9/poe.scm
@@ -19,6 +19,7 @@
 
 
 (define-module  (ice-9 poe)
+  #:use-module (ice-9 match)
   #:use-module (ice-9 weak-tables)
   #:export (pure-funcq perfect-funcq))
 
@@ -53,17 +54,13 @@
       (set! ring (cdr ring))
       next)))
 
-(define funcq-memo (make-weak-key-hash-table 523)) ; !!! randomly selected 
values
-(define funcq-buffer (make-gc-buffer 256))
-
 (define (funcq-hash arg-list n)
-  (let ((it (let loop ((x 0)
-                      (arg-list arg-list))
-             (if (null? arg-list)
-                 (modulo x n)
-                 (loop (logior x (hashq (car arg-list) 4194303))
-                       (cdr arg-list))))))
-    it))
+  (let loop ((x 0)
+            (arg-list arg-list))
+    (if (null? arg-list)
+       (modulo x n)
+       (loop (logior x (hashq (car arg-list) 4194303))
+         (cdr arg-list)))))
 
 ;; return true if lists X and Y are the same length and each element is `eq?'
 (define (eq?-list x y)
@@ -73,21 +70,27 @@
           (eq? (car x) (car y))
           (eq?-list (cdr x) (cdr y)))))
 
-(define (funcq-assoc arg-list alist)
-  (if (null? alist)
-      #f
-      (if (eq?-list arg-list (caar alist))
-         (car alist)
-         (funcq-assoc arg-list (cdr alist)))))
-
+(define (funcq-assoc args alist)
+  (match alist
+    (() #f)
+    ((head . tail)
+     (if (eq?-list (car head) args)
+         head
+         tail))))
+
+(define funcq-memo
+  (make-weak-key-hash-table #:equal? eq?-list
+                            #:hash funcq-hash
+                            #:initial-size 523)) ; !!! randomly selected values
+(define funcq-buffer (make-gc-buffer 256))
 
 (define not-found (list 'not-found))
 
-
 (define (pure-funcq base-func)
   (lambda args
     (let* ((key (cons base-func args))
-           (cached (hashx-ref funcq-hash funcq-assoc funcq-memo key 
not-found)))
+           (cached (weak-key-hash-table-ref funcq-memo key
+                                            #:default (lambda (_) not-found))))
       (if (not (eq? cached not-found))
          (begin
            (funcq-buffer key)
@@ -95,7 +98,7 @@
            
          (let ((val (apply base-func args)))
            (funcq-buffer key)
-           (hashx-set! funcq-hash funcq-assoc funcq-memo key val)
+           (weak-key-hash-table-set! funcq-memo key val)
            val)))))
 
 
@@ -108,6 +111,13 @@
 
 (define (perfect-funcq size base-func)
   (define funcq-memo (make-hash-table size))
+  (define (funcq-assoc args alist)
+    (match alist
+      (() #f)
+      ((head . tail)
+       (if (eq?-list (car head) args)
+           head
+           tail))))
 
   (lambda args
     (let* ((key (cons base-func args))
diff --git a/module/ice-9/popen.scm b/module/ice-9/popen.scm
index 0cc7d16ba..43b5d2f62 100644
--- a/module/ice-9/popen.scm
+++ b/module/ice-9/popen.scm
@@ -25,7 +25,7 @@
   #:use-module (ice-9 weak-tables)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-9)
-  #:export (port/pid-table open-pipe* open-pipe close-pipe open-input-pipe
+  #:export (open-pipe* open-pipe close-pipe open-input-pipe
             open-output-pipe open-input-output-pipe pipeline))
 
 (eval-when (expand load eval)
@@ -80,12 +80,6 @@
 ;; an open pipe is gc'd or a close-port is used.
 (define pipe-guardian (make-guardian))
 
-;; a weak hash-table to store the process ids.
-;; XXX use of this table is deprecated.  It is no longer used here, and
-;; is populated for backward compatibility only (since it is exported).
-(define port/pid-table (make-weak-key-hash-table))
-(define port/pid-table-mutex (make-mutex))
-
 (define (pipe->fdes)
   (let ((p (pipe)))
    (cons (port->fdes (car p))
@@ -146,10 +140,6 @@ port to the process is created: it should be the value of
         (pipe-guardian pipe-info)
         (%set-port-property! port 'popen-pipe-info pipe-info)
 
-        ;; XXX populate port/pid-table for backward compatibility.
-        (with-mutex port/pid-table-mutex
-          (hashq-set! port/pid-table port pid))
-
         port))))
 
 (define (open-pipe command mode)
diff --git a/module/ice-9/source-properties.scm 
b/module/ice-9/source-properties.scm
index 0fa5336a6..b8abc276e 100644
--- a/module/ice-9/source-properties.scm
+++ b/module/ice-9/source-properties.scm
@@ -54,7 +54,8 @@
 
 (define (source-properties obj)
   (if (supports-source-properties? obj)
-      (hashq-ref global-source-properties obj '())
+      (weak-key-hash-table-ref global-source-properties obj
+                               #:default (lambda (k) '()))
       '()))
 
 (define (set-source-properties! obj props)
@@ -62,7 +63,7 @@
     (scm-error 'wrong-type-arg "set-source-properties!"
                "Unexpected immediate value: ~S"
                (list obj) #f))
-  (hashq-set! global-source-properties obj props))
+  (weak-key-hash-table-set! global-source-properties obj props))
 
 (define (source-property obj key)
   (and (supports-source-properties? obj)
diff --git a/module/ice-9/weak-tables.scm b/module/ice-9/weak-tables.scm
index 924ceec23..59864f5a7 100644
--- a/module/ice-9/weak-tables.scm
+++ b/module/ice-9/weak-tables.scm
@@ -21,15 +21,361 @@
 
 
 (define-module (ice-9 weak-tables)
+  #:use-module (ice-9 ephemerons)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 threads)
+  #:use-module (srfi srfi-9)
   ;; FIXME: Change to #:export when deprecated code removed.
   #:replace (make-weak-key-hash-table
+             weak-key-hash-table?
+
              make-weak-value-hash-table
+             weak-value-hash-table?
+
              make-doubly-weak-hash-table
+             doubly-weak-hash-table?)
 
-             weak-key-hash-table?
-             weak-value-hash-table?
-             doubly-weak-hash-table?))
+  #:export (weak-key-hash-table-ref
+            weak-key-hash-table-set!
+            weak-key-hash-table-remove!
+            weak-key-hash-table-clear!
+            weak-key-hash-table-fold
+            weak-key-hash-table-for-each
+            weak-key-hash-table-map->list
+
+            weak-value-hash-table-ref
+            weak-value-hash-table-set!
+            weak-value-hash-table-remove!
+            weak-value-hash-table-clear!
+            weak-value-hash-table-fold
+            weak-value-hash-table-for-each
+            weak-value-hash-table-map->list
+
+            doubly-weak-hash-table-ref
+            doubly-weak-hash-table-set!
+            doubly-weak-hash-table-remove!
+            doubly-weak-hash-table-clear!
+            doubly-weak-hash-table-fold
+            doubly-weak-hash-table-for-each
+            doubly-weak-hash-table-map->list))
+
+
+
+;;;
+;;; Weak key hash tables are a thin wrapper over ephemeron tables.  They
+;;; implement weak-key mappings whose values can be updated in place.
+;;; They are concurrent and lock-free, but not yet resizable.
+;;;
+
+(define-record-type <weak-key-hash-table>
+  (%make-weak-key-hash-table find insert! buckets)
+  %weak-key-hash-table?
+  (find weak-key-hash-table-find)
+  (insert! weak-key-hash-table-insert!)
+  (buckets weak-key-hash-table-buckets))
+
+(define-syntax-rule (primitive=? f prim)
+  (or (eq? f prim) (eq? f 'prim)))
+
+(define make-weak-key-hash-table
+  (let ()
+    (define-syntax-rule (define-accessors find insert! equal? hash)
+      (begin
+        (define (find buckets k)
+          (let ((idx (hash k (ephemeron-table-length buckets))))
+            (let lp ((chain (ephemeron-table-ref buckets idx)))
+              (match chain
+                (#f #f)
+                (e (if (equal? (ephemeron-key e) k)
+                       e
+                       (lp (ephemeron-next e))))))))
+
+        (define (insert! buckets k e)
+          (let ((idx (hash k (ephemeron-table-length buckets))))
+            (let retry ((chain (ephemeron-table-ref buckets idx)))
+              (let walk ((link chain))
+                (cond
+                 ((not link)
+                  ;; Key was not in table when we started looking; try
+                  ;; to add it.
+                  (let* ((prev (ephemeron-table-try-push! buckets idx e 
chain)))
+                    (if (eq? prev chain)
+                        ;; Success.
+                        (values e #t)
+                        ;; Lost a race with another inserter; retry.
+                        (retry prev))))
+                 ((equal? (ephemeron-key link) k)
+                  ;; Found an existing association; return it.
+                  (values link #f))
+                 (else
+                  ;; Chain link for some other key; keep looking.
+                  (walk (ephemeron-next link))))))))))
+
+    (define-accessors findq insertq! eq? hashq)
+    (define-accessors findv insertv! eqv? hashv)
+    (define-accessors find insert! equal? hash)
+
+    (define (compute-accessors %equal? %hash)
+      (cond
+       ((and (primitive=? %equal? eq?) (primitive=? %hash hashq))
+        (values findq insertq!))
+       ((and (primitive=? %equal? eqv?) (primitive=? %hash hashv))
+        (values findv insertv!))
+       ((and (primitive=? %equal? equal?) (primitive=? %hash hash))
+        (values find insert!))
+       (else
+        (define-accessors find insert! %equal? %hash)
+        (values find insert!))))
+
+    (lambda* (#:optional (size 127)
+              #:key (equal? 'eq?) (hash 'hashq) (initial-size size))
+      (define-values (find insert!) (compute-accessors equal? hash))
+      (%make-weak-key-hash-table find insert!
+                                 (make-ephemeron-table initial-size)))))
+
+(define* (weak-key-hash-table-ref table k #:key (default (lambda (k) #f)))
+  (match table
+    (($ <weak-key-hash-table> find insert! buckets)
+     (match (find buckets k)
+       (#f (default k))
+       (e (ephemeron-value e))))))
+
+(define (weak-key-hash-table-set! table k v)
+  (match table
+    (($ <weak-key-hash-table> find insert! buckets)
+     (call-with-values (lambda () (insert! buckets k (make-ephemeron k v)))
+       (lambda (e inserted?)
+         (unless inserted?
+           (ephemeron-swap! e v))
+         (values))))))
+
+(define (weak-key-hash-table-remove! table k)
+  (match table
+    (($ <weak-key-hash-table> find insert! buckets)
+     (match (find buckets k)
+       (#f #f)
+       (e
+        (ephemeron-mark-dead! e)
+        #t)))))
+
+(define (weak-key-hash-table-clear! table)
+  (match table
+    (($ <weak-key-hash-table> find insert! buckets)
+     (let ((len (ephemeron-table-length buckets)))
+       (let lp ((i 0))
+         (when (< i len)
+           (ephemeron-table-clear! buckets i)
+           (lp (1+ i))))
+       (values)))))
+
+(define (weak-key-hash-table-fold proc init table)
+  (match table
+    (($ <weak-key-hash-table> find insert! buckets)
+     (let ((len (ephemeron-table-length buckets)))
+       (let visit-bucket ((i 0) (seed init))
+         (cond
+          ((< i len)
+           (let visit-chain ((chain (ephemeron-table-ref buckets i))
+                             (seed seed))
+             (if chain
+                 (let ((k (ephemeron-key chain))
+                       (v (ephemeron-value chain)))
+                   (visit-chain (ephemeron-next chain)
+                                (if k
+                                    (proc k v seed)
+                                    seed)))
+                 (visit-bucket (1+ i) seed))))
+          (else seed)))))))
+
+(define* (weak-key-hash-table-for-each proc table)
+  (weak-key-hash-table-fold (lambda (k v seed) (proc k v) seed) #f table)
+  (values))
+
+(define* (weak-key-hash-table-map->list proc table)
+  (weak-key-hash-table-fold (lambda (k v seed) (cons (proc k v) seed))
+                            '() table))
+
+
+
+
+;;;
+;;; Weak value hash tables implement a key-value mapping, where each
+;;; mapping is in place if and only if the value is otherwise reachable.
+;;; They are implemented as a normal hash table whose values are
+;;; ephemerons.  Because normal hash tables are not concurrent, accesses
+;;; to a weak value table are serialized through a lock.  On the other
+;;; hand, weak value tables are resizeable.
+;;;
+
+(define-record-type <weak-value-hash-table>
+  (%make-weak-value-hash-table lock find set! remove! store)
+  %weak-value-hash-table?
+  (lock weak-value-hash-table-lock)
+  (find %weak-value-hash-table-find)
+  (set! %weak-value-hash-table-set!)
+  (remove! %weak-value-hash-table-remove!)
+  (store weak-value-hash-table-store))
+
+(define make-weak-value-hash-table
+  (let ()
+    (define (make-assoc equal?)
+      (lambda (alist k)
+        (let lp ((alist alist))
+          (match alist
+            (() #f)
+            ((head . tail)
+             (if (equal? (car head) k)
+                 head
+                 (lp tail)))))))
+
+    (define (compute-accessors %equal? %hash)
+      (cond
+       ((and (primitive=? %equal? eq?) (primitive=? %hash hashq))
+        (values hashq-get-handle hashq-set! hashq-remove!))
+       ((and (primitive=? %equal? eqv?) (primitive=? %hash hashv))
+        (values hashv-get-handle hashv-set! hashv-remove!))
+       ((and (primitive=? %equal? equal?) (primitive=? %hash hash))
+        (values hash-get-handle hash-set! hash-remove!))
+       (else
+        (define assoc (make-assoc %equal?))
+        (values
+         (lambda (table k)
+           (hashx-get-handle %hash assoc table k))
+         (lambda (table k v)
+           (hashx-set! %hash assoc table k v))
+         (lambda (table k)
+           (hashx-remove! %hash assoc table k))))))
+
+    (lambda* (#:optional (size 0)
+              #:key (equal? 'eq?) (hash 'hashq) (initial-size size))
+      (define-values (find set! remove!) (compute-accessors equal? hash))
+      (%make-weak-value-hash-table (make-mutex) find set! remove!
+                                   (make-hash-table initial-size)))))
+
+(define* (weak-value-hash-table-ref table k #:key (default (lambda (k) #f)))
+  (match table
+    (($ <weak-value-hash-table> lock find set! remove! store)
+     (with-mutex lock
+       (match (find store k)
+         ((k . e)
+          (or (ephemeron-key e)
+              (begin
+                ;; Ephemeron is dead.
+                (remove! store k)
+                (default k))))
+         (#f (default k)))))))
+
+(define (weak-value-hash-table-set! table k v)
+  (match table
+    (($ <weak-value-hash-table> lock find set! remove! store)
+     (with-mutex lock
+       (set! store k (make-ephemeron v #t))))))
+
+(define (weak-value-hash-table-remove! table k)
+  (match table
+    (($ <weak-value-hash-table> lock find set! remove! store)
+     (with-mutex lock
+       (remove! store k))
+     (values))))
+
+(define (weak-value-hash-table-clear! table)
+  (match table
+    (($ <weak-value-hash-table> lock find set! remove! store)
+     (with-mutex lock
+       (hash-clear! store))
+     (values))))
+
+(define (weak-value-hash-table-fold proc init table)
+  (match table
+    (($ <weak-value-hash-table> lock find set! remove! store)
+     (with-mutex lock
+       (hash-fold (lambda (k v seed)
+                    (let ((v (ephemeron-key v)))
+                      (if v
+                          (proc k v seed)
+                          seed)))
+                  init table)))))
+
+(define* (weak-value-hash-table-for-each proc table)
+  (weak-value-hash-table-fold (lambda (k v seed) (proc k v) seed) #f table)
+  (values))
+
+(define* (weak-value-hash-table-map->list proc table)
+  (weak-value-hash-table-fold (lambda (k v seed) (cons (proc k v) seed))
+                              '() table))
+
+
+
+
+;;;
+;;; Doubly-weak hash tables implement a key-value mapping, where each
+;;; mapping is in place if and only if both the key and the value are
+;;; otherwise reachable.  They are implemented as a weak key table whose
+;;; values are ephemerons.  They are concurrent and lock-free but not
+;;; resizeable.
+;;;
+
+(define-record-type <doubly-weak-hash-table>
+  (%make-doubly-weak-hash-table store)
+  %doubly-weak-hash-table?
+  (store doubly-weak-hash-table-store))
+
+(define* (make-doubly-weak-hash-table #:optional (size 127)
+                                      #:key (equal? 'eq?) (hash 'hashq)
+                                      (initial-size size))
+  (%make-doubly-weak-hash-table
+   (make-weak-key-hash-table #:equal? equal? #:hash hash
+                             #:initial-size initial-size)))
+
+(define* (doubly-weak-hash-table-ref table k #:key (default (lambda (k) #f)))
+  (match table
+    (($ <doubly-weak-hash-table> store)
+     (match (weak-key-hash-table-ref store k)
+       (#f (default k))
+       (e (or (ephemeron-key e)
+              (default k)))))))
+
+(define* (doubly-weak-hash-table-set! table k v)
+  (match table
+    (($ <doubly-weak-hash-table> store)
+     (weak-key-hash-table-set! store k (make-ephemeron v #t)))))
+
+(define* (doubly-weak-hash-table-remove! table k)
+  (match table
+    (($ <doubly-weak-hash-table> store)
+     (weak-key-hash-table-remove! store k))))
+
+(define* (doubly-weak-hash-table-clear! table)
+  (match table
+    (($ <doubly-weak-hash-table> store)
+     (weak-key-hash-table-clear! store))))
+
+(define (weak-value-hash-table-fold proc init table)
+  (match table
+    (($ <doubly-weak-hash-table> store)
+     (weak-key-hash-table-fold (lambda (k v seed)
+                                 (let ((v (ephemeron-key v)))
+                                   (if v
+                                       (proc k v seed)
+                                       seed)))
+                               init store))))
+
+(define* (doubly-weak-hash-table-for-each proc table)
+  (doubly-weak-hash-table-fold (lambda (k v seed) (proc k v) seed) #f table)
+  (values))
+
+(define* (doubly-weak-hash-table-map->list proc table)
+  (doubly-weak-hash-table-fold (lambda (k v seed) (cons (proc k v) seed))
+                               '() table))
+
+
+
 
-(eval-when (expand load eval)
-  (load-extension (string-append "libguile-" (effective-version))
-                  "scm_init_weak_tables"))
+;; Work around srfi-9's use of define-inlinable.  FIXME: Simplify once
+;; srfi-9 is simplified.
+(define (weak-key-hash-table? x)
+  (%weak-key-hash-table? x))
+(define (weak-value-hash-table? x)
+  (%weak-value-hash-table? x))
+(define (doubly-weak-hash-table? x)
+  (%doubly-weak-hash-table? x))
diff --git a/module/language/cps/compile-bytecode.scm 
b/module/language/cps/compile-bytecode.scm
index bb530c7c6..8ff16cfa5 100644
--- a/module/language/cps/compile-bytecode.scm
+++ b/module/language/cps/compile-bytecode.scm
@@ -506,7 +506,6 @@
         (#('bytevector? #f (a)) (unary emit-bytevector? a))
         (#('thread? #f (a)) (unary emit-thread? a))
         (#('weak-set? #f (a)) (unary emit-weak-set? a))
-        (#('weak-table? #f (a)) (unary emit-weak-table? a))
         (#('array? #f (a)) (unary emit-array? a))
         (#('bitvector? #f (a)) (unary emit-bitvector? a))
         (#('smob? #f (a)) (unary emit-smob? a))
diff --git a/module/language/ecmascript/array.scm 
b/module/language/ecmascript/array.scm
index 997034584..ea9b9ace1 100644
--- a/module/language/ecmascript/array.scm
+++ b/module/language/ecmascript/array.scm
@@ -1,6 +1,6 @@
 ;;; ECMAScript for Guile
 
-;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2010, 2025 Free Software Foundation, Inc.
 
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
@@ -22,6 +22,7 @@
   #:use-module (oop goops)
   #:use-module (language ecmascript base)
   #:use-module (language ecmascript function)
+  #:use-module (ice-9 weak-tables)
   #:export (*array-prototype* new-array))
 
 
@@ -43,7 +44,7 @@
                                 #:value new-array
                                 #:constructor new-array))
 
-(hashq-set! *program-wrappers* new-array *array-prototype*)
+(doubly-weak-hash-table-set! *program-wrappers* new-array *array-prototype*)
 
 (pput *array-prototype* 'prototype *array-prototype*)
 (pput *array-prototype* 'constructor new-array)
diff --git a/module/language/ecmascript/function.scm 
b/module/language/ecmascript/function.scm
index a4669ae17..0d5c24852 100644
--- a/module/language/ecmascript/function.scm
+++ b/module/language/ecmascript/function.scm
@@ -52,28 +52,28 @@
                (apply (js-value this) args))))
 
 (define-method (pget (o <applicable>) p)
-  (let ((wrapper (hashq-ref *program-wrappers* o)))
+  (let ((wrapper (doubly-weak-hash-table-ref *program-wrappers* o)))
     (if wrapper
         (pget wrapper p)
         (pget *function-prototype* p))))
 
 (define-method (pput (o <applicable>) p v)
-  (let ((wrapper (hashq-ref *program-wrappers* o)))
+  (let ((wrapper (doubly-weak-hash-table-ref *program-wrappers* o)))
     (if wrapper
         (pput wrapper p v)
         (let ((wrapper (make <js-program-wrapper> #:value o #:class "Function"
                              #:prototype *function-prototype*)))
-          (hashq-set! *program-wrappers* o wrapper)
+          (doubly-weak-hash-table-set! *program-wrappers* o wrapper)
           (pput wrapper p v)))))
 
 (define-method (js-prototype (o <applicable>))
-  (let ((wrapper (hashq-ref *program-wrappers* o)))
+  (let ((wrapper (doubly-weak-hash-table-ref *program-wrappers* o)))
     (if wrapper
         (js-prototype wrapper)
         #f)))
 
 (define-method (js-constructor (o <applicable>))
-  (let ((wrapper (hashq-ref *program-wrappers* o)))
+  (let ((wrapper (doubly-weak-hash-table-ref *program-wrappers* o)))
     (if wrapper
         (js-constructor wrapper)
         #f)))
diff --git a/module/oop/goops/save.scm b/module/oop/goops/save.scm
index caa725500..6dda93eac 100644
--- a/module/oop/goops/save.scm
+++ b/module/oop/goops/save.scm
@@ -113,22 +113,22 @@
 ;;; Readables
 ;;;
 
-(define readables (make-weak-key-hash-table 61))
+(define readables (make-weak-key-hash-table #:initial-size 61))
 
 (define-macro (readable exp)
   `(make-readable ,exp ',(copy-tree exp)))
 
 (define (make-readable obj expr)
-  (hashq-set! readables obj expr)
+  (weak-key-hash-table-set! readables obj expr)
   obj)
 
 (define (readable-expression obj)
-  `(readable ,(hashq-ref readables obj)))
+  `(readable ,(weak-key-hash-table-ref readables obj)))
 
 ;; FIXME: if obj is nil or false, this can return a false value.  OTOH
 ;; usually this is only for non-immediates.
 (define (readable? obj)
-  (hashq-ref readables obj))
+  (weak-key-hash-table-ref readables obj))
 
 ;;;
 ;;; Writer helpers
diff --git a/module/srfi/srfi-18.scm b/module/srfi/srfi-18.scm
index 60f8d4c47..d4aac8ef7 100644
--- a/module/srfi/srfi-18.scm
+++ b/module/srfi/srfi-18.scm
@@ -184,10 +184,11 @@ object (absolute point in time), or #f."
           (thunk)))
       (lambda ()
         (let ((thread (current-thread)))
-          (hash-for-each (lambda (mutex _)
-                           (when (eq? (mutex-owner mutex) thread)
-                             (abandon-mutex! mutex)))
-                         mutexes))))))
+          (weak-key-hash-table-for-each
+           (lambda (mutex _)
+             (when (eq? (mutex-owner mutex) thread)
+               (abandon-mutex! mutex)))
+           mutexes))))))
 
 (define* (make-thread thunk #:optional name)
   (let* ((sm (make-mutex 'start-mutex))
@@ -291,7 +292,7 @@ object (absolute point in time), or #f."
 (define* (mutex-lock! mutex #:optional timeout (thread (current-thread)))
   (let ((mutexes (thread-mutexes)))
     (when mutexes
-      (hashq-set! mutexes mutex #t)))
+      (weak-key-hash-table-set! mutexes mutex #t)))
   (cond
    ((threads:lock-mutex (mutex-prim mutex)
                         (timeout->absolute-time timeout))
diff --git a/module/srfi/srfi-69.scm b/module/srfi/srfi-69.scm
index efdc59bd4..a14ed8f22 100644
--- a/module/srfi/srfi-69.scm
+++ b/module/srfi/srfi-69.scm
@@ -194,6 +194,11 @@ alist keys with EQUAL-PROC."
   "Answer a new hash table using EQUAL-PROC as the comparison
 function, and HASH-PROC as the hash function.  See the reference
 manual for specifics, of which there are many."
+  (when weak
+    (issue-deprecation-warning
+     "Making weak hash tables with the SRFI-69 interface is deprecated.  "
+     "If Guile's SRFI-69 code is not updated before the next major "
+     "version, this facility will go away."))
   (make-srfi-69-hash-table
    (apply (guile-ht-ctor weak) (without-keyword-args guile-opts))
    (equivalence-proc->associator equal-proc)
diff --git a/module/system/base/types.scm b/module/system/base/types.scm
index fd35a09f2..9347dcc51 100644
--- a/module/system/base/types.scm
+++ b/module/system/base/types.scm
@@ -463,8 +463,6 @@ using BACKEND."
            (inferior-object 'vm-continuation address))
           (((_ & #x7f = %tc7-weak-set))
            (inferior-object 'weak-set address))
-          (((_ & #x7f = %tc7-weak-table))
-           (inferior-object 'weak-table address))
           (((_ & #x7f = %tc7-array))
            (inferior-object 'array address))
           (((_ & #x7f = %tc7-bitvector))
diff --git a/module/system/base/types/internal.scm 
b/module/system/base/types/internal.scm
index b739f9a9a..a0370eddc 100644
--- a/module/system/base/types/internal.scm
+++ b/module/system/base/types/internal.scm
@@ -52,7 +52,6 @@
             %tc7-bytevector
             %tc7-thread
             %tc7-weak-set
-            %tc7-weak-table
             %tc7-array
             %tc7-bitvector
             %tc7-port
@@ -149,7 +148,7 @@
   (bytevector       bytevector?            #b1111111       #b1001101)
   (thread           thread?                #b1111111       #b1001111)
   (weak-set         weak-set?              #b1111111       #b1010101)
-  (weak-table       weak-table?            #b1111111       #b1010111)
+  ;;(unused         unused                 #b1111111       #b1010111)
   (array            array?                 #b1111111       #b1011101)
   (bitvector        bitvector?             #b1111111       #b1011111)
   (finalizer        finalizer?             #b1111111       #b1100101)
diff --git a/module/system/foreign.scm b/module/system/foreign.scm
index fe068a471..4fb9f6628 100644
--- a/module/system/foreign.scm
+++ b/module/system/foreign.scm
@@ -290,10 +290,12 @@ which does the reverse.  PRINT must name a user-defined 
object printer."
              (define wrap
                ;; Use a weak hash table to preserve pointer identity, i.e.,
                ;; PTR1 == PTR2 <-> (eq? (wrap PTR1) (wrap PTR2)).
-               (let ((ptr->obj (make-weak-value-hash-table 3000)))
+               (let ((ptr->obj (make-weak-value-hash-table
+                                #:hash hash #:equal? equal?
+                                #:initial-size 3000)))
                  (lambda (ptr)
-                   (or (hash-ref ptr->obj ptr)
+                   (or (weak-value-hash-table-ref ptr->obj ptr)
                        (let ((o (%wrap ptr)))
-                         (hash-set! ptr->obj ptr o)
+                         (weak-value-hash-table-set! ptr->obj ptr o)
                          o)))))
              (set-record-type-printer! type-name print)))))))
diff --git a/module/system/vm/assembler.scm b/module/system/vm/assembler.scm
index 7fc15b9f2..d931dcd78 100644
--- a/module/system/vm/assembler.scm
+++ b/module/system/vm/assembler.scm
@@ -133,7 +133,6 @@
             emit-bytevector?
             emit-thread?
             emit-weak-set?
-            emit-weak-table?
             emit-array?
             emit-bitvector?
             emit-ephemeron?
diff --git a/test-suite/tests/gc.test b/test-suite/tests/gc.test
index 98367fac5..380690733 100644
--- a/test-suite/tests/gc.test
+++ b/test-suite/tests/gc.test
@@ -50,9 +50,9 @@
 (pass-if "weak-values versus records"
   (let ((rec-type (make-record-type 'foo '()))
        (h        (make-weak-value-hash-table 61)))
-    (hash-set! h "foo" ((record-constructor rec-type)))
+    (weak-value-hash-table-set! h "foo" ((record-constructor rec-type)))
     (gc)
-    (let ((x (hash-ref h "foo")))
+    (let ((x (weak-value-hash-table-ref h "foo")))
       (or (not x)
          ((record-predicate rec-type) x)))))
 
diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
index fe75d7b05..f95ec0281 100644
--- a/test-suite/tests/hash.test
+++ b/test-suite/tests/hash.test
@@ -366,7 +366,8 @@
 (with-test-prefix "weak key hash table"
   (pass-if "hash-for-each after gc"
     (let ((table (make-weak-key-hash-table)))
-      (hashq-set! table (list 'foo) 'bar)
+      (weak-key-hash-table-set! table (list 'foo) 'bar)
       (gc)
       ;; Iterate over deleted weak ref without crashing.
-      (unspecified? (hash-for-each (lambda (key value) key) table)))))
+      (weak-key-hash-table-for-each (lambda (key value) key) table)
+      #t)))
diff --git a/test-suite/tests/srfi-69.test b/test-suite/tests/srfi-69.test
index e99b76c6d..f9f6c3f33 100644
--- a/test-suite/tests/srfi-69.test
+++ b/test-suite/tests/srfi-69.test
@@ -1,6 +1,6 @@
 ;;;; srfi-69.test --- Test suite for SRFI 69 -*- scheme -*-
 ;;;;
-;;;;   Copyright (C) 2007 Free Software Foundation, Inc.
+;;;;   Copyright (C) 2007, 2025 Free Software Foundation, Inc.
 ;;;;
 ;;;; This library is free software; you can redistribute it and/or
 ;;;; modify it under the terms of the GNU Lesser General Public
@@ -51,6 +51,8 @@ case-insensitive strings to `equal?'-tested values."
                  '(("xy" . 42) ("abc" . 54) ("qqq" . 100))
                  (hash-table->alist ht)))))
 
+  ;; FIXME: Either revive or deprecate.
+  #;
   (pass-if-exception "Bad weakness arg to mht signals an error"
                     '(misc-error . "^Invalid weak hash table type")
     (make-hash-table equal? hash #:weak 'key-and-value))
@@ -101,6 +103,8 @@ case-insensitive strings to `equal?'-tested values."
       (and (= 1 (hash-table-size ht))
           (lset= equal? '((b . 53)) (hash-table->alist ht)))))
 
+  ;; FIXME: Either revive or deprecate.
+  #;
   (pass-if "can use all arguments, including size"
     (hash-table? (make-hash-table equal? hash #:weak 'key 31)))
 
diff --git a/test-suite/tests/types.test b/test-suite/tests/types.test
index 1ebf19bad..eeede1308 100644
--- a/test-suite/tests/types.test
+++ b/test-suite/tests/types.test
@@ -101,9 +101,6 @@
    ((open-input-string "hello") port (? inferior-object?))
    ((lambda () #t) program _)
    ((make-variable 'foo) variable _)
-   ((make-weak-key-hash-table) weak-table _)
-   ((make-weak-value-hash-table) weak-table _)
-   ((make-doubly-weak-hash-table) weak-table _)
    (#2((1 2 3) (4 5 6)) array _)
    (#*00000110 bitvector _)
    ((expt 2 70) bignum _)
diff --git a/test-suite/tests/weaks.test b/test-suite/tests/weaks.test
index 3663f39ec..0541208ae 100644
--- a/test-suite/tests/weaks.test
+++ b/test-suite/tests/weaks.test
@@ -130,7 +130,7 @@
 
 
 ;;;
-;;; Weak hash tables & weak alist vectors.
+;;; Weak hash tables.
 ;;;
 
 (define (valid? value initial-value)
@@ -140,23 +140,23 @@
   (or (not value)
       (equal? value initial-value)))
 
- (let ((x (make-weak-key-hash-table 17))
-      (y (make-weak-value-hash-table 17))
-      (z (make-doubly-weak-hash-table 17))
+(let ((x (make-weak-key-hash-table #:hash hash #:equal? equal?))
+      (y (make-weak-value-hash-table #:hash hash #:equal? equal?))
+      (z (make-doubly-weak-hash-table #:hash hash #:equal? equal?))
       (test-key "foo")
       (test-value "bar"))
   (with-test-prefix
    "weak-hash"
    (pass-if "lives"
            (begin
-             (hash-set! x test-key test-value)
-             (hash-set! y test-key test-value)
-             (hash-set! z test-key test-value)
+             (weak-key-hash-table-set! x test-key test-value)
+             (weak-value-hash-table-set! y test-key test-value)
+             (doubly-weak-hash-table-set! z test-key test-value)
              (gc)
              (gc)
-             (and (hash-ref x test-key)
-                  (hash-ref y test-key)
-                  (hash-ref z test-key)
+             (and (weak-key-hash-table-ref x test-key)
+                  (weak-value-hash-table-ref y test-key)
+                  (doubly-weak-hash-table-ref z test-key)
                   #t)))
 
    ;; In the tests below we use `string-copy' to avoid the risk of
@@ -164,117 +164,105 @@
 
    (pass-if "weak-key dies"
             (begin
-              (hash-set! x (string-copy "this") "is")
-              (hash-set! x (string-copy "a") "test")
-              (hash-set! x (string-copy "of") "the")
-              (hash-set! x (string-copy "emergency") "weak")
-              (hash-set! x (string-copy "key") "hash system")
+              (weak-key-hash-table-set! x (string-copy "this") "is")
+              (weak-key-hash-table-set! x (string-copy "a") "test")
+              (weak-key-hash-table-set! x (string-copy "of") "the")
+              (weak-key-hash-table-set! x (string-copy "emergency") "weak")
+              (weak-key-hash-table-set! x (string-copy "key") "hash system")
               (gc)
-              (let ((values (map (cut hash-ref x <>)
+              (let ((values (map (cut weak-key-hash-table-ref x <>)
                                  '("this" "a" "of" "emergency" "key"))))
                 (and (every valid? values
                             '("is" "test" "the" "weak" "hash system"))
                      (any not values)
-                     (hash-ref x test-key)
+                     (weak-key-hash-table-ref x test-key)
                      #t))))
 
    (pass-if "weak-value dies"
             (begin
-              (hash-set! y "this" (string-copy "is"))
-              (hash-set! y "a" (string-copy "test"))
-              (hash-set! y "of" (string-copy "the"))
-              (hash-set! y "emergency" (string-copy "weak"))
-              (hash-set! y "value" (string-copy "hash system"))
+              (weak-value-hash-table-set! y "this" (string-copy "is"))
+              (weak-value-hash-table-set! y "a" (string-copy "test"))
+              (weak-value-hash-table-set! y "of" (string-copy "the"))
+              (weak-value-hash-table-set! y "emergency" (string-copy "weak"))
+              (weak-value-hash-table-set! y "value" (string-copy "hash 
system"))
               (gc)
-              (let ((values (map (cut hash-ref y <>)
+              (let ((values (map (cut weak-value-hash-table-ref y <>)
                                  '("this" "a" "of" "emergency" "key"))))
                 (and (every valid? values
                             '("is" "test" "the" "weak" "hash system"))
                      (any not values)
-                     (hash-ref y test-key)
+                     (weak-value-hash-table-ref y test-key)
                      #t))))
 
    (pass-if "doubly-weak dies"
             (begin
-              (hash-set! z (string-copy "this") (string-copy "is"))
-              (hash-set! z "a" (string-copy "test"))
-              (hash-set! z (string-copy "of") "the")
-              (hash-set! z "emergency" (string-copy "weak"))
-              (hash-set! z (string-copy "all") (string-copy "hash system"))
+              (doubly-weak-hash-table-set! z (string-copy "this") (string-copy 
"is"))
+              (doubly-weak-hash-table-set! z "a" (string-copy "test"))
+              (doubly-weak-hash-table-set! z (string-copy "of") "the")
+              (doubly-weak-hash-table-set! z "emergency" (string-copy "weak"))
+              (doubly-weak-hash-table-set! z (string-copy "all") (string-copy 
"hash system"))
               (gc)
-              (let ((values (map (cut hash-ref z <>)
+              (let ((values (map (cut doubly-weak-hash-table-ref z <>)
                                  '("this" "a" "of" "emergency" "key"))))
                 (and (every valid? values
                             '("is" "test" "the" "weak" "hash system"))
                      (any not values)
-                     (hash-ref z test-key)
+                     (doubly-weak-hash-table-ref z test-key)
                      #t))))
 
-   (pass-if "hash-set!, weak val, im -> im"
-     (let ((t (make-weak-value-hash-table)))
-       (hash-set! t "foo" 1)
-       (hash-set! t "foo" 2)
-       (equal? (hash-ref t "foo") 2)))
-
-   (pass-if "hash-set!, weak val, im -> nim"
-     (let ((t (make-weak-value-hash-table)))
-       (hash-set! t "foo" 1)
-       (hash-set! t "foo" "baz")
-       (equal? (hash-ref t "foo") "baz")))
-
-   (pass-if "hash-set!, weak val, nim -> nim"
-     (let ((t (make-weak-value-hash-table)))
-       (hash-set! t "foo" "bar")
-       (hash-set! t "foo" "baz")
-       (equal? (hash-ref t "foo") "baz")))
-
-   (pass-if "hash-set!, weak val, nim -> im"
-     (let ((t (make-weak-value-hash-table)))
-       (hash-set! t "foo" "bar")
-       (hash-set! t "foo" 1)
-       (equal? (hash-ref t "foo") 1)))
-
-   (pass-if "hash-set!, weak key, returns value"
-     (let ((t (make-weak-value-hash-table))
-           (val (string #\f #\o #\o)))
-       (eq? (hashq-set! t "bar" val)
-            (hashv-set! t "bar" val)
-            (hash-set! t "bar" val)
-            val)))
+   (pass-if "weak-value-hash-table-set!, weak val, im -> im"
+     (let ((t (make-weak-value-hash-table #:equal? equal? #:hash hash)))
+       (weak-value-hash-table-set! t "foo" 1)
+       (weak-value-hash-table-set! t "foo" 2)
+       (equal? (weak-value-hash-table-ref t "foo") 2)))
+
+   (pass-if "weak-value-hash-table-set!, weak val, im -> nim"
+     (let ((t (make-weak-value-hash-table #:equal? equal? #:hash hash)))
+       (weak-value-hash-table-set! t "foo" 1)
+       (weak-value-hash-table-set! t "foo" "baz")
+       (equal? (weak-value-hash-table-ref t "foo") "baz")))
+
+   (pass-if "weak-value-hash-table-set!, weak val, nim -> nim"
+     (let ((t (make-weak-value-hash-table #:equal? equal? #:hash hash)))
+       (weak-value-hash-table-set! t "foo" "bar")
+       (weak-value-hash-table-set! t "foo" "baz")
+       (equal? (weak-value-hash-table-ref t "foo") "baz")))
+
+   (pass-if "weak-value-hash-table-set!, weak val, nim -> im"
+     (let ((t (make-weak-value-hash-table #:equal? equal? #:hash hash)))
+       (weak-value-hash-table-set! t "foo" "bar")
+       (weak-value-hash-table-set! t "foo" 1)
+       (equal? (weak-value-hash-table-ref t "foo") 1)))
 
    (pass-if "assoc can do anything"
             ;; Until 1.9.12, as hash table's custom ASSOC procedure was
             ;; called with the GC lock alloc held, which imposed severe
             ;; restrictions on what it could do (bug #29616).  This test
             ;; makes sure this is no longer the case.
-            (let ((h (make-doubly-weak-hash-table 2))
+            (let ((h (make-doubly-weak-hash-table
+                      #:initial-size 2
+                      #:hash string-hash-ci
+                      #:equal? (lambda (a b)
+                                 (make-list 123) ;; this should be possible
+                                 (gc)            ;; this too
+                                 (string-ci=? a b))))
                   (c 123)
                   (k "GNU"))
 
-              (define (assoc-ci key bucket)
-                (make-list 123) ;; this should be possible
-                (gc)            ;; this too
-                (find (lambda (p)
-                        (string-ci=? key (car p)))
-                      bucket))
-
-              (hashx-set! string-hash-ci assoc-ci h
-                          (string-copy "hello") (string-copy "world"))
-              (hashx-set! string-hash-ci assoc-ci h
-                          k "Guile")
+              (doubly-weak-hash-table-set! h (string-copy "hello")
+                                           (string-copy "world"))
+              (doubly-weak-hash-table-set! h k "Guile")
 
               (and (every (cut valid? <> "Guile")
                           (unfold (cut >= <> c)
                                   (lambda (_)
-                                    (hashx-ref string-hash-ci assoc-ci
-                                               h "gnu"))
+                                    (doubly-weak-hash-table-ref h "gnu"))
                                   1+
                                   0))
                    (every (cut valid? <> "world")
                           (unfold (cut >= <> c)
                                   (lambda (_)
-                                    (hashx-ref string-hash-ci assoc-ci
-                                               h "HELLO"))
+                                    (doubly-weak-hash-table-ref h "HELLO"))
                                   1+
                                   0))
                    #t)))))

Reply via email to