+(declaim (maybe-inline %%puthash))
+(defun %%puthash (key hash-table value)
+ (declare (optimize speed))
+ ;; We need to rehash here so that a current key can be found if it
+ ;; exists. Check that there is room for one more entry. May not be
+ ;; needed if the key is already present.
+ (maybe-rehash hash-table t)
+ ;; Search for key in the hash table.
+ (multiple-value-bind (hashing eq-based)
+ (funcall (hash-table-hash-fun hash-table) key)
+ (declare (type hash hashing))
+ (let* ((index-vector (hash-table-index-vector hash-table))
+ (length (length index-vector))
+ (index (index-for-hashing hashing length))
+ (next (aref index-vector index))
+ (kv-vector (hash-table-table hash-table))
+ (next-vector (hash-table-next-vector hash-table))
+ (hash-vector (hash-table-hash-vector hash-table))
+ (test-fun (hash-table-test-fun hash-table)))
+ (declare (type index index next))
+ (when (hash-table-weakness hash-table)
+ (set-header-data kv-vector sb!vm:vector-valid-hashing-subtype))
+ (cond ((or eq-based (not hash-vector))
+ (when eq-based
+ (set-header-data kv-vector
+ sb!vm:vector-valid-hashing-subtype))
+ ;; Search next-vector chain for a matching key.
+ (do ((next next (aref next-vector next))
+ (i 0 (1+ i)))
+ ((zerop next))
+ (declare (type index/2 next i))
+ (when (> i length)
+ (signal-corrupt-hash-table hash-table))
+ (when (eq key (aref kv-vector (* 2 next)))
+ ;; Found, just replace the value.
+ (update-hash-table-cache hash-table (* 2 next))
+ (setf (aref kv-vector (1+ (* 2 next))) value)
+ (return-from %%puthash value))))
+ (t
+ ;; Search next-vector chain for a matching key.
+ (do ((next next (aref next-vector next))
+ (i 0 (1+ i)))
+ ((zerop next))
+ (declare (type index/2 next i))
+ (when (> i length)
+ (signal-corrupt-hash-table hash-table))
+ (when (and (= hashing (aref hash-vector next))
+ (funcall test-fun key
+ (aref kv-vector (* 2 next))))
+ ;; Found, just replace the value.
+ (update-hash-table-cache hash-table (* 2 next))
+ (setf (aref kv-vector (1+ (* 2 next))) value)
+ (return-from %%puthash value)))))
+ ;; Pop a KV slot off the free list
+ (let ((free-kv-slot (hash-table-next-free-kv hash-table)))
+ (declare (type index/2 free-kv-slot))
+ ;; Double-check for overflow.
+ (aver (not (zerop free-kv-slot)))
+ (setf (hash-table-next-free-kv hash-table)
+ (aref next-vector free-kv-slot))
+ (incf (hash-table-number-entries hash-table))
+ (update-hash-table-cache hash-table (* 2 free-kv-slot))
+ (setf (aref kv-vector (* 2 free-kv-slot)) key)
+ (setf (aref kv-vector (1+ (* 2 free-kv-slot))) value)
+ ;; Setup the hash-vector if necessary.
+ (when hash-vector
+ (if (not eq-based)
+ (setf (aref hash-vector free-kv-slot) hashing)
+ (aver (= (aref hash-vector free-kv-slot)
+ +magic-hash-vector-value+))))
+ ;; Push this slot into the next chain.
+ (setf (aref next-vector free-kv-slot) next)
+ (setf (aref index-vector index) free-kv-slot)))
+ value))
+