0.8.12.7: Merge package locks, AKA "what can go wrong with a 3783 line patch?"
authorNikodemus Siivola <nikodemus@random-state.net>
Tue, 29 Jun 2004 08:50:51 +0000 (08:50 +0000)
committerNikodemus Siivola <nikodemus@random-state.net>
Tue, 29 Jun 2004 08:50:51 +0000 (08:50 +0000)
          ... Controlled by the presence of :sb-package-locks in target
                 features.
          ... This builds both with and without package locks on both
                 x86 Linux and SunOS Sparc, with both CMUCL and SBCL
                 as host -- so chances are it should build elsewhere as
                 well.
          ... Remaining TODO: turn package locking errors from lexical
                 constructs to program errors in the produced code, fix
                 the bits in SBCL that hit host's SBCL-tyle package locks
                 (relevant FIXME is in src/cold/shared.lisp).

71 files changed:
build-order.lisp-expr
contrib/sb-aclrepl/debug.lisp
contrib/sb-aclrepl/inspect.lisp
contrib/sb-grovel/defpackage.lisp
contrib/sb-grovel/foreign-glue.lisp
contrib/sb-simple-streams/package.lisp
contrib/sb-sprof/sb-sprof.lisp
doc/manual/Makefile
doc/manual/make-tempfiles.sh
doc/manual/package-locks-basic.texinfo [new file with mode: 0644]
doc/manual/package-locks-extended.texinfo [new file with mode: 0644]
doc/manual/sbcl.texinfo
make-target-2.sh
package-data-list.lisp-expr
src/code/cold-init.lisp
src/code/condition.lisp
src/code/cross-misc.lisp
src/code/debug-int.lisp
src/code/defboot.lisp
src/code/defpackage.lisp
src/code/defstruct.lisp
src/code/early-fasl.lisp
src/code/early-package.lisp [new file with mode: 0644]
src/code/early-pprint.lisp
src/code/early-setf.lisp
src/code/eval.lisp
src/code/fdefinition.lisp
src/code/fop.lisp
src/code/macros.lisp
src/code/package.lisp
src/code/profile.lisp
src/code/symbol.lisp
src/code/target-package.lisp
src/cold/shared.lisp
src/cold/warm.lisp
src/compiler/assem.lisp
src/compiler/compiler-deftype.lisp
src/compiler/early-c.lisp
src/compiler/fndb.lisp
src/compiler/info-functions.lisp
src/compiler/ir1-translators.lisp
src/compiler/ir1tran.lisp
src/compiler/ir1util.lisp
src/compiler/lexenv.lisp
src/compiler/main.lisp
src/compiler/policy.lisp
src/compiler/proclaim.lisp
src/compiler/target-main.lisp
src/pcl/boot.lisp
src/pcl/braid.lisp
src/pcl/cache.lisp
src/pcl/combin.lisp
src/pcl/ctor.lisp
src/pcl/defclass.lisp
src/pcl/defcombin.lisp
src/pcl/defs.lisp
src/pcl/dlisp.lisp
src/pcl/early-low.lisp
src/pcl/low.lisp
src/pcl/macros.lisp
src/pcl/methods.lisp
src/pcl/std-class.lisp
src/pcl/vector.lisp
src/runtime/mips-arch.c
src/runtime/mips-lispregs.h
tests/clos.impure-cload.lisp
tests/compiler.impure-cload.lisp
tests/compiler.impure.lisp
tests/package-locks.impure.lisp [new file with mode: 0644]
tests/seq.impure.lisp
version.lisp-expr

index 1c85be4..7a25279 100644 (file)
 
  ("src/code/target-extensions" :not-host)
 
 
  ("src/code/target-extensions" :not-host)
 
+ ;; Needed before the first use of WITH-SINGLE-PACKAGE-LOCKED-ERROR.
+ ("src/code/early-package" :not-host)
+
  ("src/code/early-defstructs" :not-host) ; gotta-be-first DEFSTRUCTs
 
  ("src/code/defbangstruct")
  ("src/code/early-defstructs" :not-host) ; gotta-be-first DEFSTRUCTs
 
  ("src/code/defbangstruct")
index 2b8787a..76eef97 100644 (file)
@@ -6,9 +6,11 @@
 
 (cl:in-package :sb-aclrepl)
 
 
 (cl:in-package :sb-aclrepl)
 
-
+;;; FIXME: These declaims violate package locks. Are they needed at
+;;; all? Seems not.
+#+ignore
 (declaim (special
 (declaim (special
-         sb-debug::*debug-command-level sb-debug::*debug-command-level*
+         sb-debug::*debug-command-level*
          sb-debug::*real-stack-top* sb-debug::*stack-top*
          sb-debug::*stack-top-hint* sb-debug::*current-frame*
          sb-debug::*flush-debug-errors*))
          sb-debug::*real-stack-top* sb-debug::*stack-top*
          sb-debug::*stack-top-hint* sb-debug::*current-frame*
          sb-debug::*flush-debug-errors*))
