-(defun flush-needing-rehash (table)
- (let* ((kv-vector (hash-table-table table))
- (index-vector (hash-table-index-vector table))
- (next-vector (hash-table-next-vector table))
- (length (length index-vector)))
- (do ((next (hash-table-needing-rehash table)))
- ((zerop next))
- (declare (type index/2 next))
- (let* ((key (aref kv-vector (* 2 next)))
- (hashing (pointer-hash key))
- (index (rem hashing length))
- (temp (aref next-vector next)))
- (setf (aref next-vector next) (aref index-vector index))
- (setf (aref index-vector index) next)
- (setf next temp))))
- (setf (hash-table-needing-rehash table) 0)
- (values))
+(declaim (inline maybe-rehash))
+(defun maybe-rehash (hash-table ensure-free-slot-p)
+ (when (hash-table-weakness hash-table)
+ (aver *gc-inhibit*))
+ (flet ((rehash-p ()
+ (and ensure-free-slot-p
+ (zerop (hash-table-next-free-kv hash-table))))
+ (rehash-without-growing-p ()
+ (hash-table-needs-rehash-p hash-table)))
+ (cond ((rehash-p)
+ ;; Use recursive spinlocks since for weak tables the
+ ;; spinlock has already been acquired. GC must be inhibited
+ ;; to prevent the GC from seeing a rehash in progress.
+ (sb!thread::with-recursive-system-spinlock
+ ((hash-table-spinlock hash-table) :without-gcing t)
+ ;; Repeat the condition inside the lock to ensure that if
+ ;; two reader threads enter MAYBE-REHASH at the same time
+ ;; only one rehash is performed.
+ (when (rehash-p)
+ (rehash hash-table))))
+ ((rehash-without-growing-p)
+ (sb!thread::with-recursive-system-spinlock
+ ((hash-table-spinlock hash-table) :without-gcing t)
+ (when (rehash-without-growing-p)
+ (without-gcing
+ (rehash-without-growing hash-table))))))))
+
+(declaim (inline update-hash-table-cache))
+(defun update-hash-table-cache (hash-table index)
+ (unless (hash-table-weakness hash-table)
+ (setf (hash-table-cache hash-table) index)))
+
+(defmacro with-hash-table-locks ((hash-table inline &rest pin-objects)
+ &body body)
+ `(with-concurrent-access-check ,hash-table
+ ;; Inhibit GC for the duration of BODY if the GC might mutate the
+ ;; HASH-TABLE in some way (currently true only if the table is
+ ;; weak). We also need to lock the table to ensure that two
+ ;; concurrent writers can't create a cyclical vector that would
+ ;; cause scav_weak_hash_table_chain to loop.
+ ;;
+ ;; Otherwise we can avoid the 2x-3x overhead, and just pin the key.
+ (if (hash-table-weakness ,hash-table)
+ (sb!thread::with-recursive-system-spinlock
+ ((hash-table-spinlock hash-table) :without-gcing t)
+ ,@body)
+ (with-pinned-objects ,pin-objects
+ (locally
+ ;; Inline the implementation function on the fast path
+ ;; only. (On the slow path it'll just bloat the
+ ;; generated code with no benefit).
+ (declare (inline ,@inline))
+ ,@body)))))