1.0.15.10: ASSOC and MEMBER were broken for :KEY #'IDENTITY
[sbcl.git] / src / compiler / ir1tran.lisp
index 15ac812..903a0a6 100644 (file)
 
 (declaim (special *compiler-error-bailout*))
 
+;;; *CURRENT-FORM-NUMBER* is used in FIND-SOURCE-PATHS to compute the
+;;; form number to associate with a source path. This should be bound
+;;; to an initial value of 0 before the processing of each truly
+;;; top level form.
+(declaim (type index *current-form-number*))
+(defvar *current-form-number*)
+
 ;;; *SOURCE-PATHS* is a hashtable from source code forms to the path
 ;;; taken through the source to reach the form. This provides a way to
 ;;; keep track of the location of original source forms, even when
 ;;; macroexpansions and other arbitary permutations of the code
 ;;; happen. This table is initialized by calling FIND-SOURCE-PATHS on
 ;;; the original source.
+;;;
+;;; It is fairly useless to store symbols, characters, or fixnums in
+;;; this table, as 42 is EQ to 42 no matter where in the source it
+;;; appears. GET-SOURCE-PATH and NOTE-SOURCE-PATH functions should be
+;;; always used to access this table.
 (declaim (hash-table *source-paths*))
 (defvar *source-paths*)
 
+(declaim (inline source-form-has-path-p))
+(defun source-form-has-path-p (form)
+  (not (typep form '(or symbol fixnum character))))
+
+(defun get-source-path (form)
+  (when (source-form-has-path-p form)
+    (gethash form *source-paths*)))
+
+(defun note-source-path (form &rest arguments)
+  (when (source-form-has-path-p form)
+    (setf (gethash form *source-paths*)
+          (apply #'list* 'original-source-start *current-form-number* arguments))))
+
 ;;; *CURRENT-COMPONENT* is the COMPONENT structure which we link
 ;;; blocks into as we generate them. This just serves to glue the
 ;;; emitted blocks together until local call analysis and flow graph
             (functional-kind res) :toplevel)
       res)))
 
-;;; *CURRENT-FORM-NUMBER* is used in FIND-SOURCE-PATHS to compute the
-;;; form number to associate with a source path. This should be bound
-;;; to an initial value of 0 before the processing of each truly
-;;; top level form.
-(declaim (type index *current-form-number*))
-(defvar *current-form-number*)
-
 ;;; This function is called on freshly read forms to record the
 ;;; initial location of each form (and subform.) Form is the form to
 ;;; find the paths in, and TLF-NUM is the top level form number of the
     (sub-find-source-paths form (list tlf-num)))
   (values))
 (defun sub-find-source-paths (form path)
-  (unless (gethash form *source-paths*)
-    (setf (gethash form *source-paths*)
-          (list* 'original-source-start *current-form-number* path))
+  (unless (get-source-path form)
+    (note-source-path form path)
     (incf *current-form-number*)
     (let ((pos 0)
           (subform form)
                             ;; Otherwise store the containing form. It's
                             ;; not perfect, but better than nothing.
                             (unless (zerop pos)
-                              (setf (gethash subform *source-paths*)
-                                    (list* 'original-source-start
-                                           *current-form-number*
-                                           pos
-                                           path))))
+                              (note-source-path subform pos path)))
                         (incf pos))
                       (setq subform (cdr subform))
                       (when (eq subform trail) (return)))))
   ;; namespace.
   (defun ir1-convert (start next result form)
     (ir1-error-bailout (start next result form)
-      (let* ((*current-path* (or (gethash form *source-paths*)
+      (let* ((*current-path* (or (get-source-path form)
                                  (cons form *current-path*)))
              (start (instrument-coverage start nil form)))
         (cond ((atom form)
              (let ((*print-pretty* nil)
                    ;; We rely on the printer to abbreviate FORM.
                    (*print-length* 3)
-                   (*print-level* 1))
+                   (*print-level* 3))
                (format
                 nil
                 #-sb-xc-host "(in macroexpansion of ~S)"
 \f
 ;;;; code coverage
 
+;;; Used as the CDR of the code coverage instrumentation records
+;;; (instead of NIL) to ensure that any well-behaving user code will
+;;; not have constants EQUAL to that record. This avoids problems with
+;;; the records getting coalesced with non-record conses, which then
+;;; get mutated when the instrumentation runs. Note that it's
+;;; important for multiple records for the same location to be
+;;; coalesced. -- JES, 2008-01-02
+(defconstant +code-coverage-unmarked+ '%code-coverage-unmarked%)
+
 ;;; Check the policy for whether we should generate code coverage
 ;;; instrumentation. If not, just return the original START
-;;; ctran. Otherwise ninsert code coverage instrumentation after
+;;; ctran. Otherwise insert code coverage instrumentation after
 ;;; START, and return the new ctran.
 (defun instrument-coverage (start mode form)
   ;; We don't actually use FORM for anything, it's just convenient to
                    ;; each instrument for the same block.
                    (or (gethash path *code-coverage-records*)
                        (setf (gethash path *code-coverage-records*)
-                             (cons path nil))))
+                             (cons path +code-coverage-unmarked+))))
                   (next (make-ctran))
                   (*allow-instrumenting* nil))
               (push (ctran-block start)
                              `(locally
                                   (declare (optimize speed
                                                      (safety 0)
-                                                     (debug 0)))
+                                                     (debug 0)
+                                                     (check-constant-modification 0)))
                                 ;; We're being naughty here, and
                                 ;; modifying constant data. That's ok,
                                 ;; we know what we're doing.
 ;;; EQness of the conses.
 (defun maybe-instrument-progn-like (start forms form)
   (or (when (and *allow-instrumenting*
-                 (not (gethash form *source-paths*)))
-        (let ((*current-path* (gethash forms *source-paths*)))
+                 (not (get-source-path form)))
+        (let ((*current-path* (get-source-path forms)))
           (when *current-path*
             (instrument-coverage start nil form))))
       start))
   (maphash (lambda (info cc)
              (declare (ignore info))
              (dolist (cc-entry cc)
-               (setf (cdr cc-entry) nil)))
+               (setf (cdr cc-entry) +code-coverage-unmarked+)))
            *code-coverage-info*))
 
+(defun code-coverage-record-marked (record)
+  (aver (consp record))
+  (ecase (cdr record)
+    ((#.+code-coverage-unmarked+) nil)
+    ((t) t)))
+
 \f
 ;;;; converting combinations