1.0.28.19: faster ARRAY-DIMENSION for non-vectors
[sbcl.git] / src / code / late-extensions.lisp
index 08dbd57..0d1febe 100644 (file)
 
 ;;; Used internally, but it would be nice to provide something
 ;;; like this for users as well.
-
+;;;
+;;; FIXME / IMPORTANT: If the slot is raw, the address is correct only for
+;;; instances of the specified class, not its subclasses!
 #!+sb-thread
 (defmacro define-structure-slot-addressor (name &key structure slot)
   (let* ((dd (find-defstruct-description structure t))
          (slotd (when dd (find slot (dd-slots dd) :key #'dsd-name)))
-         (index (when slotd (dsd-index slotd))))
+         (index (when slotd (dsd-index slotd)))
+         (raw-type (dsd-raw-type slotd)))
     (unless index
       (error "Slot ~S not found in ~S." slot structure))
     `(progn
          (sb!ext:truly-the
           sb!vm:word
           (+ (sb!kernel:get-lisp-obj-address instance)
-             (- (* ,(+ sb!vm:instance-slots-offset index) sb!vm:n-word-bytes)
+             (- (* ,(if (eq t raw-type)
+                        (+ sb!vm:instance-slots-offset index)
+                        (- (1+ (sb!kernel::dd-instance-length dd)) sb!vm:instance-slots-offset index
+                           (1- (sb!kernel::raw-slot-words raw-type))))
+                   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 +99,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)))
@@ -124,10 +148,10 @@ EXPERIMENTAL: Interface subject to change."
              (error "Invalid first argument to COMPARE-AND-SWAP: ~S" place))))))))
 
 (macrolet ((def (name lambda-list ref &optional set)
+             #!+compare-and-swap-vops
+             (declare (ignore ref set))
              `(defun ,name (,@lambda-list old new)
                 #!+compare-and-swap-vops
-                (declare (ignore ref set))
-                #!+compare-and-swap-vops
                 (,name ,@lambda-list old new)
                 #!-compare-and-swap-vops
                 (let ((current (,ref ,@lambda-list)))
@@ -143,6 +167,60 @@ EXPERIMENTAL: Interface subject to change."
   (def %compare-and-swap-symbol-value (symbol) symbol-value)
   (def %compare-and-swap-svref (vector index) svref))
 
+(defmacro atomic-incf (place &optional (diff 1))
+  #!+sb-doc
+  "Atomically increments PLACE by DIFF, and returns the value of PLACE before
+the increment.
+
+The incrementation is done using word-size modular arithmetic: on 32 bit
+platforms ATOMIC-INCF of #xFFFFFFFF by one results in #x0 being stored in
+PLACE.
+
+PLACE must be an accessor form whose CAR is the name of a DEFSTRUCT accessor
+whose declared type is (UNSIGNED-BYTE 32) on 32 bit platforms,
+and (UNSIGNED-BYTE 64) on 64 bit platforms.
+
+DIFF defaults to 1, and must be a (SIGNED-BYTE 32) on 32 bit platforms,
+and (SIGNED-BYTE 64) on 64 bit platforms.
+
+EXPERIMENTAL: Interface subject to change."
+  (flet ((invalid-place ()
+           (error "Invalid first argument to ATOMIC-INCF: ~S" place)))
+    (unless (consp place)
+      (invalid-place))
+    (destructuring-bind (op &rest args) place
+      (when (cdr args)
+        (invalid-place))
+      (let ((dd (info :function :structure-accessor op)))
+        (if dd
+            (let* ((structure (dd-name dd))
+                   (slotd (find op (dd-slots dd) :key #'dsd-accessor-name))
+                   (index (dsd-index slotd))
+                   (type (dsd-type slotd)))
+              (declare (ignorable structure index))
+              (unless (and (eq 'sb!vm:word (dsd-raw-type slotd))
+                           (type= (specifier-type type) (specifier-type 'sb!vm:word)))
+                (error "ATOMIC-INCF requires a slot of type (UNSIGNED-BYTE ~S), not ~S: ~S"
+                       sb!vm:n-word-bits type place))
+              (when (dsd-read-only slotd)
+                (error "Cannot use ATOMIC-INCF with structure accessor for a read-only slot: ~S"
+                       place))
+              #!+(or x86 x86-64)
+              `(truly-the sb!vm:word
+                          (%raw-instance-atomic-incf/word (the ,structure ,@args)
+                                                          ,index
+                                                          (the sb!vm:signed-word ,diff)))
+              ;; No threads outside x86 and x86-64 for now, so this is easy...
+              #!-(or x86 x86-64)
+              (with-unique-names (structure old)
+                `(sb!sys:without-interrupts
+                   (let* ((,structure ,@args)
+                          (,old (,op ,structure)))
+                     (setf (,op ,structure) (logand #.(1- (ash 1 sb!vm:n-word-bits))
+                                                    (+ ,old (the sb!vm:signed-word ,diff))))
+                     ,old))))
+            (invalid-place))))))
+
 (defun call-hooks (kind hooks &key (on-error :error))
   (dolist (hook hooks)
     (handler-case