X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fcode%2Farray.lisp;h=266c7374f99f10286c56c0bdde1ebf8b43c4be24;hb=2db410feb35e7e30c95af8f20f67e6177fa92488;hp=4b01135718adf7f881eb9bc5e9bc95821e504171;hpb=cc25b617f4713cde387b5974fda111faa193313f;p=sbcl.git diff --git a/src/code/array.lisp b/src/code/array.lisp index 4b01135..266c737 100644 --- a/src/code/array.lisp +++ b/src/code/array.lisp @@ -46,8 +46,11 @@ (fixnum index)) (%check-bound array bound index)) +(defun %with-array-data/fp (array start end) + (%with-array-data-macro array start end :check-bounds t :check-fill-pointer t)) + (defun %with-array-data (array start end) - (%with-array-data-macro array start end :fail-inline? t)) + (%with-array-data-macro array start end :check-bounds t :check-fill-pointer nil)) (defun %data-vector-and-index (array index) (if (array-header-p array) @@ -55,14 +58,6 @@ (%with-array-data array index nil) (values vector index)) (values array index))) - -;;; It'd waste space to expand copies of error handling in every -;;; inline %WITH-ARRAY-DATA, so we have them call this function -;;; instead. This is just a wrapper which is known never to return. -(defun failed-%with-array-data (array start end) - (declare (notinline %with-array-data)) - (%with-array-data array start end) - (bug "called FAILED-%WITH-ARRAY-DATA with valid array parameters?")) ;;;; MAKE-ARRAY (eval-when (:compile-toplevel :execute) @@ -328,10 +323,39 @@ of specialized arrays is supported." ;;; the type information is available. Finally, for each of these ;;; routines also provide a slow path, taken for arrays that are not ;;; vectors or not simple. -(macrolet ((define (accessor-name slow-accessor-name table-name extra-params - check-bounds) +(macrolet ((def (name table-name) `(progn (defvar ,table-name) + (defmacro ,name (array-var) + `(the function + (let ((tag 0) + (offset + #.(ecase sb!c:*backend-byte-order* + (:little-endian + (- sb!vm:other-pointer-lowtag)) + (:big-endian + (- (1- sb!vm:n-word-bytes) sb!vm:other-pointer-lowtag))))) + ;; WIDETAG-OF needs extra code to handle LIST and + ;; FUNCTION lowtags. We're only dispatching on + ;; other pointers, so let's do the lowtag + ;; extraction manually. + (when (sb!vm::%other-pointer-p ,array-var) + (setf tag + (sb!sys:sap-ref-8 (int-sap (get-lisp-obj-address ,array-var)) + offset))) + ;; SYMBOL-GLOBAL-VALUE is a performance hack + ;; for threaded builds. + (svref (sb!vm::symbol-global-value ',',table-name) tag))))))) + (def !find-data-vector-setter *data-vector-setters*) + (def !find-data-vector-setter/check-bounds *data-vector-setters/check-bounds*) + (def !find-data-vector-reffer *data-vector-reffers*) + (def !find-data-vector-reffer/check-bounds *data-vector-reffers/check-bounds*)) + +(macrolet ((%ref (accessor-getter extra-params) + `(funcall (,accessor-getter array) array index ,@extra-params)) + (define (accessor-name slow-accessor-name accessor-getter + extra-params check-bounds) + `(progn (defun ,accessor-name (array index ,@extra-params) (declare (optimize speed ;; (SAFETY 0) is ok. All calls to @@ -341,38 +365,14 @@ of specialized arrays is supported." ;; is done implicitly via the widetag ;; dispatch. (safety 0))) - #1=(funcall - (the function - (let ((tag 0) - (offset - #.(ecase sb!c:*backend-byte-order* - (:little-endian - (- sb!vm:other-pointer-lowtag)) - (:big-endian - ;; I'm not completely sure of what this - ;; 3 represents symbolically. It's - ;; just what all the LOAD-TYPE vops - ;; are doing. - (- 3 sb!vm:other-pointer-lowtag))))) - ;; WIDETAG-OF needs extra code to handle - ;; LIST and FUNCTION lowtags. We're only - ;; dispatching on other pointers, so let's - ;; do the lowtag extraction manually. - (when (sb!vm::%other-pointer-p array) - (setf tag - (sb!sys:sap-ref-8 (int-sap (get-lisp-obj-address array)) - offset))) - ;; SYMBOL-GLOBAL-VALUE is a performance hack - ;; for threaded builds. - (svref (sb!vm::symbol-global-value ',table-name) tag))) - array index ,@extra-params)) + (%ref ,accessor-getter ,extra-params)) (defun ,slow-accessor-name (array index ,@extra-params) (declare (optimize speed (safety 0))) (if (not (%array-displaced-p array)) ;; The reasonably quick path of non-displaced complex ;; arrays. (let ((array (%array-data-vector array))) - #1#) + (%ref ,accessor-getter ,extra-params)) ;; The real slow path. (with-array-data ((vector array) @@ -384,17 +384,19 @@ of specialized arrays is supported." (declare (ignore end)) (,accessor-name vector index ,@extra-params))))))) (define hairy-data-vector-ref slow-hairy-data-vector-ref - *data-vector-reffers* nil (progn)) + !find-data-vector-reffer + nil (progn)) (define hairy-data-vector-set slow-hairy-data-vector-set - *data-vector-setters* (new-value) (progn)) + !find-data-vector-setter + (new-value) (progn)) (define hairy-data-vector-ref/check-bounds slow-hairy-data-vector-ref/check-bounds - *data-vector-reffers/check-bounds* nil - (%check-bound array (array-dimension array 0))) + !find-data-vector-reffer/check-bounds + nil (%check-bound array (array-dimension array 0))) (define hairy-data-vector-set/check-bounds slow-hairy-data-vector-set/check-bounds - *data-vector-setters/check-bounds* (new-value) - (%check-bound array (array-dimension array 0)))) + !find-data-vector-setter/check-bounds + (new-value) (%check-bound array (array-dimension array 0)))) (defun hairy-ref-error (array index &optional new-value) (declare (ignore index new-value)) @@ -442,7 +444,7 @@ of specialized arrays is supported." ,@(loop for widetag in '(sb!vm:complex-vector-widetag sb!vm:complex-vector-nil-widetag sb!vm:complex-bit-vector-widetag - sb!vm:complex-character-string-widetag + #!+sb-unicode sb!vm:complex-character-string-widetag sb!vm:complex-base-string-widetag sb!vm:simple-array-widetag sb!vm:complex-array-widetag) @@ -471,6 +473,9 @@ of specialized arrays is supported." (defun data-vector-ref (array index) (hairy-data-vector-ref array index)) +(defun data-vector-ref-with-offset (array index offset) + (hairy-data-vector-ref array (+ index offset))) + ;;; SUBSCRIPTS has a dynamic-extent list structure and is destroyed (defun %array-row-major-index (array subscripts &optional (invalid-index-error-p t)) @@ -522,17 +527,17 @@ of specialized arrays is supported." t)) (defun array-row-major-index (array &rest subscripts) - (declare (dynamic-extent subscripts)) + (declare (truly-dynamic-extent subscripts)) (%array-row-major-index array subscripts)) (defun aref (array &rest subscripts) #!+sb-doc "Return the element of the ARRAY specified by the SUBSCRIPTS." - (declare (dynamic-extent subscripts)) + (declare (truly-dynamic-extent subscripts)) (row-major-aref array (%array-row-major-index array subscripts))) (defun %aset (array &rest stuff) - (declare (dynamic-extent stuff)) + (declare (truly-dynamic-extent stuff)) (let ((subscripts (butlast stuff)) (new-value (car (last stuff)))) (setf (row-major-aref array (%array-row-major-index array subscripts)) @@ -565,7 +570,7 @@ of specialized arrays is supported." #!-sb-fluid (declaim (inline (setf aref))) (defun (setf aref) (new-value array &rest subscripts) - (declare (dynamic-extent subscripts)) + (declare (truly-dynamic-extent subscripts)) (declare (type array array)) (setf (row-major-aref array (%array-row-major-index array subscripts)) new-value)) @@ -763,31 +768,37 @@ of specialized arrays is supported." (declare (array array)) (and (array-header-p array) (%array-fill-pointer-p array))) +(defun fill-pointer-error (vector arg) + (cond (arg + (aver (array-has-fill-pointer-p vector)) + (let ((max (%array-available-elements vector))) + (error 'simple-type-error + :datum arg + :expected-type (list 'integer 0 max) + :format-control "The new fill pointer, ~S, is larger than the length of the vector (~S.)" + :format-arguments (list arg max)))) + (t + (error 'simple-type-error + :datum vector + :expected-type '(and vector (satisfies array-has-fill-pointer-p)) + :format-control "~S is not an array with a fill pointer." + :format-arguments (list vector))))) + (defun fill-pointer (vector) #!+sb-doc "Return the FILL-POINTER of the given VECTOR." - (declare (vector vector)) - (if (and (array-header-p vector) (%array-fill-pointer-p vector)) + (if (array-has-fill-pointer-p vector) (%array-fill-pointer vector) - (error 'simple-type-error - :datum vector - :expected-type '(and vector (satisfies array-has-fill-pointer-p)) - :format-control "~S is not an array with a fill pointer." - :format-arguments (list vector)))) + (fill-pointer-error vector nil))) (defun %set-fill-pointer (vector new) - (declare (vector vector) (fixnum new)) - (if (and (array-header-p vector) (%array-fill-pointer-p vector)) - (if (> new (%array-available-elements vector)) - (error - "The new fill pointer, ~S, is larger than the length of the vector." - new) - (setf (%array-fill-pointer vector) new)) - (error 'simple-type-error - :datum vector - :expected-type '(and vector (satisfies array-has-fill-pointer-p)) - :format-control "~S is not an array with a fill pointer." - :format-arguments (list vector)))) + (flet ((oops (x) + (fill-pointer-error vector x))) + (if (array-has-fill-pointer-p vector) + (if (> new (%array-available-elements vector)) + (oops new) + (setf (%array-fill-pointer vector) new)) + (oops nil)))) ;;; FIXME: It'd probably make sense to use a MACROLET to share the ;;; guts of VECTOR-PUSH between VECTOR-PUSH-EXTEND. Such a macro @@ -806,19 +817,23 @@ of specialized arrays is supported." (cond ((= fill-pointer (%array-available-elements array)) nil) (t - (setf (aref array fill-pointer) new-el) + (locally (declare (optimize (safety 0))) + (setf (aref array fill-pointer) new-el)) (setf (%array-fill-pointer array) (1+ fill-pointer)) fill-pointer)))) (defun vector-push-extend (new-element vector &optional - (extension (1+ (length vector)))) - (declare (vector vector) (fixnum extension)) + (min-extension + (let ((length (length vector))) + (min (1+ length) + (- array-dimension-limit length))))) + (declare (vector vector) (fixnum min-extension)) (let ((fill-pointer (fill-pointer vector))) (declare (fixnum fill-pointer)) (when (= fill-pointer (%array-available-elements vector)) - (adjust-array vector (+ fill-pointer extension))) + (adjust-array vector (+ fill-pointer (max 1 min-extension)))) ;; disable bounds checking (locally (declare (optimize (safety 0))) (setf (aref vector fill-pointer) new-element)) @@ -964,12 +979,12 @@ of specialized arrays is supported." initial-element-p)) (if (adjustable-array-p array) (set-array-header array new-data new-length - new-length 0 dimensions nil) + nil 0 dimensions nil) (let ((new-array (make-array-header sb!vm:simple-array-widetag array-rank))) (set-array-header new-array new-data new-length - new-length 0 dimensions nil))))))))))) + nil 0 dimensions nil))))))))))) (defun get-new-fill-pointer (old-array new-array-size fill-pointer) @@ -1068,7 +1083,37 @@ of specialized arrays is supported." (setf (%array-dimension array 0) dimensions)) (setf (%array-displaced-p array) displacedp) array) + +;;; User visible extension +(declaim (ftype (function (array) (values (simple-array * (*)) &optional)) + array-storage-vector)) +(defun array-storage-vector (array) + "Returns the underlying storage vector of ARRAY, which must be a non-displaced array. + +In SBCL, if ARRAY is a of type \(SIMPLE-ARRAY * \(*)), it is its own storage +vector. Multidimensional arrays, arrays with fill pointers, and adjustable +arrays have an underlying storage vector with the same ARRAY-ELEMENT-TYPE as +ARRAY, which this function returns. + +Important note: the underlying vector is an implementation detail. Even though +this function exposes it, changes in the implementation may cause this +function to be removed without further warning." + ;; KLUDGE: Without TRULY-THE the system is not smart enough to figure out that + ;; the return value is always of the known type. + (truly-the (simple-array * (*)) + (if (array-header-p array) + (if (%array-displaced-p array) + (error "~S cannot be used with displaced arrays. Use ~S instead." + 'array-storage-vector 'array-displacement) + (%array-data-vector array)) + array))) +;;;; used by SORT + +;;; temporary vector for stable sorting vectors, allocated for each new thread +(defvar *merge-sort-temp-vector* (vector)) +(declaim (simple-vector *merge-sort-temp-vector*)) + ;;;; ZAP-ARRAY-DATA for ADJUST-ARRAY ;;; a temporary to be used when OLD-DATA and NEW-DATA are EQ. @@ -1117,18 +1162,14 @@ of specialized arrays is supported." (unless (typep initial-element element-type) (error "~S can't be used to initialize an array of type ~S." initial-element element-type))) - (without-interrupts - ;; Need to disable interrupts while using the temp-vector. - ;; An interrupt handler that also happened to call - ;; ADJUST-ARRAY could otherwise stomp on our data here. - (let ((temp (zap-array-data-temp new-length - initial-element initial-element-p))) - (declare (simple-vector temp)) - (zap-array-data-aux old-data old-dims offset temp new-dims) - (dotimes (i new-length) - (setf (aref new-data i) (aref temp i) - ;; zero out any garbage right away - (aref temp i) 0))))) + (let ((temp (zap-array-data-temp new-length + initial-element initial-element-p))) + (declare (simple-vector temp)) + (zap-array-data-aux old-data old-dims offset temp new-dims) + (dotimes (i new-length) + (setf (aref new-data i) (aref temp i) + ;; zero out any garbage right away + (aref temp i) 0)))) (t ;; When OLD-DATA and NEW-DATA are not EQ, NEW-DATA has ;; already been filled with any