1 ;;;; stuff that knows about dumping FASL files
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
14 ;;;; fasl dumper state
16 ;;; The FASL-OUTPUT structure represents everything we need to
17 ;;; know about dumping to a fasl file. (We need to objectify the
18 ;;; state because the fasdumper must be reentrant.)
19 (defstruct (fasl-output
20 (:constructor make-fasl-output
(stream))
21 (:print-object
(lambda (x s
)
22 (print-unreadable-object (x s
:type t
)
23 (prin1 (namestring (fasl-output-stream x
))
26 ;; the stream we dump to
27 (stream (missing-arg) :type stream
)
28 ;; scratch space for computing varint encodings
29 ;; FIXME: can't use the theoretical max of 10 bytes
30 ;; due to constraint in WRITE-VAR-INTEGER.
31 (varint-buf (make-array 10 :element-type
'(unsigned-byte 8) :fill-pointer t
))
32 ;; hashtables we use to keep track of dumped constants so that we
33 ;; can get them from the table rather than dumping them again. The
34 ;; SIMILAR-TABLE is used for lists and strings, and the EQ-TABLE is
35 ;; used for everything else. We use a separate EQ table to avoid
36 ;; performance pathologies with objects for which SIMILAR
37 ;; degenerates to EQL. Everything entered in the SIMILAR table is
38 ;; also entered in the EQ table.
39 (similar-table (make-similarity-table) :type hash-table
:read-only t
)
40 (eq-table (make-hash-table :test
'eq
) :type hash-table
:read-only t
)
41 ;; the INSTANCE table maps dumpable instances to unique IDs for calculating
42 ;; a similarity hash of composite objects that contain instances.
43 ;; A user-defined hash function can not use address-based hashing, and it is
44 ;; better not to add a new lazy stable hash slot to instances as a
45 ;; side-effect of compiling.
46 (instance-id-table (make-hash-table :test
'eq
) :type hash-table
:read-only t
)
47 ;; Hashtable mapping a string to a list of fop-table indices of
48 ;; symbols whose name is that string. For any name as compared
49 ;; by STRING= there can be a symbol whose name is a base string
50 ;; and/or a symbol whose name is not a base string.
51 (string=-table
(make-hash-table :test
'equal
) :type hash-table
)
52 ;; the fasloader table's current free pointer: the next offset to be used
53 (table-free 0 :type index
)
54 ;; an alist (PACKAGE . OFFSET) of the table offsets for each package
55 ;; we have currently located.
56 (packages () :type list
)
57 ;; a table mapping from the ENTRY-INFO structures for dumped XEPs to
58 ;; the table offsets of the corresponding code pointers
59 (entry-table (make-hash-table :test
'eq
) :type hash-table
)
60 ;; a table holding back-patching info for forward references to XEPs.
61 ;; The key is the ENTRY-INFO structure for the XEP, and the value is
62 ;; a list of conses (<code-handle> . <offset>), where <code-handle>
63 ;; is the offset in the table of the code object needing to be
64 ;; patched, and <offset> is the offset that must be patched.
65 (patch-table (make-hash-table :test
'eq
) :type hash-table
)
66 ;; a list of the table handles for all of the DEBUG-INFO structures
67 ;; dumped in this file. These structures must be back-patched with
68 ;; source location information when the compilation is complete.
69 (debug-info () :type list
)
70 ;; This is used to keep track of objects that we are in the process
71 ;; of dumping so that circularities can be preserved. The key is the
72 ;; object that we have previously seen, and the value is the object
73 ;; that we reference in the table to find this previously seen
74 ;; object. (The value is never NIL.)
76 ;; Except with list objects, the key and the value are always the
77 ;; same. In a list, the key will be some tail of the value.
78 (circularity-table (make-hash-table :test
'eq
) :type hash-table
)
79 ;; a hash table of structures that are allowed to be dumped. If we
80 ;; try to dump a structure that isn't in this hash table, we lose.
81 (valid-structures (make-hash-table :test
'eq
) :type hash-table
)
82 ;; a hash table of slots to be saved when dumping an instance.
83 (saved-slot-names (make-hash-table :test
'eq
) :type hash-table
))
84 (declaim (freeze-type fasl-output
))
86 ;;; Similarity hash table logic.
87 ;;; It really seems bogus to me that we do similarity checking in both
88 ;;; the IR1 namespace and the fasl dumper, even going so far as to use
89 ;;; two different ways to decide that an object is "harmless" to look up
90 ;;; (i.e. has no cyclic references).
95 ;; Do almost the same thing that EQUAL does, but:
96 ;; - consider strings to be dissimilar if their element types differ.
97 ;; - scan elements of all specialized numeric vectors (BIT is done by EQUAL)
98 (named-let recurse
((x x
) (y y
))
103 (recurse (car x
) (car y
))
104 (recurse (cdr x
) (cdr y
))))
106 ;; Incidentally, if we want to preserve non-simpleness of dumped arrays
107 ;; (which is permissible but not required), this case (and below for arrays)
108 ;; would be where to do it by returning non-similar.
110 ;; (= (widetag-of ...)) would be too strict, because a simple string
111 ;; can be be similar to a non-simple string.
112 (eq (array-element-type x
)
113 (array-element-type y
))
115 ((or pathname bit-vector
) ; fall back to EQUAL
116 ;; This could be slightly wrong, but so it always was, because we use
117 ;; (and have used) EQUAL for PATHNAME in FIND-CONSTANT, but:
118 ;; "Two pathnames S and C are similar if all corresponding pathname components are similar."
119 ;; and we readily admit that similarity of strings requires equal element types.
120 ;; So this is slightly dubious:
121 ;; (EQUAL (MAKE-PATHNAME :NAME (COERCE "A" 'SB-KERNEL:SIMPLE-CHARACTER-STRING))
122 ;; (MAKE-PATHNAME :NAME (COERCE "A" 'BASE-STRING))) => T
123 ;; On the other hand, nothing says that the pathname constructors such as
124 ;; MAKE-PATHNAME and MERGE-PATHNAMES don't convert to a canonical representation
125 ;; which renders them EQUAL when all strings are STRING=.
126 ;; This area of the language spec seems to have been a clusterfsck.
128 ;; We would need to enhance COALESCE-TREE-P to detect cycles involving
129 ;; SIMPLE-VECTOR before recursing, otherwise this could exhaust stack.
131 (and (sb-xc:typep y
'(simple-array * 1))
132 (= (length x
) (length y
))
133 (equal (array-element-type x
) (array-element-type y
))
134 (or (typep x
'(array nil
(*)))
135 (dotimes (i (length x
) t
)
136 (unless (= (aref x i
) (aref y i
)) (return nil
))))))
137 ;; How do SIMPLE-VECTOR and other array types get here?
138 ;; Answer: COALESCE-TREE-P is "weaker than" the the local COALESCE-P function in FIND-CONSTANT,
139 ;; so it may return T on trees that contain atoms that COALESCE-P would have returned NIL on.
140 ;; Therefore DUMP-NON-IMMEDIATE-OBJECT may call SIMILARP on an object for which COALESCE-P
141 ;; would have said NIL.
142 ;; As mentioned at the top of this file, this seems incredibly bad,
143 ;; But users do not tend to have object cycles involving SIMPLE-VECTOR and such, I guess?
144 ;; Anyway, the answer has to be "no" for everything else: un-EQL objects are not similar.
146 ;; This hash function is an amalgam of SXHASH and PSHASH with the following properties:
147 ;; - numbers must have the same type to be similar (same as SXHASH)
148 ;; - instances must be EQ to be similar (same as SXHASH)
149 ;; - strings and characters are compared case-sensitively (same as SXHASH)
150 ;; - arrays must have the same type to be similar
151 ;; Unlike EQUAL-HASH, we never call EQ-HASH, because there is generally no reason
152 ;; to try to look up an object that lacks a content-based hash value.
153 (defun similar-hash (x)
154 (declare (special *compile-object
*))
155 (named-let recurse
((x x
))
156 ;; There is no depth cutoff - X must not be circular,
157 ;; which was already determined as a precondition to calling this,
158 ;; except that as pointed out, we must not descend into simple-vector
159 ;; because there was no circularity checking done for arrays.
162 ((atom x
) (mix (if x
(recurse x
) #xD00F
) hash
))
163 ;; mix the hash of the CARs only, without consuming stack
164 ;; proportional to list length.
165 (setf hash
(mix (recurse (car x
)) hash
)
168 (number (sb-impl::number-sxhash x
))
169 (pathname (sb-impl::pathname-sxhash x
))
170 ((or instance simple-vector
)
171 (let ((idmap (fasl-output-instance-id-table *compile-object
*)))
172 (values (ensure-gethash x idmap
173 (let ((c (1+ (hash-table-count idmap
))))
175 ;; Arrays disregard simplicity.
176 ((array nil
(*)) #xdead
) ; don't access the data in these bastards
178 (let* ((simple-array (coerce x
'(simple-array * (*))))
179 (widetag (%other-pointer-widetag simple-array
))
180 (saetp (find widetag sb-vm
:*specialized-array-element-type-properties
*
181 :key
#'sb-vm
:saetp-typecode
))
182 (n-data-words (ceiling (sb-vm::vector-n-data-octets simple-array saetp
)
184 (hash (word-mix (length x
) widetag
)))
185 (declare (word hash
))
186 (dotimes (i n-data-words
(logand hash most-positive-fixnum
))
187 ;; FIXME: the last word of {1,2,4}-bit-per-element vectors
188 ;; needs to be masked. At worst, this fails to coalesce
189 ;; similar vectors, so it's not fatal.
190 (setq hash
(word-mix hash
(%vector-raw-bits x i
))))))
191 (character (char-code x
))
193 (defun make-similarity-table ()
194 (make-hash-table :hash-function
#'similar-hash
:test
#'similarp
))
197 ;;; When cross-compiling, it's good enough to approximate similarity as EQUAL.
199 (defun make-similarity-table () (make-hash-table :test
'equal
))
201 (defmacro get-similar
(key table
) `(gethash ,key
,table
))
203 ;;; This structure holds information about a circularity.
204 (defstruct (circularity (:copier nil
))
205 ;; the kind of modification to make to create circularity
206 (type (missing-arg) :type
(member :rplaca
:rplacd
:svset
:struct-set
:slot-set
))
207 ;; the object containing circularity
209 ;; index in object for circularity
210 (index (missing-arg) :type index
)
211 ;; slot name in object for circularity
212 (slot-name nil
:type symbol
)
213 ;; the object to be stored at INDEX in OBJECT. This is that the key
214 ;; that we were using when we discovered the circularity.
216 ;; the value that was associated with VALUE in the
217 ;; CIRCULARITY-TABLE. This is the object that we look up in the
218 ;; EQ-TABLE to locate VALUE.
221 ;;; a list of the CIRCULARITY structures for all of the circularities
222 ;;; detected in the current top level call to DUMP-OBJECT. Setting
223 ;;; this lobotomizes circularity detection as well, since circular
224 ;;; dumping uses the table.
225 (defvar *circularities-detected
*)
229 ;;; Write the byte B to the specified FASL-OUTPUT stream.
230 (defun dump-byte (b fasl-output
)
231 (declare (type (unsigned-byte 8) b
) (type fasl-output fasl-output
))
232 (write-byte b
(fasl-output-stream fasl-output
)))
234 ;; Dump a word-sized integer.
235 (defun dump-word (num fasl-output
)
236 (declare (type sb-vm
:word num
) (type fasl-output fasl-output
))
237 (let ((stream (fasl-output-stream fasl-output
)))
238 (dotimes (i sb-vm
:n-word-bytes
)
239 (write-byte (ldb (byte 8 (* 8 i
)) num
) stream
))))
241 ;; Dump a 32-bit integer.
242 (defun dump-unsigned-byte-32 (num fasl-output
)
243 (declare (type (unsigned-byte 32) num
) (type fasl-output fasl-output
))
244 (let ((stream (fasl-output-stream fasl-output
)))
246 (write-byte (ldb (byte 8 (* 8 i
)) num
) stream
))))
248 ;;; Dump NUM to the fasl stream, represented by N bytes. This works
249 ;;; for either signed or unsigned integers. There's no range checking
250 ;;; -- if you don't specify enough bytes for the number to fit, this
251 ;;; function cheerfully outputs the low bytes.
252 ;;; Multi-byte integers written by this function are always little-endian.
253 (defun dump-integer-as-n-bytes (num bytes fasl-output
)
254 (declare (integer num
) (type index bytes
))
255 (declare (type fasl-output fasl-output
))
256 (do ((n num
(ash n -
8))
259 (declare (type index i
))
260 (dump-byte (logand n
#xff
) fasl-output
))
263 (defun dump-varint (n fasl-output
)
264 (let ((buf (fasl-output-varint-buf fasl-output
)))
265 (setf (fill-pointer buf
) 0)
266 (write-var-integer n buf
)
267 (write-sequence buf
(fasl-output-stream fasl-output
))))
269 (defun dump-fop+operands
(fasl-output opcode arg1
270 &optional
(arg2 0 arg2p
) (arg3 0 arg3p
))
271 (declare (type (unsigned-byte 8) opcode
) (type word arg1 arg2 arg3
))
272 (dump-byte opcode fasl-output
)
273 (dump-varint arg1 fasl-output
)
274 (when arg2p
(dump-varint arg2 fasl-output
))
275 (when arg3p
(dump-varint arg3 fasl-output
)))
277 ;;; Dump the FOP code for the named FOP to the specified FASL-OUTPUT.
278 ;;; This macro is supposed to look functional in that it evals its
279 ;;; args, but it wants to evaluate the first arg at compile-time. For
280 ;;; this reason it should really not be a quoted symbol, but I think
281 ;;; this used to actually be a function which had to look up the fop's
282 ;;; opcode every time called. The named FOP is also treated as a string
283 ;;; designator which is interned in the package defining the FOPs.
284 (defmacro dump-fop
(fop-symbol file
&rest args
)
286 ;; EVAL is too much. Just ascertain we have a quoted symbol
287 (if (typep fop-symbol
'(cons (eql quote
) (cons symbol null
)))
289 (error "Bad 1st arg to DUMP-FOP: ~S" fop-symbol
)))
290 (val (or (gethash (intern (symbol-name fop-symbol
) #.
(find-package "SB-FASL"))
291 *fop-name-to-opcode
*)
292 (error "compiler bug: ~S is not a legal fasload operator."
294 (fop-argc (aref (car **fop-signatures
**) val
)))
296 ((not (eql (length args
) fop-argc
))
297 (error "~S takes ~D argument~:P" fop-symbol fop-argc
))
299 `(dump-byte ,val
,file
))
301 `(dump-fop+operands
,file
,val
,@args
)))))
303 ;;; Push the object at table offset Handle on the fasl stack.
304 (defun dump-push (handle fasl-output
)
305 (declare (type index handle
) (type fasl-output fasl-output
))
306 (dump-fop 'fop-push fasl-output handle
)
309 ;;; Pop the object currently on the fasl stack top into the table, and
310 ;;; return the table index, incrementing the free pointer.
311 (defun dump-pop (fasl-output)
313 (fasl-output-table-free fasl-output
)
314 (dump-fop 'fop-pop fasl-output
)
315 (incf (fasl-output-table-free fasl-output
))))
317 (defun dump-to-table (fasl-output)
319 (fasl-output-table-free fasl-output
)
320 (dump-fop 'fop-move-to-table fasl-output
)
321 (incf (fasl-output-table-free fasl-output
))))
323 (defun cdr-similarity-p (index fasl-output
)
325 (destructuring-bind (list . nthcdr
) index
326 (let ((index (gethash list
(fasl-output-eq-table fasl-output
))))
327 (when (fixnump index
)
328 (dump-push index fasl-output
)
329 (dump-fop 'fop-nthcdr fasl-output nthcdr
)
332 ;;; If X is in File's SIMILAR-TABLE, then push the object and return T,
334 (defun similar-check-table (x fasl-output
)
335 (declare (type fasl-output fasl-output
))
336 (let ((index (get-similar x
(fasl-output-similar-table fasl-output
))))
337 (cond ((fixnump index
)
338 (dump-push index fasl-output
)
340 ((cdr-similarity-p index fasl-output
)))))
342 ;;; These functions are called after dumping an object to save the
343 ;;; object in the table. The object (also passed in as X) must already
344 ;;; be on the top of the FOP stack.
345 (defun eq-save-object (x fasl-output
)
346 (declare (type fasl-output fasl-output
))
347 (setf (gethash x
(fasl-output-eq-table fasl-output
))
348 (dump-to-table fasl-output
))
350 (defun similar-save-object (x fasl-output
)
351 (declare (type fasl-output fasl-output
))
352 (let ((handle (dump-to-table fasl-output
)))
353 (setf (get-similar x
(fasl-output-similar-table fasl-output
)) handle
)
354 (setf (gethash x
(fasl-output-eq-table fasl-output
)) handle
))
356 ;;; Record X in File's CIRCULARITY-TABLE. This is called on objects
357 ;;; that we are about to dump might have a circular path through them.
359 ;;; The object must not currently be in this table, since the dumper
360 ;;; should never be recursively called on a circular reference.
361 ;;; Instead, the dumping function must detect the circularity and
362 ;;; arrange for the dumped object to be patched.
363 (defun note-potential-circularity (x fasl-output
)
364 (let ((circ (fasl-output-circularity-table fasl-output
)))
365 (aver (not (gethash x circ
)))
366 (setf (gethash x circ
) x
))
369 ;;;; opening and closing fasl files
371 ;;; Open a fasl file, write its header, and return a FASL-OUTPUT
372 ;;; object for dumping to it. Some human-readable information about
373 ;;; the source code is given by the string WHERE.
374 (defun open-fasl-output (name where
)
375 (declare (type pathname name
))
376 (flet ((fasl-write-string (string stream
)
377 ;; UTF-8 is safe to use, because +FASL-HEADER-STRING-STOP-CHAR-CODE+
378 ;; may not appear in UTF-8 encoded bytes
379 (write-sequence (string-to-octets string
:external-format
:utf-8
)
381 (let* ((stream (open name
383 :if-exists
:supersede
384 :element-type
'sb-assem
:assembly-unit
))
385 (res (make-fasl-output stream
)))
386 ;; Before the actual FASL header, write a shebang line using the current
387 ;; runtime path, so our fasls can be executed directly from the shell.
388 #-sb-xc-host
; cross-compiled fasls are not directly executable
389 (when *runtime-pathname
*
391 (format nil
"#!~A --script~%"
392 (native-namestring *runtime-pathname
* :as-file t
))
394 ;; Begin the header with the constant machine-readable (and
395 ;; semi-human-readable) string which is used to identify fasl files.
396 (fasl-write-string *fasl-header-string-start-string
* stream
)
397 ;; The constant string which begins the header is followed by
398 ;; arbitrary human-readable text, terminated by
399 ;; +FASL-HEADER-STRING-STOP-CHAR-CODE+.
401 (with-standard-io-syntax
402 (let ((*print-readably
* nil
)
403 (*print-pretty
* nil
))
407 using ~A version ~A~%"
409 (lisp-implementation-type)
410 (lisp-implementation-version))))
412 (dump-byte +fasl-header-string-stop-char-code
+ res
)
413 ;; Finish the header by outputting fasl file implementation,
414 ;; version, and key *FEATURES*.
415 (flet ((dump-counted-string (string)
416 ;; The count is dumped as a 32-bit unsigned-byte even on 64-bit
417 ;; platforms. This ensures that a x86-64 SBCL can gracefully
418 ;; detect an error when trying to read a x86 fasl, instead
419 ;; of choking on a ridiculously long counted string.
420 ;; -- JES, 2005-12-30
421 (dump-unsigned-byte-32 (length string
) res
)
422 (dotimes (i (length string
))
423 (dump-byte (char-code (aref string i
)) res
))))
424 (dump-counted-string (symbol-name +backend-fasl-file-implementation
+))
425 (dump-word +fasl-file-version
+ res
)
426 (dump-counted-string (lisp-implementation-version))
427 (dump-counted-string (compute-features-affecting-fasl-format)))
430 ;;; Close the specified FASL-OUTPUT, aborting the write if ABORT-P.
431 (defun close-fasl-output (fasl-output abort-p
)
432 (declare (type fasl-output fasl-output
))
436 (aver (zerop (hash-table-count (fasl-output-patch-table fasl-output
))))
438 (dump-fop 'fop-end-group fasl-output
(fasl-output-table-free fasl-output
)))
440 ;; That's all, folks.
441 (close (fasl-output-stream fasl-output
) :abort abort-p
)
444 ;;;; main entries to object dumping
446 ;;; This function deals with dumping objects that are complex enough
447 ;;; so that we want to cache them in the table, rather than repeatedly
448 ;;; dumping them. If the object is in the EQ-TABLE, then we push it,
449 ;;; otherwise, we do a type dispatch to a type specific dumping
450 ;;; function. The type specific branches do any appropriate
451 ;;; SIMILAR-TABLE check and table entry.
453 ;;; When we go to dump the object, we enter it in the CIRCULARITY-TABLE.
454 (defun dump-non-immediate-object (x file
)
455 (let ((index (gethash x
(fasl-output-eq-table file
))))
456 (cond ((fixnump index
)
457 (dump-push index file
))
458 ((cdr-similarity-p index file
))
461 (symbol (dump-symbol x file
))
463 (cond ((not (coalesce-tree-p x
))
465 (eq-save-object x file
))
466 ((not (similar-check-table x file
))
468 (similar-save-object x file
))))
471 (eq-save-object x file
))
474 (aver (not (classoid-p x
)))
475 (dump-object 'values-specifier-type file
)
476 (dump-object (type-specifier x
) file
)
477 (dump-fop 'fop-funcall file
1))
479 (multiple-value-bind (slot-names slot-names-p
)
480 (gethash x
(fasl-output-saved-slot-names file
))
482 (dump-instance-saving-slots x slot-names file
)
483 (dump-structure x file
)))
484 (eq-save-object x file
))
486 ;; DUMP-ARRAY (and its callees) are responsible for
487 ;; updating the EQ and SIMILAR hash tables.
490 (unless (similar-check-table x file
)
492 (ratio (dump-ratio x file
))
493 (complex (dump-complex x file
))
494 (float (dump-float x file
))
495 (integer (dump-integer x file
)))
496 (similar-save-object x file
)))
497 #+(and (not sb-xc-host
) sb-simd-pack
)
499 (unless (similar-check-table x file
)
500 (dump-fop 'fop-simd-pack file
)
501 (dump-integer-as-n-bytes (%simd-pack-tag x
) 8 file
)
502 (dump-integer-as-n-bytes (%simd-pack-low x
) 8 file
)
503 (dump-integer-as-n-bytes (%simd-pack-high x
) 8 file
)
504 (similar-save-object x file
)))
505 #+(and (not sb-xc-host
) sb-simd-pack-256
)
507 (unless (similar-check-table x file
)
508 (dump-simd-pack-256 x file
)
509 (similar-save-object x file
)))
511 ;; This probably never happens, since bad things tend to
512 ;; be detected during IR1 conversion.
513 (error "This object cannot be dumped into a fasl file:~% ~S"
517 #+(and (not sb-xc-host
) sb-simd-pack-256
)
518 (defun dump-simd-pack-256 (x file
)
519 (dump-fop 'fop-simd-pack file
)
520 (dump-integer-as-n-bytes (logior (%simd-pack-256-tag x
) (ash 1 6)) 8 file
)
521 (dump-integer-as-n-bytes (%simd-pack-256-0 x
) 8 file
)
522 (dump-integer-as-n-bytes (%simd-pack-256-1 x
) 8 file
)
523 (dump-integer-as-n-bytes (%simd-pack-256-2 x
) 8 file
)
524 (dump-integer-as-n-bytes (%simd-pack-256-3 x
) 8 file
))
526 ;;; Dump an object of any type by dispatching to the correct
527 ;;; type-specific dumping function. We pick off immediate objects,
528 ;;; symbols and magic lists here. Other objects are handled by
529 ;;; DUMP-NON-IMMEDIATE-OBJECT.
531 ;;; This is the function used for recursive calls to the fasl dumper.
532 ;;; We don't worry about creating circularities here, since it is
533 ;;; assumed that there is a top level call to DUMP-OBJECT.
534 (defun sub-dump-object (x file
)
537 (dump-non-immediate-object x file
)
538 (dump-fop 'fop-empty-list file
)))
541 (dump-fop 'fop-truth file
)
542 (dump-non-immediate-object x file
)))
543 ((fixnump x
) (dump-integer x file
))
545 (dump-fop 'fop-character file
(char-code x
)))
547 (dump-push (dump-package x file
) file
))
549 ((system-area-pointer-p x
)
550 (dump-fop 'fop-word-pointer file
)
551 (dump-integer-as-n-bytes (sap-int x
) sb-vm
:n-word-bytes file
))
553 (dump-non-immediate-object x file
))))
555 ;;; Dump stuff to backpatch already dumped objects. INFOS is the list
556 ;;; of CIRCULARITY structures describing what to do. The patching FOPs
557 ;;; take the value to store on the stack. We compute this value by
558 ;;; fetching the enclosing object from the table, and then CDR'ing it
560 (defun dump-circularities (infos file
)
561 (let ((table (fasl-output-eq-table file
)))
564 (let* ((value (circularity-value info
))
565 (enclosing (circularity-enclosing-object info
)))
566 (dump-push (gethash enclosing table
) file
)
567 (unless (eq enclosing value
)
568 (do ((current enclosing
(cdr current
))
571 (dump-fop 'fop-nthcdr file i
))
572 (declare (type index i
)))))
574 (macrolet ((fop-op (symbol)
575 (gethash (intern (symbol-name symbol
) "SB-FASL")
576 *fop-name-to-opcode
*)))
577 (dump-byte (ecase (circularity-type info
)
578 (:rplaca
(fop-op fop-rplaca
))
579 (:rplacd
(fop-op fop-rplacd
))
580 (:svset
(fop-op fop-svset
))
581 (:struct-set
(fop-op fop-structset
))
583 (dump-object (circularity-slot-name info
) file
)
584 (fop-op fop-slotset
)))
586 (dump-varint (gethash (circularity-object info
) table
) file
)
587 (dump-varint (circularity-index info
) file
))))
589 ;;; Set up stuff for circularity detection, then dump an object. All
590 ;;; shared and circular structure will be exactly preserved within a
591 ;;; single call to DUMP-OBJECT. Sharing between objects dumped by
592 ;;; separate calls is only preserved when convenient.
594 ;;; We peek at the object type so that we only pay the circular
595 ;;; detection overhead on types of objects that might be circular.
596 (defun dump-object (x file
)
597 (if (compound-object-p x
)
598 (let ((*circularities-detected
* ())
599 (circ (fasl-output-circularity-table file
)))
601 (sub-dump-object x file
)
602 (when *circularities-detected
*
603 (dump-circularities *circularities-detected
* file
)
605 (sub-dump-object x file
)))
607 ;;;; LOAD-TIME-VALUE and MAKE-LOAD-FORM support
609 ;;; Emit a funcall of the function and return the handle for the
611 (defun fasl-dump-load-time-value-lambda (fun file
)
612 (declare (type clambda fun
) (type fasl-output file
))
613 (let ((handle (gethash (leaf-info fun
)
614 (fasl-output-entry-table file
))))
616 (dump-push handle file
)
617 (dump-fop 'fop-funcall file
0))
620 ;;; Return T iff CONSTANT has already been dumped. It's been dumped if
621 ;;; it's in the EQ table.
623 ;;; Note: historically (1) the above comment was "T iff ... has not been dumped",
624 ;;; (2) the test was was also true if the constant had been validated / was in
625 ;;; the valid objects table. This led to substructures occasionally skipping the
626 ;;; validation, and hence failing the "must have been validated" test.
627 (defun fasl-constant-already-dumped-p (constant file
)
628 (and (gethash constant
(fasl-output-eq-table file
)) t
))
630 ;;; Use HANDLE whenever we try to dump CONSTANT. HANDLE should have been
631 ;;; returned earlier by FASL-DUMP-LOAD-TIME-VALUE-LAMBDA.
632 (defun fasl-note-handle-for-constant (constant handle file
)
633 (let ((table (fasl-output-eq-table file
)))
634 (when (gethash constant table
)
635 (error "~S already dumped?" constant
))
636 (setf (gethash constant table
) handle
))
639 ;;; Note that the specified structure can just be dumped by
640 ;;; enumerating the slots.
641 (defun fasl-validate-structure (structure file
)
642 (setf (gethash structure
(fasl-output-valid-structures file
)) t
)
645 ;;; Note that the specified standard object can just be dumped by
646 ;;; saving its slot values.
647 (defun fasl-note-instance-saves-slots (instance slot-names file
)
648 (setf (gethash instance
(fasl-output-saved-slot-names file
)) slot-names
)
653 (defun dump-ratio (x file
)
654 (sub-dump-object (numerator x
) file
)
655 (sub-dump-object (denominator x
) file
)
656 (dump-fop 'fop-ratio file
))
658 #+(and long-float x86
)
659 (defun dump-long-float (float file
)
660 (declare (long-float float
))
661 (let ((exp-bits (long-float-exp-bits float
))
662 (high-bits (long-float-high-bits float
))
663 (low-bits (long-float-low-bits float
)))
664 ;; We could get away with DUMP-WORD here, since the x86 has 4-byte words,
665 ;; but we prefer to make things as explicit as possible.
667 (dump-integer-as-n-bytes low-bits
4 file
)
668 (dump-integer-as-n-bytes high-bits
4 file
)
669 (dump-integer-as-n-bytes exp-bits
2 file
)))
671 #+(and long-float sparc
)
672 (defun dump-long-float (float file
)
673 (declare (long-float float
))
674 (let ((exp-bits (long-float-exp-bits float
))
675 (high-bits (long-float-high-bits float
))
676 (mid-bits (long-float-mid-bits float
))
677 (low-bits (long-float-low-bits float
)))
678 ;; We could get away with DUMP-WORD here, since the sparc has 4-byte
679 ;; words, but we prefer to make things as explicit as possible.
681 (dump-integer-as-n-bytes low-bits
4 file
)
682 (dump-integer-as-n-bytes mid-bits
4 file
)
683 (dump-integer-as-n-bytes high-bits
4 file
)
684 (dump-integer-as-n-bytes exp-bits
4 file
)))
686 (defun dump-integer (n file
)
690 (0 (dump-fop 'fop-int-const0 file
))
691 (1 (dump-fop 'fop-int-const1 file
))
692 (2 (dump-fop 'fop-int-const2 file
))
693 (-1 (dump-fop 'fop-int-const-neg1 file
))
694 (t (dump-fop 'fop-byte-integer file
)
695 (dump-byte (logand #xFF n
) file
))))
696 ((unsigned-byte #.
(1- sb-vm
:n-word-bits
))
697 (dump-fop 'fop-word-integer file
)
700 (dump-fop 'fop-word-integer file
)
701 (dump-integer-as-n-bytes n sb-vm
:n-word-bytes file
))
703 (let ((bytes (ceiling (1+ (integer-length n
)) 8)))
704 (dump-fop 'fop-integer file bytes
)
705 (dump-integer-as-n-bytes n bytes file
)))))
707 (defun dump-float (x file
)
710 (dump-fop 'fop-single-float file
)
711 (dump-integer-as-n-bytes (single-float-bits x
) 4 file
))
713 (dump-fop 'fop-double-float file
)
714 (dump-integer-as-n-bytes (double-float-low-bits x
) 4 file
)
715 (dump-integer-as-n-bytes (double-float-high-bits x
) 4 file
))
718 (dump-fop 'fop-long-float file
)
719 (dump-long-float x file
))))
721 (defun dump-complex (x file
)
722 (let ((re (realpart x
))
725 ((complex single-float
)
726 (dump-fop 'fop-complex-single-float file
)
727 (dump-integer-as-n-bytes (single-float-bits re
) 4 file
)
728 (dump-integer-as-n-bytes (single-float-bits im
) 4 file
))
729 ((complex double-float
)
730 (dump-fop 'fop-complex-double-float file
)
731 (dump-integer-as-n-bytes (double-float-low-bits re
) 4 file
)
732 (dump-integer-as-n-bytes (double-float-high-bits re
) 4 file
)
733 (dump-integer-as-n-bytes (double-float-low-bits im
) 4 file
)
734 (dump-integer-as-n-bytes (double-float-high-bits im
) 4 file
))
736 ((complex long-float
)
737 (dump-fop 'fop-complex-long-float file
)
738 (dump-long-float re file
)
739 (dump-long-float im file
))
741 (sub-dump-object re file
)
742 (sub-dump-object im file
)
743 (dump-fop 'fop-complex file
)))))
747 ;;; Return the table index of PKG, adding the package to the table if
748 ;;; necessary. During cold load, we read the string as a normal string
749 ;;; so that we can do the package lookup at cold load time.
751 ;;; FIXME: Despite the parallelism in names, the functionality of
752 ;;; this function is not parallel to other functions DUMP-FOO, e.g.
753 ;;; DUMP-SYMBOL and DUMP-LIST. The mapping between names and behavior
754 ;;; should be made more consistent.
755 (declaim (ftype (function (package fasl-output
) index
) dump-package
))
756 (defun dump-package (pkg file
)
757 (declare (inline assoc
))
758 (cond ((cdr (assoc pkg
(fasl-output-packages file
) :test
#'eq
)))
760 (let ((s (sb-xc:package-name pkg
)))
761 (dump-fop 'fop-named-package-save file
(length s
))
762 ;; Package names are always dumped as varint-encoded character strings
763 ;; except on non-unicode builds.
764 (dump-chars (coerce s
'(simple-array character
(*))) file nil
))
765 (let ((entry (fasl-output-table-free file
)))
766 (incf (fasl-output-table-free file
))
767 (push (cons pkg entry
) (fasl-output-packages file
))
772 ;;; Dump a list, setting up patching information when there are
773 ;;; circularities. We scan down the list, checking for CDR and CAR
776 ;;; If there is a CDR circularity, we terminate the list with NIL and
777 ;;; make a CIRCULARITY notation for the CDR of the previous cons.
779 ;;; If there is no CDR circularity, then we mark the current cons and
780 ;;; check for a CAR circularity. When there is a CAR circularity, we
781 ;;; make the CAR NIL initially, arranging for the current cons to be
784 ;;; Otherwise, we recursively call the dumper to dump the current
786 (defun dump-list (list file
&optional coalesce
)
788 (not (gethash list
(fasl-output-circularity-table file
)))))
789 (let ((circ (fasl-output-circularity-table file
)))
790 (flet ((cdr-circularity (obj n
)
791 ;; COALESCE means there's no cycles
792 (let ((ref (gethash obj circ
)))
794 (push (make-circularity :type
:rplacd
798 :enclosing-object ref
)
799 *circularities-detected
*)
800 (terminate-undotted-list n file
)
802 (do* ((l list
(cdr l
))
806 (terminate-undotted-list n file
))
808 (cond ((cdr-circularity l n
))
810 (sub-dump-object l file
)
811 (terminate-dotted-list n file
))))))
812 (declare (type index n
))
813 (when (cdr-circularity l n
)
816 ;; if this CONS is EQ to some other object we have already
817 ;; dumped, dump a reference to that instead.
818 (let* ((table (if coalesce
819 (fasl-output-similar-table file
)
820 (fasl-output-eq-table file
)))
821 (index (gethash l table
)))
822 (cond ((fixnump index
)
823 (dump-push index file
)
824 (terminate-dotted-list n file
)
826 ((cdr-similarity-p index file
)
828 (terminate-dotted-list n file
))
831 ;; put an entry for this cons into the fasl output cons table,
832 ;; for the benefit of dumping later constants
833 (let ((index (cons list n
)))
834 (setf (gethash l
(fasl-output-eq-table file
)) index
)
836 (setf (gethash l
(fasl-output-similar-table file
)) index
))))
838 (setf (gethash l circ
) list
)
841 (ref (gethash obj circ
)))
843 (push (make-circularity :type
:rplaca
847 :enclosing-object ref
)
848 *circularities-detected
*)
849 (sub-dump-object nil file
))
850 ;; Avoid coalescing if COALESCE-TREE-P decided not to
852 ;; This is the same as DUMP-NON-IMMEDIATE-OBJECT but
853 ;; without calling COALESCE-TREE-P again.
854 (let ((index (gethash obj
(fasl-output-eq-table file
))))
855 (cond ((fixnump index
)
856 (dump-push index file
))
857 ((cdr-similarity-p index file
))
860 (eq-save-object obj file
))
861 ((not (similar-check-table obj file
))
862 (dump-list obj file t
)
863 (similar-save-object obj file
)))))
865 (sub-dump-object obj file
))))))))
867 (defconstant fop-list-base-opcode
128)
869 (defun terminate-dotted-list (n file
)
870 (declare (type index n
) (type fasl-output file
))
873 (dump-byte (logior fop-list-base-opcode
#b10000 n
) file
))
875 (dump-byte (logior fop-list-base-opcode
#b10000
) file
)
876 (dump-varint (- n
16) file
))))
878 (defun terminate-undotted-list (n file
)
879 (declare (type index n
) (type fasl-output file
))
882 (dump-byte (logior fop-list-base-opcode n
) file
))
884 (dump-byte (logior fop-list-base-opcode
) file
)
885 (dump-varint (- n
16) file
))))
889 ;;; Dump the array thing.
890 (defun dump-array (x file
)
893 (dump-multi-dim-array x file
)))
895 ;;; Dump the vector object. If it's not simple, then actually dump a
896 ;;; simple realization of it. But we enter the original in the EQ or SIMILAR
898 (defun dump-vector (x file
)
899 (let ((simple-version (if (array-header-p x
)
900 (coerce x
`(simple-array
901 ,(array-element-type x
)
904 (typecase simple-version
905 ;; On the host, take all strings to be simple-base-string.
906 ;; In the target, really test for simple-base-string.
907 (#+sb-xc-host simple-string
#-sb-xc-host simple-base-string
908 (unless (similar-check-table x file
)
909 (dump-fop 'fop-base-string file
(length simple-version
))
910 (dump-chars simple-version file t
)
911 (similar-save-object x file
)))
913 ((simple-array character
(*))
914 #-sb-unicode
(bug "how did we get here?")
915 (unless (similar-check-table x file
)
916 (dump-fop 'fop-character-string file
(length simple-version
))
917 (dump-chars simple-version file nil
)
918 (similar-save-object x file
)))
919 ;; SB-XC:SIMPLE-VECTOR will not match an array whose element type
920 ;; the host upgraded to T but whose expressed type was not T.
922 (dump-simple-vector simple-version file
)
923 (eq-save-object x file
)
924 (unless (eq x simple-version
)
925 ;; In case it has circularities that need to be patched
927 (setf (gethash simple-version
(fasl-output-eq-table file
))
928 (gethash x
(fasl-output-eq-table file
)))))
930 (unless (similar-check-table x file
)
931 (dump-specialized-vector simple-version file
)
932 (similar-save-object x file
))))))
934 ;;; Dump a SIMPLE-VECTOR, handling any circularities.
935 (defun dump-simple-vector (v file
)
936 (declare (type simple-vector v
) (type fasl-output file
))
937 (note-potential-circularity v file
)
938 (do ((index 0 (1+ index
))
940 (circ (fasl-output-circularity-table file
)))
942 (dump-fop 'fop-vector file length
))
943 (let* ((obj (aref v index
))
944 (ref (gethash obj circ
)))
946 (push (make-circularity :type
:svset
950 :enclosing-object ref
)
951 *circularities-detected
*)
952 (sub-dump-object nil file
))
954 (sub-dump-object obj file
))))))
956 (defun dump-specialized-vector (vector file
&key data-only
)
957 ;; The DATA-ONLY option was for the now-obsolete trace-table,
958 ;; but it seems like a good option to keep around.
959 #-sb-xc-host
(declare (type (simple-unboxed-array (*)) vector
))
960 (let* ((length (length vector
))
961 (widetag (%other-pointer-widetag vector
))
962 (bits-per-elt (sb-vm::simple-array-widetag-
>bits-per-elt widetag
)))
964 ;; fop-spec-vector doesn't grok trailing #\null convention.
965 (aver (and (/= widetag sb-vm
:simple-base-string-widetag
)
966 (/= widetag sb-vm
:simple-vector-widetag
)))
967 (dump-fop 'fop-spec-vector file length
)
968 (dump-byte widetag file
))
971 (when (or (= widetag sb-vm
:simple-array-fixnum-widetag
)
972 (= widetag sb-vm
:simple-array-unsigned-fixnum-widetag
))
973 ;; Fixnum vector contents are tagged numbers. Make a copy.
974 (setq vector
(map 'vector
(lambda (x) (ash x sb-vm
:n-fixnum-tag-bits
))
977 ;; cross-io doesn't know about fasl streams, so use actual stream.
978 (sb-impl::buffer-output
(fasl-output-stream file
)
981 (ceiling (* length bits-per-elt
) sb-vm
:n-byte-bits
)
982 #+sb-xc-host bits-per-elt
)))
984 ;;; Dump a multi-dimensional array. Note: any displacements are folded out.
985 (defun dump-multi-dim-array (array file
)
986 (note-potential-circularity array file
)
987 (let ((rank (array-rank array
)))
989 (dump-integer (array-dimension array i
) file
))
990 (with-array-data ((vector array
) (start) (end))
991 (if (and (= start
0) (= end
(length vector
)))
992 (sub-dump-object vector file
)
993 (sub-dump-object (subseq vector start end
) file
)))
994 (dump-fop 'fop-array file rank
)
995 (eq-save-object array file
)))
998 ;;; Dump string-ish things.
1000 ;;; Dump a SIMPLE-STRING.
1001 (defun dump-chars (s fasl-output base-string-p
)
1002 (declare (type simple-string s
))
1003 (if (or base-string-p
#-sb-unicode t
) ; if non-unicode, every char is 1 byte
1005 (dump-byte (char-code c
) fasl-output
))
1006 (dovector (c s
) ; varint (a/k/a LEB128) is better for this than UTF-8.
1007 (dump-varint (char-code c
) fasl-output
))))
1009 ;;; If we get here, it is assumed that the symbol isn't in the table,
1010 ;;; but we are responsible for putting it there when appropriate.
1011 (defun dump-symbol (s file
)
1012 (declare (type fasl-output file
))
1013 (let* ((pname (symbol-name s
))
1014 (pname-length (length pname
))
1015 ;; If no unicode, then all strings are base-string-p.
1016 ;; On the host, everything is base-string-p.
1017 (base-string-p (and #-sb-xc-host
(typep pname
'base-string
)))
1018 (length+flag
(logior (ash pname-length
1) (if base-string-p
1 0)))
1019 (dumped-as-copy nil
)
1020 (pkg (sb-xc:symbol-package s
)))
1022 (let ((this-base-p base-string-p
))
1023 (dolist (lookalike (gethash pname
(fasl-output-string=-table file
))
1024 (dump-fop 'fop-uninterned-symbol-save
1026 ;; Find the right kind of lookalike symbol.
1027 ;; [what about a symbol whose name is a (simple-array nil (0))?]
1029 (and #-sb-xc-host
(typep (symbol-name lookalike
) 'base-string
))))
1030 (when (or (and this-base-p that-base-p
)
1031 (and (not this-base-p
) (not that-base-p
)))
1032 (dump-fop 'fop-copy-symbol-save file
1033 (gethash lookalike
(fasl-output-eq-table file
)))
1034 (return (setq dumped-as-copy t
)))))))
1035 ((eq pkg
*cl-package
*)
1036 (dump-fop 'fop-lisp-symbol-save file length
+flag
))
1037 ((eq pkg
*keyword-package
*)
1038 (dump-fop 'fop-keyword-symbol-save file length
+flag
))
1040 (let ((pkg-index (dump-package pkg file
)))
1041 (if (eq (find-symbol pname pkg
) :inherited
)
1042 (dump-fop 'fop-symbol-in-package-save file length
+flag pkg-index
)
1043 (dump-fop 'fop-symbol-in-package-internal-save file length
+flag pkg-index
)))))
1045 (unless dumped-as-copy
1046 (dump-chars pname file base-string-p
)
1047 (push s
(gethash (symbol-name s
) (fasl-output-string=-table file
))))
1049 (setf (gethash s
(fasl-output-eq-table file
))
1050 (fasl-output-table-free file
))
1052 (incf (fasl-output-table-free file
)))
1056 ;;;; component (function) dumping
1058 (defun dump-segment (segment code-length fasl-output
)
1059 (declare (type sb-assem
:segment segment
)
1060 (type fasl-output fasl-output
))
1061 (let* ((stream (fasl-output-stream fasl-output
))
1062 (n-written (write-segment-contents segment stream
)))
1063 ;; In CMU CL there was no enforced connection between the CODE-LENGTH
1064 ;; argument and the number of bytes actually written. I added this
1065 ;; assertion while trying to debug portable genesis. -- WHN 19990902
1066 (unless (= code-length n-written
)
1067 (bug "code-length=~W, n-written=~W" code-length n-written
)))
1070 (eval-when (:compile-toplevel
)
1071 (assert (<= (length +fixup-kinds
+) 16))) ; fixup-kind fits in 4 bits
1073 (defconstant-eqx +fixup-flavors
+
1075 :card-table-index-mask
:symbol-tls-index
1076 :alien-code-linkage-index
:alien-data-linkage-index
1077 :foreign
:foreign-dataref
1079 :layout
:immobile-symbol
:linkage-cell
1084 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
1085 (defun encoded-fixup-flavor (flavor)
1086 (or (position flavor
+fixup-flavors
+)
1087 (error "Bad fixup flavor ~s" flavor
))))
1089 ;;; Pack the aspects of a fixup into an integer.
1090 ;;; DATA is for asm routine fixups. The routine can be represented in 8 bits,
1091 ;;; so the fixup can be reduced to one word instead of an integer and a symbol.
1092 (declaim (inline !pack-fixup-info
))
1093 (defun !pack-fixup-info
(offset kind flavor data
)
1095 (the (mod 16) (or (position kind
+fixup-kinds
+)
1096 (error "Bad fixup kind ~s" kind
)))
1098 (ash (the (mod 16) (encoded-fixup-flavor flavor
)) 4)
1100 (ash (the (mod 256) data
) 8)
1101 ;; whatever it needs
1104 #-
(or x86 x86-64
) ; these two architectures provide an overriding definition
1105 (defun pack-fixups-for-reapplication (fixup-notes)
1107 (dolist (note fixup-notes
(pack-code-fixup-locs result
))
1108 (let ((fixup (fixup-note-fixup note
)))
1109 (when (eq (fixup-flavor fixup
) :card-table-index-mask
)
1110 (push (fixup-note-position note
) result
))))))
1112 ;;; Fasl files encode <flavor,kind> in a packed integer. Dispatching on the integer
1113 ;;; is simple, but the case keys still want to be symbols.
1114 (defmacro fixup-flavor-case
(flavor-id &rest clauses
)
1115 (declare (notinline position
))
1117 ,@(mapcar (lambda (clause)
1118 (if (eq (car clause
) t
)
1120 (cons (mapcar (lambda (kwd) (encoded-fixup-flavor kwd
))
1121 (ensure-list (car clause
)))
1125 ;;; Dump all the fixups. The two CASE statements below check that each
1126 ;;; fixnum has a NAME of the type appropriate to the flavor.
1127 (defun dump-fixups (fixup-notes alloc-points fasl-output
&aux
(nelements 2))
1128 (declare (type list fixup-notes
) (type fasl-output fasl-output
))
1129 ;; "retained" fixups are those whose offset in the code needs to be
1130 ;; remembered for subsequent reapplication by the garbage collector,
1131 ;; or in some cases, on core startup.
1132 (dump-object (pack-fixups-for-reapplication fixup-notes
) fasl-output
)
1133 (dump-object alloc-points fasl-output
)
1134 (dolist (note fixup-notes nelements
)
1135 (let* ((fixup (fixup-note-fixup note
))
1136 (name (fixup-name fixup
))
1137 (flavor (fixup-flavor fixup
))
1138 (flavor-id (encoded-fixup-flavor flavor
))
1140 (fixup-flavor-case flavor-id
1141 ((:code-object
:card-table-index-mask
)
1143 1) ; avoid dumping a general operand
1144 #-sb-xc-host
; ASM routine indices aren't known to the cross-compiler
1146 (the (integer 1 *) ; must not be nonzero. 0 decodes as no numeric operand
1147 (cddr (gethash name
(%asm-routine-table
*assembler-routines
*)))))))
1149 (!pack-fixup-info
(fixup-note-position note
) (fixup-note-kind note
)
1150 flavor
(or numeric-operand
0))))
1151 (dump-object info fasl-output
)
1153 (incf nelements
) ; used 1 element of the fasl stack
1155 (fixup-flavor-case flavor-id
1156 ((:alien-code-linkage-index
:alien-data-linkage-index
1157 :foreign
:foreign-dataref
) (the string name
))
1161 (layout-classoid-name name
)))
1162 (:layout-id
(the layout name
))
1165 ;; Only #+immobile-space can use the following two flavors.
1166 ;; An :IMMOBILE-SYMBOL fixup references the symbol itself,
1167 ;; whereas a :SYMBOL-VALUE fixup references the value of the symbol.
1168 ;; In the latter case, the symbol's address doesn't matter,
1169 ;; but its global value must be an immobile object.
1170 :immobile-symbol
:symbol-value
)
1172 (t name
)))) ; function name
1173 (dump-object operand fasl-output
)
1174 (incf nelements
2))))))
1176 ;;; Dump out the constant pool and code-vector for component, push the
1177 ;;; result in the table, and return the offset.
1179 ;;; The only tricky thing is handling constant-pool references to
1180 ;;; functions. If we have already dumped the function, then we just
1181 ;;; push the code pointer. Otherwise, we must create back-patching
1182 ;;; information so that the constant will be set when the function is
1183 ;;; eventually dumped. This is a bit awkward, since we don't have the
1184 ;;; handle for the code object being dumped while we are dumping its
1187 ;;; We dump trap objects in any unused slots or forward referenced slots.
1188 (defun dump-code-object (component code-segment code-length fixups alloc-points fasl-output
)
1189 (declare (type component component
)
1190 (type index code-length
)
1191 (type fasl-output fasl-output
))
1192 (let* ((2comp (component-info component
))
1193 (constants (ir2-component-constants 2comp
))
1194 (header-length (length constants
)))
1197 ;; Dump the constants, noting any :ENTRY constants that have to
1199 (loop for i from sb-vm
:code-constants-offset below header-length do
1200 (binding* ((entry (aref constants i
))
1202 (if (listp entry
) (values (car entry
) (cadr entry
)))))
1205 (cond ((leaf-has-source-name-p entry
)
1206 (named-constants (cons (leaf-source-name entry
) i
))
1207 (dump-fop 'fop-misc-trap fasl-output
))
1209 (dump-object (constant-value entry
) fasl-output
))))
1211 (dump-fop 'fop-misc-trap fasl-output
))
1215 (let* ((info (leaf-info payload
))
1216 (handle (gethash info
1217 (fasl-output-entry-table fasl-output
))))
1218 (declare (type entry-info info
))
1219 (cond (handle (dump-push handle fasl-output
))
1221 (patches (cons info i
))
1222 (dump-fop 'fop-misc-trap fasl-output
)))))
1224 (dump-push payload fasl-output
))
1226 ;; It's possible for other fdefns to be found in the header not resulting
1227 ;; from IR2-CONVERT-GLOBAL-VAR, for example (L-T-V (find-or-create-fdefn ...)).
1228 ;; Those fdefns would not use FOP-FDEFN.
1229 (dump-object payload fasl-output
)
1230 (dump-fop 'fop-fdefn fasl-output
))
1232 (dump-object payload fasl-output
)
1233 (dump-fop 'fop-known-fun fasl-output
))
1235 ;; Avoid the coalescence done by DUMP-VECTOR
1236 (dump-specialized-vector (make-array (cdr entry
)
1237 :element-type
'(unsigned-byte 8)
1238 :initial-element
#xFF
)
1241 ;; Dump the debug info.
1242 (let ((info (debug-info-for-component component
)))
1243 (fasl-validate-structure info fasl-output
)
1244 (dump-object info fasl-output
)
1245 (push (dump-to-table fasl-output
)
1246 (fasl-output-debug-info fasl-output
)))
1248 (let ((n-fixup-elts (dump-fixups fixups alloc-points fasl-output
)))
1249 (dump-fop 'fop-load-code fasl-output
1250 (logior (ash header-length
1)
1251 (if (code-immobile-p component
) 1 0))
1254 ;; Fasl dumper/loader convention allows at most 3 integer args.
1255 ;; Others have to be written with explicit calls.
1256 (dump-integer-as-n-bytes (length (ir2-component-entries 2comp
))
1259 (dump-segment code-segment code-length fasl-output
)
1261 (let ((handle (dump-pop fasl-output
)))
1262 (dolist (patch (patches))
1263 (push (cons handle
(cdr patch
))
1264 (gethash (car patch
)
1265 (fasl-output-patch-table fasl-output
))))
1266 (dolist (named-constant (named-constants))
1267 (dump-object (car named-constant
) fasl-output
)
1268 (dump-push handle fasl-output
)
1269 (dump-fop 'fop-named-constant-set fasl-output
(cdr named-constant
)))
1272 ;;; This is only called from assemfile, which doesn't exist in the target.
1274 (defun dump-assembler-routines (code-segment octets fixups alloc-points routines file
)
1275 (let ((n-fixup-elts (dump-fixups fixups alloc-points file
)))
1276 ;; The name -> address table has to be created before applying fixups
1277 ;; because a fixup may refer to an entry point in the same code component.
1278 ;; So these go on the stack last, i.e. nearest the top.
1279 ;; Reversing sorts the entry points in ascending address order
1280 ;; except possibly when there are multiple entry points to one routine
1281 (unless (= (length (remove-duplicates (mapcar 'car routines
)))
1283 (error "Duplicated asm routine name"))
1284 (dolist (routine (reverse routines
))
1285 (dump-object (car routine
) file
)
1286 (dump-integer (+ (label-position (cadr routine
)) (caddr routine
))
1288 (dump-fop 'fop-assembler-code file
)
1289 (dump-word (length routines
) file
)
1290 (dump-word (length octets
) file
)
1291 (dump-word n-fixup-elts file
)
1292 (write-segment-contents code-segment
(fasl-output-stream file
))
1295 ;;; Alter the code object referenced by CODE-HANDLE at the specified
1296 ;;; OFFSET, storing the object referenced by ENTRY-HANDLE.
1297 (defun dump-alter-code-object (code-handle offset entry-handle file
)
1298 (declare (type index code-handle entry-handle offset
))
1299 (declare (type fasl-output file
))
1300 (dump-push code-handle file
)
1301 (dump-push entry-handle file
)
1302 (dump-fop 'fop-alter-code file offset
)
1305 ;;; Dump the code, constants, etc. for component. We pass in the
1306 ;;; assembler fixups, code vector and node info.
1307 (defun fasl-dump-component (component code-segment code-length fixups alloc-points file
)
1308 (declare (type component component
))
1309 (declare (type fasl-output file
))
1312 (let ((info (ir2-component-dyncount-info (component-info component
))))
1314 (fasl-validate-structure info file
)))
1316 (let* ((2comp (component-info component
))
1317 (entries (ir2-component-entries 2comp
))
1318 (nfuns (length entries
))
1320 (dump-code-object component code-segment code-length fixups
1324 (dolist (entry entries
)
1325 (dump-push code-handle file
)
1326 (dump-fop 'fop-fun-entry file
(decf fun-index
))
1327 (let ((entry-handle (dump-pop file
)))
1328 ;; When cross compiling, if the entry is a DEFUN, then we also
1329 ;; dump a FOP-FSET so that the cold loader can instantiate the
1330 ;; definition at cold-load time, allowing forward references
1331 ;; to functions in top-level forms. If the entry is a
1332 ;; DEFMETHOD, we dump a FOP-MSET so that the cold loader
1333 ;; recognizes the method definition.
1335 (let ((name (entry-info-name entry
)))
1336 (cond ((legal-fun-name-p name
)
1337 (dump-object name file
)
1338 (dump-push entry-handle file
)
1339 (dump-fop 'fop-fset file
))
1341 (eq (first name
) 'sb-pcl
::fast-method
))
1342 (let ((method (second name
))
1343 (qualifiers (butlast (cddr name
)))
1344 (specializers (first (last name
))))
1345 (dump-object method file
)
1346 (dump-object qualifiers file
)
1347 (dump-object specializers file
)
1348 (dump-push entry-handle file
)
1349 (dump-fop 'fop-mset file
)))))
1350 (setf (gethash entry
(fasl-output-entry-table file
)) entry-handle
)
1351 (let ((old (gethash entry
(fasl-output-patch-table file
))))
1354 (dump-alter-code-object (car patch
)
1358 (remhash entry
(fasl-output-patch-table file
)))))))
1361 ;;; Dump a FOP-FUNCALL to call an already-dumped top level lambda at
1363 (defun fasl-dump-toplevel-lambda-call (fun fasl-output
)
1364 (declare (type clambda fun
) (type fasl-output fasl-output
))
1365 (let ((handle (gethash (leaf-info fun
)
1366 (fasl-output-entry-table fasl-output
))))
1368 (dump-push handle fasl-output
)
1369 (dump-fop 'fop-funcall-for-effect fasl-output
0))
1372 ;;; Dump some information to allow partial reconstruction of the
1373 ;;; DEBUG-SOURCE structure.
1374 (defun fasl-dump-partial-source-info (info file
)
1375 (declare (type source-info info
) (type fasl-output file
))
1376 (let ((partial (debug-source-for-info info
)))
1377 (dump-object (debug-source-namestring partial
) file
)
1378 (dump-object (debug-source-created partial
) file
)
1379 (dump-object (debug-source-plist partial
) file
)
1380 (dump-fop 'fop-note-partial-source-info file
)))
1382 ;;; Compute the correct list of DEBUG-SOURCE structures and backpatch
1383 ;;; all of the dumped DEBUG-INFO structures. We clear the
1384 ;;; FASL-OUTPUT-DEBUG-INFO, so that subsequent components with
1385 ;;; different source info may be dumped.
1386 (defun fasl-dump-source-info (info file
)
1387 (declare (type source-info info
) (type fasl-output file
))
1388 (let ((res (debug-source-for-info info
)))
1389 (fasl-validate-structure res file
)
1390 (dump-object res file
)
1391 (let ((res-handle (dump-pop file
)))
1392 (dolist (info-handle (fasl-output-debug-info file
))
1393 (dump-push res-handle file
)
1394 (dump-fop 'fop-structset file info-handle
(get-dsd-index debug-info source
)))))
1396 (setf (fasl-output-debug-info file
) nil
)
1399 ;;;; dumping structures
1401 (defun dump-structure (struct file
)
1402 (unless (gethash struct
(fasl-output-valid-structures file
))
1403 (error "attempt to dump invalid structure:~% ~S~%How did this happen?"
1405 (note-potential-circularity struct file
)
1406 (do* ((length (%instance-length struct
))
1407 (layout (%instance-layout struct
))
1408 (bitmap (layout-bitmap layout
))
1409 (circ (fasl-output-circularity-table file
))
1410 (index sb-vm
:instance-data-start
(1+ index
)))
1412 (dump-non-immediate-object layout file
)
1413 (dump-fop 'fop-struct file length
))
1414 (let* ((obj (if (logbitp index bitmap
)
1415 (%instance-ref struct index
)
1416 (%raw-instance-ref
/word struct index
)))
1417 (ref (gethash obj circ
)))
1418 (sub-dump-object (cond (ref
1419 (push (make-circularity :type
:struct-set
1423 :enclosing-object ref
)
1424 *circularities-detected
*)
1429 (defun dump-layout (obj file
)
1430 (when (layout-invalid obj
)
1431 (compiler-error "attempt to dump reference to obsolete class: ~S"
1432 (layout-classoid obj
)))
1433 ;; STANDARD-OBJECT could in theory be dumpable, but nothing else,
1434 ;; because all its subclasses can evolve to have new layouts.
1435 (aver (not (logtest (layout-flags obj
) +pcl-object-layout-flag
+)))
1436 (let ((name (layout-classoid-name obj
)))
1437 ;; Q: Shouldn't we aver that NAME is the proper name for its classoid?
1439 (compiler-error "dumping anonymous layout: ~S" obj
))
1440 ;; The target lisp can save some space in fasls (sometimes),
1441 ;; but the cross-compiler can't because we need to construct the
1442 ;; cold representation of all layouts, not reference host layouts.
1444 (let ((fop (known-layout-fop name
)))
1446 (return-from dump-layout
(dump-byte fop file
))))
1447 (dump-object name file
))
1448 (sub-dump-object (layout-bitmap obj
) file
)
1449 (sub-dump-object (layout-inherits obj
) file
)
1450 (dump-fop 'fop-layout file
1451 (1+ (layout-depthoid obj
)) ; non-stack args can't be negative
1452 (logand (layout-flags obj
) sb-kernel
::layout-flags-mask
)
1453 (layout-length obj
)))
1455 ;;;; dumping instances which just save their slots
1457 (defun dump-instance-saving-slots (object slot-names file
)
1458 (note-potential-circularity object file
)
1459 (let ((circ (fasl-output-circularity-table file
)))
1460 (dolist (slot-name slot-names
)
1461 (if (slot-boundp object slot-name
)
1462 (let* ((value (slot-value object slot-name
))
1463 (ref (gethash value circ
)))
1465 (push (make-circularity :type
:slot-set
1468 :slot-name slot-name
1470 :enclosing-object ref
)
1471 *circularities-detected
*)
1472 (sub-dump-object nil file
))
1474 (sub-dump-object value file
))))
1475 (dump-fop 'fop-misc-trap file
))
1476 (sub-dump-object slot-name file
)))
1477 (sub-dump-object (class-name (class-of object
)) file
)
1478 (dump-fop 'fop-instance file
(length slot-names
)))
1482 (defun dump-code-coverage-records (cc file
)
1483 (declare (type list cc
))
1484 (dump-object cc file
)
1485 (dump-fop 'fop-record-code-coverage file
))
1487 ;;; NOTE: this is unused at present and may never have been necessary-
1488 ;;; full-calls can be inferred at load-time by tracking :LINKAGE-CELL fixups or FOP-FDEFN.
1489 (defun dump-emitted-full-calls (hash-table fasl
)
1490 (let ((list (%hash-table-alist hash-table
)))
1491 #+sb-xc-host
; enforce host-insensitive reproducible ordering
1492 (labels ((symbol< (a b
)
1493 (cond ((string< a b
) t
)
1495 ;; this does find a few pairs of lookalikes
1496 (string< (cl:package-name
(sb-xc:symbol-package a
))
1497 (cl:package-name
(sb-xc:symbol-package b
))))))
1499 (cond ((and (atom a
) (atom b
)) (symbol< a b
))
1500 ((atom a
) t
) ; symbol < list
1501 ((atom b
) nil
) ; opposite
1502 ((symbol< (cadr a
) (cadr b
))))))
1503 (setq list
(sort list
#'fname
< :key
#'car
)))
1504 (dump-object list fasl
)
1505 (dump-fop 'fop-note-full-calls fasl
)))