@@ -45,7 +47,7 @@
           
           (if (zerop *break-level*) ; restart added by SBCL
               (repl :continuable continuable)       
           
           (if (zerop *break-level*) ; restart added by SBCL
               (repl :continuable continuable)       
-              (let ((level *break-level*)) 
+              (let ((level *break-level*))
                 (with-simple-restart
                     (abort "~@<Reduce debugger level (to break level ~W).~@:>"
                            level)
                 (with-simple-restart
                     (abort "~@<Reduce debugger level (to break level ~W).~@:>"
                            level)
index b09fc59..f807776 100644 (file)
@@ -12,7 +12,8 @@
 (eval-when (:compile-toplevel :load-toplevel :execute)
   (defconstant +default-inspect-length+ 20))
 
 (eval-when (:compile-toplevel :load-toplevel :execute)
   (defconstant +default-inspect-length+ 20))
 
-(defstruct inspect
+(defstruct (%inspect (:constructor make-inspect)
+                    (:conc-name inspect-))
   ;; stack of parents of inspected object
   object-stack 
   ;;  a stack of indices of parent object components
   ;; stack of parents of inspected object
   object-stack 
   ;;  a stack of indices of parent object components
index ffeb518..5f161b1 100644 (file)
@@ -1,4 +1,9 @@
 (defpackage "SB-GROVEL"
   (:export "GROVEL-CONSTANTS-FILE")
 (defpackage "SB-GROVEL"
   (:export "GROVEL-CONSTANTS-FILE")
+  (:shadow "TYPE" "UNION")
+  ;; FIXME: This is a really quick and dirty package lock compliance
+  ;; fix, that should be redone. Specifically, this is needed to address the
+  ;; nasty things done with SB-ALIEN:STRUCT.
+  #+sb-package-locks
+  (:implement "SB-ALIEN")
   (:use "COMMON-LISP" "SB-ALIEN" "ASDF" "SB-EXT"))
   (:use "COMMON-LISP" "SB-ALIEN" "ASDF" "SB-EXT"))
-
index c15509f..e07bb59 100644 (file)
@@ -303,14 +303,14 @@ deeply nested structures."
     (labels ((accessor (root rpath)
               (apply #'sane-slot 'struct (mapcar 'name (append (rest rpath) (list root))))))
       `((defun ,(intern accessor-name) (struct)
     (labels ((accessor (root rpath)
               (apply #'sane-slot 'struct (mapcar 'name (append (rest rpath) (list root))))))
       `((defun ,(intern accessor-name) (struct)
-         (declare (type (alien ,struct-name) struct)
+         (declare (cl:type (alien ,struct-name) struct)
                   (optimize (speed 3)))
          (,(accessor-modifier-for (reintern (type root) (find-package :sb-grovel))
                                   :getter)
            ,(accessor root rpath) ,(size root)))
        (defun (setf ,(intern accessor-name)) (new-val struct)
                   (optimize (speed 3)))
          (,(accessor-modifier-for (reintern (type root) (find-package :sb-grovel))
                                   :getter)
            ,(accessor root rpath) ,(size root)))
        (defun (setf ,(intern accessor-name)) (new-val struct)
-         (declare (type (alien ,struct-name) struct)
-                  (type ,(lisp-type-for (type root) (size root)) new-val)
+         (declare (cl:type (alien ,struct-name) struct)
+                  (cl:type ,(lisp-type-for (type root) (size root)) new-val)
                   (optimize (speed 3)))
          ,(let* ((accessor-modifier (accessor-modifier-for (reintern (type root)
                                                                      (find-package :sb-grovel))
                   (optimize (speed 3)))
          ,(let* ((accessor-modifier (accessor-modifier-for (reintern (type root)
                                                                      (find-package :sb-grovel))
index 622fb5c..8e80524 100644 (file)
@@ -11,6 +11,9 @@
   (:use #:common-lisp)
   (:import-from #:sb-kernel #:ansi-stream #:charpos #:line-length)
   (:import-from #:sb-gray #:fundamental-stream)
   (:use #:common-lisp)
   (:import-from #:sb-kernel #:ansi-stream #:charpos #:line-length)
   (:import-from #:sb-gray #:fundamental-stream)
+  #+sb-package-locks
+  ;; FIXME: Using deffoo! or equivalent might be nicer.
+  (:implement #:common-lisp #:sb-kernel #:sb-int)
   (:export ;; Stream classes
    #:STREAM
    #:SIMPLE-STREAM
   (:export ;; Stream classes
    #:STREAM
    #:SIMPLE-STREAM
index fdeba62..eb0640e 100644 (file)
 (defun topological-sort (dag)
   (let ((sorted ())
        (dfn -1))
 (defun topological-sort (dag)
   (let ((sorted ())
        (dfn -1))
-    (labels ((sort (v)
+    (labels ((rec-sort (v)
               (setf (vertex-visited v) t)
               (setf (vertex-dfn v) (incf dfn))
               (dolist (e (vertex-edges v))
                 (unless (vertex-visited (edge-vertex e))
               (setf (vertex-visited v) t)
               (setf (vertex-dfn v) (incf dfn))
               (dolist (e (vertex-edges v))
                 (unless (vertex-visited (edge-vertex e))
-                  (sort (edge-vertex e))))
+                  (rec-sort (edge-vertex e))))
               (push v sorted)))
               (push v sorted)))
-      (map-vertices #'sort dag)
+      (map-vertices #'rec-sort dag)
       (nreverse sorted))))
 
 ;;; Reduce graph G to a dag by coalescing strongly connected components
       (nreverse sorted))))
 
 ;;; Reduce graph G to a dag by coalescing strongly connected components
                     (rotatef (aref vec i) (aref vec j))))
           (key (i)
             (aref vec (+ i key-offset)))
                     (rotatef (aref vec i) (aref vec j))))
           (key (i)
             (aref vec (+ i key-offset)))
-          (sort (from to)
+          (rec-sort (from to)
             (when (> to from) 
               (let* ((mid (* element-size
                              (round (+ (/ from element-size)
             (when (> to from) 
               (let* ((mid (* element-size
                              (round (+ (/ from element-size)
                    (when (< j i) (return))
                    (rotate i j))
                 (rotate from j)
                    (when (< j i) (return))
                    (rotate i j))
                 (rotate from j)
-                (sort from (- j element-size))
-                (sort i to)))))
-    (sort from to)
+                (rec-sort from (- j element-size))
+                (rec-sort i to)))))
+    (rec-sort from to)
     vec))
 
 \f
     vec))
 
 \f
     (format t "~& Count     %                   Parts~%")
     (do-vertices (node call-graph)
       (when (cycle-p node)
     (format t "~& Count     %                   Parts~%")
     (do-vertices (node call-graph)
       (when (cycle-p node)
-       (flet ((print (indent index count percent name)
+       (flet ((print-info (indent index count percent name)
                 (format t "~&~6d ~5,1f ~11@t ~V@t  ~s [~d]~%"
                         count percent indent name index)))
          (print-separator)
                 (format t "~&~6d ~5,1f ~11@t ~V@t  ~s [~d]~%"
                         count percent indent name index)))
          (print-separator)
                  (samples-percent call-graph (cycle-count node))
                  (node-name node))
          (dolist (v (vertex-scc-vertices node))
                  (samples-percent call-graph (cycle-count node))
                  (node-name node))
          (dolist (v (vertex-scc-vertices node))
-           (print 4 (node-index v) (node-count v)
-                  (samples-percent call-graph (node-count v))
-                  (node-name v))))))
+           (print-info 4 (node-index v) (node-count v)
+                        (samples-percent call-graph (node-count v))
+                        (node-name v))))))
     (print-separator)
     (format t "~2%")))
 
     (print-separator)
     (format t "~2%")))
 
     (print-cycles call-graph)
     (flet ((find-call (from to)
             (find to (node-edges from) :key #'call-vertex))
     (print-cycles call-graph)
     (flet ((find-call (from to)
             (find to (node-edges from) :key #'call-vertex))
-          (print (indent index count percent name)
+          (print-info (indent index count percent name)
             (format t "~&~6d ~5,1f ~11@t ~V@t  ~s [~d]~%"
                     count percent indent name index)))
       (format t "~&                               Callers~%")
             (format t "~&~6d ~5,1f ~11@t ~V@t  ~s [~d]~%"
                     count percent indent name index)))
       (format t "~&                               Callers~%")
        ;; Print caller information.
        (dolist (caller (node-callers node))
          (let ((call (find-call caller node)))
        ;; Print caller information.
        (dolist (caller (node-callers node))
          (let ((call (find-call caller node)))
-           (print 4 (node-index caller)
-                  (call-count call)
-                  (samples-percent call-graph (call-count call))
-                  (node-name caller))))
+           (print-info 4 (node-index caller)
+                        (call-count call)
+                        (samples-percent call-graph (call-count call))
+                        (node-name caller))))
        ;; Print the node itself.
        (format t "~&~6d ~5,1f ~6d ~5,1f   ~s [~d]~%"
                (node-count node)
        ;; Print the node itself.
        (format t "~&~6d ~5,1f ~6d ~5,1f   ~s [~d]~%"
                (node-count node)
                (node-index node))
        ;; Print callees.
        (do-edges (call called node)
                (node-index node))
        ;; Print callees.
        (do-edges (call called node)
-         (print 4 (node-index called)
-                (call-count call)
-                (samples-percent call-graph (call-count call))
-                (node-name called))))
+         (print-info 4 (node-index called)
+                      (call-count call)
+                      (samples-percent call-graph (call-count call))
+                      (node-name called))))
       (print-separator)
       (format t "~2%")
       (print-flat call-graph :stream stream :max max
       (print-separator)
       (format t "~2%")
       (print-flat call-graph :stream stream :max max
index bbb8fa3..c9b03dd 100644 (file)
@@ -91,6 +91,7 @@ clean:
        rm -f *~ *.bak *.orig \#*\# .\#* texput.log *.fasl
        rm -rf $(HTMLDIR) $(DOCSTRINGDIR)
        rm -f contrib-docs.texi-temp
        rm -f *~ *.bak *.orig \#*\# .\#* texput.log *.fasl
        rm -rf $(HTMLDIR) $(DOCSTRINGDIR)
        rm -f contrib-docs.texi-temp
+       rm -f package-locks.texi-temp
        rm -f $(PSFILE) $(PDFFILE) $(DVIFILE) html-stamp tempfiles-stamp
        rm -f $(TMPFILES) contrib-doc-list.texi-temp
        rm -f sbcl.info sbcl.info-*
        rm -f $(PSFILE) $(PDFFILE) $(DVIFILE) html-stamp tempfiles-stamp
        rm -f $(TMPFILES) contrib-doc-list.texi-temp
        rm -f sbcl.info sbcl.info-*
index 629e68c..777d03c 100644 (file)
 # We create the documentation from the in-tree sbcl if it is found,
 # else an installed sbcl is used.
 sbclsystem=`pwd`/../../src/runtime/sbcl
 # We create the documentation from the in-tree sbcl if it is found,
 # else an installed sbcl is used.
 sbclsystem=`pwd`/../../src/runtime/sbcl
-if [ -e $sbclsystem ] 
+sbclcore=`pwd`/../../output/sbcl.core
+if [ -e $sbclsystem ] && [ -e $sbclcore ] 
 then
 then
-SBCL="${1:-$sbclsystem --core `pwd`/../../output/sbcl.core}"
-export SBCL_HOME=`pwd`/../../contrib
+    SBCL="${1:-$sbclsystem --core $sbclcore}"
+    export SBCL_HOME=`pwd`/../../contrib
 else
 else
-SBCL="${1:-`which sbcl`}"
+    SBCL="${1:-`which sbcl`}"
 fi
 
 # Output directory.  This has to end with a slash (it's interpreted by
 fi
 
 # Output directory.  This has to end with a slash (it's interpreted by
@@ -41,3 +42,11 @@ echo "(progn (load \"docstrings.lisp\") (dolist (module (quote ($MODULES))) (req
 
 echo /creating contrib-docs.texi-temp
 echo "(load \"create-contrib-doc-list.lisp\")" | $SBCL --noinform --sysinit /dev/null --userinit /dev/null --noprint --disable-debugger
 
 echo /creating contrib-docs.texi-temp
 echo "(load \"create-contrib-doc-list.lisp\")" | $SBCL --noinform --sysinit /dev/null --userinit /dev/null --noprint --disable-debugger
+
+echo /creating package-locks.texi-temp
+if $SBCL --noinform --sysinit /dev/null --userinit /dev/null --noprint --disable-debugger --eval '(quit :unix-status #+sb-package-locks 0 #-sb-package-locks 1)'
+then
+    cp package-locks-extended.texinfo package-locks.texi-temp
+else
+    cp package-locks-basic.texinfo package-locks.texi-temp
+fi
diff --git a/doc/manual/package-locks-basic.texinfo b/doc/manual/package-locks-basic.texinfo
new file mode 100644 (file)
index 0000000..d5fa812
--- /dev/null
@@ -0,0 +1,7 @@
+@node Package Locks
+@chapter Package Locks
+
+SBCL does not currently include package locking support by default. To
+build SBCL with package locking enabled add @code{:sb-package-locks}
+to target @code{*features*} as per instructions in the file
+@file{INSTALL}.
diff --git a/doc/manual/package-locks-extended.texinfo b/doc/manual/package-locks-extended.texinfo
new file mode 100644 (file)
index 0000000..8a1435d
--- /dev/null
@@ -0,0 +1,333 @@
+@include package-locks-basic.texinfo
+
+None of the following sections apply to SBCL built
+without package locks.
+
+The interface described here is experimental: incompatible changes
+in future SBCL releases are possible, even expected.
+
+@menu
+* Package Locking Overview::                    
+* Implementation Packages::     
+* Package Locked Errors::       
+* Package Locks in Compiled Code::               
+* Package Lock Violations::     
+* Package Lock Dictionary::
+@end menu
+
+@node Package Locking Overview
+@section Package Locking Overview
+Package locks protect against unintentional modifications of a
+package: they provide similar protection to user packages as is
+mandated to @code{common-lisp} package by the ANSI specification. They
+are not, and should not be used as a security measure.
+
+Newly created packages are by default unlocked (see the @code{:lock}
+option to @code{defpackage}).
+
+The package @code{common-lisp} and SBCL internal implementation
+packages are locked by default, including @code{sb-ext}.
+
+It may be beneficial to lock @code{common-lisp-user} as well, to
+ensure that various libraries don't pollute it without asking,
+but this is not currently done by default.
+
+@node Implementation Packages
+@section Implementation Packages
+
+Each package has a list of associated implementation packages. A
+locked package, and the symbols whose home package it is, can be
+modified without violating package locks only when @code{*package*} is
+bound to one of the implementation packages of the locked package.
+
+Unless explicitly altered by @code{defpackage},
+@code{sb-ext:add-implementation-package}, or
+@code{sb-ext:remove-implementation-package} each package is its own
+(only) implementation package.
+
+@node Package Locked Errors
+@section Package Locked Errors
+
+If an operation violates a package lock, a continuable error that is
+of a subtype of @code{sb-ext:package-lock-violation} (subtype of
+@code{package-error}) is signalled when the operation is attempted.
+
+Additional restarts may be established for continuable package lock
+violations for interactive use.
+
+The actual type of the error depends on circumstances that caused the
+violation: operations on packages signal errors of type
+@code{sb-ext:package-locked-error}, and operations on symbols signal
+errors of type @code{sb-ext:symbol-package-locked-error}.
+
+@node Package Locks in Compiled Code
+@section Package Locks in Compiled Code
+
+@subsection Lexical bindings and declarations
+
+Compiling lexical binding constructs or lexical declarations that
+violate package locks package cause a compile-time package-lock
+violation. A complete listing of operators affect by this is:
+@code{let}, @code{let*}, @code{flet}, @code{labels}, @code{macrolet},
+and @code{symbol-macrolet}, @code{declare}.
+
+Package locks affecting both lexical bindings and declarations can be
+disabled at compile-time with @code{sb-ext:disable-package-locks}
+declaration, and re-enabled with @code{sb-ext:enable-package-locks}
+declaration. Constructs compiled with package locks thusly disabled
+are guaranteed not to signal package lock violation errors at runtime.
+
+Example:
+
+@lisp
+(in-package :locked)
+
+(defun foo () ...)
+
+(defmacro with-foo (&body body)
+  `(locally (declare (disable-package-locks locked:foo))
+     (flet ((foo () ...))
+       (declare (enable-package-locks locked:foo)) ; re-enable for body
+       ,@@body)))
+@end lisp
+
+@subsection Interned symbols
+
+If compiled code contains interned symbols, then loading that code
+into an image without the said symbols will not cause a package lock
+violation even if the packages in question are locked.
+
+@subsection Other limitations on compiled code
+
+With the exception of the aforementioned contructs, and interned
+symbols, behaviour is unspecified if package locks affecting compiled
+code are not the same during loading of the code or execution.
+
+Specifically, code compiled with packages unlocked may or may not fail
+to signal package-lock-violations even if the packages are locked at
+runtime, and code compiled with packages locked may or may not signal
+spurious package-lock-violations at runtime even if the packages are
+unlocked.
+
+In practise all this means that package-locks have a neglible
+performance penalty in compiled code as long as they are not violated.
+
+@node Package Lock Violations
+@section Package Lock Violations
+
+@heading Operations on Packages
+
+Following actions cause a package lock violation if the package
+operated on is locked, and @code{*package*} is not an implementation
+package of that package, and the action would cause a change in the
+state of the package (eg. exporting already external symbols is
+allowed). Package lock violations caused by these operations signal
+errors of type @code{sb-ext:package-locked-error}.
+
+@enumerate
+@item
+Shadowing a symbol in a package.
+
+@item
+Importing a symbol to a package.
+
+@item
+Uninterning a symbol from a package.
+
+@item
+Exporting a symbol from a package.
+
+@item
+Unexporting a symbol from a package.
+
+@item
+Changing the packages used by a package.
+
+@item
+Renaming a package.
+
+@item
+Deleting a package.
+
+@end enumerate
+
+@heading Operations on Symbols
+
+Following actions cause a package lock violation if the home package
+of the symbol operated on is locked, and @code{*package*} is not an
+implementation package of that package. Package lock violations caused
+by these action signal errors of type
+@code{sb-ext:symbol-package-locked-error}.
+
+These actions cause only one package lock violation per lexically
+apparent violated package.
+
+Example:
+
+@lisp
+;; Packages FOO and BAR are locked.
+;;
+;; Two lexically apparent violated packages: exactly two
+;; package-locked-errors will be signalled.
+
+(defclass foo:point ()
+  ((x :accessor bar:x)
+   (y :accessor bar:y)))
+@end lisp
+
+@enumerate
+@item
+Binding or altering its value lexically or dynamically, or
+establishing it as a symbol-macro.
+
+Exceptions:
+
+@itemize @minus
+@item
+If the symbol is not defined as a constant, global symbol-macro or a
+global dynamic variable, it may be lexically bound or established as a
+local symbol macro.
+
+@item
+If the symbol is defined as a global dynamic variable, it may be
+assigned or bound.
+
+@end itemize
+
+@item
+Defining, undefining, or binding it, or its setf name as a function.
+
+Exceptions:
+
+@itemize @minus
+@item
+If the symbol is not defined as a function, macro, or special operator
+it and its setf name may be lexically bound as a function.
+
+@end itemize
+
+@item
+Defining, undefining, or binding it as a macro or compiler macro.
+
+Exceptions:
+
+@itemize @minus
+@item
+If the symbol is not defined as a function, macro, or special operator
+it may be lexically bound as a macro.
+
+@end itemize
+
+@item
+Defining it as a type specifier or structure.
+
+@item
+Defining it as a declaration with a declaration proclamation.
+
+@item
+Declaring or proclaiming it special.
+
+@item
+Declaring or proclaiming its type or ftype.
+
+Exceptions:
+
+@itemize @minus
+@item
+If the symbol may be lexically bound, the type of that binding may be
+declared.
+
+@item
+If the symbol may be lexically bound as a function, the ftype of that
+binding may be declared.
+
+@end itemize
+
+@item
+Defining a setf expander for it.
+
+@item
+Defining it as a method combination type.
+
+@item
+Using it as the class-name argument to setf of find-class.
+
+@end enumerate
+
+@node Package Lock Dictionary
+@section Package Lock Dictionary
+
+@deftp {Declaration} sb-ext:disable-package-locks
+
+Syntax: @code{(sb-ext:disable-package-locks symbol*)}
+
+Disables package locks affecting the named symbols during compilation
+in the lexical scope of the declaration. Disabling locks on symbols
+whose home package is unlocked, or disabling an already disabled lock,
+has no effect.
+@end deftp
+
+@deftp {Declaration} sb-ext:enable-package-locks
+
+Syntax: @code{(sb-ext:enable-package-locks symbol*)}
+
+Re-enables package locks affecting the named symbols during
+compilation in the lexical scope of the declaration. Enabling locks
+that were not first disabled with @code{sb-ext:disable-package-locks}
+declararion, or enabling locks that are already enabled has no effect.
+@end deftp
+
+@include condition-sb-ext-package-lock-violation.texinfo
+@include condition-sb-ext-package-locked-error.texinfo
+@include condition-sb-ext-symbol-package-locked-error.texinfo
+
+@defun sb-ext:package-locked-error-symbol @var{symbol-package-locked-error}
+
+Returns the symbol that caused the @code{symbol-package-locked-error}
+condition.
+@end defun
+
+@include fun-sb-ext-package-locked-p.texinfo
+@include fun-sb-ext-lock-package.texinfo
+@include fun-sb-ext-unlock-package.texinfo
+@include fun-sb-ext-package-implemented-by-list.texinfo
+@include fun-sb-ext-package-implements-list.texinfo
+@include fun-sb-ext-add-implementation-package.texinfo
+@include fun-sb-ext-remove-implementation-package.texinfo
+@include macro-sb-ext-without-package-locks.texinfo
+@include macro-sb-ext-with-unlocked-packages.texinfo
+
+@defmac defpackage name [[@var{option}]]* @result{} package
+
+Options are extended to include the following:
+
+@itemize
+@item
+@code{:lock} @var{boolean}
+
+If the argument to @code{:lock} is @code{t}, the package is initially
+locked.  If @code{:lock} is not provided it defaults to @code{nil}.
+
+@item
+@code{:implement} @var{package-designator}*
+
+The package is added as an implementation package to the packages
+named. If @code{:implement} is not provided, it defaults to the
+package itself.
+@end itemize
+
+Example:
+
+@lisp
+(defpackage "FOO" (:export "BAR") (:lock t) (:implement))
+(defpackage "FOO-INT" (:use "FOO") (:implement "FOO" "FOO-INT"))
+
+;;; is equivalent to
+
+(defpackage "FOO") (:export "BAR"))
+(lock-package "FOO")
+(remove-implementation-package "FOO" "FOO")
+(defpackage "FOO-INT" (:use "BAR"))
+(add-implementation-package "FOO-INT" "FOO")
+@end lisp
+@end defmac
index f2146e5..bcc05cd 100644 (file)
@@ -62,6 +62,7 @@ provided with absolutely no warranty. See the @file{COPYING} and
 * Efficiency::
 * Beyond The ANSI Standard::
 * The Foreign Function Interface::
 * Efficiency::
 * Beyond The ANSI Standard::
 * The Foreign Function Interface::
+* Package Locks::
 * Contributed Modules::
 * Concept Index::
 * Function Index::
 * Contributed Modules::
 * Concept Index::
 * Function Index::
@@ -78,6 +79,7 @@ provided with absolutely no warranty. See the @file{COPYING} and
 @include efficiency.texinfo
 @include beyond-ansi.texinfo
 @include ffi.texinfo
 @include efficiency.texinfo
 @include beyond-ansi.texinfo
 @include ffi.texinfo
+@include package-locks.texi-temp
 @include contrib-modules.texinfo
 @include backmatter.texinfo
 
 @include contrib-modules.texinfo
 @include backmatter.texinfo
 
index fb1c8c1..6b3cd21 100644 (file)
@@ -78,6 +78,12 @@ echo //doing warm init
                             (space 1)
                             (speed 1)))
 
                             (space 1)
                             (speed 1)))
 
+        ;; Lock internal packages
+        #+sb-package-locks
+        (dolist (p (list-all-packages))
+          (unless (member p (mapcar #'find-package '(:keyword :cl-user)))
+             (lock-package p)))
+
         (sb-int:/show "done with warm.lisp, about to SAVE-LISP-AND-DIE")
        ;; Even if /SHOW output was wanted during build, it's probably
        ;; not wanted by default after build is complete. (And if it's
         (sb-int:/show "done with warm.lisp, about to SAVE-LISP-AND-DIE")
        ;; Even if /SHOW output was wanted during build, it's probably
        ;; not wanted by default after build is complete. (And if it's
index 8d46924..f0ab524 100644 (file)
@@ -560,6 +560,23 @@ like *STACK-TOP-HINT* and unsupported stuff like *TRACED-FUN-LIST*."
               "DEFCONSTANT-UNEQL" "DEFCONSTANT-UNEQL-NAME"
               "DEFCONSTANT-UNEQL-NEW-VALUE" "DEFCONSTANT-UNEQL-OLD-VALUE"
 
               "DEFCONSTANT-UNEQL" "DEFCONSTANT-UNEQL-NAME"
               "DEFCONSTANT-UNEQL-NEW-VALUE" "DEFCONSTANT-UNEQL-OLD-VALUE"
 
+               ;; package-locking stuff
+               #!+sb-package-locks "PACKAGE-LOCKED-P" 
+               #!+sb-package-locks "LOCK-PACKAGE" 
+               #!+sb-package-locks "UNLOCK-PACKAGE"
+               #!+sb-package-locks "PACKAGE-IMPLEMENTED-BY-LIST" 
+               #!+sb-package-locks "PACKAGE-IMPLEMENTS-LIST"
+               #!+sb-package-locks "ADD-IMPLEMENTATION-PACKAGE" 
+               #!+sb-package-locks "REMOVE-IMPLEMENTATION-PACKAGE"
+               #!+sb-package-locks "WITH-UNLOCKED-PACKAGES"
+               #!+sb-package-locks "PACKAGE-LOCK-VIOLATION"
+               #!+sb-package-locks "PACKAGE-LOCKED-ERROR"
+               #!+sb-package-locks "SYMBOL-PACKAGE-LOCKED-ERROR"            
+               #!+sb-package-locks "PACKAGE-LOCKED-ERROR-SYMBOL"
+               "WITHOUT-PACKAGE-LOCKS"
+               "DISABLE-PACKAGE-LOCKS"
+               "ENABLE-PACKAGE-LOCKS"
+
               ;; error signalled when attempt to load an invalid fasl
               ;; is made, so that user code can try to recompile, etc.
               "INVALID-FASL"
               ;; error signalled when attempt to load an invalid fasl
               ;; is made, so that user code can try to recompile, etc.
               "INVALID-FASL"
@@ -1062,6 +1079,11 @@ is a good idea, but see SB-SYS re. blurring of boundaries."
                       "ALIEN-TYPE-TYPE"
                       "ALIEN-TYPE-TYPE-ALIEN-TYPE" "ALIEN-TYPE-TYPE-P"
                       "ALLOCATE-VECTOR"
                       "ALIEN-TYPE-TYPE"
                       "ALIEN-TYPE-TYPE-ALIEN-TYPE" "ALIEN-TYPE-TYPE-P"
                       "ALLOCATE-VECTOR"
+                       "ASSERT-SYMBOL-HOME-PACKAGE-UNLOCKED"
+                       "DISABLED-PACKAGE-LOCKS"
+                       "WITH-SINGLE-PACKAGE-LOCKED-ERROR"
+                       "PACKAGE-ERROR-FORMAT-ARGUMENTS"
+                       "PACKAGE-ERROR-FORMAT-CONTROL"
                       "ALWAYS-SUBTYPEP" "ARGS-TYPE" "ARGS-TYPE-ALLOWP"
                       "ARGS-TYPE-KEYP"
                       "ARGS-TYPE-KEYWORDS" "ARGS-TYPE-OPTIONAL" "ARGS-TYPE-P"
                       "ALWAYS-SUBTYPEP" "ARGS-TYPE" "ARGS-TYPE-ALLOWP"
                       "ARGS-TYPE-KEYP"
                       "ARGS-TYPE-KEYWORDS" "ARGS-TYPE-OPTIONAL" "ARGS-TYPE-P"
index 9711add..9757734 100644 (file)
   ;; this to be initialized, so we initialize it right away.
   (show-and-call !random-cold-init)
 
   ;; this to be initialized, so we initialize it right away.
   (show-and-call !random-cold-init)
 
+  (show-and-call !early-package-cold-init)
   (show-and-call !package-cold-init)
   
   ;; All sorts of things need INFO and/or (SETF INFO).
   (show-and-call !package-cold-init)
   
   ;; All sorts of things need INFO and/or (SETF INFO).
index 5345544..6b971ec 100644 (file)
 (eval-when (:compile-toplevel :load-toplevel :execute)
 (defun %compiler-define-condition (name direct-supers layout
                                   all-readers all-writers)
 (eval-when (:compile-toplevel :load-toplevel :execute)
 (defun %compiler-define-condition (name direct-supers layout
                                   all-readers all-writers)
-  (sb!xc:proclaim `(ftype (function (t) t) ,@all-readers))
-  (sb!xc:proclaim `(ftype (function (t t) t) ,@all-writers))
-  (multiple-value-bind (class old-layout)
-      (insured-find-classoid name
-                            #'condition-classoid-p
-                            #'make-condition-classoid)
-    (setf (layout-classoid layout) class)
-    (setf (classoid-direct-superclasses class)
-         (mapcar #'find-classoid direct-supers))
-    (cond ((not old-layout)
-          (register-layout layout))
-         ((not *type-system-initialized*)
-          (setf (layout-classoid old-layout) class)
-          (setq layout old-layout)
-          (unless (eq (classoid-layout class) layout)
+  (with-single-package-locked-error 
+      (:symbol name "defining ~A as a condition")
+    (sb!xc:proclaim `(ftype (function (t) t) ,@all-readers))
+    (sb!xc:proclaim `(ftype (function (t t) t) ,@all-writers))
+    (multiple-value-bind (class old-layout)
+       (insured-find-classoid name
+                              #'condition-classoid-p
+                              #'make-condition-classoid)
+      (setf (layout-classoid layout) class)
+      (setf (classoid-direct-superclasses class)
+           (mapcar #'find-classoid direct-supers))
+      (cond ((not old-layout)
+            (register-layout layout))
+           ((not *type-system-initialized*)
+            (setf (layout-classoid old-layout) class)
+            (setq layout old-layout)
+            (unless (eq (classoid-layout class) layout)
+              (register-layout layout)))
+           ((redefine-layout-warning "current"
+                                     old-layout
+                                     "new"
+                                     (layout-length layout)
+                                     (layout-inherits layout)
+                                     (layout-depthoid layout))
+            (register-layout layout :invalidate t))
+           ((not (classoid-layout class))
             (register-layout layout)))
             (register-layout layout)))
-         ((redefine-layout-warning "current"
-                                   old-layout
-                                   "new"
-                                   (layout-length layout)
-                                   (layout-inherits layout)
-                                   (layout-depthoid layout))
-          (register-layout layout :invalidate t))
-         ((not (classoid-layout class))
-          (register-layout layout)))
-
-    (setf (layout-info layout)
-         (locally
-           ;; KLUDGE: There's a FIND-CLASS DEFTRANSFORM for constant class
-           ;; names which creates fast but non-cold-loadable, non-compact
-           ;; code. In this context, we'd rather have compact, cold-loadable
-           ;; code. -- WHN 19990928
-           (declare (notinline find-classoid))
-           (layout-info (classoid-layout (find-classoid 'condition)))))
-
-    (setf (find-classoid name) class)
-
-    ;; Initialize CPL slot.
-    (setf (condition-classoid-cpl class)
-         (remove-if-not #'condition-classoid-p 
-                        (std-compute-class-precedence-list class))))
+      
+      (setf (layout-info layout)
+           (locally
+               ;; KLUDGE: There's a FIND-CLASS DEFTRANSFORM for constant class
+               ;; names which creates fast but non-cold-loadable, non-compact
+               ;; code. In this context, we'd rather have compact, cold-loadable
+               ;; code. -- WHN 19990928
+               (declare (notinline find-classoid))
+             (layout-info (classoid-layout (find-classoid 'condition)))))
+      
+      (setf (find-classoid name) class)
+      
+      ;; Initialize CPL slot.
+      (setf (condition-classoid-cpl class)
+           (remove-if-not #'condition-classoid-p 
+                          (std-compute-class-precedence-list class)))))
   (values))
 ) ; EVAL-WHEN
 
   (values))
 ) ; EVAL-WHEN
 
 
 (defun %define-condition (name parent-types layout slots documentation
                          report default-initargs all-readers all-writers)
 
 (defun %define-condition (name parent-types layout slots documentation
                          report default-initargs all-readers all-writers)
-  (%compiler-define-condition name parent-types layout all-readers all-writers)
-  (let ((class (find-classoid name)))
-    (setf (condition-classoid-slots class) slots)
-    (setf (condition-classoid-report class) report)
-    (setf (condition-classoid-default-initargs class) default-initargs)
-    (setf (fdocumentation name 'type) documentation)
-
-    (dolist (slot slots)
-
-      ;; Set up reader and writer functions.
-      (let ((slot-name (condition-slot-name slot)))
-       (dolist (reader (condition-slot-readers slot))
-          (install-condition-slot-reader reader name slot-name))
-       (dolist (writer (condition-slot-writers slot))
-         (install-condition-slot-writer writer name slot-name))))
-
-    ;; Compute effective slots and set up the class and hairy slots
-    ;; (subsets of the effective slots.)
-    (let ((eslots (compute-effective-slots class))
-         (e-def-initargs
-          (reduce #'append
-                  (mapcar #'condition-classoid-default-initargs
+  (with-single-package-locked-error 
+      (:symbol name "defining ~A as a condition")
+    (%compiler-define-condition name parent-types layout all-readers all-writers)
+    (let ((class (find-classoid name)))
+      (setf (condition-classoid-slots class) slots)
+      (setf (condition-classoid-report class) report)
+      (setf (condition-classoid-default-initargs class) default-initargs)
+      (setf (fdocumentation name 'type) documentation)
+      
+      (dolist (slot slots)
+       
+       ;; Set up reader and writer functions.
+       (let ((slot-name (condition-slot-name slot)))
+         (dolist (reader (condition-slot-readers slot))
+           (install-condition-slot-reader reader name slot-name))
+         (dolist (writer (condition-slot-writers slot))
+           (install-condition-slot-writer writer name slot-name))))
+      
+      ;; Compute effective slots and set up the class and hairy slots
+      ;; (subsets of the effective slots.)
+      (let ((eslots (compute-effective-slots class))
+           (e-def-initargs
+            (reduce #'append
+                    (mapcar #'condition-classoid-default-initargs
                           (condition-classoid-cpl class)))))
                           (condition-classoid-cpl class)))))
-      (dolist (slot eslots)
-       (ecase (condition-slot-allocation slot)
-         (:class
-          (unless (condition-slot-cell slot)
-            (setf (condition-slot-cell slot)
-                  (list (if (condition-slot-initform-p slot)
-                            (let ((initform (condition-slot-initform slot)))
-                              (if (functionp initform)
-                                  (funcall initform)
-                                  initform))
-                            *empty-condition-slot*))))
-          (push slot (condition-classoid-class-slots class)))
-         ((:instance nil)
-          (setf (condition-slot-allocation slot) :instance)
-          (when (or (functionp (condition-slot-initform slot))
-                    (dolist (initarg (condition-slot-initargs slot) nil)
-                      (when (functionp (getf e-def-initargs initarg))
-                        (return t))))
-            (push slot (condition-classoid-hairy-slots class))))))))
-  name)
+       (dolist (slot eslots)
+         (ecase (condition-slot-allocation slot)
+           (:class
+            (unless (condition-slot-cell slot)
+              (setf (condition-slot-cell slot)
+                    (list (if (condition-slot-initform-p slot)
+                              (let ((initform (condition-slot-initform slot)))
+                                (if (functionp initform)
+                                    (funcall initform)
+                                    initform))
+                              *empty-condition-slot*))))
+            (push slot (condition-classoid-class-slots class)))
+           ((:instance nil)
+            (setf (condition-slot-allocation slot) :instance)
+            (when (or (functionp (condition-slot-initform slot))
+                      (dolist (initarg (condition-slot-initargs slot) nil)
+                        (when (functionp (getf e-def-initargs initarg))
+                          (return t))))
+              (push slot (condition-classoid-hairy-slots class))))))))
+    name))
 
 (defmacro define-condition (name (&rest parent-types) (&rest slot-specs)
                                 &body options)
 
 (defmacro define-condition (name (&rest parent-types) (&rest slot-specs)
                                 &body options)
 
 (define-condition extension-failure (reference-condition simple-error)
   ())
 
 (define-condition extension-failure (reference-condition simple-error)
   ())
+
+#!+sb-package-locks
+(progn
+
+(define-condition package-lock-violation (reference-condition package-error)
+  ((format-control :initform nil :initarg :format-control 
+                  :reader package-error-format-control)
+   (format-arguments :initform nil :initarg :format-arguments
+                    :reader package-error-format-arguments))
+  (:report 
+   (lambda (condition stream)
+     (let ((control (package-error-format-control condition))
+          (*print-pretty* nil))
+       (if control
+          (format stream "Package lock on ~S violated when ~?."
+                  (package-error-package condition)
+                  control
+                  (package-error-format-arguments condition))
+          (format stream "Package lock on ~S violated."
+                  (package-error-package condition))))))
+  ;; no :default-initargs -- reference-stuff provided by the
+  ;; signalling form in target-package.lisp
+  #!+sb-doc
+  (:documentation
+   "Subtype of CL:PACKAGE-ERROR. A subtype of this error is signalled
+when a package-lock is violated."))
+
+(define-condition package-locked-error (package-lock-violation) ()
+  #!+sb-doc
+  (:documentation
+   "Subtype of SB-EXT:PACKAGE-LOCK-VIOLATION. An error of this type is
+signalled when an operation on a package violates a package lock."))
+
+
+(define-condition symbol-package-locked-error (package-lock-violation)
+  ((symbol :initarg :symbol :reader package-locked-error-symbol))
+  #!+sb-doc
+  (:documentation
+   "Subtype of SB-EXT:PACKAGE-LOCK-VIOLATION. An error of this type is
+signalled when an operation on a symbol violates a package lock. The
+symbol that caused the violation is accessed by the function
+SB-EXT:PACKAGE-LOCKED-ERROR-SYMBOL."))
+
+) ; progn
 \f
 ;;;; various other (not specified by ANSI) CONDITIONs
 ;;;;
 \f
 ;;;; various other (not specified by ANSI) CONDITIONs
 ;;;;
index 868d3f6..2b2a6c5 100644 (file)
 #!+alpha
 (defun sb!vm::ash-left-mod64 (integer amount)
   (ldb (byte 64 0) (ash integer amount)))
 #!+alpha
 (defun sb!vm::ash-left-mod64 (integer amount)
   (ldb (byte 64 0) (ash integer amount)))
+
+;;; package locking nops for the cross-compiler
+
+(defmacro without-package-locks (&body body)
+  `(progn ,@body))
+
+(defmacro with-single-package-locked-error ((&optional kind thing &rest format) 
+                                           &body body)
+  (declare (ignore kind thing format))
+  `(progn ,@body))
+
+(defmacro with-deferred-package-lock-violations (&body body)
+  `(flet ((prepend-package-lock-violations (forms) forms)
+         (package-lock-violations () nil))
+    ,@body))
+
+(defun assert-package-unlocked (package &optional control &rest args)
+  (declare (ignore control args))
+  package)
+
+(defun assert-symbol-home-package-unlocked (name format &key continuablep)
+  (declare (ignore format continuablep))
+  name)
+
+(deftype package-lock-violation () nil)
+
+(deftype package-locked-error () nil)
+
+(deftype symbol-package-locked-error () nil)
+
+(declaim (declaration enable-package-locks disable-package-locks))
index bd9e7a0..eb0a395 100644 (file)
   (let* ((len (length vars))
         (width (length (format nil "~W" (1- len)))))
     (dotimes (i len)
   (let* ((len (length vars))
         (width (length (format nil "~W" (1- len)))))
     (dotimes (i len)
-      (setf (compiled-debug-var-symbol (svref vars i))
-           (intern (format nil "ARG-~V,'0D" width i)
-                   ;; KLUDGE: It's somewhat nasty to have a bare
-                   ;; package name string here. It would be
-                   ;; nicer to have #.(FIND-PACKAGE "SB!DEBUG")
-                   ;; instead, since then at least it would transform
-                   ;; correctly under package renaming and stuff.
-                   ;; However, genesis can't handle dumped packages..
-                   ;; -- WHN 20000129
-                   ;;
-                   ;; FIXME: Maybe this could be fixed by moving the
-                   ;; whole debug-int.lisp file to warm init? (after
-                   ;; which dumping a #.(FIND-PACKAGE ..) expression
-                   ;; would work fine) If this is possible, it would
-                   ;; probably be a good thing, since minimizing the
-                   ;; amount of stuff in cold init is basically good.
-                   (or (find-package "SB-DEBUG")
-                       (find-package "SB!DEBUG")))))))
+      (without-package-locks
+        (setf (compiled-debug-var-symbol (svref vars i))
+              (intern (format nil "ARG-~V,'0D" width i)
+                      ;; KLUDGE: It's somewhat nasty to have a bare
+                      ;; package name string here. It would be
+                      ;; nicer to have #.(FIND-PACKAGE "SB!DEBUG")
+                      ;; instead, since then at least it would transform
+                      ;; correctly under package renaming and stuff.
+                      ;; However, genesis can't handle dumped packages..
+                      ;; -- WHN 20000129
+                      ;;
+                      ;; FIXME: Maybe this could be fixed by moving the
+                      ;; whole debug-int.lisp file to warm init? (after
+                      ;; which dumping a #.(FIND-PACKAGE ..) expression
+                      ;; would work fine) If this is possible, it would
+                      ;; probably be a good thing, since minimizing the
+                      ;; amount of stuff in cold init is basically good.
+                      (or (find-package "SB-DEBUG")
+                          (find-package "SB!DEBUG"))))))))
 
 ;;; Parse the packed representation of DEBUG-VARs from
 ;;; DEBUG-FUN's SB!C::COMPILED-DEBUG-FUN, returning a vector
 
 ;;; Parse the packed representation of DEBUG-VARs from
 ;;; DEBUG-FUN's SB!C::COMPILED-DEBUG-FUN, returning a vector
index a9cfbf7..964639f 100644 (file)
   ;; something sane, (1) doing so doesn't really fix the bug, and 
   ;; (2) doing probably isn't even really safe.
   #+nil (setf (%fun-name def) name)
   ;; something sane, (1) doing so doesn't really fix the bug, and 
   ;; (2) doing probably isn't even really safe.
   #+nil (setf (%fun-name def) name)
-
+  
   (when doc
     (setf (fdocumentation name 'function) doc))
   name)
   (when doc
     (setf (fdocumentation name 'function) doc))
   name)
index efb100e..cb83743 100644 (file)
     nil))
 
 (defmacro defpackage (package &rest options)
     nil))
 
 (defmacro defpackage (package &rest options)
-  #!+sb-doc
-  "Defines a new package called PACKAGE. Each of OPTIONS should be one of the
-   following:
-     (:NICKNAMES {package-name}*)
-     (:SIZE <integer>)
-     (:SHADOW {symbol-name}*)
-     (:SHADOWING-IMPORT-FROM <package-name> {symbol-name}*)
-     (:USE {package-name}*)
-     (:IMPORT-FROM <package-name> {symbol-name}*)
-     (:INTERN {symbol-name}*)
-     (:EXPORT {symbol-name}*)
-     (:DOCUMENTATION doc-string)
-   All options except :SIZE and :DOCUMENTATION can be used multiple times."
+  #!+sb-doc 
+  #.(format nil 
+  "Defines a new package called PACKAGE. Each of OPTIONS should be one of the 
+   following: ~{~&~4T~A~}
+   All options except ~{~A, ~}and :DOCUMENTATION can be used multiple 
+   times."
+  '((:nicknames "{package-name}*")
+    (:size "<integer>")
+    (:shadow "{symbol-name}*")
+    (:shadowing-import-from "<package-name> {symbol-name}*")
+    (:use "{package-name}*")
+    (:import-from "<package-name> {symbol-name}*")
+    (:intern "{symbol-name}*")
+    (:export "{symbol-name}*")
+    #!+sb-package-locks (:implement "{package-name}*")
+    #!+sb-package-locks (:lock "boolean")
+    (:documentation "doc-string"))
+  '(:size #!+sb-package-locks :lock))
   (let ((nicknames nil)
        (size nil)
        (shadows nil)
   (let ((nicknames nil)
        (size nil)
        (shadows nil)
        (imports nil)
        (interns nil)
        (exports nil)
        (imports nil)
        (interns nil)
        (exports nil)
+       (implement (stringify-names (list package) "package"))
+       (implement-p nil)
+       (lock nil)
        (doc nil))
        (doc nil))
+    #!-sb-package-locks    
+    (declare (ignore implement-p))
     (dolist (option options)
       (unless (consp option)
        (error 'simple-program-error
     (dolist (option options)
       (unless (consp option)
        (error 'simple-program-error
        (:export
         (let ((new (stringify-names (cdr option) "symbol")))
           (setf exports (append exports new))))
        (:export
         (let ((new (stringify-names (cdr option) "symbol")))
           (setf exports (append exports new))))
+       #!+sb-package-locks
+       (:implement
+        (unless implement-p 
+          (setf implement nil))
+        (let ((new (stringify-names (cdr option) "package")))
+          (setf implement (append implement new)
+                implement-p t)))
+       #!+sb-package-locks
+       (:lock
+        (when lock
+          (error 'simple-program-error
+                 :format-control "multiple :LOCK options"))
+        (setf lock (coerce (second option) 'boolean)))
        (:documentation
         (when doc
           (error 'simple-program-error
        (:documentation
         (when doc
           (error 'simple-program-error
     `(eval-when (:compile-toplevel :load-toplevel :execute)
        (%defpackage ,(stringify-name package "package") ',nicknames ',size
                    ',shadows ',shadowing-imports ',(if use-p use :default)
     `(eval-when (:compile-toplevel :load-toplevel :execute)
        (%defpackage ,(stringify-name package "package") ',nicknames ',size
                    ',shadows ',shadowing-imports ',(if use-p use :default)
-                   ',imports ',interns ',exports ',doc))))
+                   ',imports ',interns ',exports ',implement ',lock ',doc))))
 
 (defun check-disjoint (&rest args)
   ;; An arg is (:key . set)
 
 (defun check-disjoint (&rest args)
   ;; An arg is (:key . set)
          names))
 
 (defun %defpackage (name nicknames size shadows shadowing-imports
          names))
 
 (defun %defpackage (name nicknames size shadows shadowing-imports
-                        use imports interns exports doc-string)
+                   use imports interns exports implement lock doc-string)
   (declare (type simple-base-string name)
           (type list nicknames shadows shadowing-imports
                 imports interns exports)
           (type (or list (member :default)) use)
   (declare (type simple-base-string name)
           (type list nicknames shadows shadowing-imports
                 imports interns exports)
           (type (or list (member :default)) use)
-          (type (or simple-base-string null) doc-string))
+          (type (or simple-base-string null) doc-string)
+          #!-sb-package-locks
+          (ignore implement lock))
   (let ((package (or (find-package name)
                     (progn
                       (when (eq use :default)
   (let ((package (or (find-package name)
                     (progn
                       (when (eq use :default)
          (warn 'package-at-variance
                :format-control "~A also exports the following symbols:~%  ~S" 
                :format-arguments (list name diff)))))
          (warn 'package-at-variance
                :format-control "~A also exports the following symbols:~%  ~S" 
                :format-arguments (list name diff)))))
+    #!+sb-package-locks
+    (progn
+      ;; Handle packages this is an implementation package of
+      (dolist (p implement)
+       (add-implementation-package package p))
+      ;; Handle lock
+      (setf (package-lock package) lock))
     ;; Handle documentation.
     (setf (package-doc-string package) doc-string)
     package))
     ;; Handle documentation.
     (setf (package-doc-string package) doc-string)
     package))
index 6d70ebe..b0f374b 100644 (file)
        (if (dd-class-p dd)
           (let ((inherits (inherits-for-structure dd)))
             `(progn
        (if (dd-class-p dd)
           (let ((inherits (inherits-for-structure dd)))
             `(progn
-               ;; Note we intentionally call %DEFSTRUCT first, and
-               ;; especially before %COMPILER-DEFSTRUCT. %DEFSTRUCT
-               ;; has the tests (and resulting CERROR) for collisions
-               ;; with LAYOUTs which already exist in the runtime. If
-               ;; there are any collisions, we want the user's
-               ;; response to CERROR to control what happens.
-               ;; Especially, if the user responds to the collision
-               ;; with ABORT, we don't want %COMPILER-DEFSTRUCT to
-               ;; modify the definition of the class.
+               ;; Note we intentionally enforce package locks and
+               ;; call %DEFSTRUCT first, and especially before
+               ;; %COMPILER-DEFSTRUCT. %DEFSTRUCT has the tests (and
+               ;; resulting CERROR) for collisions with LAYOUTs which
+               ;; already exist in the runtime. If there are any
+               ;; collisions, we want the user's response to CERROR
+               ;; to control what happens. Especially, if the user
+               ;; responds to the collision with ABORT, we don't want
+               ;; %COMPILER-DEFSTRUCT to modify the definition of the
+               ;; class.
+               (with-single-package-locked-error
+                   (:symbol ',name "defining ~A as a structure"))
                (%defstruct ',dd ',inherits)
                (eval-when (:compile-toplevel :load-toplevel :execute)
                  (%compiler-defstruct ',dd ',inherits))
                (%defstruct ',dd ',inherits)
                (eval-when (:compile-toplevel :load-toplevel :execute)
                  (%compiler-defstruct ',dd ',inherits))
                            (class-method-definitions dd)))
                ',name))
           `(progn
                            (class-method-definitions dd)))
                ',name))
           `(progn
+             (with-single-package-locked-error
+                 (:symbol ',name "defining ~A as a structure"))
              (eval-when (:compile-toplevel :load-toplevel :execute)
                (setf (info :typed-structure :info ',name) ',dd))
              ,@(unless expanding-into-code-for-xc-host-p
              (eval-when (:compile-toplevel :load-toplevel :execute)
                (setf (info :typed-structure :info ',name) ',dd))
              ,@(unless expanding-into-code-for-xc-host-p
index 5115bcb..4f80e72 100644 (file)
@@ -35,7 +35,7 @@
 
 (macrolet ((define-fasl-format-features ()
              (let (;; master value for *F-P-A-F-F*
 
 (macrolet ((define-fasl-format-features ()
              (let (;; master value for *F-P-A-F-F*
-                  (fpaff '(:sb-thread)))
+                  (fpaff '(:sb-thread :sb-package-locks)))
               `(progn
                  ;; a list of *(SHEBANG-)FEATURES* flags which affect
                  ;; binary compatibility, i.e. which must be the same
               `(progn
                  ;; a list of *(SHEBANG-)FEATURES* flags which affect
                  ;; binary compatibility, i.e. which must be the same
 (defvar *load-print* nil
   #!+sb-doc
   "the default for the :PRINT argument to LOAD")
 (defvar *load-print* nil
   #!+sb-doc
   "the default for the :PRINT argument to LOAD")
+
 (defvar *load-verbose* nil
   ;; Note that CMU CL's default for this was T, and ANSI says it's
   ;; implementation-dependent. We choose NIL on the theory that it's
 (defvar *load-verbose* nil
   ;; Note that CMU CL's default for this was T, and ANSI says it's
   ;; implementation-dependent. We choose NIL on the theory that it's
   "the default for the :VERBOSE argument to LOAD")
 
 (defvar *load-code-verbose* nil)
   "the default for the :VERBOSE argument to LOAD")
 
 (defvar *load-code-verbose* nil)
-
diff --git a/src/code/early-package.lisp b/src/code/early-package.lisp
new file mode 100644 (file)
index 0000000..1084cdf
--- /dev/null
@@ -0,0 +1,66 @@
+;;;; Package (locking) related macros needed on the target before most
+;;;; of the package machinery is available.
+;;;;
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; This software is derived from the CMU CL system, which was
+;;;; written at Carnegie Mellon University and released into the
+;;;; public domain. The software is in the public domain and is
+;;;; provided with absolutely no warranty. See the COPYING and CREDITS
+;;;; files for more information.
+
+(in-package "SB!IMPL")
+
+(!begin-collecting-cold-init-forms)
+
+;;; Unbound outside package lock context, inside either list of
+;;; packages for which locks are ignored, T when locks for
+;;; all packages are ignored, and :invalid outside package-lock
+;;; context. FIXME: This needs to be rebound for each thread.
+(defvar *ignored-package-locks* 
+  (error "*IGNORED-PACKAGE-LOCKS* should be set up in cold-init."))
+(!cold-init-forms
+  (setf *ignored-package-locks* :invalid))
+
+(defmacro with-single-package-locked-error ((&optional kind thing &rest format) 
+                                           &body body)
+  #!-sb-package-locks (declare (ignore kind thing format))
+  #!-sb-package-locks
+  `(progn ,@body)
+  #!+sb-package-locks
+  (with-unique-names (topmost)
+    `(progn
+       (/show0 ,(first format))
+       (let ((,topmost nil))
+        ;; We use assignment and conditional restoration instead of
+        ;; dynamic binding because we want the ignored locks
+        ;; to propagate to the topmost context.
+        (when (eq :invalid *ignored-package-locks*)
+          (setf *ignored-package-locks* nil
+                ,topmost t))
+        (unwind-protect
+             (progn 
+               ,@(ecase kind
+                  (:symbol 
+                   `((assert-symbol-home-package-unlocked ,thing ,@format)))
+                  (:package
+                   `((assert-package-unlocked 
+                      (find-undeleted-package-or-lose ,thing) ,@format)))
+                  ((nil)
+                   `()))
+               ,@body)
+          (when ,topmost
+            (setf *ignored-package-locks* :invalid)))))))
+
+(defmacro without-package-locks (&body body)
+  #!+sb-doc
+  "Ignores all runtime package lock violations during the execution of
+body. Body can begin with declarations."
+  #!-sb-package-locks
+  `(progn ,@body)
+  #!+sb-package-locks
+  `(let ((*ignored-package-locks* t))
+    ,@body))
+
+(!defun-from-collected-cold-init-forms !early-package-cold-init)
index 4b61727..0fd0895 100644 (file)
                            (incf ,count-name)
                            ,@(when object
                                `((pop ,object-var)))))
                            (incf ,count-name)
                            ,@(when object
                                `((pop ,object-var)))))
-                    (declare (ignorable #',pp-pop-name))
-                    (macrolet ((pprint-pop ()
-                                 '(,pp-pop-name))
-                               (pprint-exit-if-list-exhausted ()
-                                 ,(if object
-                                      `'(when (null ,object-var)
-                                          (return-from ,block-name nil))
-                                      `'(return-from ,block-name nil))))
-                      ,@body)))
+                    (locally
+                        (declare (disable-package-locks 
+                                  pprint-pop pprint-exit-if-list-exhausted))
+                      (macrolet ((pprint-pop ()
+                                   '(,pp-pop-name))
+                                 (pprint-exit-if-list-exhausted ()
+                                   ,(if object
+                                        `'(when (null ,object-var)
+                                           (return-from ,block-name nil))
+                                        `'(return-from ,block-name nil))))
+                        (declare (enable-package-locks
+                                  pprint-pop pprint-exit-if-list-exhausted))
+                        ,@body))))
                 ;; FIXME: Don't we need UNWIND-PROTECT to ensure this
                 ;; always gets executed?
                 (end-logical-block ,stream-var)))))
                 ;; FIXME: Don't we need UNWIND-PROTECT to ensure this
                 ;; always gets executed?
                 (end-logical-block ,stream-var)))))
index 7f6dce7..2185a96 100644 (file)
@@ -337,6 +337,8 @@ GET-SETF-EXPANSION directly."
 (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
   ;;; Assign SETF macro information for NAME, making all appropriate checks.
   (defun assign-setf-macro (name expander inverse doc)
 (eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
   ;;; Assign SETF macro information for NAME, making all appropriate checks.
   (defun assign-setf-macro (name expander inverse doc)
+    (with-single-package-locked-error
+       (:symbol name "defining a setf-expander for ~A"))
     (cond ((gethash name sb!c:*setf-assumed-fboundp*)
           (warn
            "defining setf macro for ~S when ~S was previously ~
     (cond ((gethash name sb!c:*setf-assumed-fboundp*)
           (warn
            "defining setf macro for ~S when ~S was previously ~
index d77f90f..9a3cdf1 100644 (file)
@@ -46,7 +46,7 @@
        (eval-in-lexenv (first i) lexenv)
        (return (eval-in-lexenv (first i) lexenv)))))
 
        (eval-in-lexenv (first i) lexenv)
        (return (eval-in-lexenv (first i) lexenv)))))
 
-(defun eval-locally (exp lexenv &optional vars)
+(defun eval-locally (exp lexenv &key vars)
   (multiple-value-bind (body decls)
       (parse-body (rest exp) :doc-string-allowed nil)
     (let ((lexenv
   (multiple-value-bind (body decls)
       (parse-body (rest exp) :doc-string-allowed nil)
     (let ((lexenv
            ;; undefined things can be accumulated [and
            ;; then thrown away, as it happens]). -- CSR,
            ;; 2002-10-24
            ;; undefined things can be accumulated [and
            ;; then thrown away, as it happens]). -- CSR,
            ;; 2002-10-24
-           (let ((sb!c:*lexenv* lexenv)
-                 (sb!c::*free-funs* (make-hash-table :test 'equal))
-                 (sb!c::*free-vars* (make-hash-table :test 'eq))
-                 (sb!c::*undefined-warnings* nil))
+           (let* ((sb!c:*lexenv* lexenv)
+                 (sb!c::*free-funs* (make-hash-table :test 'equal))
+                 (sb!c::*free-vars* (make-hash-table :test 'eq))
+                 (sb!c::*undefined-warnings* nil))
              ;; FIXME: VALUES declaration
              (sb!c::process-decls decls
                                   vars
              ;; FIXME: VALUES declaration
              (sb!c::process-decls decls
                                   vars
             ((macrolet)
              (destructuring-bind (definitions &rest body)
                  (rest exp)
             ((macrolet)
              (destructuring-bind (definitions &rest body)
                  (rest exp)
-               (let ((lexenv
+                (let ((lexenv
                        (let ((sb!c:*lexenv* lexenv))
                          (sb!c::funcall-in-macrolet-lexenv
                           definitions
                        (let ((sb!c:*lexenv* lexenv))
                          (sb!c::funcall-in-macrolet-lexenv
                           definitions
                           :eval))))
                   (eval-locally `(locally ,@body) lexenv))))
             ((symbol-macrolet)
                           :eval))))
                   (eval-locally `(locally ,@body) lexenv))))
             ((symbol-macrolet)
-             (destructuring-bind (definitions &rest body)
-                 (rest exp)
+             (destructuring-bind (definitions &rest body) (rest exp)
                 (multiple-value-bind (lexenv vars)
                     (let ((sb!c:*lexenv* lexenv))
                       (sb!c::funcall-in-symbol-macrolet-lexenv
                 (multiple-value-bind (lexenv vars)
                     (let ((sb!c:*lexenv* lexenv))
                       (sb!c::funcall-in-symbol-macrolet-lexenv
                        (lambda (&key vars)
                          (values sb!c:*lexenv* vars))
                        :eval))
                        (lambda (&key vars)
                          (values sb!c:*lexenv* vars))
                        :eval))
-                  (eval-locally `(locally ,@body) lexenv vars))))
+                  (eval-locally `(locally ,@body) lexenv :vars vars))))
             (t
              (if (and (symbolp name)
                       (eq (info :function :kind name) :function))
             (t
              (if (and (symbolp name)
                       (eq (info :function :kind name) :function))
index 943eb2e..59ca173 100644 (file)
   #!+sb-doc
   "Set NAME's global function definition."
   (declare (type function new-value) (optimize (safety 1)))
   #!+sb-doc
   "Set NAME's global function definition."
   (declare (type function new-value) (optimize (safety 1)))
-  (let ((fdefn (fdefinition-object name t)))
-    ;; *SETF-FDEFINITION-HOOK* won't be bound when initially running
-    ;; top level forms in the kernel core startup.
-    (when (boundp '*setf-fdefinition-hook*)
-      (dolist (f *setf-fdefinition-hook*)
-        (declare (type function f))
-       (funcall f name new-value)))
-
-    (let ((encap-info (encapsulation-info (fdefn-fun fdefn))))
-      (cond (encap-info
-            (loop
-              (let ((more-info
-                     (encapsulation-info
-                      (encapsulation-info-definition encap-info))))
-                (if more-info
-                    (setf encap-info more-info)
-                    (return
-                     (setf (encapsulation-info-definition encap-info)
-                           new-value))))))
-           (t
-            (setf (fdefn-fun fdefn) new-value))))))
+  (with-single-package-locked-error (:symbol name "setting fdefinition of ~A")
+    (let ((fdefn (fdefinition-object name t)))
+      ;; *SETF-FDEFINITION-HOOK* won't be bound when initially running
+      ;; top level forms in the kernel core startup.
+      (when (boundp '*setf-fdefinition-hook*)
+       (dolist (f *setf-fdefinition-hook*)
+         (declare (type function f))
+         (funcall f name new-value)))
+      
+      (let ((encap-info (encapsulation-info (fdefn-fun fdefn))))
+       (cond (encap-info
+              (loop
+               (let ((more-info
+                      (encapsulation-info
+                       (encapsulation-info-definition encap-info))))
+                 (if more-info
+                     (setf encap-info more-info)
+                     (return
+                       (setf (encapsulation-info-definition encap-info)
+                             new-value))))))
+             (t
+              (setf (fdefn-fun fdefn) new-value)))))))
 \f
 ;;;; FBOUNDP and FMAKUNBOUND
 
 \f
 ;;;; FBOUNDP and FMAKUNBOUND
 
 (defun fmakunbound (name)
   #!+sb-doc
   "Make NAME have no global function definition."
 (defun fmakunbound (name)
   #!+sb-doc
   "Make NAME have no global function definition."
-  (let ((fdefn (fdefinition-object name nil)))
-    (when fdefn
-      (fdefn-makunbound fdefn)))
-  (sb!kernel:undefine-fun-name name)
-  name)
+  (with-single-package-locked-error 
+      (:symbol name "removing the function or macro definition of ~A")
+    (let ((fdefn (fdefinition-object name nil)))
+      (when fdefn
+       (fdefn-makunbound fdefn)))
+    (sb!kernel:undefine-fun-name name)
+    name))
index 20f7ad7..758e8b4 100644 (file)
                        (read-string-as-bytes *fasl-input-stream*
                                              ,n-buffer
                                              ,n-size)
                        (read-string-as-bytes *fasl-input-stream*
                                              ,n-buffer
                                              ,n-size)
-                       (push-fop-table (intern* ,n-buffer
-                                                ,n-size
-                                                ,n-package)))))))))
+                       (push-fop-table (without-package-locks
+                                        (intern* ,n-buffer
+                                                 ,n-size
+                                                 ,n-package))))))))))
 
   ;; Note: CMU CL had FOP-SYMBOL-SAVE and FOP-SMALL-SYMBOL-SAVE, but
   ;; since they made the behavior of the fasloader depend on the
 
   ;; Note: CMU CL had FOP-SYMBOL-SAVE and FOP-SMALL-SYMBOL-SAVE, but
   ;; since they made the behavior of the fasloader depend on the
index 5c64df2..0843787 100644 (file)
@@ -79,6 +79,8 @@
     (error 'simple-type-error :datum name :expected-type 'symbol
           :format-control "Symbol macro name is not a symbol: ~S."
           :format-arguments (list name)))
     (error 'simple-type-error :datum name :expected-type 'symbol
           :format-control "Symbol macro name is not a symbol: ~S."
           :format-arguments (list name)))
+  (with-single-package-locked-error 
+      (:symbol name "defining ~A as a symbol-macro"))
   (ecase (info :variable :kind name)
     ((:macro :global nil)
      (setf (info :variable :kind name) :macro)
   (ecase (info :variable :kind name)
     ((:macro :global nil)
      (setf (info :variable :kind name) :macro)
index 8e14a5e..59f2f24 100644 (file)
   ;; shadowing symbols
   (%shadowing-symbols () :type list)
   ;; documentation string for this package
   ;; shadowing symbols
   (%shadowing-symbols () :type list)
   ;; documentation string for this package
-  (doc-string nil :type (or simple-base-string null)))
+  (doc-string nil :type (or simple-base-string null))
+  ;; package locking
+  #!+sb-package-locks
+  (lock nil :type boolean)
+  #!+sb-package-locks
+  (%implementation-packages nil :type list))
 \f
 ;;;; iteration macros
 
 \f
 ;;;; iteration macros
 
index 729be4f..30bd69d 100644 (file)
   (let ((encapsulated-fun (fdefinition name)))
     (multiple-value-bind (encapsulation-fun read-stats-fun clear-stats-fun)
        (profile-encapsulation-lambdas encapsulated-fun)
   (let ((encapsulated-fun (fdefinition name)))
     (multiple-value-bind (encapsulation-fun read-stats-fun clear-stats-fun)
        (profile-encapsulation-lambdas encapsulated-fun)
-      (setf (fdefinition name)
-           encapsulation-fun)
+      (without-package-locks
+       (setf (fdefinition name)
+            encapsulation-fun))
       (setf (gethash name *profiled-fun-name->info*)
            (make-profile-info :name name
                               :encapsulated-fun encapsulated-fun
       (setf (gethash name *profiled-fun-name->info*)
            (make-profile-info :name name
                               :encapsulated-fun encapsulated-fun
     (cond (pinfo
           (remhash name *profiled-fun-name->info*)
           (if (eq (fdefinition name) (profile-info-encapsulation-fun pinfo))
     (cond (pinfo
           (remhash name *profiled-fun-name->info*)
           (if (eq (fdefinition name) (profile-info-encapsulation-fun pinfo))
-              (setf (fdefinition name) (profile-info-encapsulated-fun pinfo))
+              (without-package-locks
+               (setf (fdefinition name) (profile-info-encapsulated-fun pinfo)))
               (warn "preserving current definition of redefined function ~S"
                     name)))
          (t
               (warn "preserving current definition of redefined function ~S"
                     name)))
          (t
@@ -515,5 +517,6 @@ Lisp process."
 ;;; different machine running at a different speed. We avoid this by
 ;;; erasing *CALL-OVERHEAD* whenever we save a .core file.
 (pushnew (lambda ()
 ;;; different machine running at a different speed. We avoid this by
 ;;; erasing *CALL-OVERHEAD* whenever we save a .core file.
 (pushnew (lambda ()
-          (makunbound '*overhead*))
+          (without-package-locks
+           (makunbound '*overhead*)))
         *before-save-initializations*)
         *before-save-initializations*)
index e24c33e..557141b 100644 (file)
 (defun makunbound (symbol)
   #!+sb-doc
   "Make SYMBOL unbound, removing any value it may currently have."
 (defun makunbound (symbol)
   #!+sb-doc
   "Make SYMBOL unbound, removing any value it may currently have."
-  (set symbol
-       (%primitive sb!c:make-other-immediate-type
-                  0
-                  sb!vm:unbound-marker-widetag))
-  symbol)
+  (with-single-package-locked-error (:symbol symbol "unbinding the symbol ~A")
+    (set symbol
+        (%primitive sb!c:make-other-immediate-type
+                    0
+                    sb!vm:unbound-marker-widetag))
+    symbol))
 
 ;;; Return the built-in hash value for SYMBOL.
 (defun symbol-hash (symbol)
 
 ;;; Return the built-in hash value for SYMBOL.
 (defun symbol-hash (symbol)
@@ -58,7 +59,9 @@
 
 (defun (setf symbol-function) (new-value symbol)
   (declare (type symbol symbol) (type function new-value))
 
 (defun (setf symbol-function) (new-value symbol)
   (declare (type symbol symbol) (type function new-value))
-  (setf (%coerce-name-to-fun symbol) new-value))
+  (with-single-package-locked-error 
+      (:symbol symbol "setting the symbol-function of ~A")
+    (setf (%coerce-name-to-fun symbol) new-value)))
 
 (defun symbol-plist (symbol)
   #!+sb-doc
 
 (defun symbol-plist (symbol)
   #!+sb-doc
index ab640e9..074e43d 100644 (file)
           (setf res (%make-package-hashtable table hash size)))
       res)))
 \f
           (setf res (%make-package-hashtable table hash size)))
       res)))
 \f
+;;;; package locking operations, built conditionally on :sb-package-locks
+
+#!+sb-package-locks
+(progn
+(defun package-locked-p (package) 
+  #!+sb-doc 
+  "Returns T when PACKAGE is locked, NIL otherwise. Signals an error
+if PACKAGE doesn't designate a valid package."
+  (package-lock (find-undeleted-package-or-lose package)))
+
+(defun lock-package (package)
+  #!+sb-doc 
+  "Locks PACKAGE and returns T. Has no effect if PACKAGE was already
+locked. Signals an error if PACKAGE is not a valid package designator"
+  (setf (package-lock (find-undeleted-package-or-lose package)) t))
+
+(defun unlock-package (package)
+  #!+sb-doc 
+  "Unlocks PACKAGE and returns T. Has no effect if PACKAGE was already
+unlocked. Signals an error if PACKAGE is not a valid package designator."
+  (setf (package-lock (find-undeleted-package-or-lose package)) nil)
+  t)
+
+(defun package-implemented-by-list (package)
+  #!+sb-doc 
+  "Returns a list containing the implementation packages of
+PACKAGE. Signals an error if PACKAGE is not a valid package designator."
+  (package-%implementation-packages (find-undeleted-package-or-lose package)))
+
+(defun package-implements-list (package) 
+  #!+sb-doc 
+  "Returns the packages that PACKAGE is an implementation package
+of. Signals an error if PACKAGE is not a valid package designator."
+  (let ((package (find-undeleted-package-or-lose package)))
+    (loop for x in (list-all-packages)
+          when (member package (package-%implementation-packages x))
+          collect x)))
+
+(defun add-implementation-package (packages-to-add 
+                                  &optional (package *package*))
+  #!+sb-doc 
+  "Adds PACKAGES-TO-ADD as implementation packages of PACKAGE. Signals
+an error if PACKAGE or any of the PACKAGES-TO-ADD is not a valid
+package designator."
+  (let ((package (find-undeleted-package-or-lose package))
+       (packages-to-add (package-listify packages-to-add)))
+    (setf (package-%implementation-packages package)
+          (union (package-%implementation-packages package)
+                 (mapcar #'find-undeleted-package-or-lose packages-to-add)))))
+
+(defun remove-implementation-package (packages-to-remove 
+                                     &optional (package *package*)) 
+  #!+sb-doc 
+  "Removes PACKAGES-TO-REMOVE from the implementation packages of
+PACKAGE. Signals an error if PACKAGE or any of the PACKAGES-TO-REMOVE
+is not a valid package designator."
+  (let ((package (find-undeleted-package-or-lose package))
+       (packages-to-remove (package-listify packages-to-remove)))
+    (setf (package-%implementation-packages package)
+          (nset-difference 
+           (package-%implementation-packages package)
+           (mapcar #'find-undeleted-package-or-lose packages-to-remove)))))
+
+(defmacro with-unlocked-packages ((&rest packages) &body forms)
+  #!+sb-doc
+  "Unlocks PACKAGES for the dynamic scope of the body. Signals an
+error if any of PACKAGES is not a valid package designator."
+  (with-unique-names (unlocked-packages)
+    `(let (,unlocked-packages)
+      (unwind-protect
+           (progn 
+             (dolist (p ',packages)
+               (when (package-locked-p p)
+                 (push p ,unlocked-packages)
+                 (unlock-package p)))
+             ,@forms)
+        (dolist (p ,unlocked-packages)
+         (when (find-package p)
+           (lock-package p)))))))
+
+(defun package-lock-violation (package &key (symbol nil symbol-p)
+                               format-control format-arguments)
+  (let ((restart :continue)
+        (cl-violation-p (eq package (find-package :common-lisp))))
+    (flet ((error-arguments ()
+             (append (list (if symbol-p
+                               'symbol-package-locked-error
+                               'package-locked-error)
+                           :package package
+                           :format-control format-control
+                             :format-arguments format-arguments)
+                       (when symbol-p (list :symbol symbol))
+                       (list :references
+                             (append '((:sbcl :node "Package Locks"))
+                                     (when cl-violation-p
+                                       '((:ansi-cl :section (11 1 2 1 2)))))))))
+      (restart-case
+          (apply #'cerror "Ignore the package lock." (error-arguments))
+        (:ignore-all ()
+          :report "Ignore all package locks in the context of this operation."
+          (setf restart :ignore-all))
+        (:unlock-package ()
+          :report "Unlock the package."
+          (setf restart :unlock-package)))
+      (ecase restart
+        (:continue
+         (pushnew package *ignored-package-locks*))
+        (:ignore-all
+         (setf *ignored-package-locks* t))
+        (:unlock-package
+         (unlock-package package))))))
+
+(defun package-lock-violation-p (package &optional (symbol nil symbolp))
+  ;; KLUDGE: (package-lock package) needs to be before
+  ;; comparison to *package*, since during cold init this gets
+  ;; called before *package* is bound -- but no package should
+  ;; be locked at that point.
+  (and package 
+       (package-lock package)
+       ;; In package or implementation package
+       (not (or (eq package *package*)
+                (member *package* (package-%implementation-packages package))))
+       ;; Runtime disabling
+       (not (eq t *ignored-package-locks*))
+       (or (eq :invalid *ignored-package-locks*)
+           (not (member package *ignored-package-locks*)))
+       ;; declarations for symbols
+       (not (and symbolp (member symbol (disabled-package-locks))))))
+
+(defun disabled-package-locks ()
+  (if (boundp 'sb!c::*lexenv*)
+      (sb!c::lexenv-disabled-package-locks sb!c::*lexenv*)
+      sb!c::*disabled-package-locks*))
+
+) ; progn
+
+;;;; more package-locking these are NOPs unless :sb-package-locks is
+;;;; in target features. Cross-compiler NOPs for these are in cross-misc.
+
+;;; The right way to establish a package lock context is
+;;; WITH-SINGLE-PACKAGE-LOCKED-ERROR, defined in early-package.lisp
+;;;
+;;; Must be used inside the dynamic contour established by
+;;; WITH-SINGLE-PACKAGE-LOCKED-ERROR
+(defun assert-package-unlocked (package &optional format-control 
+                               &rest format-arguments)
+  #!-sb-package-locks 
+  (declare (ignore format-control format-arguments))
+  #!+sb-package-locks
+  (when (package-lock-violation-p package)
+    (package-lock-violation package 
+                           :format-control format-control 
+                           :format-arguments format-arguments))
+  package)
+
+;;; Must be used inside the dynamic contour established by
+;;; WITH-SINGLE-PACKAGE-LOCKED-ERROR.
+;;;
+;;; FIXME: Maybe we should establish such contours for he toplevel
+;;; and others, so that %set-fdefinition and others could just use
+;;; this.
+(defun assert-symbol-home-package-unlocked (name format)
+  #!-sb-package-locks
+  (declare (ignore format))
+  #!+sb-package-locks
+  (let* ((symbol (etypecase name
+                  (symbol name)
+                  (list (if (eq 'setf (first name))
+                            (second name)
+                            ;; Skip (class-predicate foo), etc.
+                            ;; FIXME: MOP and package-lock
+                            ;; interaction needs to be thought about.
+                            (return-from 
+                             assert-symbol-home-package-unlocked
+                              name)))))
+        (package (symbol-package symbol)))
+    (when (package-lock-violation-p package symbol)
+      (package-lock-violation package 
+                             :symbol symbol
+                             :format-control format
+                             :format-arguments (list name))))
+  name)
+
+\f
 ;;;; miscellaneous PACKAGE operations
 
 (def!method print-object ((package package) stream)
 ;;;; miscellaneous PACKAGE operations
 
 (def!method print-object ((package package) stream)
   "Changes the name and nicknames for a package."
   (let* ((package (find-undeleted-package-or-lose package))
         (name (string name))
   "Changes the name and nicknames for a package."
   (let* ((package (find-undeleted-package-or-lose package))
         (name (string name))
-        (found (find-package name)))
+        (found (find-package name))
+        (nicks (mapcar #'string nicknames)))
     (unless (or (not found) (eq found package))
       (error 'simple-package-error
             :package name
             :format-control "A package named ~S already exists."
             :format-arguments (list name)))
     (unless (or (not found) (eq found package))
       (error 'simple-package-error
             :package name
             :format-control "A package named ~S already exists."
             :format-arguments (list name)))
-    (remhash (package-%name package) *package-names*)
-    (dolist (n (package-%nicknames package))
-      (remhash n *package-names*))
-     (setf (package-%name package) name)
-    (setf (gethash name *package-names*) package)
-    (setf (package-%nicknames package) ())
-    (enter-new-nicknames package nicknames)
+    (with-single-package-locked-error ()
+       (unless (and (string= name (package-name package))
+                    (null (set-difference nicks (package-nicknames package) 
+                                      :test #'string=)))
+         (assert-package-unlocked package "rename as ~A~@[ with nickname~P ~
+                                           ~{~A~^, ~}~]" 
+                                  name (length nicks) nicks))
+      ;; do the renaming
+      (remhash (package-%name package) *package-names*)
+      (dolist (n (package-%nicknames package))
+       (remhash n *package-names*))
+      (setf (package-%name package) name
+           (gethash name *package-names*) package
+           (package-%nicknames package) ())
+      (enter-new-nicknames package nicknames))
     package))
 
 (defun delete-package (package-or-name)
     package))
 
 (defun delete-package (package-or-name)
          ((not (package-name package)) ; already deleted
           nil)
          (t
          ((not (package-name package)) ; already deleted
           nil)
          (t
-          (let ((use-list (package-used-by-list package)))
-            (when use-list
-              ;; This continuable error is specified by ANSI.
-              (with-simple-restart
-                  (continue "Remove dependency in other packages.")
-                (error 'simple-package-error
-                       :package package
-                       :format-control
-                       "Package ~S is used by package(s):~%  ~S"
-                       :format-arguments
-                       (list (package-name package)
-                             (mapcar #'package-name use-list))))
-              (dolist (p use-list)
-                (unuse-package package p))))
-          (dolist (used (package-use-list package))
-            (unuse-package used package))
-          (do-symbols (sym package)
-            (unintern sym package))
-          (remhash (package-name package) *package-names*)
-          (dolist (nick (package-nicknames package))
-            (remhash nick *package-names*))
-          (setf (package-%name package) nil
-                ;; Setting PACKAGE-%NAME to NIL is required in order to
-                ;; make PACKAGE-NAME return NIL for a deleted package as
-                ;; ANSI requires. Setting the other slots to NIL
-                ;; and blowing away the PACKAGE-HASHTABLES is just done
-                ;; for tidiness and to help the GC.
-                (package-%nicknames package) nil
-                (package-%use-list package) nil
-                (package-tables package) nil
-                (package-%shadowing-symbols package) nil
-                (package-internal-symbols package)
-                (make-or-remake-package-hashtable 0)
-                (package-external-symbols package)
-                (make-or-remake-package-hashtable 0))
-          t))))
+          (with-single-package-locked-error
+              (:package package "deleting package ~A" package)
+            (let ((use-list (package-used-by-list package)))
+              (when use-list
+                ;; This continuable error is specified by ANSI.
+                (with-simple-restart
+                    (continue "Remove dependency in other packages.")
+                  (error 'simple-package-error
+                         :package package
+                         :format-control
+                         "Package ~S is used by package(s):~%  ~S"
+                         :format-arguments
+                         (list (package-name package)
+                               (mapcar #'package-name use-list))))
+                (dolist (p use-list)
+                  (unuse-package package p))))
+            (dolist (used (package-use-list package))
+              (unuse-package used package))
+            (do-symbols (sym package)
+              (unintern sym package))
+            (remhash (package-name package) *package-names*)
+            (dolist (nick (package-nicknames package))
+              (remhash nick *package-names*))
+            (setf (package-%name package) nil
+                  ;; Setting PACKAGE-%NAME to NIL is required in order to
+                  ;; make PACKAGE-NAME return NIL for a deleted package as
+                  ;; ANSI requires. Setting the other slots to NIL
+                  ;; and blowing away the PACKAGE-HASHTABLES is just done
+                  ;; for tidiness and to help the GC.
+                  (package-%nicknames package) nil
+                  (package-%use-list package) nil
+                  (package-tables package) nil
+                  (package-%shadowing-symbols package) nil
+                  (package-internal-symbols package)
+                  (make-or-remake-package-hashtable 0)
+                  (package-external-symbols package)
+                  (make-or-remake-package-hashtable 0))
+            t)))))
 
 (defun list-all-packages ()
   #!+sb-doc
 
 (defun list-all-packages ()
   #!+sb-doc
   ;; logic is.
   (let ((name (if (simple-string-p name)
                name
   ;; logic is.
   (let ((name (if (simple-string-p name)
                name
-               (coerce name 'simple-string))))
+               (coerce name 'simple-string)))
+       (package (find-undeleted-package-or-lose package)))
     (declare (simple-string name))
     (declare (simple-string name))
-    (intern* name
-            (length name)
-            (find-undeleted-package-or-lose package))))
+      (intern* name
+              (length name)
+              package)))
 
 (defun find-symbol (name &optional (package (sane-package)))
   #!+sb-doc
 
 (defun find-symbol (name &optional (package (sane-package)))
   #!+sb-doc
 (defun intern* (name length package)
   (declare (simple-string name))
   (multiple-value-bind (symbol where) (find-symbol* name length package)
 (defun intern* (name length package)
   (declare (simple-string name))
   (multiple-value-bind (symbol where) (find-symbol* name length package)
-    (if where
-       (values symbol where)
-       (let ((symbol (make-symbol (subseq name 0 length))))
-         (%set-symbol-package symbol package)
-         (cond ((eq package *keyword-package*)
-                (add-symbol (package-external-symbols package) symbol)
-                (%set-symbol-value symbol symbol))
-               (t
-                (add-symbol (package-internal-symbols package) symbol)))
-         (values symbol nil)))))
+    (cond (where
+          (values symbol where))
+         (t
+          (let ((symbol-name (subseq name 0 length)))
+            (with-single-package-locked-error 
+                (:package package "interning ~A" symbol-name)
+              (let ((symbol (make-symbol symbol-name)))
+                (%set-symbol-package symbol package)
+                (cond ((eq package *keyword-package*)
+                       (add-symbol (package-external-symbols package) symbol)
+                       (%set-symbol-value symbol symbol))
+                      (t
+                       (add-symbol (package-internal-symbols package) symbol)))
+                (values symbol nil))))))))
 
 ;;; Check internal and external symbols, then scan down the list
 ;;; of hashtables for inherited symbols. When an inherited symbol
 
 ;;; Check internal and external symbols, then scan down the list
 ;;; of hashtables for inherited symbols. When an inherited symbol
         (shadowing-symbols (package-%shadowing-symbols package)))
     (declare (list shadowing-symbols))
 
         (shadowing-symbols (package-%shadowing-symbols package)))
     (declare (list shadowing-symbols))
 
-    ;; If a name conflict is revealed, give use a chance to shadowing-import
-    ;; one of the accessible symbols.
-    (when (member symbol shadowing-symbols)
-      (let ((cset ()))
-       (dolist (p (package-%use-list package))
-         (multiple-value-bind (s w) (find-external-symbol name p)
-           (when w (pushnew s cset))))
-       (when (cdr cset)
-         (loop
-          (cerror
-           "Prompt for a symbol to SHADOWING-IMPORT."
-           "Uninterning symbol ~S causes name conflict among these symbols:~%~S"
-           symbol cset)
-          (write-string "Symbol to shadowing-import: " *query-io*)
-          (let ((sym (read *query-io*)))
-            (cond
-             ((not (symbolp sym))
-              (format *query-io* "~S is not a symbol." sym))
-             ((not (member sym cset))
-              (format *query-io* "~S is not one of the conflicting symbols." sym))
-             (t
-              (shadowing-import sym package)
-              (return-from unintern t)))))))
-      (setf (package-%shadowing-symbols package)
-           (remove symbol shadowing-symbols)))
-
-    (multiple-value-bind (s w) (find-symbol name package)
-      (declare (ignore s))
-      (cond ((or (eq w :internal) (eq w :external))
-            (nuke-symbol (if (eq w :internal)
-                             (package-internal-symbols package)
-                             (package-external-symbols package))
-                         name)
-            (if (eq (symbol-package symbol) package)
-                (%set-symbol-package symbol nil))
-            t)
-           (t nil)))))
+    (with-single-package-locked-error ()
+      (when (find-symbol name package)
+       (assert-package-unlocked package "uninterning ~A" name))
+      
+      ;; If a name conflict is revealed, give use a chance to shadowing-import
+      ;; one of the accessible symbols.
+      (when (member symbol shadowing-symbols)
+       (let ((cset ()))
+         (dolist (p (package-%use-list package))
+           (multiple-value-bind (s w) (find-external-symbol name p)
+             (when w (pushnew s cset))))
+         (when (cdr cset)
+           (loop
+            (cerror
+             "Prompt for a symbol to SHADOWING-IMPORT."
+             "Uninterning symbol ~S causes name conflict among these symbols:~%~S"
+             symbol cset)
+            (write-string "Symbol to shadowing-import: " *query-io*)
+            (let ((sym (read *query-io*)))
+              (cond
+                ((not (symbolp sym))
+                 (format *query-io* "~S is not a symbol." sym))
+                ((not (member sym cset))
+                 (format *query-io* "~S is not one of the conflicting symbols." sym))
+                (t
+                 (shadowing-import sym package)
+                 (return-from unintern t)))))))
+       (setf (package-%shadowing-symbols package)
+             (remove symbol shadowing-symbols)))
+
+      (multiple-value-bind (s w) (find-symbol name package)
+       (declare (ignore s))
+       (cond ((or (eq w :internal) (eq w :external))
+              (nuke-symbol (if (eq w :internal)
+                               (package-internal-symbols package)
+                               (package-external-symbols package))
+                           name)
+              (if (eq (symbol-package symbol) package)
+                  (%set-symbol-package symbol nil))
+              t)
+             (t nil))))))
 \f
 ;;; Take a symbol-or-list-of-symbols and return a list, checking types.
 (defun symbol-listify (thing)
 \f
 ;;; Take a symbol-or-list-of-symbols and return a list, checking types.
 (defun symbol-listify (thing)
        (t
         (error "~S is neither a symbol nor a list of symbols." thing))))
 
        (t
         (error "~S is neither a symbol nor a list of symbols." thing))))
 
+(defun string-listify (thing)
+  (mapcar #'string (if (listp thing) 
+                      thing 
+                      (list thing))))
+
 ;;; This is like UNINTERN, except if SYMBOL is inherited, it chases
 ;;; down the package it is inherited from and uninterns it there. Used
 ;;; for name-conflict resolution. Shadowing symbols are not uninterned
 ;;; This is like UNINTERN, except if SYMBOL is inherited, it chases
 ;;; down the package it is inherited from and uninterns it there. Used
 ;;; for name-conflict resolution. Shadowing symbols are not uninterned
        (declare (ignore s))
        (unless (or w (member sym syms))
          (push sym syms))))
        (declare (ignore s))
        (unless (or w (member sym syms))
          (push sym syms))))
-    ;; Find symbols and packages with conflicts.
-    (let ((used-by (package-%used-by-list package))
-         (cpackages ())
-         (cset ()))
-      (dolist (sym syms)
-       (let ((name (symbol-name sym)))
-         (dolist (p used-by)
-           (multiple-value-bind (s w) (find-symbol name p)
-             (when (and w (not (eq s sym))
-                        (not (member s (package-%shadowing-symbols p))))
-               (pushnew sym cset)
-               (pushnew p cpackages))))))
-      (when cset
-       (restart-case
-           (error
-            'simple-package-error
-            :package package
-            :format-control
-            "Exporting these symbols from the ~A package:~%~S~%~
-             results in name conflicts with these packages:~%~{~A ~}"
-            :format-arguments
-            (list (package-%name package) cset
-                  (mapcar #'package-%name cpackages)))
-         (unintern-conflicting-symbols ()
-          :report "Unintern conflicting symbols."
-          (dolist (p cpackages)
-            (dolist (sym cset)
-              (moby-unintern sym p))))
-         (skip-exporting-these-symbols ()
-          :report "Skip exporting conflicting symbols."
-          (setq syms (nset-difference syms cset))))))
-
-    ;; Check that all symbols are accessible. If not, ask to import them.
-    (let ((missing ())
-         (imports ()))
-      (dolist (sym syms)
-       (multiple-value-bind (s w) (find-symbol (symbol-name sym) package)
-         (cond ((not (and w (eq s sym)))
-                (push sym missing))
-               ((eq w :inherited)
-                (push sym imports)))))
-      (when missing
-       (with-simple-restart
-           (continue "Import these symbols into the ~A package."
-             (package-%name package))
-         (error 'simple-package-error
-                :package package
-                :format-control
-                "These symbols are not accessible in the ~A package:~%~S"
-                :format-arguments
-                (list (package-%name package) missing)))
-       (import missing package))
-      (import imports package))
-
-    ;; And now, three pages later, we export the suckers.
-    (let ((internal (package-internal-symbols package))
-         (external (package-external-symbols package)))
-      (dolist (sym syms)
-       (nuke-symbol internal (symbol-name sym))
-       (add-symbol external sym)))
-    t))
+    (with-single-package-locked-error ()
+      (when syms
+       (assert-package-unlocked package "exporting symbol~P ~{~A~^, ~}"
+                                (length syms) syms))
+      ;; Find symbols and packages with conflicts.
+      (let ((used-by (package-%used-by-list package))
+           (cpackages ())
+           (cset ()))
+       (dolist (sym syms)
+         (let ((name (symbol-name sym)))
+           (dolist (p used-by)
+             (multiple-value-bind (s w) (find-symbol name p)
+               (when (and w (not (eq s sym))
+                          (not (member s (package-%shadowing-symbols p))))
+                 (pushnew sym cset)
+                 (pushnew p cpackages))))))
+       (when cset
+         (restart-case
+             (error
+              'simple-package-error
+              :package package
+              :format-control
+              "Exporting these symbols from the ~A package:~%~S~%~
+               results in name conflicts with these packages:~%~{~A ~}"
+              :format-arguments
+              (list (package-%name package) cset
+                    (mapcar #'package-%name cpackages)))
+           (unintern-conflicting-symbols ()
+             :report "Unintern conflicting symbols."
+             (dolist (p cpackages)
+               (dolist (sym cset)
+                 (moby-unintern sym p))))
+           (skip-exporting-these-symbols ()
+             :report "Skip exporting conflicting symbols."
+             (setq syms (nset-difference syms cset))))))
+
+      ;; Check that all symbols are accessible. If not, ask to import them.
+      (let ((missing ())
+           (imports ()))
+       (dolist (sym syms)
+         (multiple-value-bind (s w) (find-symbol (symbol-name sym) package)
+           (cond ((not (and w (eq s sym)))
+                  (push sym missing))
+                 ((eq w :inherited)
+                  (push sym imports)))))
+       (when missing
+         (with-simple-restart
+             (continue "Import these symbols into the ~A package."
+                       (package-%name package))
+           (error 'simple-package-error
+                  :package package
+                  :format-control
+                  "These symbols are not accessible in the ~A package:~%~S"
+                  :format-arguments
+                  (list (package-%name package) missing)))
+         (import missing package))
+       (import imports package))
+
+      ;; And now, three pages later, we export the suckers.
+      (let ((internal (package-internal-symbols package))
+           (external (package-external-symbols package)))
+       (dolist (sym syms)
+         (nuke-symbol internal (symbol-name sym))
+         (add-symbol external sym))))
+      t))
 \f
 ;;; Check that all symbols are accessible, then move from external to internal.
 (defun unexport (symbols &optional (package (sane-package)))
 \f
 ;;; Check that all symbols are accessible, then move from external to internal.
 (defun unexport (symbols &optional (package (sane-package)))
                      :format-control "~S is not accessible in the ~A package."
                      :format-arguments (list sym (package-%name package))))
              ((eq w :external) (pushnew sym syms)))))
                      :format-control "~S is not accessible in the ~A package."
                      :format-arguments (list sym (package-%name package))))
              ((eq w :external) (pushnew sym syms)))))
-
-    (let ((internal (package-internal-symbols package))
-         (external (package-external-symbols package)))
-      (dolist (sym syms)
-       (add-symbol internal sym)
-       (nuke-symbol external (symbol-name sym))))
+    (with-single-package-locked-error ()
+      (when syms
+       (assert-package-unlocked package "unexporting symbol~P ~{~A~^, ~}"
+                                (length syms) syms))
+      (let ((internal (package-internal-symbols package))
+           (external (package-external-symbols package)))
+       (dolist (sym syms)
+         (add-symbol internal sym)
+         (nuke-symbol external (symbol-name sym)))))
     t))
 \f
 ;;; Check for name conflict caused by the import and let the user
     t))
 \f
 ;;; Check for name conflict caused by the import and let the user
   "Make Symbols accessible as internal symbols in Package. If a symbol
   is already accessible then it has no effect. If a name conflict
   would result from the importation, then a correctable error is signalled."
   "Make Symbols accessible as internal symbols in Package. If a symbol
   is already accessible then it has no effect. If a name conflict
   would result from the importation, then a correctable error is signalled."
-  (let ((package (find-undeleted-package-or-lose package))
-       (symbols (symbol-listify symbols))
-       (syms ())
-       (cset ()))
+  (let* ((package (find-undeleted-package-or-lose package))
+        (symbols (symbol-listify symbols))
+        (homeless (remove-if #'symbol-package symbols))
+        (syms ())
+        (cset ()))
     (dolist (sym symbols)
       (multiple-value-bind (s w) (find-symbol (symbol-name sym) package)
        (cond ((not w)
     (dolist (sym symbols)
       (multiple-value-bind (s w) (find-symbol (symbol-name sym) package)
        (cond ((not w)
                     (push sym syms))))
              ((not (eq s sym)) (push sym cset))
              ((eq w :inherited) (push sym syms)))))
                     (push sym syms))))
              ((not (eq s sym)) (push sym cset))
              ((eq w :inherited) (push sym syms)))))
-    (when cset
-      ;; ANSI specifies that this error is correctable.
-      (with-simple-restart
-         (continue "Import these symbols with Shadowing-Import.")
-       (error 'simple-package-error
-              :package package
-              :format-control
-              "Importing these symbols into the ~A package ~
+    (with-single-package-locked-error ()
+      (when (or homeless syms cset)
+       (let ((union (delete-duplicates (append homeless syms cset))))
+         (assert-package-unlocked package "importing symbol~P ~{~A~^, ~}" 
+                                  (length union) union)))
+      (when cset
+       ;; ANSI specifies that this error is correctable.
+       (with-simple-restart
+           (continue "Import these symbols with Shadowing-Import.")
+         (error 'simple-package-error
+                :package package
+                :format-control
+                "Importing these symbols into the ~A package ~
                causes a name conflict:~%~S"
                causes a name conflict:~%~S"
-              :format-arguments (list (package-%name package) cset))))
-    ;; Add the new symbols to the internal hashtable.
-    (let ((internal (package-internal-symbols package)))
-      (dolist (sym syms)
-       (add-symbol internal sym)))
-    ;; If any of the symbols are uninterned, make them be owned by Package.
-    (dolist (sym symbols)
-      (unless (symbol-package sym) (%set-symbol-package sym package)))
-    (shadowing-import cset package)))
+                :format-arguments (list (package-%name package) cset))))
+      ;; Add the new symbols to the internal hashtable.
+      (let ((internal (package-internal-symbols package)))
+       (dolist (sym syms)
+         (add-symbol internal sym)))
+      ;; If any of the symbols are uninterned, make them be owned by Package.
+      (dolist (sym homeless)
+       (%set-symbol-package sym package))
+      (shadowing-import cset package))))
 \f
 ;;; If a conflicting symbol is present, unintern it, otherwise just
 ;;; stick the symbol in.
 \f
 ;;; If a conflicting symbol is present, unintern it, otherwise just
 ;;; stick the symbol in.
   a symbol of the same name is present, then it is uninterned.
   The symbols are added to the Package-Shadowing-Symbols."
   (let* ((package (find-undeleted-package-or-lose package))
   a symbol of the same name is present, then it is uninterned.
   The symbols are added to the Package-Shadowing-Symbols."
   (let* ((package (find-undeleted-package-or-lose package))
-        (internal (package-internal-symbols package)))
-    (dolist (sym (symbol-listify symbols))
-      (multiple-value-bind (s w) (find-symbol (symbol-name sym) package)
-       (unless (and w (not (eq w :inherited)) (eq s sym))
-         (when (or (eq w :internal) (eq w :external))
-           ;; If it was shadowed, we don't want UNINTERN to flame out...
-           (setf (package-%shadowing-symbols package)
-                 (remove s (the list (package-%shadowing-symbols package))))
-           (unintern s package))
-         (add-symbol internal sym))
-       (pushnew sym (package-%shadowing-symbols package)))))
+        (internal (package-internal-symbols package))
+        (symbols (symbol-listify symbols))
+        (lock-asserted-p nil))
+    (with-single-package-locked-error ()
+      (dolist (sym symbols)
+       (multiple-value-bind (s w) (find-symbol (symbol-name sym) package)
+         (unless (or lock-asserted-p 
+                     (and (eq s sym) 
+                          (member s (package-shadowing-symbols package))))
+           (assert-package-unlocked package "shadowing-importing symbol~P ~
+                                           ~{~A~^, ~}" (length symbols) symbols)
+           (setf lock-asserted-p t))
+         (unless (and w (not (eq w :inherited)) (eq s sym))
+           (when (or (eq w :internal) (eq w :external))
+             ;; If it was shadowed, we don't want UNINTERN to flame out...
+             (setf (package-%shadowing-symbols package)
+                   (remove s (the list (package-%shadowing-symbols package))))
+             (unintern s package))
+           (add-symbol internal sym))
+         (pushnew sym (package-%shadowing-symbols package))))))
   t)
 
 (defun shadow (symbols &optional (package (sane-package)))
   t)
 
 (defun shadow (symbols &optional (package (sane-package)))
   the existing symbol is placed in the shadowing symbols list if it is
   not already present."
   (let* ((package (find-undeleted-package-or-lose package))
   the existing symbol is placed in the shadowing symbols list if it is
   not already present."
   (let* ((package (find-undeleted-package-or-lose package))
-        (internal (package-internal-symbols package)))
-    (dolist (name (mapcar #'string
-                         (if (listp symbols) symbols (list symbols))))
-      (multiple-value-bind (s w) (find-symbol name package)
-       (when (or (not w) (eq w :inherited))
-         (setq s (make-symbol name))
-         (%set-symbol-package s package)
-         (add-symbol internal s))
-       (pushnew s (package-%shadowing-symbols package)))))
+        (internal (package-internal-symbols package))
+        (symbols (string-listify symbols))
+        (lock-asserted-p nil))
+    (flet ((present-p (w)
+            (and w (not (eq w :inherited)))))
+      (with-single-package-locked-error ()
+       (dolist (name symbols)
+         (multiple-value-bind (s w) (find-symbol name package)
+           (unless (or lock-asserted-p 
+                       (and (present-p w)
+                            (member s (package-shadowing-symbols package))))
+             (assert-package-unlocked package "shadowing symbol~P ~{~A~^, ~}"
+                                      (length symbols) symbols)
+             (setf lock-asserted-p t))
+           (unless (present-p w)
+             (setq s (make-symbol name))
+             (%set-symbol-package s package)
+             (add-symbol internal s))
+           (pushnew s (package-%shadowing-symbols package)))))))
   t)
 \f
 ;;; Do stuff to use a package, with all kinds of fun name-conflict checking.
   t)
 \f
 ;;; Do stuff to use a package, with all kinds of fun name-conflict checking.
        (package (find-undeleted-package-or-lose package)))
 
     ;; Loop over each package, USE'ing one at a time...
        (package (find-undeleted-package-or-lose package)))
 
     ;; Loop over each package, USE'ing one at a time...
-    (dolist (pkg packages)
-      (unless (member pkg (package-%use-list package))
-       (let ((cset ())
-             (shadowing-symbols (package-%shadowing-symbols package))
-             (use-list (package-%use-list package)))
-
-         ;;   If the number of symbols already accessible is less than the
-         ;; number to be inherited then it is faster to run the test the
-         ;; other way. This is particularly valuable in the case of
-         ;; a new package USEing Lisp.
-         (cond
-          ((< (+ (package-internal-symbol-count package)
-                 (package-external-symbol-count package)
-                 (let ((res 0))
-                   (dolist (p use-list res)
-                     (incf res (package-external-symbol-count p)))))
-              (package-external-symbol-count pkg))
-           (do-symbols (sym package)
-             (multiple-value-bind (s w)
-                 (find-external-symbol (symbol-name sym) pkg)
-               (when (and w (not (eq s sym))
-                          (not (member sym shadowing-symbols)))
-                 (push sym cset))))
-           (dolist (p use-list)
-             (do-external-symbols (sym p)
-               (multiple-value-bind (s w)
-                   (find-external-symbol (symbol-name sym) pkg)
-                 (when (and w (not (eq s sym))
-                            (not (member (find-symbol (symbol-name sym)
-                                                      package)
-                                         shadowing-symbols)))
-                   (push sym cset))))))
-          (t
-           (do-external-symbols (sym pkg)
-             (multiple-value-bind (s w)
-                 (find-symbol (symbol-name sym) package)
-               (when (and w (not (eq s sym))
-                          (not (member s shadowing-symbols)))
-                 (push s cset))))))
-
-         (when cset
-           (cerror
-            "Unintern the conflicting symbols in the ~2*~A package."
-            "Using package ~A results in name conflicts for these symbols:~%~
-              ~S"
-            (package-%name pkg) cset (package-%name package))
-           (dolist (s cset) (moby-unintern s package))))
-
-       (push pkg (package-%use-list package))
-       (push (package-external-symbols pkg) (cdr (package-tables package)))
-       (push package (package-%used-by-list pkg)))))
+    (with-single-package-locked-error ()
+      (dolist (pkg packages)
+       (unless (member pkg (package-%use-list package))
+         (assert-package-unlocked package "using package~P ~{~A~^, ~}"
+                                  (length packages) packages)
+         (let ((cset ())
+               (shadowing-symbols (package-%shadowing-symbols package))
+               (use-list (package-%use-list package)))
+         
+           ;;   If the number of symbols already accessible is less than the
+           ;; number to be inherited then it is faster to run the test the
+           ;; other way. This is particularly valuable in the case of
+           ;; a new package USEing Lisp.
+           (cond
+             ((< (+ (package-internal-symbol-count package)
+                    (package-external-symbol-count package)
+                    (let ((res 0))
+                      (dolist (p use-list res)
+                        (incf res (package-external-symbol-count p)))))
+                 (package-external-symbol-count pkg))
+              (do-symbols (sym package)
+                (multiple-value-bind (s w)
+                    (find-external-symbol (symbol-name sym) pkg)
+                  (when (and w (not (eq s sym))
+                             (not (member sym shadowing-symbols)))
+                    (push sym cset))))
+              (dolist (p use-list)
+                (do-external-symbols (sym p)
+                  (multiple-value-bind (s w)
+                      (find-external-symbol (symbol-name sym) pkg)
+                    (when (and w (not (eq s sym))
+                               (not (member (find-symbol (symbol-name sym)
+                                                         package)
+                                            shadowing-symbols)))
+                      (push sym cset))))))
+             (t
+              (do-external-symbols (sym pkg)
+                (multiple-value-bind (s w)
+                    (find-symbol (symbol-name sym) package)
+                  (when (and w (not (eq s sym))
+                             (not (member s shadowing-symbols)))
+                    (push s cset))))))
+
+           (when cset
+             (cerror
+              "Unintern the conflicting symbols in the ~2*~A package."
+              "Using package ~A results in name conflicts for these symbols:~%~
+                ~S"
+              (package-%name pkg) cset (package-%name package))
+             (dolist (s cset) (moby-unintern s package))))
+
+         (push pkg (package-%use-list package))
+         (push (package-external-symbols pkg) (cdr (package-tables package)))
+         (push package (package-%used-by-list pkg))))))
   t)
 
 (defun unuse-package (packages-to-unuse &optional (package (sane-package)))
   #!+sb-doc
   "Remove PACKAGES-TO-UNUSE from the USE list for PACKAGE."
   t)
 
 (defun unuse-package (packages-to-unuse &optional (package (sane-package)))
   #!+sb-doc
   "Remove PACKAGES-TO-UNUSE from the USE list for PACKAGE."
-  (let ((package (find-undeleted-package-or-lose package)))
-    (dolist (p (package-listify packages-to-unuse))
-      (setf (package-%use-list package)
-           (remove p (the list (package-%use-list package))))
-      (setf (package-tables package)
-           (delete (package-external-symbols p)
-                   (the list (package-tables package))))
-      (setf (package-%used-by-list p)
-           (remove package (the list (package-%used-by-list p)))))
+  (let ((package (find-undeleted-package-or-lose package))
+       (packages (package-listify packages-to-unuse)))
+    (with-single-package-locked-error ()
+      (dolist (p packages)
+       (when (member p (package-use-list package))
+         (assert-package-unlocked package "unusing package~P ~{~A~^, ~}"
+                                  (length packages) packages))
+       (setf (package-%use-list package)
+             (remove p (the list (package-%use-list package))))
+       (setf (package-tables package)
+             (delete (package-external-symbols p)
+                     (the list (package-tables package))))
+       (setf (package-%used-by-list p)
+             (remove package (the list (package-%used-by-list p))))))
     t))
 
 (defun find-all-symbols (string-or-symbol)
     t))
 
 (defun find-all-symbols (string-or-symbol)
index 95f125a..f523aa8 100644 (file)
 
 (in-package "SB-COLD")
 
 
 (in-package "SB-COLD")
 
+;;; FIXME: This is embarassing -- SBCL violates SBCL style-package locks
+;;; on the host lisp. Rather then find and fix all cases right now,
+;;; let's just remain self-hosting. The problems at least involve
+;;; a few defvars and local macros with names in the CL package.
+#+(and sbcl sb-package-locks)
+(dolist (p (list-all-packages))
+  (sb-ext:unlock-package p))
+
 ;;; prefixes for filename stems when cross-compiling. These are quite arbitrary
 ;;; (although of course they shouldn't collide with anything we don't want to
 ;;; write over). In particular, they can be either relative path names (e.g.
 ;;; prefixes for filename stems when cross-compiling. These are quite arbitrary
 ;;; (although of course they shouldn't collide with anything we don't want to
 ;;; write over). In particular, they can be either relative path names (e.g.
index f6892a9..bd355bf 100644 (file)
 \f
 ;;;; general warm init compilation policy
 
 \f
 ;;;; general warm init compilation policy
 
-
 (proclaim '(optimize (compilation-speed 1)
                     (debug #+sb-show 2 #-sb-show 1)
                     (inhibit-warnings 2)
                     (safety 2)
                     (space 1)
                     (speed 2)))
 (proclaim '(optimize (compilation-speed 1)
                     (debug #+sb-show 2 #-sb-show 1)
                     (inhibit-warnings 2)
                     (safety 2)
                     (space 1)
                     (speed 2)))
+
 \f
 ;;;; package hacking
 
 \f
 ;;;; package hacking
 
               "public: the default package for user code and data")
 #+sb-doc (setf (documentation (find-package "KEYWORD") t)
               "public: home of keywords")
               "public: the default package for user code and data")
 #+sb-doc (setf (documentation (find-package "KEYWORD") t)
               "public: home of keywords")
+\f
+
index ba5c68e..3a9e453 100644 (file)
              ,@(mapcar (lambda (name)
                          `(,name (gen-label)))
                        new-labels))
              ,@(mapcar (lambda (name)
                          `(,name (gen-label)))
                        new-labels))
-       (declare (ignorable ,vop-var ,seg-var))
+       (declare (ignorable ,vop-var ,seg-var)
+                ;; Must be done so that contribs and user code doing
+                ;; low-level stuff don't need to worry about this.
+                (disable-package-locks %%current-segment%% %%current-vop%%))
        (macrolet ((%%current-segment%% () '**current-segment**)
                   (%%current-vop%% () '**current-vop**))
        (macrolet ((%%current-segment%% () '**current-segment**)
                   (%%current-vop%% () '**current-vop**))
-        (symbol-macrolet (,@(when (or inherited-labels nested-labels)
-                              `((..inherited-labels.. ,nested-labels))))
-          ,@(mapcar (lambda (form)
-                      (if (label-name-p form)
-                          `(emit-label ,form)
-                          form))
-                    body)))))))
+          ;; KLUDGE: Some host lisps (CMUCL 18e Sparc at least)
+          ;; can't deal with this declaration, so disable it on host.
+          ;; Ditto for later ENABLE-PACKAGE-LOCKS %%C-S%% declaration.
+          #-sb-xc-host
+         (declare (enable-package-locks %%current-segment%% %%current-vop%%))
+         (symbol-macrolet (,@(when (or inherited-labels nested-labels)
+                                   `((..inherited-labels.. ,nested-labels))))
+             ,@(mapcar (lambda (form)
+                         (if (label-name-p form)
+                             `(emit-label ,form)
+                             form))
+                       body)))))))
 #+sb-xc-host
 (sb!xc:defmacro assemble ((&optional segment vop &key labels)
                          &body body
 #+sb-xc-host
 (sb!xc:defmacro assemble ((&optional segment vop &key labels)
                          &body body
        (declare (ignorable ,vop-var ,seg-var))
        (macrolet ((%%current-segment%% () '**current-segment**)
                   (%%current-vop%% () '**current-vop**))
        (declare (ignorable ,vop-var ,seg-var))
        (macrolet ((%%current-segment%% () '**current-segment**)
                   (%%current-vop%% () '**current-vop**))
-        (symbol-macrolet (,@(when (or inherited-labels nested-labels)
-                              `((..inherited-labels.. ,nested-labels))))
-          ,@(mapcar (lambda (form)
-                      (if (label-name-p form)
-                          `(emit-label ,form)
-                          form))
-                    body)))))))
+         (symbol-macrolet (,@(when (or inherited-labels nested-labels)
+                                   `((..inherited-labels.. ,nested-labels))))
+             ,@(mapcar (lambda (form)
+                         (if (label-name-p form)
+                             `(emit-label ,form)
+                             form))
+                       body)))))))
 
 (defmacro inst (&whole whole instruction &rest args &environment env)
   #!+sb-doc
 
 (defmacro inst (&whole whole instruction &rest args &environment env)
   #!+sb-doc
           ,@(when decls
               `((declare ,@decls)))
           (let ((,postits (segment-postits ,segment-name)))
           ,@(when decls
               `((declare ,@decls)))
           (let ((,postits (segment-postits ,segment-name)))
+            ;; Must be done so that contribs and user code doing
+            ;; low-level stuff don't need to worry about this.
+            (declare (disable-package-locks %%current-segment%%))
             (setf (segment-postits ,segment-name) nil)
             (macrolet ((%%current-segment%% ()
                          (error "You can't use INST without an ~
                                  ASSEMBLE inside emitters.")))
             (setf (segment-postits ,segment-name) nil)
             (macrolet ((%%current-segment%% ()
                          (error "You can't use INST without an ~
                                  ASSEMBLE inside emitters.")))
+               ;; KLUDGE: Some host lisps (CMUCL 18e Sparc at least)
+               ;; can't deal with this declaration, so disable it on host
+               ;; Ditto for earlier ENABLE-PACKAGE-LOCKS %%C-S%% %%C-V%%
+               ;; declaration.
+               #-sb-xc-host
+              (declare (enable-package-locks %%current-segment%%))
               ,@emitter))
           (values))
         (eval-when (:compile-toplevel :load-toplevel :execute)
               ,@emitter))
           (values))
         (eval-when (:compile-toplevel :load-toplevel :execute)
index 2a1ddce..322b06b 100644 (file)
@@ -14,6 +14,8 @@
 (/show0 "compiler-deftype.lisp 14")
 
 (defun %compiler-deftype (name expander &optional doc)
 (/show0 "compiler-deftype.lisp 14")
 
 (defun %compiler-deftype (name expander &optional doc)
+  (with-single-package-locked-error
+      (:symbol name "defining ~A as a type specifier"))
   (ecase (info :type :kind name)
     (:primitive
      (when *type-system-initialized*
   (ecase (info :type :kind name)
     (:primitive
      (when *type-system-initialized*
index d308bdd..43d22da 100644 (file)
 (defvar *current-component*)
 (defvar *delayed-ir1-transforms*)
 (defvar *handled-conditions*)
 (defvar *current-component*)
 (defvar *delayed-ir1-transforms*)
 (defvar *handled-conditions*)
+(defvar *disabled-package-locks*)
 (defvar *policy*)
 (defvar *dynamic-counts-tn*)
 (defvar *elsewhere*)
 (defvar *policy*)
 (defvar *dynamic-counts-tn*)
 (defvar *elsewhere*)
index d0f3312..77430a4 100644 (file)
   (values)
   ())
 (defknown style-warn (string &rest t) null ())
   (values)
   ())
 (defknown style-warn (string &rest t) null ())
+
index a2dccfd..5188227 100644 (file)
     (error "can't SETF COMPILER-MACRO-FUNCTION when ENV is non-NIL"))
   (when (eq (info :function :kind name) :special-form)
     (error "~S names a special form." name))
     (error "can't SETF COMPILER-MACRO-FUNCTION when ENV is non-NIL"))
   (when (eq (info :function :kind name) :special-form)
     (error "~S names a special form." name))
-  (setf (info :function :compiler-macro-function name) function)
-  function)
+  (with-single-package-locked-error 
+      (:symbol name "setting the compiler-macro-function of ~A")
+    (setf (info :function :compiler-macro-function name) function)
+    function))
 \f
 ;;;; a subset of DOCUMENTATION functionality for bootstrapping
 
 \f
 ;;;; a subset of DOCUMENTATION functionality for bootstrapping
 
index 3c65f27..fc91bee 100644 (file)
     (compiler-style-warn "duplicate definitions in ~S" definitions))
   (let* ((processed-definitions (mapcar definitionize-fun definitions))
          (*lexenv* (make-lexenv definitionize-keyword processed-definitions)))
     (compiler-style-warn "duplicate definitions in ~S" definitions))
   (let* ((processed-definitions (mapcar definitionize-fun definitions))
          (*lexenv* (make-lexenv definitionize-keyword processed-definitions)))
+    ;; I wonder how much of an compiler performance penalty this
+    ;; non-constant keyword is.
     (funcall fun definitionize-keyword processed-definitions)))
 
 ;;; Tweak LEXENV to include the DEFINITIONS from a MACROLET, then
     (funcall fun definitionize-keyword processed-definitions)))
 
 ;;; Tweak LEXENV to include the DEFINITIONS from a MACROLET, then
       (destructuring-bind (name arglist &body body) definition
         (unless (symbolp name)
           (fail "The local macro name ~S is not a symbol." name))
       (destructuring-bind (name arglist &body body) definition
         (unless (symbolp name)
           (fail "The local macro name ~S is not a symbol." name))
+       (when (fboundp name)
+         (with-single-package-locked-error
+             (:symbol name "binding ~A as a local macro")))
         (unless (listp arglist)
           (fail "The local macro argument list ~S is not a list."
                 arglist))
         (unless (listp arglist)
           (fail "The local macro argument list ~S is not a list."
                 arglist))
       (destructuring-bind (name expansion) definition
         (unless (symbolp name)
           (fail "The local symbol macro name ~S is not a symbol." name))
       (destructuring-bind (name expansion) definition
         (unless (symbolp name)
           (fail "The local symbol macro name ~S is not a symbol." name))
+       (when (or (boundp name) (eq (info :variable :kind name) :macro))
+         (with-single-package-locked-error
+             (:symbol name "binding ~A as a local symbol-macro")))
         (let ((kind (info :variable :kind name)))
           (when (member kind '(:special :constant))
             (fail "Attempt to bind a ~(~A~) variable with SYMBOL-MACROLET: ~S"
                   kind name)))
         (let ((kind (info :variable :kind name)))
           (when (member kind '(:special :constant))
             (fail "Attempt to bind a ~(~A~) variable with SYMBOL-MACROLET: ~S"
                   kind name)))
+       ;; A magical cons that MACROEXPAND-1 understands.
         `(,name . (MACRO . ,expansion))))))
 
 (defun funcall-in-symbol-macrolet-lexenv (definitions fun context)
         `(,name . (MACRO . ,expansion))))))
 
 (defun funcall-in-symbol-macrolet-lexenv (definitions fun context)
                 (vars var)
                 (names name)
                 (vals (second spec)))))))
                 (vars var)
                 (names name)
                 (vals (second spec)))))))
-
+    (dolist (name (names))
+      (when (eq (info :variable :kind name) :macro)
+       (with-single-package-locked-error
+           (:symbol name "lexically binding symbol-macro ~A"))))
     (values (vars) (vals))))
 
 (def-ir1-translator let ((bindings &body body) start next result)
     (values (vars) (vals))))
 
 (def-ir1-translator let ((bindings &body body) start next result)
                      ((next result)
                       (processing-decls (decls vars nil next result)
                         (let ((fun (ir1-convert-lambda-body
                      ((next result)
                       (processing-decls (decls vars nil next result)
                         (let ((fun (ir1-convert-lambda-body
-                                    forms vars
-                                    :debug-name (debug-namify "LET "
-                                                             bindings))))
+                                    forms
+                                    vars
+                                    :debug-name (debug-namify "LET S"
+                                                              bindings))))
                           (reference-leaf start ctran fun-lvar fun))
                         (values next result))))
             (ir1-convert-combination-args fun-lvar ctran next result values))))))
                           (reference-leaf start ctran fun-lvar fun))
                         (values next result))))
             (ir1-convert-combination-args fun-lvar ctran next result values))))))
       (parse-body body :doc-string-allowed nil)
     (multiple-value-bind (vars values) (extract-let-vars bindings 'let*)
       (processing-decls (decls vars nil start next)
       (parse-body body :doc-string-allowed nil)
     (multiple-value-bind (vars values) (extract-let-vars bindings 'let*)
       (processing-decls (decls vars nil start next)
-        (ir1-convert-aux-bindings start next result forms vars values)))))
+        (ir1-convert-aux-bindings start 
+                                  next 
+                                  result
+                                  forms
+                                  vars 
+                                  values)))))
 
 ;;; logic shared between IR1 translators for LOCALLY, MACROLET,
 ;;; and SYMBOL-MACROLET
 
 ;;; logic shared between IR1 translators for LOCALLY, MACROLET,
 ;;; and SYMBOL-MACROLET
 
       (let ((name (first def)))
        (check-fun-name name)
 
       (let ((name (first def)))
        (check-fun-name name)
+       (when (fboundp name)
+         (with-single-package-locked-error
+             (:symbol name "binding ~A as a local function")))
        (names name)
        (multiple-value-bind (forms decls) (parse-body (cddr def))
          (defs `(lambda ,(second def)
        (names name)
        (multiple-value-bind (forms decls) (parse-body (cddr def))
          (defs `(lambda ,(second def)
   (multiple-value-bind (forms decls)
       (parse-body body :doc-string-allowed nil)
     (multiple-value-bind (names defs)
   (multiple-value-bind (forms decls)
       (parse-body body :doc-string-allowed nil)
     (multiple-value-bind (names defs)
-       (extract-flet-vars definitions 'flet)
+        (extract-flet-vars definitions 'flet)
       (let ((fvars (mapcar (lambda (n d)
                              (ir1-convert-lambda d
                                                  :source-name n
       (let ((fvars (mapcar (lambda (n d)
                              (ir1-convert-lambda d
                                                  :source-name n
                            names defs)))
         (processing-decls (decls nil fvars next result)
           (let ((*lexenv* (make-lexenv :funs (pairlis names fvars))))
                            names defs)))
         (processing-decls (decls nil fvars next result)
           (let ((*lexenv* (make-lexenv :funs (pairlis names fvars))))
-            (ir1-convert-progn-body start next result forms)))))))
+            (ir1-convert-progn-body start 
+                                    next 
+                                    result
+                                    forms)))))))
 
 (def-ir1-translator labels ((definitions &body body) start next result)
   #!+sb-doc
 
 (def-ir1-translator labels ((definitions &body body) start next result)
   #!+sb-doc
   each other."
   (multiple-value-bind (forms decls) (parse-body body :doc-string-allowed nil)
     (multiple-value-bind (names defs)
   each other."
   (multiple-value-bind (forms decls) (parse-body body :doc-string-allowed nil)
     (multiple-value-bind (names defs)
-       (extract-flet-vars definitions 'labels)
-      (let* ( ;; dummy LABELS functions, to be used as placeholders
+        (extract-flet-vars definitions 'labels)
+      (let* (;; dummy LABELS functions, to be used as placeholders
              ;; during construction of real LABELS functions
              ;; during construction of real LABELS functions
-            (placeholder-funs (mapcar (lambda (name)
-                                        (make-functional
-                                         :%source-name name
-                                         :%debug-name (debug-namify
-                                                       "LABELS placeholder "
-                                                       name)))
-                                      names))
-            ;; (like PAIRLIS but guaranteed to preserve ordering:)
-            (placeholder-fenv (mapcar #'cons names placeholder-funs))
+             (placeholder-funs (mapcar (lambda (name)
+                                         (make-functional
+                                          :%source-name name
+                                          :%debug-name (debug-namify
+                                                        "LABELS placeholder "
+                                                        name)))
+                                       names))
+             ;; (like PAIRLIS but guaranteed to preserve ordering:)
+             (placeholder-fenv (mapcar #'cons names placeholder-funs))
              ;; the real LABELS functions, compiled in a LEXENV which
              ;; includes the dummy LABELS functions
              ;; the real LABELS functions, compiled in a LEXENV which
              ;; includes the dummy LABELS functions
-            (real-funs
-             (let ((*lexenv* (make-lexenv :funs placeholder-fenv)))
-               (mapcar (lambda (name def)
-                         (ir1-convert-lambda def
-                                             :source-name name
-                                             :debug-name (debug-namify
-                                                          "LABELS " name)
-                                             :allow-debug-catch-tag t))
-                       names defs))))
-
+             (real-funs
+              (let ((*lexenv* (make-lexenv :funs placeholder-fenv)))
+                (mapcar (lambda (name def)
+                          (ir1-convert-lambda def
+                                              :source-name name
+                                              :debug-name (debug-namify
+                                                           "LABELS " name)
+                                              :allow-debug-catch-tag t))
+                        names defs))))
+        
         ;; Modify all the references to the dummy function leaves so
         ;; that they point to the real function leaves.
         ;; Modify all the references to the dummy function leaves so
         ;; that they point to the real function leaves.
-       (loop for real-fun in real-funs and
-             placeholder-cons in placeholder-fenv do
-             (substitute-leaf real-fun (cdr placeholder-cons))
-             (setf (cdr placeholder-cons) real-fun))
-
+        (loop for real-fun in real-funs and
+              placeholder-cons in placeholder-fenv do
+              (substitute-leaf real-fun (cdr placeholder-cons))
+              (setf (cdr placeholder-cons) real-fun))
+        
         ;; Voila.
         ;; Voila.
-       (processing-decls (decls nil real-funs next result)
+        (processing-decls (decls nil real-funs next result)
           (let ((*lexenv* (make-lexenv
                            ;; Use a proper FENV here (not the
                            ;; placeholder used earlier) so that if the
                            ;; lexical environment is used for inline
                            ;; expansion we'll get the right functions.
                            :funs (pairlis names real-funs))))
           (let ((*lexenv* (make-lexenv
                            ;; Use a proper FENV here (not the
                            ;; placeholder used earlier) so that if the
                            ;; lexical environment is used for inline
                            ;; expansion we'll get the right functions.
                            :funs (pairlis names real-funs))))
-            (ir1-convert-progn-body start next result forms)))))))
+            (ir1-convert-progn-body start 
+                                    next 
+                                    result
+                                    forms)))))))
+
 \f
 ;;;; the THE special operator, and friends
 
 \f
 ;;;; the THE special operator, and friends
 
    (with-unique-names (exit-block)
      `(block ,exit-block
        (%within-cleanup
    (with-unique-names (exit-block)
      `(block ,exit-block
        (%within-cleanup
-           :catch
-           (%catch (%escape-fun ,exit-block) ,tag)
-         ,@body)))))
+        :catch (%catch (%escape-fun ,exit-block) ,tag)
+        ,@body)))))
 
 (def-ir1-translator unwind-protect
     ((protected &body cleanup) start next result)
 
 (def-ir1-translator unwind-protect
     ((protected &body cleanup) start next result)
index 37ddb42..22654d1 100644 (file)
     (collect ((restr nil cons)
              (new-vars nil cons))
       (dolist (var-name (rest decl))
     (collect ((restr nil cons)
              (new-vars nil cons))
       (dolist (var-name (rest decl))
+       (when (boundp var-name)
+         (with-single-package-locked-error
+              (:symbol var-name "declaring the type of ~A")))
        (let* ((bound-var (find-in-bindings vars var-name))
               (var (or bound-var
                        (lexenv-find var-name vars)
        (let* ((bound-var (find-in-bindings vars var-name))
               (var (or bound-var
                        (lexenv-find var-name vars)
   (let ((type (compiler-specifier-type spec)))
     (collect ((res nil cons))
       (dolist (name names)
   (let ((type (compiler-specifier-type spec)))
     (collect ((res nil cons))
       (dolist (name names)
+       (when (fboundp name)
+         (with-single-package-locked-error
+              (:symbol name "declaring the ftype of ~A")))
        (let ((found (find name fvars
                           :key #'leaf-source-name
                           :test #'equal)))
        (let ((found (find name fvars
                           :key #'leaf-source-name
                           :test #'equal)))
   (declare (list spec vars) (type lexenv res))
   (collect ((new-venv nil cons))
     (dolist (name (cdr spec))
   (declare (list spec vars) (type lexenv res))
   (collect ((new-venv nil cons))
     (dolist (name (cdr spec))
+      (with-single-package-locked-error
+          (:symbol name "declaring ~A special"))
       (let ((var (find-in-bindings vars name)))
        (etypecase var
          (cons
       (let ((var (find-in-bindings vars name)))
        (etypecase var
          (cons
        (dynamic-extent
        (process-dx-decl (cdr spec) vars)
         res)
        (dynamic-extent
        (process-dx-decl (cdr spec) vars)
         res)
+       ((disable-package-locks enable-package-locks)
+        (make-lexenv
+         :default res
+         :disabled-package-locks (process-package-lock-decl 
+                                  spec (lexenv-disabled-package-locks res))))
        (t
         (unless (info :declaration :recognized (first spec))
           (compiler-warn "unrecognized declaration ~S" raw-spec))
        (t
         (unless (info :declaration :recognized (first spec))
           (compiler-warn "unrecognized declaration ~S" raw-spec))
index 1f7cb2e..7600eeb 100644 (file)
                         (lambda (lexenv-lambda default))
                         (cleanup (lexenv-cleanup default))
                         (handled-conditions (lexenv-handled-conditions default))
                         (lambda (lexenv-lambda default))
                         (cleanup (lexenv-cleanup default))
                         (handled-conditions (lexenv-handled-conditions default))
+                        (disabled-package-locks 
+                         (lexenv-disabled-package-locks default))
                         (policy (lexenv-policy default)))
   (macrolet ((frob (var slot)
               `(let ((old (,slot default)))
                         (policy (lexenv-policy default)))
   (macrolet ((frob (var slot)
               `(let ((old (,slot default)))
      (frob blocks lexenv-blocks)
      (frob tags lexenv-tags)
      (frob type-restrictions lexenv-type-restrictions)
      (frob blocks lexenv-blocks)
      (frob tags lexenv-tags)
      (frob type-restrictions lexenv-type-restrictions)
-     lambda cleanup handled-conditions policy)))
+     lambda cleanup handled-conditions 
+     disabled-package-locks policy)))
 
 ;;; Makes a LEXENV, suitable for using in a MACROLET introduced
 ;;; macroexpander
 
 ;;; Makes a LEXENV, suitable for using in a MACROLET introduced
 ;;; macroexpander
      nil
      nil
      (lexenv-handled-conditions lexenv)
      nil
      nil
      (lexenv-handled-conditions lexenv)
+     (lexenv-disabled-package-locks lexenv)
      (lexenv-policy lexenv))))
 \f
 ;;;; flow/DFO/component hackery
      (lexenv-policy lexenv))))
 \f
 ;;;; flow/DFO/component hackery
index f89df35..d9d57f2 100644 (file)
@@ -27,7 +27,7 @@
                           (funs vars blocks tags
                                  type-restrictions
                                 lambda cleanup handled-conditions
                           (funs vars blocks tags
                                  type-restrictions
                                 lambda cleanup handled-conditions
-                                policy)))
+                                disabled-package-locks policy)))
   ;; an alist of (NAME . WHAT), where WHAT is either a FUNCTIONAL (a
   ;; local function), a DEFINED-FUN, representing an
   ;; INLINE/NOTINLINE declaration, or a list (MACRO . <function>) (a
   ;; an alist of (NAME . WHAT), where WHAT is either a FUNCTIONAL (a
   ;; local function), a DEFINED-FUN, representing an
   ;; INLINE/NOTINLINE declaration, or a list (MACRO . <function>) (a
@@ -64,6 +64,8 @@
   (cleanup nil)
   ;; condition types we handle with a handler around the compiler
   (handled-conditions *handled-conditions*)
   (cleanup nil)
   ;; condition types we handle with a handler around the compiler
   (handled-conditions *handled-conditions*)
+  ;; lexically disabled package locks (list of symbols)
+  (disabled-package-locks *disabled-package-locks*)
   ;; the current OPTIMIZE policy
   (policy *policy* :type policy))
 
   ;; the current OPTIMIZE policy
   (policy *policy* :type policy))
 
index 47b4c92..ff1bcce 100644 (file)
 (defun convert-and-maybe-compile (form path)
   (declare (list path))
   (let* ((*lexenv* (make-lexenv :policy *policy*
 (defun convert-and-maybe-compile (form path)
   (declare (list path))
   (let* ((*lexenv* (make-lexenv :policy *policy*
-                               :handled-conditions *handled-conditions*))
+                               :handled-conditions *handled-conditions*
+                               :disabled-package-locks *disabled-package-locks*))
         (tll (ir1-toplevel form path nil)))
     (cond ((eq *block-compile* t) (push tll *toplevel-lambdas*))
          (t (compile-toplevel (list tll) nil)))))
         (tll (ir1-toplevel form path nil)))
     (cond ((eq *block-compile* t) (push tll *toplevel-lambdas*))
          (t (compile-toplevel (list tll) nil)))))
           ;; issue a warning instead of silently screwing up.
           (*policy* (lexenv-policy *lexenv*))
           ;; This is probably also a hack
           ;; issue a warning instead of silently screwing up.
           (*policy* (lexenv-policy *lexenv*))
           ;; This is probably also a hack
-          (*handled-conditions* (lexenv-handled-conditions *lexenv*)))
+          (*handled-conditions* (lexenv-handled-conditions *lexenv*))
+          ;; ditto
+          (*disabled-package-locks* (lexenv-disabled-package-locks *lexenv*)))
       (process-toplevel-progn forms path compile-time-too))))
 
 ;;; Parse an EVAL-WHEN situations list, returning three flags,
       (process-toplevel-progn forms path compile-time-too))))
 
 ;;; Parse an EVAL-WHEN situations list, returning three flags,
   (when name
     (legal-fun-name-or-type-error name))
   (let* ((*lexenv* (make-lexenv :policy *policy*
   (when name
     (legal-fun-name-or-type-error name))
   (let* ((*lexenv* (make-lexenv :policy *policy*
-                               :handled-conditions *handled-conditions*))
+                               :handled-conditions *handled-conditions*
+                               :disabled-package-locks *disabled-package-locks*))
          (fun (make-functional-from-toplevel-lambda lambda-expression
                                                    :name name
                                                    :path path)))
          (fun (make-functional-from-toplevel-lambda lambda-expression
                                                    :name name
                                                    :path path)))
                      ((macrolet)
                       (funcall-in-macrolet-lexenv
                        magic
                      ((macrolet)
                       (funcall-in-macrolet-lexenv
                        magic
-                       (lambda (&key funs)
+                       (lambda (&key funs prepend)
                          (declare (ignore funs))
                          (declare (ignore funs))
+                        (aver (null prepend))
                          (process-toplevel-locally body
                                                    path
                                                    compile-time-too))
                          (process-toplevel-locally body
                                                    path
                                                    compile-time-too))
                      ((symbol-macrolet)
                       (funcall-in-symbol-macrolet-lexenv
                        magic
                      ((symbol-macrolet)
                       (funcall-in-symbol-macrolet-lexenv
                        magic
-                       (lambda (&key vars)
+                       (lambda (&key vars prepend)
+                        (aver (null prepend))
                          (process-toplevel-locally body
                                                    path
                                                    compile-time-too
                          (process-toplevel-locally body
                                                    path
                                                    compile-time-too
 
         (*policy* *policy*)
        (*handled-conditions* *handled-conditions*)
 
         (*policy* *policy*)
        (*handled-conditions* *handled-conditions*)
+       (*disabled-package-locks* *disabled-package-locks*)
         (*lexenv* (make-null-lexenv))
         (*block-compile* *block-compile-arg*)
         (*source-info* info)
         (*lexenv* (make-null-lexenv))
         (*block-compile* *block-compile-arg*)
         (*source-info* info)
index 47becfd..d3bfe86 100644 (file)
@@ -73,8 +73,9 @@
                  (cons name 1))
                *policy-qualities*))
   ;; not actually POLICY, but very similar
                  (cons name 1))
                *policy-qualities*))
   ;; not actually POLICY, but very similar
-  (setf *handled-conditions* nil))
-  
+  (setf *handled-conditions* nil
+       *disabled-package-locks* nil))
+
 ;;; On the cross-compilation host, we initialize immediately (not
 ;;; waiting for "cold init", since cold init doesn't exist on
 ;;; cross-compilation host).
 ;;; On the cross-compilation host, we initialize immediately (not
 ;;; waiting for "cold init", since cold init doesn't exist on
 ;;; cross-compilation host).
index d189c90..a26b2a4 100644 (file)
         (mapcar (lambda (x) (list x 'muffle-warning)) (cdr spec)))
    list))
 
         (mapcar (lambda (x) (list x 'muffle-warning)) (cdr spec)))
    list))
 
+(declaim (ftype (function (list list) list)
+                process-package-lock-decl))
+(defun process-package-lock-decl (spec old)
+  (let ((decl (car spec))
+        (list (cdr spec)))
+    (ecase decl
+      (disable-package-locks
+       (union old list :test #'equal))
+      (enable-package-locks
+       (set-difference old list :test #'equal)))))
+
 ;;; ANSI defines the declaration (FOO X Y) to be equivalent to
 ;;; (TYPE FOO X Y) when FOO is a type specifier. This function
 ;;; implements that by converting (FOO X Y) to (TYPE FOO X Y).
 ;;; ANSI defines the declaration (FOO X Y) to be equivalent to
 ;;; (TYPE FOO X Y) when FOO is a type specifier. This function
 ;;; implements that by converting (FOO X Y) to (TYPE FOO X Y).
           (error "can't declare a non-symbol as SPECIAL: ~S" name))
         (when (constantp name)
           (error "can't declare a constant as SPECIAL: ~S" name))
           (error "can't declare a non-symbol as SPECIAL: ~S" name))
         (when (constantp name)
           (error "can't declare a constant as SPECIAL: ~S" name))
+        (with-single-package-locked-error
+             (:symbol name "globally declaraing ~A special"))
         (clear-info :variable :constant-value name)
         (setf (info :variable :kind name) :special)))
       (type
         (clear-info :variable :constant-value name)
         (setf (info :variable :kind name) :special)))
       (type
             (dolist (name (rest args))
               (unless (symbolp name)
                 (error "can't declare TYPE of a non-symbol: ~S" name))
             (dolist (name (rest args))
               (unless (symbolp name)
                 (error "can't declare TYPE of a non-symbol: ~S" name))
+              (with-single-package-locked-error
+                   (:symbol name "globally declaring the type of ~A"))
               (when (eq (info :variable :where-from name) :declared)
                 (let ((old-type (info :variable :type name)))
                   (when (type/= type old-type)
               (when (eq (info :variable :where-from name) :declared)
                 (let ((old-type (info :variable :type name)))
                   (when (type/= type old-type)
             (unless (csubtypep ctype (specifier-type 'function))
               (error "not a function type: ~S" (first args)))
             (dolist (name (rest args))
             (unless (csubtypep ctype (specifier-type 'function))
               (error "not a function type: ~S" (first args)))
             (dolist (name (rest args))
+              (with-single-package-locked-error
+                   (:symbol name "globally declaring the ftype of ~A"))
                (when (eq (info :function :where-from name) :declared)
                  (let ((old-type (info :function :type name)))
                    (when (type/= ctype old-type)
                (when (eq (info :function :where-from name) :declared)
                  (let ((old-type (info :function :type name)))
                    (when (type/= ctype old-type)
       (unmuffle-conditions
        (setq *handled-conditions*
             (process-unmuffle-conditions-decl form *handled-conditions*)))
       (unmuffle-conditions
        (setq *handled-conditions*
             (process-unmuffle-conditions-decl form *handled-conditions*)))
+      ((disable-package-locks enable-package-locks)
+         (setq *disabled-package-locks*
+               (process-package-lock-decl form *disabled-package-locks*)))
       ((inline notinline maybe-inline)
        (dolist (name args)
         (proclaim-as-fun-name name) ; since implicitly it is a function
       ((inline notinline maybe-inline)
        (dolist (name args)
         (proclaim-as-fun-name name) ; since implicitly it is a function
           (error "In~%  ~S~%the declaration to be recognized is not a ~
                   symbol:~%  ~S"
                  form decl))
           (error "In~%  ~S~%the declaration to be recognized is not a ~
                   symbol:~%  ~S"
                  form decl))
+        (with-single-package-locked-error
+             (:symbol decl "globally declaring ~A as a declaration proclamation"))
         (setf (info :declaration :recognized decl) t)))
       (t
        (unless (info :declaration :recognized kind)
         (setf (info :declaration :recognized decl) t)))
       (t
        (unless (info :declaration :recognized kind)
index b031250..8a1cffb 100644 (file)
@@ -72,6 +72,8 @@
             (*policy* (lexenv-policy *lexenv*))
             ;; see above
             (*handled-conditions* (lexenv-handled-conditions *lexenv*))
             (*policy* (lexenv-policy *lexenv*))
             ;; see above
             (*handled-conditions* (lexenv-handled-conditions *lexenv*))
+            ;; ditto
+            (*disabled-package-locks* (lexenv-disabled-package-locks *lexenv*))
             ;; FIXME: ANSI doesn't say anything about CL:COMPILE
             ;; interacting with these variables, so we shouldn't. As
             ;; of SBCL 0.6.7, COMPILE-FILE controls its verbosity by
             ;; FIXME: ANSI doesn't say anything about CL:COMPILE
             ;; interacting with these variables, so we shouldn't. As
             ;; of SBCL 0.6.7, COMPILE-FILE controls its verbosity by
index e88a9de..e89443f 100644 (file)
@@ -437,14 +437,14 @@ bootstrapping.
               (mname `(,(if (eq (cadr initargs-form) :function)
                             'method 'fast-method)
                        ,name ,@qualifiers ,specls))
               (mname `(,(if (eq (cadr initargs-form) :function)
                             'method 'fast-method)
                        ,name ,@qualifiers ,specls))
-              (mname-sym (intern (let ((*print-pretty* nil)
-                                       ;; (We bind *PACKAGE* to
-                                       ;; KEYWORD here as a way to
-                                       ;; force symbols to be printed
-                                       ;; with explicit package
-                                       ;; prefixes.)
-                                       (*package* *keyword-package*))
-                                   (format nil "~S" mname)))))
+              (mname-sym (let ((*print-pretty* nil)
+                               ;; (We bind *PACKAGE* to KEYWORD here
+                               ;; as a way to force symbols to be
+                               ;; printed with explicit package
+                               ;; prefixes.)
+                               (target *package*)
+                               (*package* *keyword-package*))
+                           (format-symbol target "~S" mname))))
          `(progn
             (defun ,mname-sym ,(cadr fn-lambda)
               ,@(cddr fn-lambda))
          `(progn
             (defun ,mname-sym ,(cadr fn-lambda)
               ,@(cddr fn-lambda))
@@ -460,7 +460,7 @@ bootstrapping.
         `(list ,@(mapcar (lambda (specializer)
                            (if (consp specializer)
                                ``(,',(car specializer)
         `(list ,@(mapcar (lambda (specializer)
                            (if (consp specializer)
                                ``(,',(car specializer)
-                                  ,,(cadr specializer))
+                                     ,,(cadr specializer))
                                `',specializer))
                          specializers))
         unspecialized-lambda-list
                                `',specializer))
                          specializers))
         unspecialized-lambda-list
@@ -1428,10 +1428,10 @@ bootstrapping.
                                   ;; failing that, to use a special
                                   ;; symbol prefix denoting privateness.
                                   ;; -- WHN 19991201
                                   ;; failing that, to use a special
                                   ;; symbol prefix denoting privateness.
                                   ;; -- WHN 19991201
-                                  (intern (format nil "FAST-~A"
-                                                  (car method-spec))
-                                          *pcl-package*)))
-                        ,@(cdr method-spec))))
+                                  (format-symbol *pcl-package*
+                                                 "FAST-~A" 
+                                                 (car method-spec))))
+                       ,@(cdr method-spec))))
            (set-fun-name mff name)
            (unless mf
              (set-mf-property :name name)))))
            (set-fun-name mff name)
            (unless mf
              (set-mf-property :name name)))))
@@ -1939,7 +1939,7 @@ bootstrapping.
     (let ((method-class (getf ,all-keys :method-class '.shes-not-there.)))
       (unless (eq method-class '.shes-not-there.)
         (setf (getf ,all-keys :method-class)
     (let ((method-class (getf ,all-keys :method-class '.shes-not-there.)))
       (unless (eq method-class '.shes-not-there.)
         (setf (getf ,all-keys :method-class)
-                (find-class method-class t ,env))))))
+             (find-class method-class t ,env))))))
 
 (defun real-ensure-gf-using-class--generic-function
        (existing
 
 (defun real-ensure-gf-using-class--generic-function
        (existing
index 9e65da9..9aec60e 100644 (file)
@@ -97,8 +97,7 @@
 (defmacro !initial-classes-and-wrappers (&rest classes)
   `(progn
      ,@(mapcar (lambda (class)
 (defmacro !initial-classes-and-wrappers (&rest classes)
   `(progn
      ,@(mapcar (lambda (class)
-                (let ((wr (intern (format nil "~A-WRAPPER" class)
-                                  *pcl-package*)))
+                (let ((wr (format-symbol *pcl-package* "~A-WRAPPER" class)))
                   `(setf ,wr ,(if (eq class 'standard-generic-function)
                                   '*sgf-wrapper*
                                   `(boot-make-wrapper
                   `(setf ,wr ,(if (eq class 'standard-generic-function)
                                   '*sgf-wrapper*
                                   `(boot-make-wrapper
                                   (boot-make-wrapper (length slots) name))))
                   (proto nil))
              (when (eq name t) (setq *the-wrapper-of-t* wrapper))
                                   (boot-make-wrapper (length slots) name))))
                   (proto nil))
              (when (eq name t) (setq *the-wrapper-of-t* wrapper))
-             (set (intern (format nil "*THE-CLASS-~A*" (symbol-name name))
-                          *pcl-package*)
-                  class)
+             (set (make-class-symbol name) class)
              (dolist (slot slots)
                (unless (eq (getf slot :allocation :instance) :instance)
                  (error "Slot allocation ~S is not supported in bootstrap."
              (dolist (slot slots)
                (unless (eq (getf slot :allocation :instance) :instance)
                  (error "Slot allocation ~S is not supported in bootstrap."
index 766e7e7..b3e44d3 100644 (file)
 
 (defun dfun-arg-symbol (arg-number)
   (or (nth arg-number (the list *dfun-arg-symbols*))
 
 (defun dfun-arg-symbol (arg-number)
   (or (nth arg-number (the list *dfun-arg-symbols*))
-      (intern (format nil ".ARG~A." arg-number) *pcl-package*)))
+      (format-symbol *pcl-package* ".ARG~A." arg-number)))
 
 (defvar *slot-vector-symbols* '(.SLOTS0. .SLOTS1. .SLOTS2. .SLOTS3.))
 
 (defun slot-vector-symbol (arg-number)
   (or (nth arg-number (the list *slot-vector-symbols*))
 
 (defvar *slot-vector-symbols* '(.SLOTS0. .SLOTS1. .SLOTS2. .SLOTS3.))
 
 (defun slot-vector-symbol (arg-number)
   (or (nth arg-number (the list *slot-vector-symbols*))
-      (intern (format nil ".SLOTS~A." arg-number) *pcl-package*)))
+      (format-symbol *pcl-package* ".SLOTS~A." arg-number)))
 
 ;; FIXME: There ought to be a good way to factor out the idiom:
 ;;
 
 ;; FIXME: There ought to be a good way to factor out the idiom:
 ;;
index 31141b4..a4d72a4 100644 (file)
 
 (defun get-effective-method-gensym ()
   (or (pop *rebound-effective-method-gensyms*)
 
 (defun get-effective-method-gensym ()
   (or (pop *rebound-effective-method-gensyms*)
-      (let ((new (intern (format nil
-                                "EFFECTIVE-METHOD-GENSYM-~D"
-                                (length *global-effective-method-gensyms*))
-                        *pcl-package*)))
+      (let ((new (format-symbol *pcl-package*
+                               "EFFECTIVE-METHOD-GENSYM-~D"
+                               (length *global-effective-method-gensyms*))))
        (setq *global-effective-method-gensyms*
              (append *global-effective-method-gensyms* (list new)))
        new)))
        (setq *global-effective-method-gensyms*
              (append *global-effective-method-gensyms* (list new)))
        new)))
index ca88083..5a3dd01 100644 (file)
        (*print-case* :upcase)
        (*print-pretty* nil)
        (*print-gensym* t))
        (*print-case* :upcase)
        (*print-pretty* nil)
        (*print-gensym* t))
-    (intern (format nil "CTOR ~S::~S ~S ~S"
-                   (package-name (symbol-package class-name))
-                   (symbol-name class-name)
-                   (plist-keys initargs)
-                   (plist-values initargs :test #'constantp))
-           *pcl-package*)))
+    (format-symbol *pcl-package* "CTOR ~S::~S ~S ~S"
+                  (package-name (symbol-package class-name))
+                  (symbol-name class-name)
+                  (plist-keys initargs)
+                  (plist-values initargs :test #'constantp))))
 
 ;;;
 ;;; Keep this a separate function for testing.
 
 ;;;
 ;;; Keep this a separate function for testing.
 ;;; Keep this a separate function for testing.
 ;;;
 (defun make-ctor (function-name class-name initargs)
 ;;; Keep this a separate function for testing.
 ;;;
 (defun make-ctor (function-name class-name initargs)
-  (let ((ctor (%make-ctor function-name class-name nil initargs)))
-    (push ctor *all-ctors*)
-    (setf (symbol-function function-name) ctor)
-    (install-initial-constructor ctor :force-p t)
-    ctor))
+  (without-package-locks ; for (setf symbol-function)
+   (let ((ctor (%make-ctor function-name class-name nil initargs)))
+     (push ctor *all-ctors*)
+     (setf (symbol-function function-name) ctor)
+     (install-initial-constructor ctor :force-p t)
+     ctor)))
 
 \f
 ;;; ***********************************************
 
 \f
 ;;; ***********************************************
             (let ((ps #(.p0. .p1. .p2. .p3. .p4. .p5.)))
               (if (array-in-bounds-p ps i)
                   (aref ps i)
             (let ((ps #(.p0. .p1. .p2. .p3. .p4. .p5.)))
               (if (array-in-bounds-p ps i)
                   (aref ps i)
-                  (intern (format nil ".P~D." i) *pcl-package*))))
+                  (format-symbol *pcl-package* ".P~D." i))))
           ;;
           ;; Check if CLASS-NAME is a constant symbol.  Give up if
           ;; not.
           ;;
           ;; Check if CLASS-NAME is a constant symbol.  Give up if
           ;; not.
          ;; Return code constructing a ctor at load time, which, when
          ;; called, will set its funcallable instance function to an
          ;; optimized constructor function.
          ;; Return code constructing a ctor at load time, which, when
          ;; called, will set its funcallable instance function to an
          ;; optimized constructor function.
-         `(let ((.x. (load-time-value
-                      (ensure-ctor ',function-name ',class-name ',initargs))))
-            (declare (ignore .x.))
-            ;;; ??? check if this is worth it.
-            (declare
-             (ftype (or (function ,(make-list (length value-forms)
-                                              :initial-element t)
-                                  t)
-                        (function (&rest t) t))
-                    ,function-name))
-            (,function-name ,@value-forms)))))))
+         `(locally 
+              (declare (disable-package-locks ,function-name))
+           (let ((.x. (load-time-value
+                       (ensure-ctor ',function-name ',class-name ',initargs))))
+             (declare (ignore .x.))
+             ;; ??? check if this is worth it.
+             (declare
+              (ftype (or (function ,(make-list (length value-forms)
+                                               :initial-element t)
+                                   t)
+                         (function (&rest t) t))
+                     ,function-name))
+             (,function-name ,@value-forms))))))))
 
 \f
 ;;; **************************************************
 
 \f
 ;;; **************************************************
               (let ((ps #(.d0. .d1. .d2. .d3. .d4. .d5.)))
                 (if (array-in-bounds-p ps i)
                     (aref ps i)
               (let ((ps #(.d0. .d1. .d2. .d3. .d4. .d5.)))
                 (if (array-in-bounds-p ps i)
                     (aref ps i)
-                    (intern (format nil ".D~D." i) *pcl-package*)))))
+                    (format-symbol *pcl-package* ".D~D." i)))))
       ;; Loop over supplied initargs and values and record which
       ;; instance and class slots they initialize.
       (loop for (key value) on initargs by #'cddr
       ;; Loop over supplied initargs and values and record which
       ;; instance and class slots they initialize.
       (loop for (key value) on initargs by #'cddr
                      (if (consp location)
                          (class-init location 'param value)
                          (instance-init location 'param value)))))
                      (if (consp location)
                          (class-init location 'param value)
                          (instance-init location 'param value)))))
+      ;;
       ;; Loop over default initargs of the class, recording
       ;; initializations of slots that have not been initialized
       ;; above.  Default initargs which are not in the supplied
       ;; initargs are treated as if they were appended to supplied
       ;; initargs, that is, their values must be evaluated even
       ;; if not actually used for initializing a slot.
       ;; Loop over default initargs of the class, recording
       ;; initializations of slots that have not been initialized
       ;; above.  Default initargs which are not in the supplied
       ;; initargs are treated as if they were appended to supplied
       ;; initargs, that is, their values must be evaluated even
       ;; if not actually used for initializing a slot.
+      ;;
       (loop for (key initfn initform) in default-initargs and i from 0
            unless (member key initkeys :test #'eq) do
       (loop for (key initfn initform) in default-initargs and i from 0
            unless (member key initkeys :test #'eq) do
-             (let* ((type (if (constantp initform) 'constant 'var))
-                    (init (if (eq type 'var) initfn initform)))
-               (when (eq type 'var)
-                 (let ((init-var (default-init-var-name i)))
-                   (setq init init-var)
-                   (push (cons init-var initfn) default-inits)))
-               (dolist (location (initarg-locations key))
-                 (if (consp location)
-                     (class-init location type init)
-                     (instance-init location type init)))))
+           (let* ((type (if (constantp initform) 'constant 'var))
+                  (init (if (eq type 'var) initfn initform)))
+             (when (eq type 'var)
+               (let ((init-var (default-init-var-name i)))
+                 (setq init init-var)
+                 (push (cons init-var initfn) default-inits)))
+             (dolist (location (initarg-locations key))
+               (if (consp location)
+                   (class-init location type init)
+                   (instance-init location type init)))))
       ;; Loop over all slots of the class, filling in the rest from
       ;; slot initforms.
       (loop for slotd in (class-slots class)
       ;; Loop over all slots of the class, filling in the rest from
       ;; slot initforms.
       (loop for slotd in (class-slots class)
index 87b2c1e..f525d4a 100644 (file)
                                         mclass
                                         *the-class-structure-class*))))))
           (let ((defclass-form
                                         mclass
                                         *the-class-structure-class*))))))
           (let ((defclass-form
-                 `(progn
-                    (let ,(mapcar #'cdr *initfunctions-for-this-defclass*)
-                      (%compiler-defclass ',name
-                                          ',*readers-for-this-defclass*
-                                          ',*writers-for-this-defclass*
-                                          ',*slot-names-for-this-defclass*)
-                      (load-defclass ',name
-                                     ',metaclass
-                                     ',supers
-                                     (list ,@canonical-slots)
-                                     (list ,@(apply #'append
-                                                    (when defstruct-p
-                                                      '(:from-defclass-p t))
-                                                    other-initargs)))))))
+                   `(progn
+                     (let ,(mapcar #'cdr *initfunctions-for-this-defclass*)
+                       (with-single-package-locked-error
+                           (:symbol ',name "defining ~A as a class")
+                         (%compiler-defclass ',name
+                                             ',*readers-for-this-defclass*
+                                             ',*writers-for-this-defclass*
+                                             ',*slot-names-for-this-defclass*)
+                         (load-defclass ',name
+                                        ',metaclass
+                                        ',supers
+                                        (list ,@canonical-slots)
+                                        (list ,@(apply #'append
+                                                       (when defstruct-p
+                                                         '(:from-defclass-p t))
+                                                       other-initargs))))))))
             (if defstruct-p
                (progn
                  ;; FIXME: (YUK!) Why do we do this? Because in order
             (if defstruct-p
                (progn
                  ;; FIXME: (YUK!) Why do we do this? Because in order
                                      (and (not (eq name 'structure-object))
                                           *the-class-structure-object*)))
                         (defstruct-form (make-structure-class-defstruct-form
                                      (and (not (eq name 'structure-object))
                                           *the-class-structure-object*)))
                         (defstruct-form (make-structure-class-defstruct-form
-                                         name (class-direct-slots (find-class name)) include)))
+                                         name (class-direct-slots (find-class name))
+                                         include)))
                    `(progn
                      (eval-when (:compile-toplevel :load-toplevel :execute)
                        ,defstruct-form) ; really compile the defstruct-form
                    `(progn
                      (eval-when (:compile-toplevel :load-toplevel :execute)
                        ,defstruct-form) ; really compile the defstruct-form
                     ,defclass-form)))))))))
 
 (defun %compiler-defclass (name readers writers slot-names)
                     ,defclass-form)))))))))
 
 (defun %compiler-defclass (name readers writers slot-names)
-  (preinform-compiler-about-class-type name)
-  (proclaim `(ftype (function (t) t)
-             ,@readers
-             ,@(mapcar #'slot-reader-name slot-names)
-             ,@(mapcar #'slot-boundp-name slot-names)))
-  (proclaim `(ftype (function (t t) t)
-             ,@writers ,@(mapcar #'slot-writer-name slot-names))))
+  (with-single-package-locked-error (:symbol name "defining ~A as a class")
+    (preinform-compiler-about-class-type name)
+    (proclaim `(ftype (function (t) t)
+               ,@readers
+               ,@(mapcar #'slot-reader-name slot-names)
+               ,@(mapcar #'slot-boundp-name slot-names)))
+    (proclaim `(ftype (function (t t) t)
+               ,@writers ,@(mapcar #'slot-writer-name slot-names)))))
 
 (defun make-initfunction (initform)
   (cond ((or (eq initform t)
 
 (defun make-initfunction (initform)
   (cond ((or (eq initform t)
index 8b71ed4..060f4a0 100644 (file)
 \f
 (defmacro define-method-combination (&whole form &rest args)
   (declare (ignore args))
 \f
 (defmacro define-method-combination (&whole form &rest args)
   (declare (ignore args))
-  (if (and (cddr form)
-          (listp (caddr form)))
-      (expand-long-defcombin form)
-      (expand-short-defcombin form)))
+  `(progn
+     (with-single-package-locked-error
+        (:symbol ',(second form) "defining ~A as a method combination"))
+     ,(if (and (cddr form)
+              (listp (caddr form)))
+         (expand-long-defcombin form)
+         (expand-short-defcombin form))))
 \f
 ;;;; standard method combination
 
 \f
 ;;;; standard method combination
 
index c0bff27..f247747 100644 (file)
 
 (defun get-built-in-class-symbol (class-name)
   (or (cadr (assq class-name *built-in-class-symbols*))
 
 (defun get-built-in-class-symbol (class-name)
   (or (cadr (assq class-name *built-in-class-symbols*))
-      (let ((symbol (intern (format nil
-                                   "*THE-CLASS-~A*"
-                                   (symbol-name class-name))
-                           *pcl-package*)))
+      (let ((symbol (make-class-symbol class-name)))
        (push (list class-name symbol) *built-in-class-symbols*)
        symbol)))
 
 (defun get-built-in-wrapper-symbol (class-name)
   (or (cadr (assq class-name *built-in-wrapper-symbols*))
        (push (list class-name symbol) *built-in-class-symbols*)
        symbol)))
 
 (defun get-built-in-wrapper-symbol (class-name)
   (or (cadr (assq class-name *built-in-wrapper-symbols*))
-      (let ((symbol (intern (format nil
-                                   "*THE-WRAPPER-OF-~A*"
-                                   (symbol-name class-name))
-                           *pcl-package*)))
+      (let ((symbol (make-wrapper-symbol class-name)))
        (push (list class-name symbol) *built-in-wrapper-symbols*)
        symbol)))
 \f
        (push (list class-name symbol) *built-in-wrapper-symbols*)
        symbol)))
 \f
index e6de19f..6b388e4 100644 (file)
         (wrapper-bindings (mapcan (lambda (arg mt)
                                     (unless (eq mt t)
                                       (incf index)
         (wrapper-bindings (mapcan (lambda (arg mt)
                                     (unless (eq mt t)
                                       (incf index)
-                                      `((,(intern (format nil
-                                                          "WRAPPER-~D"
-                                                          index)
-                                                  *pcl-package*)
+                                      `((,(format-symbol *pcl-package*
+                                                         "WRAPPER-~D"
+                                                         index)
                                          ,(emit-fetch-wrapper
                                            mt arg 'miss (pop slot-regs))))))
                                   args metatypes))
                                          ,(emit-fetch-wrapper
                                            mt arg 'miss (pop slot-regs))))))
                                   args metatypes))
index 5db39e8..cfad90f 100644 (file)
                      (classoid-layout classoid))
                     'defstruct-description)))))
 
                      (classoid-layout classoid))
                     'defstruct-description)))))
 
+;;; Symbol contruction utilities
+(defun format-symbol (package format-string &rest format-arguments)
+  (without-package-locks
+   (intern (apply #'format nil format-string format-arguments) package)))
+
+(defun make-class-symbol (class-name)
+  (format-symbol *pcl-package* "*THE-CLASS-~A*" (symbol-name class-name)))
+
+(defun make-wrapper-symbol (class-name)
+  (format-symbol *pcl-package* "*THE-WRAPPER-~A*" (symbol-name class-name)))
+
 (defun condition-type-p (type)
   (and (symbolp type)
        (condition-classoid-p (find-classoid type nil))))
 (defun condition-type-p (type)
   (and (symbolp type)
        (condition-classoid-p (find-classoid type nil))))
index 1f9a12c..ea468f4 100644 (file)
 (defun intern-fun-name (name)
   (cond ((symbolp name) name)
        ((listp name)
 (defun intern-fun-name (name)
   (cond ((symbolp name) name)
        ((listp name)
-        (intern (let ((*package* *pcl-package*)
-                      (*print-case* :upcase)
-                      (*print-pretty* nil)
-                      (*print-gensym* t))
-                  (format nil "~S" name))
-                *pcl-package*))))
+        (let ((*package* *pcl-package*)
+              (*print-case* :upcase)
+              (*print-pretty* nil)
+              (*print-gensym* t))
+          (format-symbol *pcl-package* "~S" name)))))
+
 \f
 ;;; FIXME: probably no longer needed after init
 (defmacro precompile-random-code-segments (&optional system)
 \f
 ;;; FIXME: probably no longer needed after init
 (defmacro precompile-random-code-segments (&optional system)
index 44c4127..156d1e4 100644 (file)
 
 (defun (setf find-class) (new-value name &optional errorp environment)
   (declare (ignore errorp environment))
 
 (defun (setf find-class) (new-value name &optional errorp environment)
   (declare (ignore errorp environment))
-  (if (legal-class-name-p name)
-      (let ((cell (find-class-cell name)))
-       (setf (find-class-cell-class cell) new-value)
-       (when (and (eq *boot-state* 'complete) (null new-value))
-         (setf (find-classoid name) nil))
-       (when (or (eq *boot-state* 'complete)
-                 (eq *boot-state* 'braid))
-         (when (and new-value (class-wrapper new-value))
-           (setf (find-class-cell-predicate cell)
-                 (fdefinition (class-predicate-name new-value))))
-         (update-ctors 'setf-find-class :class new-value :name name))
-       new-value)
-      (error "~S is not a legal class name." name)))
+  (cond ((legal-class-name-p name)
+        (with-single-package-locked-error
+            (:symbol name "using ~A as the class-name argument in ~
+                           (SETF FIND-CLASS)"))
+        (let ((cell (find-class-cell name)))
+          (setf (find-class-cell-class cell) new-value)
+          (when (and (eq *boot-state* 'complete) (null new-value))
+            (setf (find-classoid name) nil))
+          (when (or (eq *boot-state* 'complete)
+                    (eq *boot-state* 'braid))
+            (when (and new-value (class-wrapper new-value))
+              (setf (find-class-cell-predicate cell)
+                    (fdefinition (class-predicate-name new-value))))
+            (update-ctors 'setf-find-class :class new-value :name name))
+          new-value))
+       (t
+        (error "~S is not a legal class name." name))))
 
 (/show "pcl/macros.lisp 230")
 
 
 (/show "pcl/macros.lisp 230")
 
index c15b6c8..20158c0 100644 (file)
 (defun make-discriminating-function-arglist (number-required-arguments restp)
   (nconc (let ((args nil))
            (dotimes (i number-required-arguments)
 (defun make-discriminating-function-arglist (number-required-arguments restp)
   (nconc (let ((args nil))
            (dotimes (i number-required-arguments)
-             (push (intern (format nil "Discriminating Function Arg ~D" i))
+             (push (format-symbol *package* ;; ! is this right?
+                                 "Discriminating Function Arg ~D"
+                                 i)
                    args))
            (nreverse args))
         (when restp
                    args))
            (nreverse args))
         (when restp
-              `(&rest ,(intern "Discriminating Function &rest Arg")))))
+              `(&rest ,(format-symbol *package* 
+                                      "Discriminating Function &rest Arg")))))
 \f
 (defmethod generic-function-argument-precedence-order
     ((gf standard-generic-function))
 \f
 (defmethod generic-function-argument-precedence-order
     ((gf standard-generic-function))
index ca020b4..46cdf63 100644 (file)
         args))
 
 (defmethod ensure-class-using-class ((class null) name &rest args &key)
         args))
 
 (defmethod ensure-class-using-class ((class null) name &rest args &key)
-  (multiple-value-bind (meta initargs)
-      (ensure-class-values class args)
-    (set-class-type-translation (class-prototype meta) name)
-    (setf class (apply #'make-instance meta :name name initargs)
-         (find-class name) class)
-    (set-class-type-translation class name)
-    class))
+  (without-package-locks
+   (multiple-value-bind (meta initargs)
+       (ensure-class-values class args)
+     (set-class-type-translation (class-prototype meta) name)
+     (setf class (apply #'make-instance meta :name name initargs)
+          (find-class name) class)
+     (set-class-type-translation class name)
+     class)))
 
 (defmethod ensure-class-using-class ((class pcl-class) name &rest args &key)
 
 (defmethod ensure-class-using-class ((class pcl-class) name &rest args &key)
-  (multiple-value-bind (meta initargs)
-      (ensure-class-values class args)
-    (unless (eq (class-of class) meta)
-      (apply #'change-class class meta initargs))
-    (apply #'reinitialize-instance class initargs)
-    (setf (find-class name) class)
-    (set-class-type-translation class name)
-    class))
+  (without-package-locks
+   (multiple-value-bind (meta initargs)
+       (ensure-class-values class args)
+     (unless (eq (class-of class) meta)
+       (apply #'change-class class meta initargs))
+     (apply #'reinitialize-instance class initargs)
+     (setf (find-class name) class)
+     (set-class-type-translation class name)
+     class)))
 
 (defmethod class-predicate-name ((class t))
   'constantly-nil)
 
 (defmethod class-predicate-name ((class t))
   'constantly-nil)
   (flet ((compute-preliminary-cpl (root)
           (let ((*allow-forward-referenced-classes-in-cpl-p* t))
             (compute-class-precedence-list root))))
   (flet ((compute-preliminary-cpl (root)
           (let ((*allow-forward-referenced-classes-in-cpl-p* t))
             (compute-class-precedence-list root))))
-    (unless (class-finalized-p class)
-      (let ((name (class-name class)))
-       (setf (find-class name) class)
-       ;; KLUDGE: This is fairly horrible.  We need to make a
-       ;; full-fledged CLASSOID here, not just tell the compiler that
-       ;; some class is forthcoming, because there are legitimate
-       ;; questions one can ask of the type system, implemented in
-       ;; terms of CLASSOIDs, involving forward-referenced classes. So.
-       (when (and (eq *boot-state* 'complete)
-                  (null (find-classoid name nil)))
-         (setf (find-classoid name)
-               (make-standard-classoid :name name)))
-       (set-class-type-translation class name)
-       (let ((layout (make-wrapper 0 class))
-             (classoid (find-classoid name)))
-         (setf (layout-classoid layout) classoid)
-         (setf (classoid-pcl-class classoid) class)
-         (setf (slot-value class 'wrapper) layout)
-         (let ((cpl (compute-preliminary-cpl class)))
-           (setf (layout-inherits layout)
-                 (order-layout-inherits
-                  (map 'simple-vector #'class-wrapper
-                       (reverse (rest cpl))))))
-         (register-layout layout :invalidate t)
-         (setf (classoid-layout classoid) layout)
-         (mapc #'make-preliminary-layout (class-direct-subclasses class)))))))
+    (without-package-locks
+     (unless (class-finalized-p class)
+       (let ((name (class-name class)))
+        (setf (find-class name) class)
+        ;; KLUDGE: This is fairly horrible.  We need to make a
+        ;; full-fledged CLASSOID here, not just tell the compiler that
+        ;; some class is forthcoming, because there are legitimate
+        ;; questions one can ask of the type system, implemented in
+        ;; terms of CLASSOIDs, involving forward-referenced classes. So.
+        (when (and (eq *boot-state* 'complete)
+                   (null (find-classoid name nil)))
+          (setf (find-classoid name)
+                (make-standard-classoid :name name)))
+        (set-class-type-translation class name)
+        (let ((layout (make-wrapper 0 class))
+              (classoid (find-classoid name)))
+          (setf (layout-classoid layout) classoid)
+          (setf (classoid-pcl-class classoid) class)
+          (setf (slot-value class 'wrapper) layout)
+          (let ((cpl (compute-preliminary-cpl class)))
+            (setf (layout-inherits layout)
+                  (order-layout-inherits
+                   (map 'simple-vector #'class-wrapper
+                        (reverse (rest cpl))))))
+          (register-layout layout :invalidate t)
+          (setf (classoid-layout classoid) layout)
+          (mapc #'make-preliminary-layout (class-direct-subclasses class))))))))
 
 
 (defmethod shared-initialize :before ((class class) slot-names &key name)
 
 
 (defmethod shared-initialize :before ((class class) slot-names &key name)
     (error "Structure slots must have :INSTANCE allocation.")))
 
 (defun make-structure-class-defstruct-form (name direct-slots include)
     (error "Structure slots must have :INSTANCE allocation.")))
 
 (defun make-structure-class-defstruct-form (name direct-slots include)
-  (let* ((conc-name (intern (format nil "~S structure class " name)))
-         (constructor (intern (format nil "~Aconstructor" conc-name)))
+  (let* ((conc-name (format-symbol *package* "~S structure class " name))
+         (constructor (format-symbol *package* "~Aconstructor" conc-name))
          (defstruct `(defstruct (,name
                                  ,@(when include
                                          `((:include ,(class-name include))))
          (defstruct `(defstruct (,name
                                  ,@(when include
                                          `((:include ,(class-name include))))
                    (mapcar (lambda (pl)
                              (when defstruct-p
                                (let* ((slot-name (getf pl :name))
                    (mapcar (lambda (pl)
                              (when defstruct-p
                                (let* ((slot-name (getf pl :name))
-                                      (acc-name
-                                       (format nil
-                                               "~S structure class ~A"
-                                               name slot-name))
-                                      (accessor (intern acc-name)))
+                                      (accessor
+                                       (format-symbol *package*
+                                                      "~S structure class ~A"
+                                                      name slot-name)))
                                  (setq pl (list* :defstruct-accessor-symbol
                                                  accessor pl))))
                              (make-direct-slotd class pl))
                                  (setq pl (list* :defstruct-accessor-symbol
                                                  accessor pl))))
                              (make-direct-slotd class pl))
   (fix-slot-accessors class dslotds 'remove))
 
 (defun fix-slot-accessors (class dslotds add/remove)
   (fix-slot-accessors class dslotds 'remove))
 
 (defun fix-slot-accessors (class dslotds add/remove)
-  (flet ((fix (gfspec name r/w)
-          (let* ((ll (case r/w (r '(object)) (w '(new-value object))))
-                 (gf (if (fboundp gfspec)
-                         (ensure-generic-function gfspec)
-                         (ensure-generic-function gfspec :lambda-list ll))))
-            (case r/w
-              (r (if (eq add/remove 'add)
-                     (add-reader-method class gf name)
-                     (remove-reader-method class gf)))
-              (w (if (eq add/remove 'add)
-                     (add-writer-method class gf name)
-                     (remove-writer-method class gf)))))))
-    (dolist (dslotd dslotds)
-      (let ((slot-name (slot-definition-name dslotd)))
-       (dolist (r (slot-definition-readers dslotd)) (fix r slot-name 'r))
-       (dolist (w (slot-definition-writers dslotd)) (fix w slot-name 'w))))))
+  ;; We disable package locks here, since defining a class can trigger
+  ;; the update of the accessors of another class -- which might lead
+  ;; to package lock violations if we didn't.
+  (without-package-locks
+      (flet ((fix (gfspec name r/w)
+              (let* ((ll (case r/w (r '(object)) (w '(new-value object))))
+                     (gf (if (fboundp gfspec)
+                             (ensure-generic-function gfspec)
+                             (ensure-generic-function gfspec :lambda-list ll))))
+                (case r/w
+                  (r (if (eq add/remove 'add)
+                         (add-reader-method class gf name)
+                         (remove-reader-method class gf)))
+                  (w (if (eq add/remove 'add)
+                         (add-writer-method class gf name)
+                         (remove-writer-method class gf)))))))
+       (dolist (dslotd dslotds)
+         (let ((slot-name (slot-definition-name dslotd)))
+           (dolist (r (slot-definition-readers dslotd)) 
+             (fix r slot-name 'r))
+           (dolist (w (slot-definition-writers dslotd)) 
+             (fix w slot-name 'w)))))))
 \f
 (defun add-direct-subclasses (class supers)
   (dolist (super supers)
 \f
 (defun add-direct-subclasses (class supers)
   (dolist (super supers)
   ;; Note that we can't simply delay the finalization when CLASS has
   ;; no forward referenced superclasses because that causes bootstrap
   ;; problems.
   ;; Note that we can't simply delay the finalization when CLASS has
   ;; no forward referenced superclasses because that causes bootstrap
   ;; problems.
-  (when (and (not finalizep)
-            (not (class-finalized-p class))
+  (without-package-locks
+   (when (and (not finalizep)
+             (not (class-finalized-p class))
+             (not (class-has-a-forward-referenced-superclass-p class)))
+     (finalize-inheritance class)
+     (return-from update-class))
+   (when (or finalizep (class-finalized-p class)
             (not (class-has-a-forward-referenced-superclass-p class)))
             (not (class-has-a-forward-referenced-superclass-p class)))
-    (finalize-inheritance class)
-    (return-from update-class))
-  (when (or finalizep (class-finalized-p class)
-           (not (class-has-a-forward-referenced-superclass-p class)))
-    (setf (find-class (class-name class)) class)
-    (update-cpl class (compute-class-precedence-list class))
-    ;; This invocation of UPDATE-SLOTS, in practice, finalizes the
-    ;; class.  The hoops above are to ensure that FINALIZE-INHERITANCE
+     (setf (find-class (class-name class)) class)
+     (update-cpl class (compute-class-precedence-list class))
+     ;; This invocation of UPDATE-SLOTS, in practice, finalizes the
+     ;; class.  The hoops above are to ensure that FINALIZE-INHERITANCE
     ;; is called at finalization, so that MOP programmers can hook
     ;; is called at finalization, so that MOP programmers can hook
-    ;; into the system as described in "Class Finalization Protocol"
-    ;; (section 5.5.2 of AMOP).
-    (update-slots class (compute-slots class))
-    (update-gfs-of-class class)
-    (update-initargs class (compute-default-initargs class))
-    (update-ctors 'finalize-inheritance :class class))
-  (unless finalizep
-    (dolist (sub (class-direct-subclasses class)) (update-class sub nil))))
+     ;; into the system as described in "Class Finalization Protocol"
+     ;; (section 5.5.2 of AMOP).
+     (update-slots class (compute-slots class))
+     (update-gfs-of-class class)
+     (update-initargs class (compute-default-initargs class))
+     (update-ctors 'finalize-inheritance :class class))
+   (unless finalizep
+     (dolist (sub (class-direct-subclasses class)) (update-class sub nil)))))
 
 (defun update-cpl (class cpl)
   (if (class-finalized-p class)
 
 (defun update-cpl (class cpl)
   (if (class-finalized-p class)
index f75acf6..995fa6f 100644 (file)
       `(list*
        :fast-function
        (,(if (body-method-name body) 'named-lambda 'lambda)
       `(list*
        :fast-function
        (,(if (body-method-name body) 'named-lambda 'lambda)
-        ,@(when (body-method-name body)
-            (list (body-method-name body))) ; function name
-        (.pv-cell. .next-method-call. ,@args+rest-arg) ; function args
-        ;; body of the function
-        (declare (ignorable .pv-cell. .next-method-call.))
-        ,@outer-decls
-        (macrolet ((pv-env ((pv calls pv-table-symbol pv-parameters)
-                            &rest forms)
-                           (declare (ignore pv-table-symbol
-                                            pv-parameters))
-                           `(let ((,pv (car .pv-cell.))
-                                  (,calls (cdr .pv-cell.)))
-                              (declare ,(make-pv-type-declaration pv)
-                                       ,(make-calls-type-declaration calls))
-                              ,pv ,calls
-                              ,@forms)))
-          (fast-lexical-method-functions
-           (,(car lmf-params) .next-method-call. ,req-args ,rest-arg
-            ,@(cdddr lmf-params))
-           ,@inner-decls
-           ,@body-sans-decls)))
+         ,@(when (body-method-name body)
+                 (list (body-method-name body))) ; function name
+         (.pv-cell. .next-method-call. ,@args+rest-arg) ; function args
+         ;; body of the function
+         (declare (ignorable .pv-cell. .next-method-call.))
+         ,@outer-decls
+         (declare (disable-package-locks pv-env))
+          (macrolet ((pv-env ((pv calls pv-table-symbol pv-parameters)
+                              &rest forms)
+                       (declare (ignore pv-table-symbol
+                                        pv-parameters))
+                       (declare (enable-package-locks pv-env))
+                       `(let ((,pv (car .pv-cell.))
+                              (,calls (cdr .pv-cell.)))
+                          (declare ,(make-pv-type-declaration pv)
+                                   ,(make-calls-type-declaration calls))
+                          ,pv ,calls
+                          ,@forms)))
+            (declare (enable-package-locks pv-env))
+            (fast-lexical-method-functions
+             (,(car lmf-params) .next-method-call. ,req-args ,rest-arg
+               ,@(cdddr lmf-params))
+             ,@inner-decls
+             ,@body-sans-decls)))
        ',initargs))))
 
 ;;; Use arrays and hash tables and the fngen stuff to make this much
        ',initargs))))
 
 ;;; Use arrays and hash tables and the fngen stuff to make this much
                        (setf (get (car fname) 'method-sym)
                              (let ((str (symbol-name (car fname))))
                                (if (string= "FAST-" str :end2 5)
                        (setf (get (car fname) 'method-sym)
                              (let ((str (symbol-name (car fname))))
                                (if (string= "FAST-" str :end2 5)
-                                   (intern (subseq str 5) *pcl-package*)
+                                   (format-symbol *pcl-package* (subseq str 5))
                                    (car fname)))))
                    ,@(cdr fname))))
       (set-fun-name method-function name))
                                    (car fname)))))
                    ,@(cdr fname))))
       (set-fun-name method-function name))
index 7b68e65..b2c927e 100644 (file)
@@ -1,7 +1,5 @@
 /*
 
 /*
 
- $Header$
-
  This code was written as part of the CMU Common Lisp project at
  Carnegie Mellon University, and has been placed in the public domain.
 
  This code was written as part of the CMU Common Lisp project at
  Carnegie Mellon University, and has been placed in the public domain.
 
index ff9b78a..47f9a5a 100644 (file)
@@ -1,5 +1,3 @@
-/* $Header$ */
-
 #ifdef LANGUAGE_ASSEMBLY
 #define REG(num) $ ## num
 #else
 #ifdef LANGUAGE_ASSEMBLY
 #define REG(num) $ ## num
 #else
index 67032c5..e9e09b5 100644 (file)
@@ -73,7 +73,7 @@
 ;;; in a similar vein, we should be able to define methods on classes
 ;;; that are effectively unknown to the type system:
 (sb-mop:ensure-class 'unknown-type)
 ;;; in a similar vein, we should be able to define methods on classes
 ;;; that are effectively unknown to the type system:
 (sb-mop:ensure-class 'unknown-type)
-(defmethod method ((x unknown-type)) x)
+(defmethod method-on-unknown ((x unknown-type)) x)
 ;;; (we can't call it without defining methods on allocate-instance
 ;;; etc., but we should be able to define it).
 \f
 ;;; (we can't call it without defining methods on allocate-instance
 ;;; etc., but we should be able to define it).
 \f
index 956c43c..bdd3550 100644 (file)
 ;;; bug 313: source transforms were "lisp-1"
 (defun srctran-lisp1-1 (cadr) (if (functionp cadr) (funcall cadr 1) nil))
 (assert (eql (funcall (eval #'srctran-lisp1-1) #'identity) 1))
 ;;; bug 313: source transforms were "lisp-1"
 (defun srctran-lisp1-1 (cadr) (if (functionp cadr) (funcall cadr 1) nil))
 (assert (eql (funcall (eval #'srctran-lisp1-1) #'identity) 1))
-(defvar caar)
+(without-package-locks 
+   ;; this be a nasal demon, but test anyways
+   (defvar caar))
 (defun srctran-lisp1-2 (caar) (funcall (sb-ext:truly-the function caar) 1))
 (assert (eql (funcall (eval #'srctran-lisp1-2) #'identity) 1))
 \f
 (defun srctran-lisp1-2 (caar) (funcall (sb-ext:truly-the function caar) 1))
 (assert (eql (funcall (eval #'srctran-lisp1-2) #'identity) 1))
 \f
index f94e582..e8f86a0 100644 (file)
 ;;; BUG 48a. and b. (symbol-macrolet handling), fixed by Eric Marsden
 ;;; and Raymond Toy for CMUCL, fix ported for sbcl-0.7.6.18.
 (multiple-value-bind (function warnings-p failure-p)
 ;;; BUG 48a. and b. (symbol-macrolet handling), fixed by Eric Marsden
 ;;; and Raymond Toy for CMUCL, fix ported for sbcl-0.7.6.18.
 (multiple-value-bind (function warnings-p failure-p)
-    (compile nil '(lambda () (symbol-macrolet ((t nil)) t)))
+    (compile nil '(lambda ()
+                   ;; not interested in the package lock violation here
+                   (declare (sb-ext:disable-package-locks t))
+                   (symbol-macrolet ((t nil)) t)))
   (assert failure-p)
   (assert (raises-error? (funcall function) program-error)))
 (multiple-value-bind (function warnings-p failure-p)
     (compile nil
             '(lambda ()
   (assert failure-p)
   (assert (raises-error? (funcall function) program-error)))
 (multiple-value-bind (function warnings-p failure-p)
     (compile nil
             '(lambda ()
+               ;; not interested in the package lock violation here
+               (declare (sb-ext:disable-package-locks *standard-input*))
                (symbol-macrolet ((*standard-input* nil))
                  *standard-input*)))
   (assert failure-p)
                (symbol-macrolet ((*standard-input* nil))
                  *standard-input*)))
   (assert failure-p)
diff --git a/tests/package-locks.impure.lisp b/tests/package-locks.impure.lisp
new file mode 100644 (file)
index 0000000..de47170
--- /dev/null
@@ -0,0 +1,439 @@
+;;;; package lock tests with side effects
+
+;;;; This software is part of the SBCL system. See the README file for
+;;;; more information.
+;;;;
+;;;; While most of SBCL is derived from the CMU CL system, the test
+;;;; files (like this one) were written from scratch after the fork
+;;;; from CMU CL.
+;;;; 
+;;;; This software is in the public domain and is provided with
+;;;; absolutely no warranty. See the COPYING and CREDITS files for
+;;;; more information.
+
+(in-package :cl-user)
+
+(load "assertoid.lisp")
+(use-package "ASSERTOID")
+
+#-sb-package-locks
+(sb-ext:quit :unix-status 104)
+
+;;;; Our little labrats and a few utilities
+
+(defpackage :test-used)
+
+(defpackage :test-unused)
+
+(defpackage :test-aux (:export #:noslot))
+
+(defpackage :test
+  (:use :test-used)
+  (:shadow #:shadowed)
+  (:export 
+   #:*special*
+   #:car
+   #:cdr
+   #:class
+   #:constant
+   #:external
+   #:function
+   #:macro
+   #:noclass
+   #:noclass-slot
+   #:nocondition
+   #:nocondition-slot
+   #:nospecial
+   #:nostruct
+   #:nostruct2
+   #:nostruct-slot
+   #:nosymbol-macro
+   #:notype
+   #:num
+   #:numfun
+   #:shadowed
+   #:symbol-macro
+   #:unused
+   ))
+
+(defvar *uninterned* "UNINTERNED")
+(defvar *interned* "INTERNED")
+
+(defun maybe-unintern (name package)
+    (let ((s (find-symbol name package)))
+      (when s
+       (unintern s package))))
+
+(defun set-test-locks (lock-p)
+  (dolist (p '(:test :test-aux :test-delete))
+    (when (find-package p)
+      (if lock-p
+         (sb-ext:lock-package p)
+         (sb-ext:unlock-package p)))))
+
+(defun reset-test ()
+  "Reset TEST package to a known state, ensure that TEST-DELETE exists."
+  (unless (find-package :test-delete)
+    (make-package :test-delete))
+  (sb-ext:with-unlocked-packages (:test :test-aux)
+    (dolist (s '(test:nosymbol-macro 
+                test:noclass test:nostruct test:nostruct2 test:nocondition))
+      (makunbound s)
+      (unintern s)
+      (intern (symbol-name s) :test))
+    (rename-package (find-package :test) :test)    
+    (unexport (intern "INTERNAL" :test) :test)
+    (intern *interned* :test)
+    (use-package :test-used :test)
+    (export 'test::external :test)
+    (unuse-package :test-unused :test)
+    (defclass test:class () ())
+    (defun test:function () 'test:function)
+    (defmacro test:macro () ''test:macro)
+    (defparameter test:*special* 'test:*special*)
+    (defconstant test:constant 'test:constant)
+    (intern "UNUSED" :test)
+    (dolist (s '(test:nocondition-slot test:noclass-slot test:nostruct-slot
+                test-aux:noslot))
+      (fmakunbound s))
+    (ignore-errors (progn
+                    (fmakunbound 'test:unused)
+                    (makunbound 'test:unused)))
+    (maybe-unintern *uninterned* :test)
+    (maybe-unintern "NOT-FROM-TEST" :test)
+    (defconstant test:num 0)
+    (define-symbol-macro test:symbol-macro "SYMBOL-MACRO")
+    (defun test:numfun (n) n)
+    (defun test:car (cons) (cl:car cons))
+    (defun (setf test:cdr) (obj cons) (setf (cl:cdr cons) obj))
+    (assert (not (find-symbol *uninterned* :test)))))
+
+(defun tmp-fmakunbound (x)
+  "FMAKUNDBOUND x, then restore the original binding."
+  (let ((f (fdefinition x)))
+    (fmakunbound x)
+    (ignore-errors (setf (fdefinition x) f))))
+
+(defmacro with-error-info ((string &rest args) &body forms)
+  `(handler-bind ((error (lambda (e)
+                          (format t ,string ,@args)
+                          (finish-output))))
+     (progn ,@forms)))
+
+;;;; Test cases
+
+;;; A collection of forms that are legal both with and without package
+;;; locks.
+(defvar *legal-forms*
+  '(;; package alterations that don't actually mutate the package
+    (intern *interned* :test)
+    (import 'test:unused :test)
+    (shadowing-import 'test:shadowed :test)
+    (export 'test:unused :test)
+    (unexport 'test::internal :test)
+    (let ((p (find-package :test)))
+      (rename-package p :test))
+    (use-package :test-used :test)
+    (unuse-package :test-unused :test)
+    (shadow "SHADOWED" :test)
+    (let ((s (with-unlocked-packages (:test) 
+              (let ((s (intern *uninterned* :test)))
+                (unintern s :test)
+                s))))
+      (unintern s :test))
+
+    ;; binding and altering value
+    (let ((test:function 123))
+      (assert (eql test:function 123)))
+    (let ((test:*special* :foo))
+      (assert (eql test:*special* :foo)))
+    (progn
+      (setf test:*special* :quux)
+      (assert (eql test:*special* :quux)))
+    (let ((test:unused :zot))
+      (assert (eql test:unused :zot)))
+    
+    ;; symbol-macrolet
+    (symbol-macrolet ((test:function :sym-ok))
+        (assert (eql test:function :sym-ok)))
+    (symbol-macrolet ((test:unused :sym-ok2))
+        (assert (eql test:unused :sym-ok2)))
+
+    ;; binding as a function
+    (flet ((test:*special* () :yes))
+      (assert (eql (test:*special*) :yes)))
+    (flet ((test:unused () :yes!))
+      (assert (eql (test:unused) :yes!)))
+    (labels ((test:*special* () :yes))
+      (assert (eql (test:*special*) :yes)))
+    (labels ((test:unused () :yes!))
+      (assert (eql (test:unused) :yes!)))
+
+    ;; binding as a macro
+    (macrolet ((test:*special* () :ok))
+      (assert (eql (test:*special*) :ok)))
+    ))
+
+;;; A collection of forms that cause runtime package lock violations
+;;; on TEST, and will also signal an error on LOAD even if first
+;;; compiled with COMPILE-FILE with TEST unlocked.
+(defvar *illegal-runtime-forms*
+  '(;; package alterations
+    (intern *uninterned* :test)
+    (import 'not-from-test :test)
+    (export 'test::internal :test)
+    (unexport 'test:external :test)
+    (shadowing-import 'not-from-test :test)
+    (let ((p (find-package :test)))
+      (rename-package p :test '(:test-nick)))
+    (use-package :test-unused :test)
+    (unuse-package :test-used :test)
+    (shadow 'not-from-test :test)
+    (unintern (or (find-symbol *interned* :test) (error "bugo")) :test)
+    (delete-package :test-delete)
+
+    ;; defining or undefining as a function
+    (defun test:unused () 'foo)
+    (setf (fdefinition 'test:unused) (lambda () 'bar))
+    (setf (symbol-function 'test:unused) (lambda () 'quux))
+    (tmp-fmakunbound 'test:function)
+
+    ;; defining or undefining as a macro or compiler macro
+    (defmacro test:unused () ''foo)
+    (setf (macro-function 'test:unused) (constantly 'foo))
+    (define-compiler-macro test:unused (&whole form arg) 
+      form)
+    (setf (compiler-macro-function 'test:unused) (constantly 'foo))
+    
+    ;; type-specifier or structure
+    (progn
+      (defstruct test:nostruct test:nostruct-slot)
+      ;; test creation as well, since the structure-class won't be
+      ;; finalized before that
+      (make-nostruct :nostruct-slot :foo))
+    (defclass test:noclass () 
+      ((slot :initform nil :accessor test:noclass-slot)))
+    (deftype test:notype () 'string)
+    (define-condition test:nocondition (error)
+      ((slot :initform nil :accessor test:nocondition-slot)))
+
+    ;; symbol-macro
+    (define-symbol-macro test:nosymbol-macro 'foo)
+
+    ;; declaration proclamation
+    (proclaim '(declaration test:unused))
+
+    ;; declare special
+    (declaim (special test:nospecial))
+    (proclaim '(special test:nospecial))
+
+    ;; declare type
+    (declaim (type fixnum test:num))
+    (proclaim '(type fixnum test:num))
+
+    ;; declare ftype
+    (declaim (ftype (function (fixnum) fixnum) test:numfun))
+    (proclaim '(ftype (function (fixnum) fixnum) test:numfun))
+
+    ;; setf expanders
+    (defsetf test:car rplaca) ; strictly speaking wrong, but ok as a test
+    (defsetf test:car (cons) (new-car)
+      `(setf (car ,cons) ,new-car))
+    (define-setf-expander test:car (place)
+      (multiple-value-bind (dummies vals newval setter getter)
+         (get-setf-expansion place)
+        (let ((store (gensym)))
+          (values dummies
+                  vals
+                  `(,store)
+                  `(progn (rplaca ,getter ,store) ,store)
+                  `(car ,getter)))))
+
+    ;; setf function names
+    (defun (setf test:function) (obj)
+      obj)
+    (tmp-fmakunbound '(setf test:cdr))    
+    
+    ;; define-method-combination
+    (define-method-combination test:unused)
+    
+    ;; setf find-class
+    (setf (find-class 'test:class) (find-class 'standard-class))
+    ))
+
+;;; Forms that cause violations on two distinct packages.
+(defvar *illegal-double-forms*
+  '((defclass test:noclass () ((x :accessor test-aux:noslot)))
+    (define-condition test:nocondition (error)
+      ((x :accessor test-aux:noslot)))))
+
+;;; A collection of forms that cause compile-time package lock
+;;; violations on TEST, and will not signal an error on LOAD if first
+;;; compiled by COMPILE-FILE with test unlocked. CAR is the affected
+;;; symbol, CDR the form affecting it.
+(defvar *illegal-compile-time-forms-alist*
+  '(;; binding
+
+    ;; binding as a function
+    (test:function . (flet ((test:function () :shite))
+                       (test:function)))
+    (test:function . (labels ((test:function () :shite))
+                       (test:function)))
+    (test:macro . (flet ((test:macro () :shite))
+                    (test:macro)))
+    (test:macro . (labels ((test:macro () :shite))
+                    (test:macro)))
+
+    ;; macrolet
+    (test:function . (macrolet ((test:function () :yuk))
+                       (test:function)))
+    (test:macro . (macrolet ((test:macro () :yuk))
+                    (test:macro)))
+
+    ;; setf name
+    (test:function . (flet (((setf test:function) (obj)
+                              obj))
+                       (setf (test:function) 1)))
+
+    ;; ftype
+    (test:function . (locally
+                         (declare (ftype function test:function))
+                       (cons t t)))
+
+    ;; type
+    (test:num . (locally
+                    (declare (type fixnum test:num))
+                  (cons t t)))
+      
+    ;; special
+    (test:nospecial . (locally
+                          (declare (special test:nospecial))
+                        (cons t t)))
+
+    ;; declare ftype
+    (test:numfun . (locally
+                       (declare (ftype (function (fixnum) fixnum) test:numfun))
+                     (cons t t)))))
+
+(defvar *illegal-compile-time-forms* (mapcar #'cdr *illegal-compile-time-forms-alist*))
+
+(defvar *illegal-forms* (append *illegal-runtime-forms*
+                                *illegal-compile-time-forms*
+                                *illegal-double-forms*))
+
+;;;; Running the tests
+
+;;; Unlocked. No errors nowhere.
+(reset-test)
+(set-test-locks nil)
+(dolist (form (append *legal-forms* *illegal-forms*))
+  (with-error-info ("~Unlocked form: ~S~%" form)
+    (eval form)))
+
+;;; Locked. Errors for all illegal forms, none for legal.
+(reset-test)
+(set-test-locks t)
+(dolist (form *legal-forms*)
+  (with-error-info ("locked legal form: ~S~%" form)
+    (eval form)))
+(reset-test)
+(set-test-locks t)
+(dolist (form (append *illegal-runtime-forms* *illegal-double-forms*))
+  (with-error-info ("locked illegal runtime form: ~S~%" form)
+    (let ((fun (compile nil `(lambda () ,form))))
+      (assert (raises-error? (funcall fun) sb-ext:package-lock-violation)))))
+(dolist (pair *illegal-compile-time-forms-alist*)
+  (let ((form (cdr pair)))
+    (with-error-info ("locked illegal compile-time form: ~S~%" form)
+      (assert (raises-error? (compile nil `(lambda () ,form)) sb-ext:package-lock-violation)))))
+
+;;; Locked, WITHOUT-PACKAGE-LOCKS for runtime errors.
+(reset-test)
+(set-test-locks t)
+(dolist (form *illegal-runtime-forms*)
+  (with-error-info ("without-package-locks illegal runtime form: ~S~%" form)
+    (funcall (compile nil `(lambda () (without-package-locks ,form))))))
+
+;;; Locked, WITHOUT-PACKAGE-LOCKS & DISABLE-PACKAGE-LOCKS for compile-time errors.
+(reset-test)
+(set-test-locks t)
+(dolist (pair *illegal-compile-time-forms-alist*)
+  (destructuring-bind (sym . form) pair
+    (with-error-info ("without-package-locks illegal compile-time form: ~S~%" form)
+      (let ((fun (without-package-locks (compile nil `(lambda () ,form)))))
+        (funcall fun)))))
+(reset-test)
+(set-test-locks t)
+(dolist (pair *illegal-compile-time-forms-alist*)
+  (destructuring-bind (sym . form) pair
+    (with-error-info ("disable-package-locks illegal compile-time form: ~S~%" form)
+      (funcall (compile nil `(lambda ()
+                              (declare (disable-package-locks ,sym))
+                              ,form))))))
+
+;;; Locked, one error per "lexically apparent violated package", also
+;;; test restarts.
+(reset-test)
+(set-test-locks t)
+(dolist (form (append *illegal-runtime-forms* *illegal-compile-time-forms*))
+  (with-error-info ("one error per form: ~S~%")
+    (let ((errorp nil))
+      (handler-bind ((package-lock-violation (lambda (e)
+                                               (when errorp
+                                                 (error "multiple errors"))
+                                               (setf errorp t)
+                                               (continue e))))
+        (eval form)))))
+(dolist (form *illegal-double-forms*)
+  (with-error-info ("two errors per form: ~S~%" form)
+    (let ((error-count 0))
+      ;; check that we don't get multiple errors from a single form
+      (handler-bind ((package-lock-violation (lambda (x)
+                                               (declare (ignore x))
+                                               (incf error-count)
+                                               (continue x))))
+       (eval form)
+       (unless (= 2 error-count)
+         (error "expected 2 errors per form, got ~A for ~A" 
+                error-count form))))))
+
+;;; COMPILE-FILE when unlocked, LOAD locked -- *illegal-runtime-forms* only
+(let* ((tmp "package-locks.tmp.lisp")
+       (fasl (compile-file-pathname tmp))
+       (n 0))
+  (dolist (form *illegal-runtime-forms*)
+    (unwind-protect
+        (with-simple-restart (next "~S failed, continue with next test" form)
+          (reset-test)
+          (set-test-locks nil)
+          (with-open-file (f tmp :direction :output)
+            (prin1 form f))
+          (multiple-value-bind (file warnings failure-p) (compile-file tmp)
+            (set-test-locks t)
+            (assert (raises-error? (load fasl) sb-ext:package-lock-violation))))
+      (when (probe-file tmp)
+       (delete-file tmp))
+      (when (probe-file fasl)
+       (delete-file fasl)))))
+
+;;;; Tests for enable-package-locks declarations
+(reset-test)
+(set-test-locks t)
+(dolist (pair *illegal-compile-time-forms-alist*)
+  (destructuring-bind (sym . form) pair
+    (assert (raises-error?
+             (compile nil `(lambda ()
+                            (declare (disable-package-locks ,sym))
+                            ,form
+                            (locally (declare (enable-package-locks ,sym))
+                              ,form)))
+             package-lock-violation))
+    (assert (raises-error?
+             (eval `(locally (declare (disable-package-locks ,sym))
+                     ,form
+                     (locally (declare (enable-package-locks ,sym))
+                       ,form)))
+             package-lock-violation))))
+
+;;; WOOT! Done.
+(sb-ext:quit :unix-status 104)
index e41d17d..91d3231 100644 (file)
 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
 ;;;; more information.
 
 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
 ;;;; more information.
 
-(in-package :cl-user)
-
 (load "assertoid.lisp")
 (load "assertoid.lisp")
-(use-package "ASSERTOID")
+
+(defpackage :seq-test
+  (:use :cl :assertoid))
+
+(in-package :seq-test)
 
 ;;; helper functions for exercising SEQUENCE code on data of many
 ;;; specialized types, and in many different optimization scenarios
 
 ;;; helper functions for exercising SEQUENCE code on data of many
 ;;; specialized types, and in many different optimization scenarios
            (read-char s)))))
 \f
 ;;; success
            (read-char s)))))
 \f
 ;;; success
-(quit :unix-status 104)
+(sb-ext:quit :unix-status 104)
index f593c3a..d8c812c 100644 (file)
@@ -17,4 +17,4 @@
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
 ;;; checkins which aren't released. (And occasionally for internal
 ;;; versions, especially for internal versions off the main CVS
 ;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.8.12.6"
+"0.8.12.7"