unless (member (caar record) '(:then :else))
collect (list mode
(car record)
- (ecase (cdr record)
- ((t) 1)
- ((nil) 2)))))
+ (if (sb-c::code-coverage-record-marked record)
+ 1
+ 2))))
(:branch
(let ((hash (make-hash-table :test 'equal)))
(dolist (record records)
(when (member (car path) '(:then :else))
(setf (gethash (cdr path) hash)
(logior (gethash (cdr path) hash 0)
- (ash (if (cdr record)
+ (ash (if (sb-c::code-coverage-record-marked record)
1
2)
(if (eql (car path) :then)
\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)
(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