"%ADJOIN-TEST-NOT"
"%ARRAY-AVAILABLE-ELEMENTS" "%ARRAY-DATA-VECTOR"
"%ARRAY-DIMENSION" "%ARRAY-DISPLACED-P"
+ "%ARRAY-DISPLACED-FROM"
"%ARRAY-DISPLACEMENT" "%ARRAY-FILL-POINTER"
"%ARRAY-FILL-POINTER-P" "%ARRAY-RANK"
"%ASSOC"
"%CHECK-GENERIC-SEQUENCE-BOUNDS"
"%CHECK-VECTOR-SEQUENCE-BOUNDS"
"%CLOSURE-FUN" "%CLOSURE-INDEX-REF"
+ "%COMPARE-AND-SWAP-ARRAY-DISPLACED-FROM"
"%COMPARE-AND-SWAP-CAR"
"%COMPARE-AND-SWAP-CDR"
"%COMPARE-AND-SWAP-INSTANCE-REF"
"DEFINE-STRUCTURE-SLOT-ADDRESSOR"
"DEFINED-FTYPE-MATCHES-DECLARED-FTYPE-P"
"!DEFSTRUCT-WITH-ALTERNATE-METACLASS" "DESCEND-INTO"
- "DISPLACED-TO-ARRAY-TOO-SMALL-ERROR"
"DIVISION-BY-ZERO-ERROR" "DOUBLE-FLOAT-EXPONENT"
"DOUBLE-FLOAT-HIGH-BITS" "DOUBLE-FLOAT-INT-EXPONENT"
"DOUBLE-FLOAT-LOW-BITS" "DOUBLE-FLOAT-SIGNIFICAND"
"*ALLOC-SIGNAL*"
"ANY-REG-SC-NUMBER" "ARRAY-DATA-SLOT" "ARRAY-DIMENSIONS-OFFSET"
"ARRAY-DISPLACED-P-SLOT" "ARRAY-DISPLACEMENT-SLOT"
+ "ARRAY-DISPLACED-FROM-SLOT"
"ARRAY-ELEMENTS-SLOT" "ARRAY-FILL-POINTER-P-SLOT"
"ARRAY-FILL-POINTER-SLOT" "ATOMIC-FLAG"
"CHARACTER-REG-SC-NUMBER"
(def %array-available-elements)
(def %array-data-vector)
(def %array-displacement)
- (def %array-displaced-p))
+ (def %array-displaced-p)
+ (def %array-diplaced-from))
(defun %array-rank (array)
(%array-rank array))
(setf (%array-fill-pointer-p array) nil)))
(setf (%array-available-elements array) total-size)
(setf (%array-data-vector array) data)
+ (setf (%array-displaced-from array) nil)
(cond (displaced-to
(when (or initial-element-p initial-contents-p)
(error "Neither :INITIAL-ELEMENT nor :INITIAL-CONTENTS ~
(array-total-size displaced-to))
(error "~S doesn't have enough elements." displaced-to))
(setf (%array-displacement array) offset)
- (setf (%array-displaced-p array) t)))
+ (setf (%array-displaced-p array) t)
+ (%save-displaced-array-backpointer array data)))
(t
(setf (%array-displaced-p array) nil)))
(let ((axis 0))
(error "Axis number ~W is too big; ~S only has ~D dimension~:P."
axis-number array (%array-rank array)))
(t
- ;; ANSI sayeth (ADJUST-ARRAY dictionary entry):
- ;;
- ;; "If A is displaced to B, the consequences are
- ;; unspecified if B is adjusted in such a way that it no
- ;; longer has enough elements to satisfy A.
- ;;
- ;; In situations where this matters we should be doing a
- ;; bounds-check, which in turn uses ARRAY-DIMENSION -- so
- ;; this seems like a good place to signal an error.
- (multiple-value-bind (target offset) (array-displacement array)
- (when (and target
- (> (array-total-size array)
- (- (array-total-size target) offset)))
- (error 'displaced-to-array-too-small-error
- :format-control "~@<The displaced-to array is too small. ~S ~
- elements after offset required, ~S available.~:@>"
- :format-arguments (list (array-total-size array)
- (- (array-total-size target) offset))))
- (%array-dimension array axis-number)))))
+ (%array-dimension array axis-number))))
(defun array-dimensions (array)
#!+sb-doc
(set-array-header array array-data array-size
(get-new-fill-pointer array array-size
fill-pointer)
- 0 dimensions nil)
+ 0 dimensions nil nil)
(if (array-header-p array)
;; simple multidimensional or single dimensional array
(make-array dimensions
(set-array-header array displaced-to array-size
(get-new-fill-pointer array array-size
fill-pointer)
- displacement dimensions t)
+ displacement dimensions t nil)
;; simple multidimensional or single dimensional array
(make-array dimensions
:element-type element-type
(set-array-header array new-data new-length
(get-new-fill-pointer array new-length
fill-pointer)
- 0 dimensions nil)
+ 0 dimensions nil nil)
new-data))))
(t
(let ((old-length (%array-available-elements array))
initial-element-p))
(if (adjustable-array-p array)
(set-array-header array new-data new-length
- nil 0 dimensions nil)
+ nil 0 dimensions nil nil)
(let ((new-array
(make-array-header
sb!vm:simple-array-widetag array-rank)))
(set-array-header new-array new-data new-length
- nil 0 dimensions nil)))))))))))
+ nil 0 dimensions nil t)))))))))))
(defun get-new-fill-pointer (old-array new-array-size fill-pointer)
vector)
(t (subseq vector 0 new-length))))
+(defun %save-displaced-array-backpointer (array data)
+ (when (array-header-p data)
+ (let* ((old (%array-displaced-from data))
+ (new (cons (make-weak-pointer array) old)))
+ (loop until (eq old (%compare-and-swap-array-displaced-from data old new))
+ do (setf old (%array-displaced-from data)
+ new (rplacd new (remove-if-not #'weak-pointer-value old)))))))
+
;;; Fill in array header with the provided information, and return the array.
(defun set-array-header (array data length fill-pointer displacement dimensions
- &optional displacedp)
+ displacedp newp)
+ (if newp
+ (setf (%array-displaced-from array) nil)
+ ;; ANSI sayeth (ADJUST-ARRAY dictionary entry):
+ ;;
+ ;; "If A is displaced to B, the consequences are unspecified if B is
+ ;; adjusted in such a way that it no longer has enough elements to
+ ;; satisfy A.
+ ;;
+ ;; so check the backpointers and signal an error if appropriate.
+ (dolist (p (%array-displaced-from array))
+ (let ((from (weak-pointer-value p)))
+ (when from
+ (let ((requires (+ (%array-available-elements from)
+ (%array-displacement from))))
+ (unless (>= length requires)
+ (error 'simple-reference-error
+ :format-control "Cannot shrink ~S to ~S elements: displaced array ~S requires at least ~S elements."
+ :format-arguments (list 'adjust-array length from requires))))))))
+ (%save-displaced-array-backpointer array data)
(setf (%array-data-vector array) data)
(setf (%array-available-elements array) length)
(cond (fill-pointer
;;; BUG 315: "no bounds check for access to displaced array"
;;; reported by Bruno Haible sbcl-devel "various SBCL bugs" from CLISP
;;; test suite.
-(multiple-value-bind (val err)
- (ignore-errors
- (locally (declare (optimize (safety 3) (speed 0)))
- (let* ((x (make-array 10 :fill-pointer 4 :element-type 'character
- :initial-element #\space :adjustable t))
- (y (make-array 10 :fill-pointer 4 :element-type 'character
- :displaced-to x)))
- (adjust-array x '(5))
- (char y 5))))
- (assert (and (not val) (typep err 'sb-kernel:displaced-to-array-too-small-error))))
+(locally (declare (optimize (safety 3) (speed 0)))
+ (let* ((x (make-array 10 :fill-pointer 4 :element-type 'character
+ :initial-element #\space :adjustable t))
+ (y (make-array 10 :fill-pointer 4 :element-type 'character
+ :displaced-to x)))
+ (handler-case
+ (adjust-array x '(5))
+ (error (e)
+ (assert (typep e 'sb-int:simple-reference-error))
+ (assert (equal '((:ansi-cl function adjust-array))
+ (sb-int:reference-condition-references e)))))))
;;; MISC.527: bit-vector bitwise operations used LENGTH to get a size
;;; of a vector