(type string x))
(unless *cold-load-dump*
(let ((handle (cdr (assoc
- (array-element-type x)
+ #+sb-xc-host 'base-char ; for repeatable xc fasls
+ #-sb-xc-host (array-element-type x)
(gethash x (fasl-output-equal-table fasl-output))))))
(cond
(handle (dump-push handle fasl-output) t)
(type string x))
(unless *cold-load-dump*
(let ((handle (dump-pop fasl-output)))
- (push (cons (array-element-type x) handle)
+ (push (cons #+sb-xc-host 'base-char ; repeatable xc fasls
+ #-sb-xc-host (array-element-type x)
+ handle)
(gethash x (fasl-output-equal-table fasl-output)))
(setf (gethash x (fasl-output-eq-table fasl-output)) handle)
(dump-push handle fasl-output)))
\f
;;;; opening and closing fasl files
-;;; A utility function to write strings to (unsigned-byte 8) streams.
-;;; We restrict this to ASCII (with the averrance) because of
-;;; ambiguity of higher bytes: Unicode, some ISO-8859-x, or what? This
-;;; could be revisited in the event of doing funky things with stream
-;;; encodings -- CSR, 2002-04-25
-(defun fasl-write-string (string stream)
- (loop for char across string
- do (let ((code (char-code char)))
- (aver (<= 0 code 127))
- (write-byte code stream))))
-
;;; Open a fasl file, write its header, and return a FASL-OUTPUT
;;; object for dumping to it. Some human-readable information about
;;; the source code is given by the string WHERE.
(defun open-fasl-output (name where)
(declare (type pathname name))
- (let* ((stream (open name
- :direction :output
- :if-exists :supersede
- :element-type 'sb!assem:assembly-unit))
- (res (make-fasl-output :stream stream)))
-
- ;; Begin the header with the constant machine-readable (and
- ;; semi-human-readable) string which is used to identify fasl files.
- (fasl-write-string *fasl-header-string-start-string* stream)
-
- ;; The constant string which begins the header is followed by
- ;; arbitrary human-readable text, terminated by a special
- ;; character code.
- (fasl-write-string
- (with-standard-io-syntax
- (let ((*print-readably* nil)
- (*print-pretty* nil))
- (format nil
- "~% ~
- compiled from ~S~% ~
- at ~A~% ~
- on ~A~% ~
- using ~A version ~A~%"
- where
- (format-universal-time nil (get-universal-time))
- (machine-instance)
- (sb!xc:lisp-implementation-type)
- (sb!xc:lisp-implementation-version))))
- stream)
- (dump-byte +fasl-header-string-stop-char-code+ res)
-
- ;; Finish the header by outputting fasl file implementation,
- ;; version, and key *FEATURES*.
- (flet ((dump-counted-string (string)
- ;; The count is dumped as a 32-bit unsigned-byte even on 64-bit
- ;; platforms. This ensures that a x86-64 SBCL can gracefully
- ;; detect an error when trying to read a x86 fasl, instead
- ;; of choking on a ridiculously long counted string.
- ;; -- JES, 2005-12-30
- (dump-unsigned-byte-32 (length string) res)
- (dotimes (i (length string))
- (dump-byte (char-code (aref string i)) res))))
- (dump-counted-string (symbol-name +backend-fasl-file-implementation+))
- (dump-word +fasl-file-version+ res)
- (dump-counted-string *features-affecting-fasl-format*))
-
- res))
+ (flet ((fasl-write-string (string stream)
+ ;; SB-EXT:STRING-TO-OCTETS is not available while cross-compiling
+ #+sb-xc-host
+ (loop for char across string
+ do (let ((code (char-code char)))
+ (unless (<= 0 code 127)
+ (setf char #\?))
+ (write-byte code stream)))
+ ;; UTF-8 is safe to use, because +FASL-HEADER-STRING-STOP-CHAR-CODE+
+ ;; may not appear in UTF-8 encoded bytes
+ #-sb-xc-host
+ (write-sequence (string-to-octets string :external-format :utf-8)
+ stream)))
+ (let* ((stream (open name
+ :direction :output
+ :if-exists :supersede
+ :element-type 'sb!assem:assembly-unit))
+ (res (make-fasl-output :stream stream)))
+ ;; Before the actual FASL header, write a shebang line using the current
+ ;; runtime path, so our fasls can be executed directly from the shell.
+ (when *runtime-pathname*
+ (fasl-write-string
+ (format nil "#!~A --script~%"
+ (native-namestring *runtime-pathname* :as-file t))
+ stream))
+ ;; Begin the header with the constant machine-readable (and
+ ;; semi-human-readable) string which is used to identify fasl files.
+ (fasl-write-string *fasl-header-string-start-string* stream)
+ ;; The constant string which begins the header is followed by
+ ;; arbitrary human-readable text, terminated by
+ ;; +FASL-HEADER-STRING-STOP-CHAR-CODE+.
+ (fasl-write-string
+ (with-standard-io-syntax
+ (let ((*print-readably* nil)
+ (*print-pretty* nil))
+ (format nil
+ "~% ~
+ compiled from ~S~% ~
+ at ~A~% ~
+ on ~A~% ~
+ using ~A version ~A~%"
+ where
+ #+sb-xc-host "cross-compile time"
+ #-sb-xc-host (format-universal-time nil (get-universal-time))
+ #+sb-xc-host "cross-compile host"
+ #-sb-xc-host (machine-instance)
+ (sb!xc:lisp-implementation-type)
+ (sb!xc:lisp-implementation-version))))
+ stream)
+ (dump-byte +fasl-header-string-stop-char-code+ res)
+ ;; Finish the header by outputting fasl file implementation,
+ ;; version, and key *FEATURES*.
+ (flet ((dump-counted-string (string)
+ ;; The count is dumped as a 32-bit unsigned-byte even on 64-bit
+ ;; platforms. This ensures that a x86-64 SBCL can gracefully
+ ;; detect an error when trying to read a x86 fasl, instead
+ ;; of choking on a ridiculously long counted string.
+ ;; -- JES, 2005-12-30
+ (dump-unsigned-byte-32 (length string) res)
+ (dotimes (i (length string))
+ (dump-byte (char-code (aref string i)) res))))
+ (dump-counted-string (symbol-name +backend-fasl-file-implementation+))
+ (dump-word +fasl-file-version+ res)
+ (dump-counted-string (sb!xc:lisp-implementation-version))
+ (dump-counted-string *features-affecting-fasl-format*))
+ res)))
;;; Close the specified FASL-OUTPUT, aborting the write if ABORT-P.
(defun close-fasl-output (fasl-output abort-p)
(declare (type fasl-output fasl-output))
- ;; sanity checks
- (aver (zerop (hash-table-count (fasl-output-patch-table fasl-output))))
-
- ;; End the group.
- (dump-fop 'fop-verify-empty-stack fasl-output)
- (dump-fop 'fop-verify-table-size fasl-output)
- (dump-word (fasl-output-table-free fasl-output)
- fasl-output)
- (dump-fop 'fop-end-group fasl-output)
+ (unless abort-p
+ ;; sanity checks
+ (aver (zerop (hash-table-count (fasl-output-patch-table fasl-output))))
+ ;; End the group.
+ (dump-fop 'fop-verify-empty-stack fasl-output)
+ (dump-fop 'fop-verify-table-size fasl-output)
+ (dump-word (fasl-output-table-free fasl-output)
+ fasl-output)
+ (dump-fop 'fop-end-group fasl-output))
;; That's all, folks.
(close (fasl-output-stream fasl-output) :abort abort-p)
;; take a little more care while dumping these.
;; So if better list coalescing is needed, start here.
;; -- WHN 2000-11-07
- (if (cyclic-list-p x)
+ (if (maybe-cyclic-p x)
(progn
(dump-list x file)
(eq-save-object x file))
(dump-byte 0 file))
(dump-pop file))
-;;; Return T iff CONSTANT has not already been dumped. It's been
-;;; dumped if it's in the EQ table.
+;;; Return T iff CONSTANT has already been dumped. It's been dumped if
+;;; it's in the EQ table.
+;;;
+;;; Note: historically (1) the above comment was "T iff ... has not been dumped",
+;;; (2) the test was was also true if the constant had been validated / was in
+;;; the valid objects table. This led to substructures occasionally skipping the
+;;; validation, and hence failing the "must have been validated" test.
(defun fasl-constant-already-dumped-p (constant file)
- (if (or (gethash constant (fasl-output-eq-table file))
- (gethash constant (fasl-output-valid-structures file)))
- t
- nil))
+ (and (gethash constant (fasl-output-eq-table file)) t))
;;; Use HANDLE whenever we try to dump CONSTANT. HANDLE should have been
;;; returned earlier by FASL-DUMP-LOAD-TIME-VALUE-LAMBDA.
(dump-fop 'fop-long-float file)
(dump-long-float x file))))
+(defun dump-complex-single-float (re im file)
+ (declare (single-float re im))
+ (dump-fop 'fop-complex-single-float file)
+ (dump-integer-as-n-bytes (single-float-bits re) 4 file)
+ (dump-integer-as-n-bytes (single-float-bits im) 4 file))
+
+(defun dump-complex-double-float (re im file)
+ (declare (double-float re im))
+ (dump-fop 'fop-complex-double-float file)
+ (dump-integer-as-n-bytes (double-float-low-bits re) 4 file)
+ (dump-integer-as-n-bytes (double-float-high-bits re) 4 file)
+ (dump-integer-as-n-bytes (double-float-low-bits im) 4 file)
+ (dump-integer-as-n-bytes (double-float-high-bits im) 4 file))
+
+(defun dump-complex-rational (re im file)
+ (sub-dump-object re file)
+ (sub-dump-object im file)
+ (dump-fop 'fop-complex file))
+
+#+sb-xc-host
+(defun dump-complex (x file)
+ (let ((re (realpart x))
+ (im (imagpart x)))
+ (cond ((and (typep re 'single-float)
+ (typep im 'single-float))
+ (dump-complex-single-float re im file))
+ ((and (typep re 'double-float)
+ (typep im 'double-float))
+ (dump-complex-double-float re im file))
+ ((and (typep re 'rational)
+ (typep im 'rational))
+ (dump-complex-rational re im file))
+ (t
+ (bug "Complex number too complex: ~S" x)))))
+
+#-sb-xc-host
(defun dump-complex (x file)
(typecase x
- #-sb-xc-host
((complex single-float)
- (dump-fop 'fop-complex-single-float file)
- (dump-integer-as-n-bytes (single-float-bits (realpart x)) 4 file)
- (dump-integer-as-n-bytes (single-float-bits (imagpart x)) 4 file))
- #-sb-xc-host
+ (dump-complex-single-float (realpart x) (imagpart x) file))
((complex double-float)
- (dump-fop 'fop-complex-double-float file)
- (let ((re (realpart x)))
- (declare (double-float re))
- (dump-integer-as-n-bytes (double-float-low-bits re) 4 file)
- (dump-integer-as-n-bytes (double-float-high-bits re) 4 file))
- (let ((im (imagpart x)))
- (declare (double-float im))
- (dump-integer-as-n-bytes (double-float-low-bits im) 4 file)
- (dump-integer-as-n-bytes (double-float-high-bits im) 4 file)))
+ (dump-complex-double-float (realpart x) (imagpart x) file))
#!+long-float
((complex long-float)
- ;; (There's no easy way to mix #!+LONG-FLOAT and #-SB-XC-HOST
- ;; conditionalization at read time, so we do this SB-XC-HOST
- ;; conditional at runtime instead.)
- #+sb-xc-host (error "can't dump COMPLEX-LONG-FLOAT in cross-compiler")
(dump-fop 'fop-complex-long-float file)
(dump-long-float (realpart x) file)
(dump-long-float (imagpart x) file))
(t
- (sub-dump-object (realpart x) file)
- (sub-dump-object (imagpart x) file)
- (dump-fop 'fop-complex file))))
+ (dump-complex-rational (realpart x) (imagpart x) file))))
\f
;;;; symbol dumping
(let* ((pname (symbol-name s))
(pname-length (length pname))
(pkg (symbol-package s)))
+ ;; see comment in genesis: we need this here for repeatable fasls
+ #+sb-xc-host
+ (multiple-value-bind (cl-symbol cl-status)
+ (find-symbol (symbol-name s) sb!int:*cl-package*)
+ (when (and (eq s cl-symbol)
+ (eq cl-status :external))
+ ;; special case, to work around possible xc host "design
+ ;; choice" weirdness in COMMON-LISP package
+ (setq pkg sb!int:*cl-package*)))
(cond ((null pkg)
(dump-fop* pname-length
(dump-object name file)
(dump-object (sb!c::entry-info-arguments entry) file)
(dump-object (sb!c::entry-info-type entry) file)
+ (dump-object (sb!c::entry-info-info entry) file)
(dump-fop 'fop-fun-entry file)
(dump-word (label-position (sb!c::entry-info-offset entry)) file)
(dump-pop file)))
(declare (type component component) (list trace-table))
(declare (type fasl-output file))
- (dump-fop 'fop-verify-empty-stack file)
(dump-fop 'fop-verify-table-size file)
(dump-word (fasl-output-table-free file) file)
fixups
file))
(2comp (component-info component)))
- (dump-fop 'fop-verify-empty-stack file)
(dolist (entry (sb!c::ir2-component-entries 2comp))
(let ((entry-handle (dump-one-entry entry code-handle file)))
(declare (type sb!c::source-info info))
(let ((res (sb!c::debug-source-for-info info))
(*dump-only-valid-structures* nil))
+ #+sb-xc-host (setf (sb!c::debug-source-created res) 0
+ (sb!c::debug-source-compiled res) 0)
(dump-object res fasl-output)
(let ((res-handle (dump-pop fasl-output)))
(dolist (info-handle (fasl-output-debug-info fasl-output))
(dump-push res-handle fasl-output)
(dump-fop 'fop-structset fasl-output)
(dump-word info-handle fasl-output)
- ;; FIXME: what is this bare `2'? --njf, 2004-08-16
- (dump-word 2 fasl-output))))
+ (dump-word sb!c::+debug-info-source-index+ fasl-output))
+ #+sb-xc-host
+ (progn
+ (dump-push res-handle fasl-output)
+ (dump-fop 'fop-note-debug-source fasl-output))))
(setf (fasl-output-debug-info fasl-output) nil)
(values))
\f