mirror of
git://git.code.sf.net/p/sbcl/sbcl
synced 2026-09-10 07:26:40 -04:00
Improve package iteration per lp#2080387
Some checks failed
Linux qemu / ppc64le (push) Failing after 0s
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, sse4) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (--without-sb-thread, x86-64) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc) (push) Waiting to run
Mac / build (arm64, --with-sb-thread) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread) (push) Waiting to run
Windows / build (push) Waiting to run
Some checks failed
Linux qemu / ppc64le (push) Failing after 0s
CL-host / ecl (push) Waiting to run
CL-host / clisp (push) Waiting to run
CL-host / ccl (push) Waiting to run
CL-host / cmucl (push) Waiting to run
CL-host / sbcl (push) Waiting to run
CL-host / compare-xc-host-fasls (ccl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (clisp, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (cmucl, false) (push) Blocked by required conditions
CL-host / compare-xc-host-fasls (self, false) (push) Blocked by required conditions
Linux / build (x86, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86, --without-sb-unicode, ) (push) Waiting to run
Linux / build (x86-64, --with-mark-region-gc) (push) Waiting to run
Linux / build (x86-64, --with-sb-fasteval --without-sb-eval, fasteval) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --with-sb-thread, sse4) (push) Waiting to run
Linux / build (x86-64, --without-sb-thread, ) (push) Waiting to run
Linux / build (x86-64, --without-sb-unicode, ) (push) Waiting to run
Mac / build (--without-sb-thread, x86-64) (push) Waiting to run
Mac / build (arm64, --with-mark-region-gc) (push) Waiting to run
Mac / build (arm64, --with-sb-thread) (push) Waiting to run
Mac / build (x86-64, --with-mark-region-gc) (push) Waiting to run
Mac / build (x86-64, --with-sb-thread) (push) Waiting to run
Windows / build (push) Waiting to run
Allow changing accessibility from :INTERNAL to :EXTERNAL during iteration without messing up the iterator. But now we have a duplicates problem which it's unclear whether runs slightly afoul of the spec. e.g. DO-ALL-SYMBOLS "may cause a symbol that is present in several packages to be processed more than once". Since that's not phrased as if-and-only-if, we take the liberty of returning a symbol more than once even when NOT present in more than one package. Apparently so do some other Common-Lisp implementations.
This commit is contained in:
parent
cecc5175b7
commit
132d1c042a
|
|
@ -798,7 +798,7 @@ specifies to signal a warning if SWANK package is in variance, and an error othe
|
|||
;;;
|
||||
(defun tune-hashset-sizes-of-all-packages ()
|
||||
(flet ((tune-table-size (desired-lf table)
|
||||
(resize-symbol-table table (%symtbl-count table) t desired-lf)
|
||||
(resize-symbol-table table (%symtbl-count table) 'intern desired-lf)
|
||||
;; The APROPOS-LIST R/O scan optimization is inadmissible if no R/O space
|
||||
#-darwin-jit (setf (symtbl-modified table) nil)))
|
||||
(dolist (package (list-all-packages))
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
(push x result) ; keep a strong reference to this symbol
|
||||
(push (cons (string x) (make-weak-pointer x)) result))))
|
||||
(fill cells 0)
|
||||
(resize-symbol-table table 0 t)
|
||||
(resize-symbol-table table 0 'intern)
|
||||
result)))
|
||||
(dolist (package (list-all-packages))
|
||||
;; Never discard standard symbols
|
||||
|
|
@ -33,10 +33,10 @@
|
|||
(declare (ignore package))
|
||||
(dolist (item symbols)
|
||||
(if (symbolp item)
|
||||
(add-symbol table item)
|
||||
(add-symbol table item 'intern)
|
||||
(let ((symbol (weak-pointer-value (cdr item))))
|
||||
(cond (symbol
|
||||
(add-symbol table symbol))
|
||||
(add-symbol table symbol 'intern))
|
||||
(t
|
||||
(when print
|
||||
(format t " (~a)~A~%" access (car item)))
|
||||
|
|
|
|||
|
|
@ -307,6 +307,7 @@
|
|||
|
||||
;;;; iteration macros
|
||||
|
||||
(define-thread-local *clear-resized-symbol-tables* t)
|
||||
(defmacro with-package-iterator ((mname package-list &rest symbol-types) &body body)
|
||||
"Within the lexical scope of the body forms, MNAME is defined via macrolet
|
||||
such that successive invocations of (MNAME) will return the symbols, one by
|
||||
|
|
@ -325,7 +326,7 @@ of :INHERITED :EXTERNAL :INTERNAL."
|
|||
(if (member :external symbol-types) 2 0)
|
||||
(if (member :inherited symbol-types) 4 0))))
|
||||
`(multiple-value-bind ,state (package-iter-init ,select ,package-list)
|
||||
(let (,symbol ,kind)
|
||||
(let (*clear-resized-symbol-tables* ,symbol ,kind)
|
||||
(macrolet
|
||||
((,mname ()
|
||||
'(if (eql 0 (multiple-value-setq (,@state ,symbol ,kind)
|
||||
|
|
@ -533,7 +534,7 @@ of :INHERITED :EXTERNAL :INTERNAL."
|
|||
;;; calls to ADD-SYMBOL make no attempt to preserve Robinhood's minimization
|
||||
;;; of the maximum probe sequence length. We can do it now because the
|
||||
;;; entire vector will be swapped, which is concurrent reader safe.
|
||||
(defun resize-symbol-table (table size splat &optional (load-factor 3/4))
|
||||
(defun resize-symbol-table (table size reason &optional (load-factor 3/4))
|
||||
(when (zerop size)
|
||||
(return-from resize-symbol-table
|
||||
;; Don't need a barrier here. Suppose a reader finished probing with a miss.
|
||||
|
|
@ -597,14 +598,17 @@ of :INHERITED :EXTERNAL :INTERNAL."
|
|||
(setf (symtbl-size table) (symtbl-size temp-table)
|
||||
(symtbl-free table) (symtbl-free temp-table)
|
||||
(symtbl-deleted table) 0)
|
||||
;; Splat with 0 to reduce garbage tenuring. Readers who searched the old VEC
|
||||
;; may miss spuriously, but will retry because they can detect that %CELLS changed.
|
||||
;; Exception: UNINTERN must not splat the vector because it is permitted to
|
||||
;; UNINTERN while iterating over symbols. We never re-fetch the vector, as doing
|
||||
;; that would cause extreme complications in deciding what symbols to produce.
|
||||
;; As such, we simply avoid splatting if called by UNINTERN.
|
||||
;; (Also, the constant vector of an empty package hashtable.)
|
||||
(when (and splat (not (read-only-space-obj-p old)))
|
||||
;; Try to splat with 0 to reduce garbage tenuring based on a pre-test:
|
||||
;; - If the current thread has bound *CLEAR-RESIZED-SYMBOL-TABLES* to NIL,
|
||||
;; meaning that it is within the dynamic extent of WITH-PACKAGE-ITERATOR,
|
||||
;; splat only if the package modification is NOT a permissible one.
|
||||
;; - If the currrent thread has NOT bound the special variable, always splat.
|
||||
;; Concurrent readers who searched the old VEC may miss spuriously, but will retry
|
||||
;; because they can detect that %CELLS changed. In this manner, FIND-SYMBOL
|
||||
;; remains lock-free while allowing resizing and splatting.
|
||||
(when (and (or *clear-resized-symbol-tables*
|
||||
(not (memq reason '(unintern export unexport)))) ; permissible
|
||||
(not (read-only-space-obj-p old)))
|
||||
(fill old 0))
|
||||
new)))))
|
||||
|
||||
|
|
@ -1104,7 +1108,7 @@ Experimental: interface subject to change."
|
|||
|
||||
;;; Add a symbol to a hashset. The symbol MUST NOT be present.
|
||||
;;; This operation is under the WITH-PACKAGE-GRAPH lock if called by %INTERN.
|
||||
(defun add-symbol (table symbol)
|
||||
(defun add-symbol (table symbol reason)
|
||||
(setf (symtbl-modified table) t)
|
||||
(when (zerop (symtbl-free table))
|
||||
;; The hashtable is full. Resize it to be able to hold twice the
|
||||
|
|
@ -1114,7 +1118,7 @@ Experimental: interface subject to change."
|
|||
;; N.B.: Never pass 0 for the new size, as that will assign the
|
||||
;; constant read-only vector #(0 0 0) into the cells.
|
||||
(let ((new-size (max 1 (* (- (symtbl-size table) (symtbl-deleted table)) 2))))
|
||||
(resize-symbol-table table new-size t)))
|
||||
(resize-symbol-table table new-size reason)))
|
||||
(let* ((cells (symtbl-%cells table))
|
||||
(reciprocals (car cells))
|
||||
(vec (truly-the simple-vector (cdr cells)))
|
||||
|
|
@ -1304,25 +1308,10 @@ Experimental: interface subject to change."
|
|||
(probe)))))))))
|
||||
|
||||
;;; Delete SYMBOL from TABLE, storing -1 in its place. SYMBOL must exist.
|
||||
;;;
|
||||
;;; NOTE: It's possible that NUKE-SYMBOL should never 0-fill the old symbol-table if downsizing.
|
||||
;;; CLHS nowhere implies that altering accessability of a symbol already _present_ in a package
|
||||
;;; counts as INTERNing. Iterating over directly present symbols of a package permits UNINTERN on
|
||||
;;; the current symbol, which might rehash the storage vector, creating a new one. To allow it,
|
||||
;;; UNINTERN does not 0-fill the old vector, so any observers of that vector still see all symbols
|
||||
;;; beyond the cursor. But what if the operation is EXPORT or UNEXPORT? This moves the symbol from
|
||||
;;; one table to the other for that same package. EXPORT would remove from internals and move to
|
||||
;;; externals. If the internals can down-size and 0-fill (as we do), then symbols beyond the cursor
|
||||
;;; are missed. The argument in favaor of allowing EXPORT would seem to be that EXPORT is not
|
||||
;;; technically INTERNing in this case. But the argument _against_ allowing EXPORT or UNEXPORT
|
||||
;;; is that there is one and only one exception specifically called out as permissible, namely:
|
||||
;;; "the current symbol may be uninterned from the package being traversed."
|
||||
;;; If it were _also_ intended to be permissible to EXPORT or UNEXPORT, would it not have said
|
||||
;;; that it is permissible to change accessibility ? I'm not sure.
|
||||
(defun nuke-symbol (table symbol splat)
|
||||
(defun nuke-symbol (table symbol reason)
|
||||
(let ((cells (symtbl-%cells table)))
|
||||
(when (functionp (car cells)) ; change table back to not-perfectly-hashed
|
||||
(resize-symbol-table table (length (cdr cells)) splat)))
|
||||
(resize-symbol-table table (length (cdr cells)) reason)))
|
||||
(let* ((string (symbol-name symbol))
|
||||
(length (length string))
|
||||
(hash (symbol-name-hash symbol)))
|
||||
|
|
@ -1339,7 +1328,7 @@ Experimental: interface subject to change."
|
|||
(let ((size (symtbl-size table))
|
||||
(used (%symtbl-count table)))
|
||||
(when (< used (truncate size 4))
|
||||
(resize-symbol-table table (* used 2) splat))))
|
||||
(resize-symbol-table table (* used 2) reason))))
|
||||
|
||||
(defun list-all-packages ()
|
||||
"Return a list of all existing packages."
|
||||
|
|
@ -1425,10 +1414,10 @@ Experimental: interface subject to change."
|
|||
;; This matters in the case of concurrent INTERN.
|
||||
(%set-symbol-package symbol package)
|
||||
(if ignore-lock
|
||||
(add-symbol table symbol)
|
||||
(add-symbol table symbol 'intern)
|
||||
(with-single-package-locked-error
|
||||
(:package package "interning ~A" symbol-name)
|
||||
(add-symbol table symbol)))
|
||||
(add-symbol table symbol 'intern)))
|
||||
(values symbol nil)))))))
|
||||
|
||||
(macrolet ((find/intern (function package-lookup &rest more-args)
|
||||
|
|
@ -1664,7 +1653,7 @@ uninterned."
|
|||
(package-internal-symbols package)
|
||||
(package-external-symbols package))
|
||||
symbol
|
||||
nil)
|
||||
'unintern)
|
||||
(if (eq (sb-xc:symbol-package symbol) package)
|
||||
(%set-symbol-package symbol nil))
|
||||
t)
|
||||
|
|
@ -1742,8 +1731,8 @@ uninterned."
|
|||
;; mean that some symbols in the original export list are
|
||||
;; not exportable.
|
||||
(when (eql (find-symbol (symbol-name sym) package) sym)
|
||||
(add-symbol external sym)
|
||||
(nuke-symbol internal sym t)))))
|
||||
(add-symbol external sym 'export)
|
||||
(nuke-symbol internal sym 'export)))))
|
||||
t)))
|
||||
|
||||
;;; Check that all symbols are accessible, then move from external to internal.
|
||||
|
|
@ -1768,8 +1757,8 @@ uninterned."
|
|||
(let ((internal (package-internal-symbols package))
|
||||
(external (package-external-symbols package)))
|
||||
(dolist (sym syms)
|
||||
(add-symbol internal sym)
|
||||
(nuke-symbol external sym t))))
|
||||
(add-symbol internal sym 'unexport)
|
||||
(nuke-symbol external sym 'unexport))))
|
||||
t)))
|
||||
|
||||
;;; Check for name conflict caused by the import and let the user
|
||||
|
|
@ -1817,7 +1806,7 @@ the importation, then a correctable error is signalled."
|
|||
;; Add the new symbols to the internal hashtable.
|
||||
(let ((internal (package-internal-symbols package)))
|
||||
(dolist (sym syms)
|
||||
(add-symbol internal sym)))
|
||||
(add-symbol internal sym 'import)))
|
||||
;; If any of the symbols are uninterned, make them be owned by PACKAGE.
|
||||
(dolist (sym homeless)
|
||||
(%set-symbol-package sym package))
|
||||
|
|
@ -1848,7 +1837,7 @@ the importation, then a correctable error is signalled."
|
|||
(setf (package-%shadowing-symbols package)
|
||||
(remove s (the list (package-%shadowing-symbols package))))
|
||||
(unintern s package))
|
||||
(add-symbol internal sym))
|
||||
(add-symbol internal sym 'shadowing-import))
|
||||
(pushnew sym (package-%shadowing-symbols package)))))))
|
||||
t)
|
||||
|
||||
|
|
@ -1876,7 +1865,7 @@ it is not already present."
|
|||
(unless (present-p w)
|
||||
(setq s (%make-symbol 2 name)) ; 2 = random interned symbol
|
||||
(%set-symbol-package s package)
|
||||
(add-symbol internal s))
|
||||
(add-symbol internal s 'shadow))
|
||||
(pushnew s (package-%shadowing-symbols package))))))))
|
||||
t)
|
||||
|
||||
|
|
@ -1996,7 +1985,7 @@ PACKAGE."
|
|||
(flet ((!make-table (input)
|
||||
(let ((table (make-symbol-table (length (the simple-vector input)))))
|
||||
(dovector (symbol input table)
|
||||
(add-symbol table symbol)))))
|
||||
(add-symbol table symbol 'intern)))))
|
||||
(let ((externals (!make-table external-v)))
|
||||
(setf (package-external-symbols pkg) externals
|
||||
(package-internal-symbols pkg) (!make-table internal-v)
|
||||
|
|
|
|||
12
tests/pkgiter.impure.lisp
Normal file
12
tests/pkgiter.impure.lisp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
;; lp# 2080387 but using the code of CSR, not the UB case
|
||||
(make-package :som :use nil)
|
||||
(setf *package* (find-package :som))
|
||||
(cl:defparameter *mmm* cl:nil)
|
||||
(cl:do-symbols (sym (cl:find-package :som))
|
||||
(cl:push sym *mmm*)
|
||||
(cl:export sym))
|
||||
|
||||
(cl:assert (cl:find '*mmm* *mmm*))
|
||||
(cl:assert (cl:find 'sym *mmm*))
|
||||
(cl:assert (cl:eq (cl:nth-value 1 (cl:find-symbol "*MMM*" "SOM"))
|
||||
:external))
|
||||
|
|
@ -236,6 +236,7 @@
|
|||
sb-impl::*user-hash-table-tests*
|
||||
sb-impl::*pn-dir-table*
|
||||
sb-impl::*pn-table*
|
||||
sb-impl::*clear-resized-symbol-tables*
|
||||
sb-vm::*immobile-codeblob-tree*
|
||||
sb-vm::*dynspace-codeblob-tree*
|
||||
,(maybe "SB-KERNEL" "*EVAL-CALLS*")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
(defun extern (name)
|
||||
(let ((s (make-symbol name))
|
||||
(p *package*))
|
||||
(sb-impl::add-symbol (sb-impl::package-external-symbols *package*) s)
|
||||
(sb-impl::add-symbol (sb-impl::package-external-symbols *package*) s 'intern)
|
||||
(sb-impl::%set-symbol-package s p)
|
||||
s))
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue