1.0.20.7: COMPARE-AND-SWAP on SYMBOL-VALUE to respect constants and declaimed types
authorNikodemus Siivola <nikodemus@random-state.net>
Wed, 17 Sep 2008 20:24:21 +0000 (20:24 +0000)
committerNikodemus Siivola <nikodemus@random-state.net>
Wed, 17 Sep 2008 20:24:21 +0000 (20:24 +0000)
 * For constant symbol names which are declaimed SPECIAL, insert the
   appropriate THE around the new value.

 * For other cases use ABOUT-TO-MODIFY-SYMBOL-VALUE.

 * Tests.

NEWS
src/code/late-extensions.lisp
tests/compare-and-swap.impure.lisp
version.lisp-expr

diff --git a/NEWS b/NEWS
index 449af42..6b585e8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
 ;;;; -*- coding: utf-8; -*-
-  * reduced conservativism on GENCGC platforms: on average 45% less
-    pages pinned (measured from SBCL self build).
+  * enhancement: reduced conservativism on GENCGC platforms: on
+    average 45% less pages pinned (measured from SBCL self build).
+  * bug fix: SB-EXT:COMPARE-AND-SWAP on SYMBOL-VALUE can no longer
+    mutate constant symbols or violate declaimed type of the symbol.
 
 changes in sbcl-1.0.20 relative to 1.0.19:
   * minor incompatible change: OPTIMIZE qualities
index e6b24a3..5b0fbaa 100644 (file)
@@ -66,7 +66,7 @@
              (- (* ,(+ sb!vm:instance-slots-offset index) sb!vm:n-word-bytes)
                 sb!vm:instance-pointer-lowtag)))))))
 
-(defmacro compare-and-swap (place old new)
+(defmacro compare-and-swap (place old new &environment env)
   "Atomically stores NEW in PLACE if OLD matches the current value of PLACE.
 Two values are considered to match if they are EQ. Returns the previous value
 of PLACE: if the returned value if EQ to OLD, the swap was carried out.
@@ -92,9 +92,26 @@ EXPERIMENTAL: Interface subject to change."
       ((cdr rest)
        `(%compare-and-swap-cdr (the cons ,@args) ,old ,new))
       (symbol-plist
-       `(%compare-and-swap-symbol-plist (the symbol ,@args) ,old ,new))
+       `(%compare-and-swap-symbol-plist (the symbol ,@args) ,old (the list ,new)))
       (symbol-value
-       `(%compare-and-swap-symbol-value (the symbol ,@args) ,old ,new))
+       (destructuring-bind (name) args
+         (flet ((slow (symbol)
+                  (with-unique-names (n-symbol n-old n-new)
+                    `(let ((,n-symbol ,symbol)
+                           (,n-old ,old)
+                           (,n-new ,new))
+                       (declare (symbol ,n-symbol))
+                       (about-to-modify-symbol-value ,n-symbol "compare-and-swap SYMBOL-VALUE of ~S" ,n-new)
+                       (%compare-and-swap-symbol-value ,n-symbol ,n-old ,n-new)))))
+           (if (sb!xc:constantp name env)
+               (let ((cname (constant-form-value name env)))
+                 (if (eq :special (info :variable :kind cname))
+                     ;; Since we know the symbol is a special, we can just generate
+                     ;; the type check.
+                     `(%compare-and-swap-symbol-value
+                       ',cname ,old (the ,(info :variable :type cname) ,new))
+                     (slow (list 'quote cname))))
+               (slow name)))))
       (svref
        (let ((vector (car args))
              (index (cadr args)))
index 6366043..8a034ad 100644 (file)
     (ignore-errors (compare-and-swap (svref "foo" 1) 1 2))
     (assert (not res))
     (assert (typep err 'type-error)))
+
+;; Check that we don't modify constants
+(defconstant +a-constant+ 42)
+(assert
+ (eq :error
+     (handler-case
+         (sb-ext:compare-and-swap (symbol-value '+a-constant+) 42 13)
+       (error () :error))))
+(let ((name '+a-constant+))
+  (assert
+   (eq :error
+       (handler-case
+           (sb-ext:compare-and-swap (symbol-value name) 42 13)
+         (error () :error)))))
+
+;; Check that we don't mess declaimed types
+(declaim (boolean *a-boolean*))
+(defparameter *a-boolean* t)
+(assert
+ (eq :error
+     (handler-case
+         (sb-ext:compare-and-swap (symbol-value '*a-boolean*) t 42)
+       (error () :error))))
+(let ((name '*a-boolean*))
+  (assert
+   (eq :error
+       (handler-case
+           (sb-ext:compare-and-swap (symbol-value name) t 42)
+         (error () :error)))))
index de3b135..7324dbc 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".)
-"1.0.20.6"
+"1.0.20.7"