Fix loading specialized vectors from fasls.
authorStas Boukarev <stassats@gmail.com>
Thu, 19 Sep 2013 02:24:25 +0000 (06:24 +0400)
committerStas Boukarev <stassats@gmail.com>
Thu, 19 Sep 2013 02:24:25 +0000 (06:24 +0400)
Previously vectors were dumped and loaded based on the hand crafted
typecase forms, which was quite fragile.
After the dumping part was rewritten to consult
sb-vm:*specialized-array-element-type-properties*, the loading part
broke down.
Change the way it's done altogether, simplifying things significantly.
Instead of having separate FOPs for signed and unsigned vectors,
writing bit size of elements, just dump the widetag and use just a
single FOP, fop-spec-vector. Floating point dumping routines now use
fop-spec-vector too.

src/code/fop.lisp
src/compiler/dump.lisp
src/compiler/generic/genesis.lisp
src/compiler/target-dump.lisp
tests/compiler.pure-cload.lisp

index 02dcf61..44e512d 100644 (file)
                       t)
     res))
 
-(define-fop (fop-single-float-vector 84)
+(defglobal **saetp-bits-per-length**
+    (let ((array (make-array 255 :element-type '(unsigned-byte 8)
+                                 :initial-element 255)))
+      (loop for saetp across sb!vm:*specialized-array-element-type-properties*
+            do
+            (setf (aref array (sb!vm:saetp-typecode saetp))
+                  (sb!vm:saetp-n-bits saetp)))
+      array)
+    "255 means bad entry.")
+(declaim (type (simple-array (unsigned-byte 8) (255))
+               **saetp-bits-per-length**))
+
+(define-fop (fop-spec-vector 43)
   (let* ((length (read-word-arg))
-         (result (make-array length :element-type 'single-float)))
-    (read-n-bytes *fasl-input-stream* result 0 (* length 4))
-    result))
-
-(define-fop (fop-double-float-vector 85)
-  (let* ((length (read-word-arg))
-         (result (make-array length :element-type 'double-float)))
-    (read-n-bytes *fasl-input-stream* result 0 (* length 8))
-    result))
-
-(define-fop (fop-complex-single-float-vector 86)
-  (let* ((length (read-word-arg))
-         (result (make-array length :element-type '(complex single-float))))
-    (read-n-bytes *fasl-input-stream* result 0 (* length 8))
-    result))
-
-(define-fop (fop-complex-double-float-vector 87)
-  (let* ((length (read-word-arg))
-         (result (make-array length :element-type '(complex double-float))))
-    (read-n-bytes *fasl-input-stream* result 0 (* length 16))
-    result))
-
-;;; CMU CL comment:
-;;;   *** NOT *** the FOP-INT-VECTOR as currently documented in rtguts.
-;;;   Size must be a directly supported I-vector element size, with no
-;;;   extra bits. This must be packed according to the local
-;;;   byte-ordering, allowing us to directly read the bits.
-(define-fop (fop-int-vector 43)
-  (let* ((len (read-word-arg))
-         (size (read-byte-arg))
-         (res (case size
-                (0 (make-array len :element-type 'nil))
-                (1 (make-array len :element-type 'bit))
-                (2 (make-array len :element-type '(unsigned-byte 2)))
-                (4 (make-array len :element-type '(unsigned-byte 4)))
-                (7 (prog1 (make-array len :element-type '(unsigned-byte 7))
-                     (setf size 8)))
-                (8 (make-array len :element-type '(unsigned-byte 8)))
-                (15 (prog1 (make-array len :element-type '(unsigned-byte 15))
-                      (setf size 16)))
-                (16 (make-array len :element-type '(unsigned-byte 16)))
-                (31 (prog1 (make-array len :element-type '(unsigned-byte 31))
-                      (setf size 32)))
-                (32 (make-array len :element-type '(unsigned-byte 32)))
-                #!+#.(cl:if (cl:= 64 sb!vm:n-word-bits) '(and) '(or))
-                (63 (prog1 (make-array len :element-type '(unsigned-byte 63))
-                      (setf size 64)))
-                (64 (make-array len :element-type '(unsigned-byte 64)))
-                (t (bug "losing i-vector element size: ~S" size)))))
-    (declare (type index len))
-    (read-n-bytes *fasl-input-stream*
-                  res
-                  0
-                  (ceiling (the index (* size len)) sb!vm:n-byte-bits))
-    res))
-
-;;; This is the same as FOP-INT-VECTOR, except this is for signed
-;;; SIMPLE-ARRAYs.
-(define-fop (fop-signed-int-vector 50)
-  (let* ((len (read-word-arg))
-         (size (read-byte-arg))
-         (res (case size
-                (8 (make-array len :element-type '(signed-byte 8)))
-                (16 (make-array len :element-type '(signed-byte 16)))
-                #!+#.(cl:if (cl:= 32 sb!vm:n-word-bits) '(and) '(or))
-                (29 (prog1 (make-array len :element-type '(unsigned-byte 29))
-                      (setf size 32)))
-                #!+#.(cl:if (cl:= 32 sb!vm:n-word-bits) '(and) '(or))
-                (30 (prog1 (make-array len :element-type '(signed-byte 30))
-                      (setf size 32)))
-                (32 (make-array len :element-type '(signed-byte 32)))
-                #!+#.(cl:if (cl:= 64 sb!vm:n-word-bits) '(and) '(or))
-                (60 (prog1 (make-array len :element-type '(unsigned-byte 60))
-                      (setf size 64)))
-                #!+#.(cl:if (cl:= 64 sb!vm:n-word-bits) '(and) '(or))
-                (61 (prog1 (make-array len :element-type '(signed-byte 61))
-                      (setf size 64)))
-                #!+#.(cl:if (cl:= 64 sb!vm:n-word-bits) '(and) '(or))
-                (64 (make-array len :element-type '(signed-byte 64)))
-                (t (bug "losing si-vector element size: ~S" size)))))
-    (declare (type index len))
-    (read-n-bytes *fasl-input-stream*
-                  res
-                  0
-                  (ceiling (the index (* size len)) sb!vm:n-byte-bits))
-    res))
+         (widetag (read-byte-arg))
+         (bits-per-length (aref **saetp-bits-per-length** widetag))
+         (bytes  (progn
+                   (aver (< bits-per-length 255))
+                   (ceiling (* length bits-per-length) sb!vm:n-byte-bits)))
+         (vector (allocate-vector widetag length (* bytes sb!vm:n-word-bytes))))
+    (declare (type index length))
+    (read-n-bytes *fasl-input-stream* vector 0 bytes)
+    vector))
 
 (define-fop (fop-eval 53)
   (if *skip-until*
index af54880..341bdbf 100644 (file)
       (simple-vector
        (dump-simple-vector simple-version file)
        (eq-save-object x file))
-      ((simple-array single-float (*))
-       (dump-single-float-vector simple-version file)
-       (eq-save-object x file))
-      ((simple-array double-float (*))
-       (dump-double-float-vector simple-version file)
-       (eq-save-object x file))
-      #!+long-float
-      ((simple-array long-float (*))
-       (dump-long-float-vector simple-version file)
-       (eq-save-object x file))
-      ((simple-array (complex single-float) (*))
-       (dump-complex-single-float-vector simple-version file)
-       (eq-save-object x file))
-      ((simple-array (complex double-float) (*))
-       (dump-complex-double-float-vector simple-version file)
-       (eq-save-object x file))
-      #!+long-float
-      ((simple-array (complex long-float) (*))
-       (dump-complex-long-float-vector simple-version file)
-       (eq-save-object x file))
       (t
-       (dump-i-vector simple-version file)
+       (dump-specialized-vector simple-version file)
        (eq-save-object x file)))))
 
 ;;; Dump a SIMPLE-VECTOR, handling any circularities.
 
 ;;; In the grand scheme of things I don't pretend to understand any
 ;;; more how this works, or indeed whether.  But to write out specialized
-;;; vectors in the same format as fop-int-vector expects to read them
+;;; vectors in the same format as fop-spec-vector expects to read them
 ;;; we need to be target-endian.  dump-integer-as-n-bytes always writes
 ;;; little-endian (which is correct for all other integers) so for a bigendian
 ;;; target we need to swap octets -- CSR, after DB
+#+sb-xc-host
+(defun dump-specialized-vector (vector file &key data-only)
+  (labels ((octet-swap (word bits)
+             "BITS must be a multiple of 8"
+             (do ((input word (ash input -8))
+                  (output 0 (logior (ash output 8) (logand input #xff)))
+                  (bits bits (- bits 8)))
+                 ((<= bits 0) output)))
+           (dump-unsigned-vector (widetag bytes bits)
+             (unless data-only
+               (dump-fop 'fop-spec-vector file)
+               (dump-word (length vector) file)
+               (dump-byte widetag file))
+             (dovector (i vector)
+               (dump-integer-as-n-bytes
+                (ecase sb!c:*backend-byte-order*
+                  (:little-endian i)
+                  (:big-endian (octet-swap i bits)))
+                bytes file))))
+    (etypecase vector
+      ((simple-array (unsigned-byte 8) (*))
+       (dump-unsigned-vector sb!vm:simple-array-unsigned-byte-8-widetag 1 8))
+      ((simple-array (unsigned-byte 16) (*))
+       (dump-unsigned-vector sb!vm:simple-array-unsigned-byte-16-widetag 2 16))
+      ((simple-array (unsigned-byte 32) (*))
+       (dump-unsigned-vector sb!vm:simple-array-unsigned-byte-32-widetag 4 32)))))
 
-(defun octet-swap (word bits)
-  "BITS must be a multiple of 8"
-  (do ((input word (ash input -8))
-       (output 0 (logior (ash output 8) (logand input #xff)))
-       (bits bits (- bits 8)))
-      ((<= bits 0) output)))
-
-(defun dump-i-vector (vec file &key data-only)
-  (declare (type (simple-array * (*)) vec))
-  (let ((len (length vec)))
-    (labels ((dump-unsigned-vector (size bytes)
-               (unless data-only
-                 (dump-fop 'fop-int-vector file)
-                 (dump-word len file)
-                 (dump-byte size file))
-               ;; The case which is easy to handle in a portable way is when
-               ;; the element size is a multiple of the output byte size, and
-               ;; happily that's the only case we need to be portable. (The
-               ;; cross-compiler has to output debug information (including
-               ;; (SIMPLE-ARRAY (UNSIGNED-BYTE 8) *).) The other cases are only
-               ;; needed in the target SBCL, so we let them be handled with
-               ;; unportable bit bashing.
-               (cond ((>= size 7) ; easy cases
-                      (multiple-value-bind (floor rem) (floor size 8)
-                        (aver (or (zerop rem) (= rem 7)))
-                        (when (= rem 7)
-                          (setq size (1+ size))
-                          (setq floor (1+ floor)))
-                        (dovector (i vec)
-                          (dump-integer-as-n-bytes
-                           (ecase sb!c:*backend-byte-order*
-                             (:little-endian i)
-                             (:big-endian (octet-swap i size)))
-                           floor file))))
-                     (t ; harder cases, not supported in cross-compiler
-                      (dump-raw-bytes vec bytes file))))
-             (dump-signed-vector (size bytes)
-               ;; Note: Dumping specialized signed vectors isn't
-               ;; supported in the cross-compiler. (All cases here end
-               ;; up trying to call DUMP-RAW-BYTES, which isn't
-               ;; provided in the cross-compilation host, only on the
-               ;; target machine.)
-               (unless data-only
-                 (dump-fop 'fop-signed-int-vector file)
-                 (dump-word len file)
-                 (dump-byte size file))
-               (dump-raw-bytes vec bytes file)))
-      #+sb-xc-host
-      (etypecase vec
-        ((simple-array (unsigned-byte 8) (*))
-         (dump-unsigned-vector 8 len))
-        ((simple-array (unsigned-byte 16) (*))
-         (dump-unsigned-vector 16 (* 2 len)))
-        ((simple-array (unsigned-byte 32) (*))
-         (dump-unsigned-vector 32 (* 4 len))))
-      #-sb-xc-host
-      (macrolet ((frob ()
-                   (labels ((bytes (saetp len)
-                              (let ((n-bits (sb!vm:saetp-n-bits saetp)))
-                                (if (zerop (rem n-bits 8))
-                                    `(* ,len ,(/ n-bits 8))
-                                    `(ceiling (* ,len ,n-bits) 8))))
-                            (size (ctype)
-                              (aver (numeric-type-p ctype))
-                              (let ((low (numeric-type-low ctype))
-                                    (high (numeric-type-high ctype)))
-                                (cond
-                                  ((zerop low) (integer-length high))
-                                  ((minusp low)
-                                   (aver (= (integer-length low) (integer-length high)))
-                                   (1+ (integer-length low)))
-                                  (t (bug "confused ctype: ~S" ctype)))))
-                            (clause (saetp)
-                              (let ((ctype (sb!vm:saetp-ctype saetp))
-                                    (specifier (sb!vm:saetp-specifier saetp)))
-                                (aver (or (eql ctype *empty-type*)
-                                          (numeric-type-p ctype)))
-                                (cond
-                                  ((eql ctype *empty-type*)
-                                   `((simple-array ,specifier (*))
-                                     (dump-unsigned-vector 0 0)))
-                                  ((minusp (numeric-type-low ctype))
-                                   `((simple-array ,specifier (*))
-                                     (dump-signed-vector ,(size ctype) ,(bytes saetp 'len))))
-                                  (t
-                                   (aver (zerop (numeric-type-low ctype)))
-                                   `((simple-array ,specifier (*))
-                                     (dump-unsigned-vector ,(size ctype) ,(bytes saetp 'len))))))))
-                     `(etypecase vec
-                        ,@(loop for x across sb!vm:*specialized-array-element-type-properties*
-                               when (csubtypep (sb!vm:saetp-ctype x) (specifier-type 'integer))
-                               collect (clause x))))))
-        (frob)))))
+#-sb-xc-host
+(defun dump-specialized-vector (vector file &key data-only)
+  (declare (type (simple-array * (*)) vector))
+  (let* ((length (length vector))
+         (widetag (widetag-of vector))
+         (bits-per-length (aref **saetp-bits-per-length** widetag)))
+    (aver (< bits-per-length 255))
+    (unless data-only
+      (dump-fop 'fop-spec-vector file)
+      (dump-word length file)
+      (dump-byte widetag file))
+    (dump-raw-bytes vector (ceiling (* length bits-per-length) sb!vm:n-byte-bits) file)))
 \f
 ;;; Dump characters and string-ish things.
 
       ;; These two dumps are only ones which contribute to our
       ;; TOTAL-LENGTH value.
       (dump-segment code-segment code-length fasl-output)
-      (dump-i-vector packed-trace-table fasl-output :data-only t)
+      (dump-specialized-vector packed-trace-table fasl-output :data-only t)
 
       ;; DUMP-FIXUPS does its own internal DUMP-FOPs: the bytes it
       ;; dumps aren't included in the TOTAL-LENGTH passed to our
index 93ebd3c..a6b2632 100644 (file)
@@ -2263,30 +2263,12 @@ core and return a descriptor to it."
                          (pop-stack)))
     result))
 
-(define-cold-fop (fop-int-vector)
+(define-cold-fop (fop-spec-vector)
   (let* ((len (read-word-arg))
-         (sizebits (read-byte-arg))
-         (type (case sizebits
-                 (0 sb!vm:simple-array-nil-widetag)
-                 (1 sb!vm:simple-bit-vector-widetag)
-                 (2 sb!vm:simple-array-unsigned-byte-2-widetag)
-                 (4 sb!vm:simple-array-unsigned-byte-4-widetag)
-                 (7 (prog1 sb!vm:simple-array-unsigned-byte-7-widetag
-                      (setf sizebits 8)))
-                 (8 sb!vm:simple-array-unsigned-byte-8-widetag)
-                 (15 (prog1 sb!vm:simple-array-unsigned-byte-15-widetag
-                       (setf sizebits 16)))
-                 (16 sb!vm:simple-array-unsigned-byte-16-widetag)
-                 (31 (prog1 sb!vm:simple-array-unsigned-byte-31-widetag
-                       (setf sizebits 32)))
-                 (32 sb!vm:simple-array-unsigned-byte-32-widetag)
-                 #!+#.(cl:if (cl:= 64 sb!vm:n-word-bits) '(and) '(or))
-                 (63 (prog1 sb!vm:simple-array-unsigned-byte-63-widetag
-                       (setf sizebits 64)))
-                 #!+#.(cl:if (cl:= 64 sb!vm:n-word-bits) '(and) '(or))
-                 (64 sb!vm:simple-array-unsigned-byte-64-widetag)
-                 (t (error "losing element size: ~W" sizebits))))
-         (result (allocate-vector-object *dynamic* sizebits len type))
+         (type (read-byte-arg))
+         (sizebits (aref **saetp-bits-per-length** type))
+         (result (progn (aver (< sizebits 255))
+                        (allocate-vector-object *dynamic* sizebits len type)))
          (start (+ (descriptor-byte-offset result)
                    (ash sb!vm:vector-data-offset sb!vm:word-shift)))
          (end (+ start
@@ -2298,28 +2280,6 @@ core and return a descriptor to it."
                                     :end end)
     result))
 
-(define-cold-fop (fop-single-float-vector)
-  (let* ((len (read-word-arg))
-         (result (allocate-vector-object
-                  *dynamic*
-                  sb!vm:n-word-bits
-                  len
-                  sb!vm:simple-array-single-float-widetag))
-         (start (+ (descriptor-byte-offset result)
-                   (ash sb!vm:vector-data-offset sb!vm:word-shift)))
-         (end (+ start (* len 4))))
-    (read-bigvec-as-sequence-or-die (descriptor-bytes result)
-                                    *fasl-input-stream*
-                                    :start start
-                                    :end end)
-    result))
-
-(not-cold-fop fop-double-float-vector)
-#!+long-float (not-cold-fop fop-long-float-vector)
-(not-cold-fop fop-complex-single-float-vector)
-(not-cold-fop fop-complex-double-float-vector)
-#!+long-float (not-cold-fop fop-complex-long-float-vector)
-
 (define-cold-fop (fop-array)
   (let* ((rank (read-word-arg))
          (data-vector (pop-stack))
index 038c645..dda58b4 100644 (file)
     (dump-word rank file)
     (eq-save-object array file)))
 \f
-;;;; various dump-a-number operations
-
-(defun dump-single-float-vector (vec file)
-  (let ((length (length vec)))
-    (dump-fop 'fop-single-float-vector file)
-    (dump-word length file)
-    (dump-raw-bytes vec (* length 4) file)))
-
-(defun dump-double-float-vector (vec file)
-  (let ((length (length vec)))
-    (dump-fop 'fop-double-float-vector file)
-    (dump-word length file)
-    (dump-raw-bytes vec (* length 8) file)))
-
-#!+long-float
-(defun dump-long-float-vector (vec file)
-  (let ((length (length vec)))
-    (dump-fop 'fop-long-float-vector file)
-    (dump-word length file)
-    (dump-raw-bytes vec
-                    (* length sb!vm:n-word-bytes #!+x86 3 #!+sparc 4)
-                    file)))
-
-(defun dump-complex-single-float-vector (vec file)
-  (let ((length (length vec)))
-    (dump-fop 'fop-complex-single-float-vector file)
-    (dump-word length file)
-    (dump-raw-bytes vec (* length 8) file)))
-
-(defun dump-complex-double-float-vector (vec file)
-  (let ((length (length vec)))
-    (dump-fop 'fop-complex-double-float-vector file)
-    (dump-word length file)
-    (dump-raw-bytes vec (* length 16) file)))
-
-#!+long-float
-(defun dump-complex-long-float-vector (vec file)
-  (let ((length (length vec)))
-    (dump-fop 'fop-complex-long-float-vector file)
-    (dump-word length file)
-    (dump-raw-bytes vec
-                    (* length sb!vm:n-word-bytes #!+x86 3 #!+sparc 4 2)
-                    file)))
-
 #!+(and long-float x86)
 (defun dump-long-float (float file)
   (declare (long-float float))
index 3136813..3a20ebd 100644 (file)
 ;;; MAYBE-INFER-ITERATION-VAR-TYPE did not deal with types (REAL * (n)).
 (let ((s (loop for x from (- pi) below (floor (* 2 pi)) by (/ pi 75) count t)))
   (assert (= s 219)))
+
+(with-test (:name :specialized-array-dumping)
+  (macrolet
+      ((make-tests ()
+         `(progn
+            ,@(loop for saetp across
+                    sb-vm:*specialized-array-element-type-properties*
+                    for specifier = (sb-vm:saetp-specifier saetp)
+                    for array = (make-array (if specifier 10 0)
+                                            :element-type specifier)
+                    for make-array = `(make-array ,(if specifier 10 0)
+                                                  :element-type ',specifier)
+                    collect `(assert (and (equal (type-of ,array)
+                                                 ',(type-of array))
+                                          (equalp ,array
+                                                  ,make-array)))))))
+    (make-tests)))