dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

cmucl.lisp (97185B)


      1 ;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;+" -*-
      2 ;;;
      3 ;;; License: Public Domain
      4 ;;;
      5 ;;;; Introduction
      6 ;;;
      7 ;;; This is the CMUCL implementation of the `slynk-backend' package.
      8 
      9 (defpackage slynk-cmucl
     10   (:use cl slynk-backend slynk-source-path-parser slynk-source-file-cache
     11         fwrappers))
     12 
     13 (in-package slynk-cmucl)
     14 
     15 (eval-when (:compile-toplevel :load-toplevel :execute)
     16 
     17   (let ((min-version #x20c))
     18     (assert (>= c:byte-fasl-file-version min-version)
     19             () "This file requires CMUCL version ~x or newer" min-version))
     20 
     21   (require 'gray-streams))
     22 
     23 (import-slynk-mop-symbols :pcl '(:slot-definition-documentation))
     24 
     25 (defun slynk-mop:slot-definition-documentation (slot)
     26   (documentation slot t))
     27 
     28 ;;; UTF8
     29 
     30 (locally (declare (optimize (ext:inhibit-warnings 3)))
     31   ;; Compile and load the utf8 format, if not already loaded.
     32   (stream::find-external-format :utf-8))
     33 
     34 (defimplementation string-to-utf8 (string)
     35   (let ((ef (load-time-value (stream::find-external-format :utf-8) t)))
     36     (stream:string-to-octets string :external-format ef)))
     37 
     38 (defimplementation utf8-to-string (octets)
     39   (let ((ef (load-time-value (stream::find-external-format :utf-8) t)))
     40     (stream:octets-to-string octets :external-format ef)))
     41 
     42 
     43 ;;;; TCP server
     44 ;;;
     45 ;;; In CMUCL we support all communication styles. By default we use
     46 ;;; `:SIGIO' because it is the most responsive, but it's somewhat
     47 ;;; dangerous: CMUCL is not in general "signal safe", and you don't
     48 ;;; know for sure what you'll be interrupting. Both `:FD-HANDLER' and
     49 ;;; `:SPAWN' are reasonable alternatives.
     50 
     51 (defimplementation preferred-communication-style ()
     52   :sigio)
     53 
     54 #-(or darwin mips)
     55 (defimplementation create-socket (host port &key backlog)
     56   (let* ((addr (resolve-hostname host))
     57          (addr (if (not (find-symbol "SOCKET-ERROR" :ext))
     58                    (ext:htonl addr)
     59                    addr)))
     60     (ext:create-inet-listener port :stream :reuse-address t :host addr
     61                               :backlog (or backlog 5))))
     62 
     63 ;; There seems to be a bug in create-inet-listener on Mac/OSX and Irix.
     64 #+(or darwin mips)
     65 (defimplementation create-socket (host port &key backlog)
     66   (declare (ignore host))
     67   (ext:create-inet-listener port :stream :reuse-address t))
     68 
     69 (defimplementation local-port (socket)
     70   (nth-value 1 (ext::get-socket-host-and-port (socket-fd socket))))
     71 
     72 (defimplementation close-socket (socket)
     73   (let ((fd (socket-fd socket)))
     74     (sys:invalidate-descriptor fd)
     75     (ext:close-socket fd)))
     76 
     77 (defimplementation accept-connection (socket &key
     78                                       external-format buffering timeout)
     79   (declare (ignore timeout))
     80   (make-socket-io-stream (ext:accept-tcp-connection socket)
     81                          (ecase buffering
     82                            ((t) :full)
     83                            (:line :line)
     84                            ((nil) :none))
     85                          external-format))
     86 
     87 ;;;;; Sockets
     88 
     89 (defimplementation socket-fd (socket)
     90   "Return the filedescriptor for the socket represented by SOCKET."
     91   (etypecase socket
     92     (fixnum socket)
     93     (sys:fd-stream (sys:fd-stream-fd socket))))
     94 
     95 (defun resolve-hostname (hostname)
     96   "Return the IP address of HOSTNAME as an integer (in host byte-order)."
     97   (let ((hostent (ext:lookup-host-entry hostname)))
     98     (car (ext:host-entry-addr-list hostent))))
     99 
    100 (defvar *external-format-to-coding-system*
    101   '((:iso-8859-1 "iso-latin-1-unix")
    102     #+unicode
    103     (:utf-8 "utf-8-unix")))
    104 
    105 (defimplementation find-external-format (coding-system)
    106   (car (rassoc-if (lambda (x) (member coding-system x :test #'equal))
    107                   *external-format-to-coding-system*)))
    108 
    109 (defun make-socket-io-stream (fd buffering external-format)
    110   "Create a new input/output fd-stream for FD."
    111   (cond (external-format
    112          (sys:make-fd-stream fd :input t :output t
    113                              :element-type 'character
    114                              :buffering buffering
    115                              :external-format external-format))
    116         (t
    117          (sys:make-fd-stream fd :input t :output t
    118                              :element-type '(unsigned-byte 8)
    119                              :buffering buffering))))
    120 
    121 (defimplementation make-fd-stream (fd external-format)
    122   (make-socket-io-stream fd :full external-format))
    123 
    124 (defimplementation dup (fd)
    125   (multiple-value-bind (clone error) (unix:unix-dup fd)
    126     (unless clone (error "dup failed: ~a" (unix:get-unix-error-msg error)))
    127     clone))
    128 
    129 (defimplementation command-line-args ()
    130   ext:*command-line-strings*)
    131 
    132 (defimplementation exec-image (image-file args)
    133   (multiple-value-bind (ok error)
    134       (unix:unix-execve (car (command-line-args))
    135 			(list* (car (command-line-args))
    136                                "-core" image-file
    137                                "-noinit"
    138                                args))
    139     (error "~a" (unix:get-unix-error-msg error))
    140     ok))
    141 
    142 ;;;;; Signal-driven I/O
    143 
    144 (defimplementation install-sigint-handler (function)
    145   (sys:enable-interrupt :sigint (lambda (signal code scp)
    146                                   (declare (ignore signal code scp))
    147                                   (funcall function))))
    148 
    149 (defvar *sigio-handlers* '()
    150   "List of (key . function) pairs.
    151 All functions are called on SIGIO, and the key is used for removing
    152 specific functions.")
    153 
    154 (defun reset-sigio-handlers () (setq *sigio-handlers* '()))
    155 ;; All file handlers are invalid afer reload.
    156 (pushnew 'reset-sigio-handlers ext:*after-save-initializations*)
    157 
    158 (defun set-sigio-handler ()
    159   (sys:enable-interrupt :sigio (lambda (signal code scp)
    160                                  (sigio-handler signal code scp))))
    161 
    162 (defun sigio-handler (signal code scp)
    163   (declare (ignore signal code scp))
    164   (mapc #'funcall (mapcar #'cdr *sigio-handlers*)))
    165 
    166 (defun fcntl (fd command arg)
    167   "fcntl(2) - manipulate a file descriptor."
    168   (multiple-value-bind (ok error) (unix:unix-fcntl fd command arg)
    169     (cond (ok)
    170           (t (error "fcntl: ~A" (unix:get-unix-error-msg error))))))
    171 
    172 (defimplementation add-sigio-handler (socket fn)
    173   (set-sigio-handler)
    174   (let ((fd (socket-fd socket)))
    175     (fcntl fd unix:f-setown (unix:unix-getpid))
    176     (let ((old-flags (fcntl fd unix:f-getfl 0)))
    177       (fcntl fd unix:f-setfl (logior old-flags unix:fasync)))
    178     (assert (not (assoc fd *sigio-handlers*)))
    179     (push (cons fd fn) *sigio-handlers*)))
    180 
    181 (defimplementation remove-sigio-handlers (socket)
    182   (let ((fd (socket-fd socket)))
    183     (when (assoc fd *sigio-handlers*)
    184       (setf *sigio-handlers* (remove fd *sigio-handlers* :key #'car))
    185       (let ((old-flags (fcntl fd unix:f-getfl 0)))
    186         (fcntl fd unix:f-setfl (logandc2 old-flags unix:fasync)))
    187       (sys:invalidate-descriptor fd))
    188     (assert (not (assoc fd *sigio-handlers*)))
    189     (when (null *sigio-handlers*)
    190       (sys:default-interrupt :sigio))))
    191 
    192 ;;;;; SERVE-EVENT
    193 
    194 (defimplementation add-fd-handler (socket fn)
    195   (let ((fd (socket-fd socket)))
    196     (sys:add-fd-handler fd :input (lambda (_) _ (funcall fn)))))
    197 
    198 (defimplementation remove-fd-handlers (socket)
    199   (sys:invalidate-descriptor (socket-fd socket)))
    200 
    201 (defimplementation wait-for-input (streams &optional timeout)
    202   (assert (member timeout '(nil t)))
    203   (loop
    204    (let ((ready (remove-if-not #'listen streams)))
    205      (when ready (return ready)))
    206    (when timeout (return nil))
    207    (multiple-value-bind (in out) (make-pipe)
    208      (let* ((f (constantly t))
    209             (handlers (loop for s in (cons in (mapcar #'to-fd-stream streams))
    210                             collect (add-one-shot-handler s f))))
    211        (unwind-protect
    212             (let ((*interrupt-queued-handler* (lambda ()
    213                                                 (write-char #\! out))))
    214               (when (check-sly-interrupts) (return :interrupt))
    215               (sys:serve-event))
    216          (mapc #'sys:remove-fd-handler handlers)
    217          (close in)
    218          (close out))))))
    219 
    220 (defun to-fd-stream (stream)
    221   (etypecase stream
    222     (sys:fd-stream stream)
    223     (synonym-stream
    224      (to-fd-stream
    225       (symbol-value (synonym-stream-symbol stream))))
    226     (two-way-stream
    227      (to-fd-stream (two-way-stream-input-stream stream)))))
    228 
    229 (defun add-one-shot-handler (stream function)
    230   (let (handler)
    231     (setq handler (sys:add-fd-handler (sys:fd-stream-fd stream) :input
    232                                       (lambda (fd)
    233                                         (declare (ignore fd))
    234                                         (sys:remove-fd-handler handler)
    235                                         (funcall function stream))))))
    236 
    237 (defun make-pipe ()
    238   (multiple-value-bind (in out) (unix:unix-pipe)
    239     (values (sys:make-fd-stream in :input t :buffering :none)
    240             (sys:make-fd-stream out :output t :buffering :none))))
    241 
    242 
    243 ;;;; Stream handling
    244 
    245 (defimplementation gray-package-name ()
    246   "EXT")
    247 
    248 
    249 ;;;; Compilation Commands
    250 
    251 (defvar *previous-compiler-condition* nil
    252   "Used to detect duplicates.")
    253 
    254 (defvar *previous-context* nil
    255   "Previous compiler error context.")
    256 
    257 (defvar *buffer-name* nil
    258   "The name of the Emacs buffer we are compiling from.
    259 NIL if we aren't compiling from a buffer.")
    260 
    261 (defvar *buffer-start-position* nil)
    262 (defvar *buffer-substring* nil)
    263 
    264 (defimplementation call-with-compilation-hooks (function)
    265   (let ((*previous-compiler-condition* nil)
    266         (*previous-context* nil)
    267         (*print-readably* nil))
    268     (handler-bind ((c::compiler-error #'handle-notification-condition)
    269                    (c::style-warning  #'handle-notification-condition)
    270                    (c::warning        #'handle-notification-condition))
    271       (funcall function))))
    272 
    273 (defimplementation slynk-compile-file (input-file output-file
    274                                        load-p external-format
    275                                        &key policy)
    276   (declare (ignore policy))
    277   (clear-xref-info input-file)
    278   (with-compilation-hooks ()
    279     (let ((*buffer-name* nil)
    280           (ext:*ignore-extra-close-parentheses* nil))
    281       (multiple-value-bind (output-file warnings-p failure-p)
    282           (compile-file input-file :output-file output-file
    283                         :external-format external-format)
    284         (values output-file warnings-p
    285                 (or failure-p
    286                     (when load-p
    287                       ;; Cache the latest source file for definition-finding.
    288                       (source-cache-get input-file
    289                                         (file-write-date input-file))
    290                       (not (load output-file)))))))))
    291 
    292 (defimplementation slynk-compile-string (string &key buffer position filename
    293                                                 line column policy)
    294   (declare (ignore filename line column policy))
    295   (with-compilation-hooks ()
    296     (let ((*buffer-name* buffer)
    297           (*buffer-start-position* position)
    298           (*buffer-substring* string)
    299           (source-info (list :emacs-buffer buffer
    300                              :emacs-buffer-offset position
    301                              :emacs-buffer-string string)))
    302       (with-input-from-string (stream string)
    303         (let ((failurep (ext:compile-from-stream stream :source-info
    304                                                 source-info)))
    305           (not failurep))))))
    306 
    307 
    308 ;;;;; Trapping notes
    309 ;;;
    310 ;;; We intercept conditions from the compiler and resignal them as
    311 ;;; `SLYNK:COMPILER-CONDITION's.
    312 
    313 (defun handle-notification-condition (condition)
    314   "Handle a condition caused by a compiler warning."
    315   (unless (eq condition *previous-compiler-condition*)
    316     (let ((context (c::find-error-context nil)))
    317       (setq *previous-compiler-condition* condition)
    318       (setq *previous-context* context)
    319       (signal-compiler-condition condition context))))
    320 
    321 (defun signal-compiler-condition (condition context)
    322   (signal 'compiler-condition
    323           :original-condition condition
    324           :severity (severity-for-emacs condition)
    325           :message (compiler-condition-message condition)
    326           :source-context (compiler-error-context context)
    327           :location (if (read-error-p condition)
    328                         (read-error-location condition)
    329                         (compiler-note-location context))))
    330 
    331 (defun severity-for-emacs (condition)
    332   "Return the severity of CONDITION."
    333   (etypecase condition
    334     ((satisfies read-error-p) :read-error)
    335     (c::compiler-error :error)
    336     (c::style-warning :note)
    337     (c::warning :warning)))
    338 
    339 (defun read-error-p (condition)
    340   (eq (type-of condition) 'c::compiler-read-error))
    341 
    342 (defun compiler-condition-message (condition)
    343   "Briefly describe a compiler error for Emacs.
    344 When Emacs presents the message it already has the source popped up
    345 and the source form highlighted. This makes much of the information in
    346 the error-context redundant."
    347   (princ-to-string condition))
    348 
    349 (defun compiler-error-context (error-context)
    350   "Describe context information for Emacs."
    351   (declare (type (or c::compiler-error-context null) error-context))
    352   (multiple-value-bind (enclosing source)
    353       (if error-context
    354           (values (c::compiler-error-context-enclosing-source error-context)
    355                   (c::compiler-error-context-source error-context)))
    356     (if (or enclosing source)
    357         (format nil "~@[--> ~{~<~%--> ~1:;~A ~>~}~%~]~
    358                      ~@[==>~{~&~A~}~]"
    359                 enclosing source))))
    360 
    361 (defun read-error-location (condition)
    362   (let* ((finfo (car (c::source-info-current-file c::*source-info*)))
    363          (file (c::file-info-name finfo))
    364          (pos (c::compiler-read-error-position condition)))
    365     (cond ((and (eq file :stream) *buffer-name*)
    366            (make-location (list :buffer *buffer-name*)
    367                           (list :offset *buffer-start-position* pos)))
    368           ((and (pathnamep file) (not *buffer-name*))
    369            (make-location (list :file (unix-truename file))
    370                           (list :position (1+ pos))))
    371           (t (break)))))
    372 
    373 (defun compiler-note-location (context)
    374   "Derive the location of a complier message from its context.
    375 Return a `location' record, or (:error REASON) on failure."
    376   (if (null context)
    377       (note-error-location)
    378       (with-struct (c::compiler-error-context- file-name
    379                                                original-source
    380                                                original-source-path) context
    381         (or (locate-compiler-note file-name original-source
    382                                   (reverse original-source-path))
    383             (note-error-location)))))
    384 
    385 (defun note-error-location ()
    386   "Pseudo-location for notes that can't be located."
    387   (cond (*compile-file-truename*
    388          (make-location (list :file (unix-truename *compile-file-truename*))
    389                         (list :eof)))
    390         (*buffer-name*
    391          (make-location (list :buffer *buffer-name*)
    392                         (list :position *buffer-start-position*)))
    393         (t (list :error "No error location available."))))
    394 
    395 (defun locate-compiler-note (file source source-path)
    396   (cond ((and (eq file :stream) *buffer-name*)
    397          ;; Compiling from a buffer
    398          (make-location (list :buffer *buffer-name*)
    399                         (list :offset *buffer-start-position*
    400                               (source-path-string-position
    401                                source-path *buffer-substring*))))
    402         ((and (pathnamep file) (null *buffer-name*))
    403          ;; Compiling from a file
    404          (make-location (list :file (unix-truename file))
    405                         (list :position (1+ (source-path-file-position
    406                                              source-path file)))))
    407         ((and (eq file :lisp) (stringp source))
    408          ;; No location known, but we have the source form.
    409          ;; XXX How is this case triggered?  -luke (16/May/2004)
    410          ;; This can happen if the compiler needs to expand a macro
    411          ;; but the macro-expander is not yet compiled.  Calling the
    412          ;; (interpreted) macro-expander triggers IR1 conversion of
    413          ;; the lambda expression for the expander and invokes the
    414          ;; compiler recursively.
    415          (make-location (list :source-form source)
    416                         (list :position 1)))))
    417 
    418 (defun unix-truename (pathname)
    419   (ext:unix-namestring (truename pathname)))
    420 
    421 
    422 ;;;; XREF
    423 ;;;
    424 ;;; Cross-reference support is based on the standard CMUCL `XREF'
    425 ;;; package. This package has some caveats: XREF information is
    426 ;;; recorded during compilation and not preserved in fasl files, and
    427 ;;; XREF recording is disabled by default. Redefining functions can
    428 ;;; also cause duplicate references to accumulate, but
    429 ;;; `slynk-compile-file' will automatically clear out any old records
    430 ;;; from the same filename.
    431 ;;;
    432 ;;; To enable XREF recording, set `c:*record-xref-info*' to true. To
    433 ;;; clear out the XREF database call `xref:init-xref-database'.
    434 
    435 (defmacro defxref (name function)
    436   `(defimplementation ,name (name)
    437     (xref-results (,function name))))
    438 
    439 (defxref who-calls      xref:who-calls)
    440 (defxref who-references xref:who-references)
    441 (defxref who-binds      xref:who-binds)
    442 (defxref who-sets       xref:who-sets)
    443 
    444 ;;; More types of XREF information were added since 18e:
    445 ;;;
    446 
    447 (defxref who-macroexpands xref:who-macroexpands)
    448 ;; XXX
    449 (defimplementation who-specializes (symbol)
    450   (let* ((methods (xref::who-specializes (find-class symbol)))
    451          (locations (mapcar #'method-location methods)))
    452     (mapcar #'list methods locations)))
    453 
    454 (defun xref-results (contexts)
    455   (mapcar (lambda (xref)
    456             (list (xref:xref-context-name xref)
    457                   (resolve-xref-location xref)))
    458           contexts))
    459 
    460 (defun resolve-xref-location (xref)
    461   (let ((name (xref:xref-context-name xref))
    462         (file (xref:xref-context-file xref))
    463         (source-path (xref:xref-context-source-path xref)))
    464     (cond ((and file source-path)
    465            (let ((position (source-path-file-position source-path file)))
    466              (make-location (list :file (unix-truename file))
    467                             (list :position (1+ position)))))
    468           (file
    469            (make-location (list :file (unix-truename file))
    470                           (list :function-name (string name))))
    471           (t
    472            `(:error ,(format nil "Unknown source location: ~S ~S ~S "
    473                              name file source-path))))))
    474 
    475 (defun clear-xref-info (namestring)
    476   "Clear XREF notes pertaining to NAMESTRING.
    477 This is a workaround for a CMUCL bug: XREF records are cumulative."
    478   (when c:*record-xref-info*
    479     (let ((filename (truename namestring)))
    480       (dolist (db (list xref::*who-calls*
    481                         xref::*who-is-called*
    482                         xref::*who-macroexpands*
    483                         xref::*who-references*
    484                         xref::*who-binds*
    485                         xref::*who-sets*))
    486         (maphash (lambda (target contexts)
    487                    ;; XXX update during traversal?
    488                    (setf (gethash target db)
    489                          (delete filename contexts
    490                                  :key #'xref:xref-context-file
    491                                  :test #'equalp)))
    492                  db)))))
    493 
    494 
    495 ;;;; Find callers and callees
    496 ;;;
    497 ;;; Find callers and callees by looking at the constant pool of
    498 ;;; compiled code objects.  We assume every fdefn object in the
    499 ;;; constant pool corresponds to a call to that function.  A better
    500 ;;; strategy would be to use the disassembler to find actual
    501 ;;; call-sites.
    502 
    503 (labels ((make-stack () (make-array 100 :fill-pointer 0 :adjustable t))
    504          (map-cpool (code fun)
    505            (declare (type kernel:code-component code) (type function fun))
    506            (loop for i from vm:code-constants-offset
    507                  below (kernel:get-header-data code)
    508                  do (funcall fun (kernel:code-header-ref code i))))
    509 
    510          (callees (fun)
    511            (let ((callees (make-stack)))
    512              (map-cpool (vm::find-code-object fun)
    513                         (lambda (o)
    514                           (when (kernel:fdefn-p o)
    515                             (vector-push-extend (kernel:fdefn-function o)
    516                                                 callees))))
    517              (coerce callees 'list)))
    518 
    519          (callers (fun)
    520            (declare (function fun))
    521            (let ((callers (make-stack)))
    522              (ext:gc :full t)
    523              ;; scan :dynamic first to avoid the need for even more gcing
    524              (dolist (space '(:dynamic :read-only :static))
    525                (vm::map-allocated-objects
    526                 (lambda (obj header size)
    527                   (declare (type fixnum header) (ignore size))
    528                   (when (= vm:code-header-type header)
    529                     (map-cpool obj
    530                                (lambda (c)
    531                                  (when (and (kernel:fdefn-p c)
    532                                             (eq (kernel:fdefn-function c) fun))
    533                                    (vector-push-extend obj callers))))))
    534                 space)
    535                (ext:gc))
    536              (coerce callers 'list)))
    537 
    538          (entry-points (code)
    539            (loop for entry = (kernel:%code-entry-points code)
    540                  then (kernel::%function-next entry)
    541                  while entry
    542                  collect entry))
    543 
    544          (guess-main-entry-point (entry-points)
    545            (or (find-if (lambda (fun)
    546                           (ext:valid-function-name-p
    547                            (kernel:%function-name fun)))
    548                         entry-points)
    549                (car entry-points)))
    550 
    551          (fun-dspec (fun)
    552            (list (kernel:%function-name fun) (function-location fun)))
    553 
    554          (code-dspec (code)
    555            (let ((eps (entry-points code))
    556                  (di (kernel:%code-debug-info code)))
    557              (cond (eps (fun-dspec (guess-main-entry-point eps)))
    558                    (di (list (c::debug-info-name di)
    559                              (debug-info-function-name-location di)))
    560                    (t (list (princ-to-string code)
    561                             `(:error "No src-loc available")))))))
    562   (declare (inline map-cpool))
    563 
    564   (defimplementation list-callers (symbol)
    565     (mapcar #'code-dspec (callers (coerce symbol 'function) )))
    566 
    567   (defimplementation list-callees (symbol)
    568     (mapcar #'fun-dspec (callees symbol))))
    569 
    570 (defun test-list-callers (count)
    571   (let ((funsyms '()))
    572     (do-all-symbols (s)
    573       (when (and (fboundp s)
    574                  (functionp (symbol-function s))
    575                  (not (macro-function s))
    576                  (not (special-operator-p s)))
    577         (push s funsyms)))
    578     (let ((len (length funsyms)))
    579       (dotimes (i count)
    580         (let ((sym (nth (random len) funsyms)))
    581           (format t "~s -> ~a~%" sym (mapcar #'car (list-callers sym))))))))
    582 
    583 ;; (test-list-callers 100)
    584 
    585 
    586 ;;;; Resolving source locations
    587 ;;;
    588 ;;; Our mission here is to "resolve" references to code locations into
    589 ;;; actual file/buffer names and character positions. The references
    590 ;;; we work from come out of the compiler's statically-generated debug
    591 ;;; information, such as `code-location''s and `debug-source''s. For
    592 ;;; more details, see the "Debugger Programmer's Interface" section of
    593 ;;; the CMUCL manual.
    594 ;;;
    595 ;;; The first step is usually to find the corresponding "source-path"
    596 ;;; for the location. Once we have the source-path we can pull up the
    597 ;;; source file and `READ' our way through to the right position. The
    598 ;;; main source-code groveling work is done in
    599 ;;; `slynk-source-path-parser.lisp'.
    600 
    601 (defvar *debug-definition-finding* nil
    602   "When true don't handle errors while looking for definitions.
    603 This is useful when debugging the definition-finding code.")
    604 
    605 (defmacro safe-definition-finding (&body body)
    606   "Execute BODY and return the source-location it returns.
    607 If an error occurs and `*debug-definition-finding*' is false, then
    608 return an error pseudo-location.
    609 
    610 The second return value is NIL if no error occurs, otherwise it is the
    611 condition object."
    612   `(flet ((body () ,@body))
    613     (if *debug-definition-finding*
    614         (body)
    615         (handler-case (values (progn ,@body) nil)
    616           (error (c) (values `(:error ,(trim-whitespace (princ-to-string c)))
    617                              c))))))
    618 
    619 (defun trim-whitespace (string)
    620   (string-trim #(#\newline #\space #\tab) string))
    621 
    622 (defun code-location-source-location (code-location)
    623   "Safe wrapper around `code-location-from-source-location'."
    624   (safe-definition-finding
    625    (source-location-from-code-location code-location)))
    626 
    627 (defun source-location-from-code-location (code-location)
    628   "Return the source location for CODE-LOCATION."
    629   (let ((debug-fun (di:code-location-debug-function code-location)))
    630     (when (di::bogus-debug-function-p debug-fun)
    631       ;; Those lousy cheapskates! They've put in a bogus debug source
    632       ;; because the code was compiled at a low debug setting.
    633       (error "Bogus debug function: ~A" debug-fun)))
    634   (let* ((debug-source (di:code-location-debug-source code-location))
    635          (from (di:debug-source-from debug-source))
    636          (name (di:debug-source-name debug-source)))
    637     (ecase from
    638       (:file
    639        (location-in-file name code-location debug-source))
    640       (:stream
    641        (location-in-stream code-location debug-source))
    642       (:lisp
    643        ;; The location comes from a form passed to `compile'.
    644        ;; The best we can do is return the form itself for printing.
    645        (make-location
    646         (list :source-form (with-output-to-string (*standard-output*)
    647                              (debug::print-code-location-source-form
    648                               code-location 100 t)))
    649         (list :position 1))))))
    650 
    651 (defun location-in-file (filename code-location debug-source)
    652   "Resolve the source location for CODE-LOCATION in FILENAME."
    653   (let* ((code-date (di:debug-source-created debug-source))
    654          (root-number (di:debug-source-root-number debug-source))
    655          (source-code (get-source-code filename code-date)))
    656     (with-input-from-string (s source-code)
    657       (make-location (list :file (unix-truename filename))
    658                      (list :position (1+ (code-location-stream-position
    659                                           code-location s root-number)))
    660                      `(:snippet ,(read-snippet s))))))
    661 
    662 (defun location-in-stream (code-location debug-source)
    663   "Resolve the source location for a CODE-LOCATION from a stream.
    664 This only succeeds if the code was compiled from an Emacs buffer."
    665   (unless (debug-source-info-from-emacs-buffer-p debug-source)
    666     (error "The code is compiled from a non-SLY stream."))
    667   (let* ((info (c::debug-source-info debug-source))
    668          (string (getf info :emacs-buffer-string))
    669          (position (code-location-string-offset
    670                     code-location
    671                     string)))
    672     (make-location
    673      (list :buffer (getf info :emacs-buffer))
    674      (list :offset (getf info :emacs-buffer-offset) position)
    675      (list :snippet (with-input-from-string (s string)
    676                       (file-position s position)
    677                       (read-snippet s))))))
    678 
    679 ;;;;; Function-name locations
    680 ;;;
    681 (defun debug-info-function-name-location (debug-info)
    682   "Return a function-name source-location for DEBUG-INFO.
    683 Function-name source-locations are a fallback for when precise
    684 positions aren't available."
    685   (with-struct (c::debug-info- (fname name) source) debug-info
    686     (with-struct (c::debug-source- info from name) (car source)
    687       (ecase from
    688         (:file
    689          (make-location (list :file (namestring (truename name)))
    690                         (list :function-name (string fname))))
    691         (:stream
    692          (assert (debug-source-info-from-emacs-buffer-p (car source)))
    693          (make-location (list :buffer (getf info :emacs-buffer))
    694                         (list :function-name (string fname))))
    695         (:lisp
    696          (make-location (list :source-form (princ-to-string (aref name 0)))
    697                         (list :position 1)))))))
    698 
    699 (defun debug-source-info-from-emacs-buffer-p (debug-source)
    700   "Does the `info' slot of DEBUG-SOURCE contain an Emacs buffer location?
    701 This is true for functions that were compiled directly from buffers."
    702   (info-from-emacs-buffer-p (c::debug-source-info debug-source)))
    703 
    704 (defun info-from-emacs-buffer-p (info)
    705   (and info
    706        (consp info)
    707        (eq :emacs-buffer (car info))))
    708 
    709 
    710 ;;;;; Groveling source-code for positions
    711 
    712 (defun code-location-stream-position (code-location stream root)
    713   "Return the byte offset of CODE-LOCATION in STREAM.  Extract the
    714 toplevel-form-number and form-number from CODE-LOCATION and use that
    715 to find the position of the corresponding form.
    716 
    717 Finish with STREAM positioned at the start of the code location."
    718   (let* ((location (debug::maybe-block-start-location code-location))
    719          (tlf-offset (- (di:code-location-top-level-form-offset location)
    720                         root))
    721          (form-number (di:code-location-form-number location)))
    722     (let ((pos (form-number-stream-position tlf-offset form-number stream)))
    723       (file-position stream pos)
    724       pos)))
    725 
    726 (defun form-number-stream-position (tlf-number form-number stream)
    727   "Return the starting character position of a form in STREAM.
    728 TLF-NUMBER is the top-level-form number.
    729 FORM-NUMBER is an index into a source-path table for the TLF."
    730   (multiple-value-bind (tlf position-map) (read-source-form tlf-number stream)
    731     (let* ((path-table (di:form-number-translations tlf 0))
    732            (source-path
    733             (if (<= (length path-table) form-number) ; source out of sync?
    734                 (list 0)                ; should probably signal a condition
    735                 (reverse (cdr (aref path-table form-number))))))
    736       (source-path-source-position source-path tlf position-map))))
    737 
    738 (defun code-location-string-offset (code-location string)
    739   "Return the byte offset of CODE-LOCATION in STRING.
    740 See CODE-LOCATION-STREAM-POSITION."
    741   (with-input-from-string (s string)
    742     (code-location-stream-position code-location s 0)))
    743 
    744 
    745 ;;;; Finding definitions
    746 
    747 ;;; There are a great many different types of definition for us to
    748 ;;; find. We search for definitions of every kind and return them in a
    749 ;;; list.
    750 
    751 (defimplementation find-definitions (name)
    752   (append (function-definitions name)
    753           (setf-definitions name)
    754           (variable-definitions name)
    755           (class-definitions name)
    756           (type-definitions name)
    757           (compiler-macro-definitions name)
    758           (source-transform-definitions name)
    759           (function-info-definitions name)
    760           (ir1-translator-definitions name)
    761           (template-definitions name)
    762           (primitive-definitions name)
    763           (vm-support-routine-definitions name)
    764           ))
    765 
    766 ;;;;; Functions, macros, generic functions, methods
    767 ;;;
    768 ;;; We make extensive use of the compile-time debug information that
    769 ;;; CMUCL records, in particular "debug functions" and "code
    770 ;;; locations." Refer to the "Debugger Programmer's Interface" section
    771 ;;; of the CMUCL manual for more details.
    772 
    773 (defun function-definitions (name)
    774   "Return definitions for NAME in the \"function namespace\", i.e.,
    775 regular functions, generic functions, methods and macros.
    776 NAME can any valid function name (e.g, (setf car))."
    777   (let ((macro?    (and (symbolp name) (macro-function name)))
    778         (function? (and (ext:valid-function-name-p name)
    779                         (ext:info :function :definition name)
    780                         (if (symbolp name) (fboundp name) t))))
    781     (cond (macro?
    782            (list `((defmacro ,name)
    783                    ,(function-location (macro-function name)))))
    784           (function?
    785            (let ((function (fdefinition name)))
    786              (if (genericp function)
    787                  (gf-definitions name function)
    788                  (list (list `(function ,name)
    789                              (function-location function)))))))))
    790 
    791 ;;;;;; Ordinary (non-generic/macro/special) functions
    792 ;;;
    793 ;;; First we test if FUNCTION is a closure created by defstruct, and
    794 ;;; if so extract the defstruct-description (`dd') from the closure
    795 ;;; and find the constructor for the struct.  Defstruct creates a
    796 ;;; defun for the default constructor and we use that as an
    797 ;;; approximation to the source location of the defstruct.
    798 ;;;
    799 ;;; For an ordinary function we return the source location of the
    800 ;;; first code-location we find.
    801 ;;;
    802 (defun function-location (function)
    803   "Return the source location for FUNCTION."
    804   (cond ((struct-closure-p function)
    805          (struct-closure-location function))
    806         ((c::byte-function-or-closure-p function)
    807          (byte-function-location function))
    808         (t
    809          (compiled-function-location function))))
    810 
    811 (defun compiled-function-location (function)
    812   "Return the location of a regular compiled function."
    813   (multiple-value-bind (code-location error)
    814       (safe-definition-finding (function-first-code-location function))
    815     (cond (error (list :error (princ-to-string error)))
    816           (t (code-location-source-location code-location)))))
    817 
    818 (defun function-first-code-location (function)
    819   "Return the first code-location we can find for FUNCTION."
    820   (and (function-has-debug-function-p function)
    821        (di:debug-function-start-location
    822         (di:function-debug-function function))))
    823 
    824 (defun function-has-debug-function-p (function)
    825   (di:function-debug-function function))
    826 
    827 (defun function-code-object= (closure function)
    828   (and (eq (vm::find-code-object closure)
    829            (vm::find-code-object function))
    830        (not (eq closure function))))
    831 
    832 (defun byte-function-location (fun)
    833   "Return the location of the byte-compiled function FUN."
    834   (etypecase fun
    835     ((or c::hairy-byte-function c::simple-byte-function)
    836      (let* ((di (kernel:%code-debug-info (c::byte-function-component fun))))
    837        (if di
    838            (debug-info-function-name-location di)
    839            `(:error
    840              ,(format nil "Byte-function without debug-info: ~a" fun)))))
    841     (c::byte-closure
    842      (byte-function-location (c::byte-closure-function fun)))))
    843 
    844 ;;; Here we deal with structure accessors. Note that `dd' is a
    845 ;;; "defstruct descriptor" structure in CMUCL. A `dd' describes a
    846 ;;; `defstruct''d structure.
    847 
    848 (defun struct-closure-p (function)
    849   "Is FUNCTION a closure created by defstruct?"
    850   (or (function-code-object= function #'kernel::structure-slot-accessor)
    851       (function-code-object= function #'kernel::structure-slot-setter)
    852       (function-code-object= function #'kernel::%defstruct)))
    853 
    854 (defun struct-closure-location (function)
    855   "Return the location of the structure that FUNCTION belongs to."
    856   (assert (struct-closure-p function))
    857   (safe-definition-finding
    858     (dd-location (struct-closure-dd function))))
    859 
    860 (defun struct-closure-dd (function)
    861   "Return the defstruct-definition (dd) of FUNCTION."
    862   (assert (= (kernel:get-type function) vm:closure-header-type))
    863   (flet ((find-layout (function)
    864            (sys:find-if-in-closure
    865             (lambda (x)
    866               (let ((value (if (di::indirect-value-cell-p x)
    867                                (c:value-cell-ref x)
    868                                x)))
    869 		(when (kernel::layout-p value)
    870                   (return-from find-layout value))))
    871             function)))
    872     (kernel:layout-info (find-layout function))))
    873 
    874 (defun dd-location (dd)
    875   "Return the location of a `defstruct'."
    876   (let ((ctor (struct-constructor dd)))
    877     (cond (ctor
    878            (function-location (coerce ctor 'function)))
    879           (t
    880            (let ((name (kernel:dd-name dd)))
    881              (multiple-value-bind (location foundp)
    882                  (ext:info :source-location :defvar name)
    883                (cond (foundp
    884                       (resolve-source-location location))
    885                      (t
    886                       (error "No location for defstruct: ~S" name)))))))))
    887 
    888 (defun struct-constructor (dd)
    889   "Return the name of the constructor from a defstruct definition."
    890   (let* ((constructor (or (kernel:dd-default-constructor dd)
    891                           (car (kernel::dd-constructors dd)))))
    892     (if (consp constructor) (car constructor) constructor)))
    893 
    894 ;;;;;; Generic functions and methods
    895 
    896 (defun gf-definitions (name function)
    897   "Return the definitions of a generic function and its methods."
    898   (cons (list `(defgeneric ,name) (gf-location function))
    899         (gf-method-definitions function)))
    900 
    901 (defun gf-location (gf)
    902   "Return the location of the generic function GF."
    903   (definition-source-location gf (pcl::generic-function-name gf)))
    904 
    905 (defun gf-method-definitions (gf)
    906   "Return the locations of all methods of the generic function GF."
    907   (mapcar #'method-definition (pcl::generic-function-methods gf)))
    908 
    909 (defun method-definition (method)
    910   (list (method-dspec method)
    911         (method-location method)))
    912 
    913 (defun method-dspec (method)
    914   "Return a human-readable \"definition specifier\" for METHOD."
    915   (let* ((gf (pcl:method-generic-function method))
    916          (name (pcl:generic-function-name gf))
    917          (specializers (pcl:method-specializers method))
    918          (qualifiers (pcl:method-qualifiers method)))
    919     `(method ,name ,@qualifiers ,(pcl::unparse-specializers specializers))))
    920 
    921 (defun method-location (method)
    922   (typecase method
    923     (pcl::standard-accessor-method
    924      (definition-source-location
    925          (cond ((pcl::definition-source method)
    926                 method)
    927                (t
    928                 (pcl::slot-definition-class
    929                  (pcl::accessor-method-slot-definition method))))
    930          (pcl::accessor-method-slot-name method)))
    931     (t
    932      (function-location (or (pcl::method-fast-function method)
    933                             (pcl:method-function method))))))
    934 
    935 (defun genericp (fn)
    936   (typep fn 'generic-function))
    937 
    938 ;;;;;; Types and classes
    939 
    940 (defun type-definitions (name)
    941   "Return `deftype' locations for type NAME."
    942   (maybe-make-definition (ext:info :type :expander name) 'deftype name))
    943 
    944 (defun maybe-make-definition (function kind name)
    945   "If FUNCTION is non-nil then return its definition location."
    946   (if function
    947       (list (list `(,kind ,name) (function-location function)))))
    948 
    949 (defun class-definitions (name)
    950   "Return the definition locations for the class called NAME."
    951   (if (symbolp name)
    952       (let ((class (kernel::find-class name nil)))
    953         (etypecase class
    954           (null '())
    955           (kernel::structure-class
    956            (list (list `(defstruct ,name) (dd-location (find-dd name)))))
    957           #+(or)
    958           (conditions::condition-class
    959            (list (list `(define-condition ,name)
    960                        (condition-class-location class))))
    961           (kernel::standard-class
    962            (list (list `(defclass ,name)
    963                        (pcl-class-location (find-class name)))))
    964           ((or kernel::built-in-class
    965                conditions::condition-class
    966                kernel:funcallable-structure-class)
    967            (list (list `(class ,name) (class-location class))))))))
    968 
    969 (defun pcl-class-location (class)
    970   "Return the `defclass' location for CLASS."
    971   (definition-source-location class (pcl:class-name class)))
    972 
    973 ;; FIXME: eval used for backward compatibility.
    974 (defun class-location (class)
    975   (declare (type kernel::class class))
    976   (let ((name (kernel:%class-name class)))
    977     (multiple-value-bind (loc found?)
    978         (let ((x (ignore-errors
    979                    (multiple-value-list
    980                     (eval `(ext:info :source-location :class ',name))))))
    981           (values-list x))
    982       (cond (found? (resolve-source-location loc))
    983             (`(:error
    984                ,(format nil "No location recorded for class: ~S" name)))))))
    985 
    986 (defun find-dd (name)
    987   "Find the defstruct-definition by the name of its structure-class."
    988   (let ((layout (ext:info :type :compiler-layout name)))
    989     (if layout
    990         (kernel:layout-info layout))))
    991 
    992 (defun condition-class-location (class)
    993   (let ((slots (conditions::condition-class-slots class))
    994         (name (conditions::condition-class-name class)))
    995     (cond ((null slots)
    996            `(:error ,(format nil "No location info for condition: ~A" name)))
    997           (t
    998            ;; Find the class via one of its slot-reader methods.
    999            (let* ((slot (first slots))
   1000                   (gf (fdefinition
   1001                        (first (conditions::condition-slot-readers slot)))))
   1002              (method-location
   1003               (first
   1004                (pcl:compute-applicable-methods-using-classes
   1005                 gf (list (find-class name))))))))))
   1006 
   1007 (defun make-name-in-file-location (file string)
   1008   (multiple-value-bind (filename c)
   1009       (ignore-errors
   1010         (unix-truename (merge-pathnames (make-pathname :type "lisp")
   1011                                         file)))
   1012     (cond (filename (make-location `(:file ,filename)
   1013                                    `(:function-name ,(string string))))
   1014           (t (list :error (princ-to-string c))))))
   1015 
   1016 (defun source-location-form-numbers (location)
   1017   (c::decode-form-numbers (c::form-numbers-form-numbers location)))
   1018 
   1019 (defun source-location-tlf-number (location)
   1020   (nth-value 0 (source-location-form-numbers location)))
   1021 
   1022 (defun source-location-form-number (location)
   1023   (nth-value 1 (source-location-form-numbers location)))
   1024 
   1025 (defun resolve-file-source-location (location)
   1026   (let ((filename (c::file-source-location-pathname location))
   1027         (tlf-number (source-location-tlf-number location))
   1028         (form-number (source-location-form-number location)))
   1029     (with-open-file (s filename)
   1030       (let ((pos (form-number-stream-position tlf-number form-number s)))
   1031         (make-location `(:file ,(unix-truename filename))
   1032                        `(:position ,(1+ pos)))))))
   1033 
   1034 (defun resolve-stream-source-location (location)
   1035   (let ((info (c::stream-source-location-user-info location))
   1036         (tlf-number (source-location-tlf-number location))
   1037         (form-number (source-location-form-number location)))
   1038     ;; XXX duplication in frame-source-location
   1039     (assert (info-from-emacs-buffer-p info))
   1040     (destructuring-bind (&key emacs-buffer emacs-buffer-string
   1041                               emacs-buffer-offset) info
   1042       (with-input-from-string (s emacs-buffer-string)
   1043         (let ((pos (form-number-stream-position tlf-number form-number s)))
   1044           (make-location `(:buffer ,emacs-buffer)
   1045                          `(:offset ,emacs-buffer-offset ,pos)))))))
   1046 
   1047 ;; XXX predicates for 18e backward compatibilty.  Remove them when
   1048 ;; we're 19a only.
   1049 (defun file-source-location-p (object)
   1050   (when (fboundp 'c::file-source-location-p)
   1051     (c::file-source-location-p object)))
   1052 
   1053 (defun stream-source-location-p (object)
   1054   (when (fboundp 'c::stream-source-location-p)
   1055     (c::stream-source-location-p object)))
   1056 
   1057 (defun source-location-p (object)
   1058   (or (file-source-location-p object)
   1059       (stream-source-location-p object)))
   1060 
   1061 (defun resolve-source-location (location)
   1062   (etypecase location
   1063     ((satisfies file-source-location-p)
   1064      (resolve-file-source-location location))
   1065     ((satisfies stream-source-location-p)
   1066      (resolve-stream-source-location location))))
   1067 
   1068 (defun definition-source-location (object name)
   1069   (let ((source (pcl::definition-source object)))
   1070     (etypecase source
   1071       (null
   1072        `(:error ,(format nil "No source info for: ~A" object)))
   1073       ((satisfies source-location-p)
   1074        (resolve-source-location source))
   1075       (pathname
   1076        (make-name-in-file-location source name))
   1077       (cons
   1078        (destructuring-bind ((dg name) pathname) source
   1079          (declare (ignore dg))
   1080          (etypecase pathname
   1081            (pathname (make-name-in-file-location pathname (string name)))
   1082            (null `(:error ,(format nil "Cannot resolve: ~S" source)))))))))
   1083 
   1084 (defun setf-definitions (name)
   1085   (let ((f (or (ext:info :setf :inverse name)
   1086                (ext:info :setf :expander name)
   1087                (and (symbolp name)
   1088                     (fboundp `(setf ,name))
   1089                     (fdefinition `(setf ,name))))))
   1090     (if f
   1091         `(((setf ,name) ,(function-location (cond ((functionp  f) f)
   1092                                                   ((macro-function f))
   1093                                                   ((fdefinition f)))))))))
   1094 
   1095 (defun variable-location (symbol)
   1096   (multiple-value-bind (location foundp)
   1097       ;; XXX for 18e compatibilty. rewrite this when we drop 18e
   1098       ;; support.
   1099       (ignore-errors (eval `(ext:info :source-location :defvar ',symbol)))
   1100     (if (and foundp location)
   1101         (resolve-source-location location)
   1102         `(:error ,(format nil "No source info for variable ~S" symbol)))))
   1103 
   1104 (defun variable-definitions (name)
   1105   (if (symbolp name)
   1106       (multiple-value-bind (kind recorded-p) (ext:info :variable :kind name)
   1107         (if recorded-p
   1108             (list (list `(variable ,kind ,name)
   1109                         (variable-location name)))))))
   1110 
   1111 (defun compiler-macro-definitions (symbol)
   1112   (maybe-make-definition (compiler-macro-function symbol)
   1113                          'define-compiler-macro
   1114                          symbol))
   1115 
   1116 (defun source-transform-definitions (name)
   1117   (maybe-make-definition (ext:info :function :source-transform name)
   1118                          'c:def-source-transform
   1119                          name))
   1120 
   1121 (defun function-info-definitions (name)
   1122   (let ((info (ext:info :function :info name)))
   1123     (if info
   1124         (append (loop for transform in (c::function-info-transforms info)
   1125                       collect (list `(c:deftransform ,name
   1126                                       ,(c::type-specifier
   1127                                         (c::transform-type transform)))
   1128                                     (function-location (c::transform-function
   1129                                                         transform))))
   1130                 (maybe-make-definition (c::function-info-derive-type info)
   1131                                        'c::derive-type name)
   1132                 (maybe-make-definition (c::function-info-optimizer info)
   1133                                        'c::optimizer name)
   1134                 (maybe-make-definition (c::function-info-ltn-annotate info)
   1135                                        'c::ltn-annotate name)
   1136                 (maybe-make-definition (c::function-info-ir2-convert info)
   1137                                        'c::ir2-convert name)
   1138                 (loop for template in (c::function-info-templates info)
   1139                       collect (list `(,(type-of template)
   1140                                        ,(c::template-name template))
   1141                                     (function-location
   1142                                      (c::vop-info-generator-function
   1143                                       template))))))))
   1144 
   1145 (defun ir1-translator-definitions (name)
   1146   (maybe-make-definition (ext:info :function :ir1-convert name)
   1147                          'c:def-ir1-translator name))
   1148 
   1149 (defun template-definitions (name)
   1150   (let* ((templates (c::backend-template-names c::*backend*))
   1151          (template (gethash name templates)))
   1152     (etypecase template
   1153       (null)
   1154       (c::vop-info
   1155        (maybe-make-definition (c::vop-info-generator-function template)
   1156                               (type-of template) name)))))
   1157 
   1158 ;; for cases like: (%primitive NAME ...)
   1159 (defun primitive-definitions (name)
   1160   (let ((csym (find-symbol (string name) 'c)))
   1161     (and csym
   1162          (not (eq csym name))
   1163          (template-definitions csym))))
   1164 
   1165 (defun vm-support-routine-definitions (name)
   1166   (let ((sr (c::backend-support-routines c::*backend*))
   1167         (name (find-symbol (string name) 'c)))
   1168     (and name
   1169          (slot-exists-p sr name)
   1170          (maybe-make-definition (slot-value sr name)
   1171                                 (find-symbol (string 'vm-support-routine) 'c)
   1172                                 name))))
   1173 
   1174 
   1175 ;;;; Documentation.
   1176 
   1177 (defimplementation describe-symbol-for-emacs (symbol)
   1178   (let ((result '()))
   1179     (flet ((doc (kind)
   1180              (or (documentation symbol kind) :not-documented))
   1181            (maybe-push (property value)
   1182              (when value
   1183                (setf result (list* property value result)))))
   1184       (maybe-push
   1185        :variable (multiple-value-bind (kind recorded-p)
   1186                      (ext:info variable kind symbol)
   1187                    (declare (ignore kind))
   1188                    (if (or (boundp symbol) recorded-p)
   1189                        (doc 'variable))))
   1190       (when (fboundp symbol)
   1191 	(maybe-push
   1192          (cond ((macro-function symbol)     :macro)
   1193                ((special-operator-p symbol) :special-operator)
   1194                ((genericp (fdefinition symbol)) :generic-function)
   1195                (t :function))
   1196          (doc 'function)))
   1197       (maybe-push
   1198        :setf (if (or (ext:info setf inverse symbol)
   1199                      (ext:info setf expander symbol))
   1200                  (doc 'setf)))
   1201       (maybe-push
   1202        :type (if (ext:info type kind symbol)
   1203                  (doc 'type)))
   1204       (maybe-push
   1205        :class (if (find-class symbol nil)
   1206                   (doc 'class)))
   1207       (maybe-push
   1208        :alien-type (if (not (eq (ext:info alien-type kind symbol) :unknown))
   1209                        (doc 'alien-type)))
   1210       (maybe-push
   1211        :alien-struct (if (ext:info alien-type struct symbol)
   1212                          (doc nil)))
   1213       (maybe-push
   1214        :alien-union (if (ext:info alien-type union symbol)
   1215                          (doc nil)))
   1216       (maybe-push
   1217        :alien-enum (if (ext:info alien-type enum symbol)
   1218                        (doc nil)))
   1219       result)))
   1220 
   1221 (defimplementation describe-definition (symbol namespace)
   1222   (describe (ecase namespace
   1223               (:variable
   1224                symbol)
   1225               ((:function :generic-function)
   1226                (symbol-function symbol))
   1227               (:setf
   1228                (or (ext:info setf inverse symbol)
   1229                    (ext:info setf expander symbol)))
   1230               (:type
   1231                (kernel:values-specifier-type symbol))
   1232               (:class
   1233                (find-class symbol))
   1234               (:alien-struct
   1235                (ext:info :alien-type :struct symbol))
   1236               (:alien-union
   1237                (ext:info :alien-type :union symbol))
   1238               (:alien-enum
   1239                (ext:info :alien-type :enum symbol))
   1240               (:alien-type
   1241                (ecase (ext:info :alien-type :kind symbol)
   1242                  (:primitive
   1243                   (let ((alien::*values-type-okay* t))
   1244                     (funcall (ext:info :alien-type :translator symbol)
   1245                              (list symbol))))
   1246                  ((:defined)
   1247                   (ext:info :alien-type :definition symbol))
   1248                  (:unknown :unkown))))))
   1249 
   1250 ;;;;; Argument lists
   1251 
   1252 (defimplementation arglist (fun)
   1253   (etypecase fun
   1254     (function (function-arglist fun))
   1255     (symbol (function-arglist (or (macro-function fun)
   1256                                   (symbol-function fun))))))
   1257 
   1258 (defun function-arglist (fun)
   1259   (let ((arglist
   1260          (cond ((eval:interpreted-function-p fun)
   1261                 (eval:interpreted-function-arglist fun))
   1262                ((pcl::generic-function-p fun)
   1263                 (pcl:generic-function-lambda-list fun))
   1264                ((c::byte-function-or-closure-p fun)
   1265                 (byte-code-function-arglist fun))
   1266                ((kernel:%function-arglist (kernel:%function-self fun))
   1267                 (handler-case (read-arglist fun)
   1268                   (error () :not-available)))
   1269                ;; this should work both for compiled-debug-function
   1270                ;; and for interpreted-debug-function
   1271                (t
   1272                 (handler-case (debug-function-arglist
   1273                                (di::function-debug-function fun))
   1274                   (di:unhandled-condition () :not-available))))))
   1275     (check-type arglist (or list (member :not-available)))
   1276     arglist))
   1277 
   1278 (defimplementation function-name (function)
   1279   (cond ((eval:interpreted-function-p function)
   1280          (eval:interpreted-function-name function))
   1281         ((pcl::generic-function-p function)
   1282          (pcl::generic-function-name function))
   1283         ((c::byte-function-or-closure-p function)
   1284          (c::byte-function-name function))
   1285         (t (kernel:%function-name (kernel:%function-self function)))))
   1286 
   1287 ;;; A simple case: the arglist is available as a string that we can
   1288 ;;; `read'.
   1289 
   1290 (defun read-arglist (fn)
   1291   "Parse the arglist-string of the function object FN."
   1292   (let ((string (kernel:%function-arglist
   1293                  (kernel:%function-self fn)))
   1294         (package (find-package
   1295                   (c::compiled-debug-info-package
   1296                    (kernel:%code-debug-info
   1297                     (vm::find-code-object fn))))))
   1298     (with-standard-io-syntax
   1299       (let ((*package* (or package *package*)))
   1300         (read-from-string string)))))
   1301 
   1302 ;;; A harder case: an approximate arglist is derived from available
   1303 ;;; debugging information.
   1304 
   1305 (defun debug-function-arglist (debug-function)
   1306   "Derive the argument list of DEBUG-FUNCTION from debug info."
   1307   (let ((args (di::debug-function-lambda-list debug-function))
   1308         (required '())
   1309         (optional '())
   1310         (rest '())
   1311         (key '()))
   1312     ;; collect the names of debug-vars
   1313     (dolist (arg args)
   1314       (etypecase arg
   1315         (di::debug-variable
   1316          (push (di::debug-variable-symbol arg) required))
   1317         ((member :deleted)
   1318          (push ':deleted required))
   1319         (cons
   1320          (ecase (car arg)
   1321            (:keyword
   1322             (push (second arg) key))
   1323            (:optional
   1324             (push (debug-variable-symbol-or-deleted (second arg)) optional))
   1325            (:rest
   1326             (push (debug-variable-symbol-or-deleted (second arg)) rest))))))
   1327     ;; intersperse lambda keywords as needed
   1328     (append (nreverse required)
   1329             (if optional (cons '&optional (nreverse optional)))
   1330             (if rest (cons '&rest (nreverse rest)))
   1331             (if key (cons '&key (nreverse key))))))
   1332 
   1333 (defun debug-variable-symbol-or-deleted (var)
   1334   (etypecase var
   1335     (di:debug-variable
   1336      (di::debug-variable-symbol var))
   1337     ((member :deleted)
   1338      '#:deleted)))
   1339 
   1340 (defun symbol-debug-function-arglist (fname)
   1341   "Return FNAME's debug-function-arglist and %function-arglist.
   1342 A utility for debugging DEBUG-FUNCTION-ARGLIST."
   1343   (let ((fn (fdefinition fname)))
   1344     (values (debug-function-arglist (di::function-debug-function fn))
   1345             (kernel:%function-arglist (kernel:%function-self fn)))))
   1346 
   1347 ;;; Deriving arglists for byte-compiled functions:
   1348 ;;;
   1349 (defun byte-code-function-arglist (fn)
   1350   ;; There doesn't seem to be much arglist information around for
   1351   ;; byte-code functions.  Use the arg-count and return something like
   1352   ;; (arg0 arg1 ...)
   1353   (etypecase fn
   1354     (c::simple-byte-function
   1355      (loop for i from 0 below (c::simple-byte-function-num-args fn)
   1356            collect (make-arg-symbol i)))
   1357     (c::hairy-byte-function
   1358      (hairy-byte-function-arglist fn))
   1359     (c::byte-closure
   1360      (byte-code-function-arglist (c::byte-closure-function fn)))))
   1361 
   1362 (defun make-arg-symbol (i)
   1363   (make-symbol (format nil "~A~D" (string 'arg) i)))
   1364 
   1365 ;;; A "hairy" byte-function is one that takes a variable number of
   1366 ;;; arguments. `hairy-byte-function' is a type from the bytecode
   1367 ;;; interpreter.
   1368 ;;;
   1369 (defun hairy-byte-function-arglist (fn)
   1370   (let ((counter -1))
   1371     (flet ((next-arg () (make-arg-symbol (incf counter))))
   1372       (with-struct (c::hairy-byte-function- min-args max-args rest-arg-p
   1373                                             keywords-p keywords) fn
   1374         (let ((arglist '())
   1375               (optional (- max-args min-args)))
   1376           ;; XXX isn't there a better way to write this?
   1377           ;; (Looks fine to me. -luke)
   1378           (dotimes (i min-args)
   1379             (push (next-arg) arglist))
   1380           (when (plusp optional)
   1381             (push '&optional arglist)
   1382             (dotimes (i optional)
   1383               (push (next-arg) arglist)))
   1384           (when rest-arg-p
   1385             (push '&rest arglist)
   1386             (push (next-arg) arglist))
   1387           (when keywords-p
   1388             (push '&key arglist)
   1389             (loop for (key _ __) in keywords
   1390                   do (push key arglist))
   1391             (when (eq keywords-p :allow-others)
   1392               (push '&allow-other-keys arglist)))
   1393           (nreverse arglist))))))
   1394 
   1395 
   1396 ;;;; Miscellaneous.
   1397 
   1398 (defimplementation macroexpand-all (form &optional env)
   1399   (walker:macroexpand-all form env))
   1400 
   1401 (defimplementation compiler-macroexpand-1 (form &optional env)
   1402   (ext:compiler-macroexpand-1 form env))
   1403 
   1404 (defimplementation compiler-macroexpand (form &optional env)
   1405   (ext:compiler-macroexpand form env))
   1406 
   1407 (defimplementation set-default-directory (directory)
   1408   (setf (ext:default-directory) (namestring directory))
   1409   ;; Setting *default-pathname-defaults* to an absolute directory
   1410   ;; makes the behavior of MERGE-PATHNAMES a bit more intuitive.
   1411   (setf *default-pathname-defaults* (pathname (ext:default-directory)))
   1412   (default-directory))
   1413 
   1414 (defimplementation default-directory ()
   1415   (namestring (ext:default-directory)))
   1416 
   1417 (defimplementation getpid ()
   1418   (unix:unix-getpid))
   1419 
   1420 (defimplementation lisp-implementation-type-name ()
   1421   "cmucl")
   1422 
   1423 (defimplementation quit-lisp ()
   1424   (ext::quit))
   1425 
   1426 ;;; source-path-{stream,file,string,etc}-position moved into 
   1427 ;;; slynk-source-path-parser
   1428 
   1429 
   1430 ;;;; Debugging
   1431 
   1432 (defvar *sly-db-stack-top*)
   1433 
   1434 (defimplementation call-with-debugging-environment (debugger-loop-fn)
   1435   (unix:unix-sigsetmask 0)
   1436   (let* ((*sly-db-stack-top* (or debug:*stack-top-hint* (di:top-frame)))
   1437 	 (debug:*stack-top-hint* nil)
   1438          (kernel:*current-level* 0))
   1439     (handler-bind ((di::unhandled-condition
   1440 		    (lambda (condition)
   1441                       (error 'sly-db-condition
   1442                              :original-condition condition))))
   1443       (unwind-protect
   1444            (progn
   1445              #+(or)(sys:scrub-control-stack)
   1446              (funcall debugger-loop-fn))
   1447         #+(or)(sys:scrub-control-stack)
   1448         ))))
   1449 
   1450 (defun frame-down (frame)
   1451   (handler-case (di:frame-down frame)
   1452     (di:no-debug-info () nil)))
   1453 
   1454 (defun nth-frame (index)
   1455   (do ((frame *sly-db-stack-top* (frame-down frame))
   1456        (i index (1- i)))
   1457       ((zerop i) frame)))
   1458 
   1459 (defimplementation compute-backtrace (start end)
   1460   (let ((end (or end most-positive-fixnum)))
   1461     (loop for f = (nth-frame start) then (frame-down f)
   1462           for i from start below end
   1463           while f collect f)))
   1464 
   1465 (defimplementation print-frame (frame stream)
   1466   (let ((*standard-output* stream))
   1467     (handler-case
   1468         (debug::print-frame-call frame :verbosity 1 :number nil)
   1469       (error (e)
   1470         (ignore-errors (princ e stream))))))
   1471 
   1472 (defimplementation frame-source-location (index)
   1473   (let ((frame (nth-frame index)))
   1474     (cond ((foreign-frame-p frame) (foreign-frame-source-location frame))
   1475           ((code-location-source-location (di:frame-code-location frame))))))
   1476 
   1477 (defimplementation eval-in-frame (form index)
   1478   (di:eval-in-frame (nth-frame index) form))
   1479 
   1480 (defun frame-debug-vars (frame)
   1481   "Return a vector of debug-variables in frame."
   1482   (let ((loc (di:frame-code-location frame)))
   1483     (remove-if
   1484      (lambda (v)
   1485        (not (eq (di:debug-variable-validity v loc) :valid)))
   1486      (di::debug-function-debug-variables (di:frame-debug-function frame)))))
   1487 
   1488 (defun debug-var-value (var frame)
   1489   (let* ((loc (di:frame-code-location frame))
   1490          (validity (di:debug-variable-validity var loc)))
   1491     (ecase validity
   1492       (:valid (di:debug-variable-value var frame))
   1493       ((:invalid :unknown) (make-symbol (string validity))))))
   1494 
   1495 (defimplementation frame-locals (index)
   1496   (let ((frame (nth-frame index)))
   1497     (loop for v across (frame-debug-vars frame)
   1498           collect (list :name (di:debug-variable-symbol v)
   1499                         :id (di:debug-variable-id v)
   1500                         :value (debug-var-value v frame)))))
   1501 
   1502 (defimplementation frame-var-value (frame var)
   1503   (let* ((frame (nth-frame frame))
   1504          (dvar (aref (frame-debug-vars frame) var)))
   1505     (debug-var-value dvar frame)))
   1506 
   1507 (defimplementation frame-catch-tags (index)
   1508   (mapcar #'car (di:frame-catches (nth-frame index))))
   1509 
   1510 (defimplementation frame-package (frame-number)
   1511   (let* ((frame (nth-frame frame-number))
   1512          (dbg-fun (di:frame-debug-function frame)))
   1513     (typecase dbg-fun
   1514       (di::compiled-debug-function
   1515        (let* ((comp (di::compiled-debug-function-component dbg-fun))
   1516               (dbg-info (kernel:%code-debug-info comp)))
   1517          (typecase dbg-info
   1518            (c::compiled-debug-info
   1519             (find-package (c::compiled-debug-info-package dbg-info)))))))))
   1520 
   1521 (defimplementation return-from-frame (index form)
   1522   (let ((sym (find-symbol (string 'find-debug-tag-for-frame)
   1523                           :debug-internals)))
   1524     (if sym
   1525         (let* ((frame (nth-frame index))
   1526                (probe (funcall sym frame)))
   1527           (cond (probe (throw (car probe) (eval-in-frame form index)))
   1528                 (t (format nil "Cannot return from frame: ~S" frame))))
   1529         "return-from-frame is not implemented in this version of CMUCL.")))
   1530 
   1531 (defimplementation activate-stepping (frame)
   1532   (set-step-breakpoints (nth-frame frame)))
   1533 
   1534 (defimplementation sly-db-break-on-return (frame)
   1535   (break-on-return (nth-frame frame)))
   1536 
   1537 ;;; We set the breakpoint in the caller which might be a bit confusing.
   1538 ;;;
   1539 (defun break-on-return (frame)
   1540   (let* ((caller (di:frame-down frame))
   1541          (cl (di:frame-code-location caller)))
   1542     (flet ((hook (frame bp)
   1543              (when (frame-pointer= frame caller)
   1544                (di:delete-breakpoint bp)
   1545                (signal-breakpoint bp frame))))
   1546       (let* ((info (ecase (di:code-location-kind cl)
   1547                      ((:single-value-return :unknown-return) nil)
   1548                      (:known-return (debug-function-returns
   1549                                      (di:frame-debug-function frame)))))
   1550              (bp (di:make-breakpoint #'hook cl :kind :code-location
   1551                                      :info info)))
   1552         (di:activate-breakpoint bp)
   1553         `(:ok ,(format nil "Set breakpoint in ~A" caller))))))
   1554 
   1555 (defun frame-pointer= (frame1 frame2)
   1556   "Return true if the frame pointers of FRAME1 and FRAME2 are the same."
   1557   (sys:sap= (di::frame-pointer frame1) (di::frame-pointer frame2)))
   1558 
   1559 ;;; The PC in escaped frames at a single-return-value point is
   1560 ;;; actually vm:single-value-return-byte-offset bytes after the
   1561 ;;; position given in the debug info.  Here we try to recognize such
   1562 ;;; cases.
   1563 ;;;
   1564 (defun next-code-locations (frame code-location)
   1565   "Like `debug::next-code-locations' but be careful in escaped frames."
   1566   (let ((next (debug::next-code-locations code-location)))
   1567     (flet ((adjust-pc ()
   1568              (let ((cl (di::copy-compiled-code-location code-location)))
   1569                (incf (di::compiled-code-location-pc cl)
   1570                      vm:single-value-return-byte-offset)
   1571                cl)))
   1572       (cond ((and (di::compiled-frame-escaped frame)
   1573                   (eq (di:code-location-kind code-location)
   1574                       :single-value-return)
   1575                   (= (length next) 1)
   1576                   (di:code-location= (car next) (adjust-pc)))
   1577              (debug::next-code-locations (car next)))
   1578             (t
   1579              next)))))
   1580 
   1581 (defun set-step-breakpoints (frame)
   1582   (let ((cl (di:frame-code-location frame)))
   1583     (when (di:debug-block-elsewhere-p (di:code-location-debug-block cl))
   1584       (error "Cannot step in elsewhere code"))
   1585     (let* ((debug::*bad-code-location-types*
   1586             (remove :call-site debug::*bad-code-location-types*))
   1587            (next (next-code-locations frame cl)))
   1588       (cond (next
   1589              (let ((steppoints '()))
   1590                (flet ((hook (bp-frame bp)
   1591                         (signal-breakpoint bp bp-frame)
   1592                         (mapc #'di:delete-breakpoint steppoints)))
   1593                  (dolist (code-location next)
   1594                    (let ((bp (di:make-breakpoint #'hook code-location
   1595                                                  :kind :code-location)))
   1596                      (di:activate-breakpoint bp)
   1597                      (push bp steppoints))))))
   1598             (t
   1599              (break-on-return frame))))))
   1600 
   1601 
   1602 ;; XXX the return values at return breakpoints should be passed to the
   1603 ;; user hooks. debug-int.lisp should be changed to do this cleanly.
   1604 
   1605 ;;; The sigcontext and the PC for a breakpoint invocation are not
   1606 ;;; passed to user hook functions, but we need them to extract return
   1607 ;;; values. So we advice di::handle-breakpoint and bind the values to
   1608 ;;; special variables.
   1609 ;;;
   1610 (defvar *breakpoint-sigcontext*)
   1611 (defvar *breakpoint-pc*)
   1612 
   1613 (define-fwrapper bind-breakpoint-sigcontext (offset c sigcontext)
   1614   (let ((*breakpoint-sigcontext* sigcontext)
   1615         (*breakpoint-pc* offset))
   1616     (call-next-function)))
   1617 (set-fwrappers 'di::handle-breakpoint '())
   1618 (fwrap 'di::handle-breakpoint #'bind-breakpoint-sigcontext)
   1619 
   1620 (defun sigcontext-object (sc index)
   1621   "Extract the lisp object in sigcontext SC at offset INDEX."
   1622   (kernel:make-lisp-obj (vm:sigcontext-register sc index)))
   1623 
   1624 (defun known-return-point-values (sigcontext sc-offsets)
   1625   (let ((fp (system:int-sap (vm:sigcontext-register sigcontext
   1626                                                     vm::cfp-offset))))
   1627     (system:without-gcing
   1628      (loop for sc-offset across sc-offsets
   1629            collect (di::sub-access-debug-var-slot fp sc-offset sigcontext)))))
   1630 
   1631 ;;; CMUCL returns the first few values in registers and the rest on
   1632 ;;; the stack. In the multiple value case, the number of values is
   1633 ;;; stored in a dedicated register. The values of the registers can be
   1634 ;;; accessed in the sigcontext for the breakpoint.  There are 3 kinds
   1635 ;;; of return conventions: :single-value-return, :unknown-return, and
   1636 ;;; :known-return.
   1637 ;;;
   1638 ;;; The :single-value-return convention returns the value in a
   1639 ;;; register without setting the nargs registers.
   1640 ;;;
   1641 ;;; The :unknown-return variant is used for multiple values. A
   1642 ;;; :unknown-return point consists actually of 2 breakpoints: one for
   1643 ;;; the single value case and one for the general case.  The single
   1644 ;;; value breakpoint comes vm:single-value-return-byte-offset after
   1645 ;;; the multiple value breakpoint.
   1646 ;;;
   1647 ;;; The :known-return convention is used by local functions.
   1648 ;;; :known-return is currently not supported because we don't know
   1649 ;;; where the values are passed.
   1650 ;;;
   1651 (defun breakpoint-values (breakpoint)
   1652   "Return the list of return values for a return point."
   1653   (flet ((1st (sc) (sigcontext-object sc (car vm::register-arg-offsets))))
   1654     (let ((sc (locally (declare (optimize (speed 0)))
   1655                 (alien:sap-alien *breakpoint-sigcontext* (* unix:sigcontext))))
   1656           (cl (di:breakpoint-what breakpoint)))
   1657       (ecase (di:code-location-kind cl)
   1658         (:single-value-return
   1659          (list (1st sc)))
   1660         (:known-return
   1661          (let ((info (di:breakpoint-info breakpoint)))
   1662            (if (vectorp info)
   1663                (known-return-point-values sc info)
   1664                (progn
   1665                  ;;(break)
   1666                  (list "<<known-return convention not supported>>" info)))))
   1667         (:unknown-return
   1668          (let ((mv-return-pc (di::compiled-code-location-pc cl)))
   1669            (if (= mv-return-pc *breakpoint-pc*)
   1670                (mv-function-end-breakpoint-values sc)
   1671                (list (1st sc)))))))))
   1672 
   1673 ;; XXX: di::get-function-end-breakpoint-values takes 2 arguments in
   1674 ;; newer versions of CMUCL (after ~March 2005).
   1675 (defun mv-function-end-breakpoint-values (sigcontext)
   1676   (let ((sym (find-symbol "FUNCTION-END-BREAKPOINT-VALUES/STANDARD" :di)))
   1677     (cond (sym (funcall sym sigcontext))
   1678           (t (funcall 'di::get-function-end-breakpoint-values sigcontext)))))
   1679 
   1680 (defun debug-function-returns (debug-fun)
   1681   "Return the return style of DEBUG-FUN."
   1682   (let* ((cdfun (di::compiled-debug-function-compiler-debug-fun debug-fun)))
   1683     (c::compiled-debug-function-returns cdfun)))
   1684 
   1685 (define-condition breakpoint (simple-condition)
   1686   ((message :initarg :message :reader breakpoint.message)
   1687    (values  :initarg :values  :reader breakpoint.values))
   1688   (:report (lambda (c stream) (princ (breakpoint.message c) stream))))
   1689 
   1690 (defimplementation condition-extras (condition)
   1691   (typecase condition
   1692     (breakpoint
   1693      ;; pop up the source buffer
   1694      `((:show-frame-source 0)))
   1695     (t '())))
   1696 
   1697 (defun signal-breakpoint (breakpoint frame)
   1698   "Signal a breakpoint condition for BREAKPOINT in FRAME.
   1699 Try to create a informative message."
   1700   (flet ((brk (values fstring &rest args)
   1701            (let ((msg (apply #'format nil fstring args))
   1702                  (debug:*stack-top-hint* frame))
   1703              (break 'breakpoint :message msg :values values))))
   1704     (with-struct (di::breakpoint- kind what) breakpoint
   1705       (case kind
   1706         (:code-location
   1707          (case (di:code-location-kind what)
   1708            ((:single-value-return :known-return :unknown-return)
   1709             (let ((values (breakpoint-values breakpoint)))
   1710               (brk values "Return value: ~{~S ~}" values)))
   1711            (t
   1712             #+(or)
   1713             (when (eq (di:code-location-kind what) :call-site)
   1714               (call-site-function breakpoint frame))
   1715             (brk nil "Breakpoint: ~S ~S"
   1716                  (di:code-location-kind what)
   1717                  (di::compiled-code-location-pc what)))))
   1718         (:function-start
   1719          (brk nil "Function start breakpoint"))
   1720         (t (brk nil "Breakpoint: ~A in ~A" breakpoint frame))))))
   1721 
   1722 (defimplementation sly-db-break-at-start (fname)
   1723   (let ((debug-fun (di:function-debug-function (coerce fname 'function))))
   1724     (cond ((not debug-fun)
   1725            `(:error ,(format nil "~S has no debug-function" fname)))
   1726           (t
   1727            (flet ((hook (frame bp &optional args cookie)
   1728                     (declare (ignore args cookie))
   1729                     (signal-breakpoint bp frame)))
   1730              (let ((bp (di:make-breakpoint #'hook debug-fun
   1731                                            :kind :function-start)))
   1732                (di:activate-breakpoint bp)
   1733                `(:ok ,(format nil "Set breakpoint in ~S" fname))))))))
   1734 
   1735 (defun frame-cfp (frame)
   1736   "Return the Control-Stack-Frame-Pointer for FRAME."
   1737   (etypecase frame
   1738     (di::compiled-frame (di::frame-pointer frame))
   1739     ((or di::interpreted-frame null) -1)))
   1740 
   1741 (defun frame-ip (frame)
   1742   "Return the (absolute) instruction pointer and the relative pc of FRAME."
   1743   (if (not frame)
   1744       -1
   1745       (let ((debug-fun (di::frame-debug-function frame)))
   1746         (etypecase debug-fun
   1747           (di::compiled-debug-function
   1748            (let* ((code-loc (di:frame-code-location frame))
   1749                   (component (di::compiled-debug-function-component debug-fun))
   1750                   (pc (di::compiled-code-location-pc code-loc))
   1751                   (ip (sys:without-gcing
   1752                        (sys:sap-int
   1753                         (sys:sap+ (kernel:code-instructions component) pc)))))
   1754              (values ip pc)))
   1755           (di::interpreted-debug-function -1)
   1756           (di::bogus-debug-function
   1757            #-x86
   1758            (let* ((real (di::frame-real-frame (di::frame-up frame)))
   1759                   (fp (di::frame-pointer real)))
   1760              ;;#+(or)
   1761              (progn
   1762                (format *debug-io* "Frame-real-frame = ~S~%" real)
   1763                (format *debug-io* "fp = ~S~%" fp)
   1764                (format *debug-io* "lra = ~S~%"
   1765                        (kernel:stack-ref fp vm::lra-save-offset)))
   1766              (values
   1767               (sys:int-sap
   1768                (- (kernel:get-lisp-obj-address
   1769                    (kernel:stack-ref fp vm::lra-save-offset))
   1770                   (- (ash vm:function-code-offset vm:word-shift)
   1771                      vm:function-pointer-type)))
   1772               0))
   1773            #+x86
   1774            (let ((fp (di::frame-pointer (di:frame-up frame))))
   1775              (multiple-value-bind (ra ofp) (di::x86-call-context fp)
   1776                (declare (ignore ofp))
   1777                (values ra 0))))))))
   1778 
   1779 (defun frame-registers (frame)
   1780   "Return the lisp registers CSP, CFP, IP, OCFP, LRA for FRAME-NUMBER."
   1781   (let* ((cfp (frame-cfp frame))
   1782          (csp (frame-cfp (di::frame-up frame)))
   1783          (ip (frame-ip frame))
   1784          (ocfp (frame-cfp (di::frame-down frame)))
   1785          (lra (frame-ip (di::frame-down frame))))
   1786     (values csp cfp ip ocfp lra)))
   1787 
   1788 (defun print-frame-registers (frame-number)
   1789   (let ((frame (di::frame-real-frame (nth-frame frame-number))))
   1790     (flet ((fixnum (p) (etypecase p
   1791                          (integer p)
   1792                          (sys:system-area-pointer (sys:sap-int p)))))
   1793       (apply #'format t "~
   1794 ~8X  Stack Pointer
   1795 ~8X  Frame Pointer
   1796 ~8X  Instruction Pointer
   1797 ~8X  Saved Frame Pointer
   1798 ~8X  Saved Instruction Pointer~%" (mapcar #'fixnum
   1799                       (multiple-value-list (frame-registers frame)))))))
   1800 
   1801 (defvar *gdb-program-name*
   1802   (ext:enumerate-search-list (p "path:gdb")
   1803     (when (probe-file p)
   1804       (return p))))
   1805 
   1806 (defimplementation disassemble-frame (frame-number)
   1807   (print-frame-registers frame-number)
   1808   (terpri)
   1809   (let* ((frame (di::frame-real-frame (nth-frame frame-number)))
   1810          (debug-fun (di::frame-debug-function frame)))
   1811     (etypecase debug-fun
   1812       (di::compiled-debug-function
   1813        (let* ((component (di::compiled-debug-function-component debug-fun))
   1814               (fun (di:debug-function-function debug-fun)))
   1815          (if fun
   1816              (disassemble fun)
   1817              (disassem:disassemble-code-component component))))
   1818       (di::bogus-debug-function
   1819        (cond ((probe-file *gdb-program-name*)
   1820               (let ((ip (sys:sap-int (frame-ip frame))))
   1821                 (princ (gdb-command "disas 0x~x" ip))))
   1822              (t
   1823               (format t "~%[Disassembling bogus frames not implemented]")))))))
   1824 
   1825 (defmacro with-temporary-file ((stream filename) &body body)
   1826   `(call/temporary-file (lambda (,stream ,filename) . ,body)))
   1827 
   1828 (defun call/temporary-file (fun)
   1829   (let ((name (system::pick-temporary-file-name)))
   1830     (unwind-protect
   1831          (with-open-file (stream name :direction :output :if-exists :supersede)
   1832            (funcall fun stream name))
   1833       (delete-file name))))
   1834 
   1835 (defun gdb-command (format-string &rest args)
   1836   (let ((str (gdb-exec (format nil
   1837                                "interpreter-exec mi2 \"attach ~d\"~%~
   1838                                 interpreter-exec console ~s~%detach"
   1839                                (getpid)
   1840                                (apply #'format nil format-string args))))
   1841         (prompt (format nil
   1842                         #-(and darwin x86) "~%^done~%(gdb) ~%"
   1843                         #+(and darwin x86)
   1844 "~%^done,thread-id=\"1\"~%(gdb) ~%")))
   1845     (subseq str (+ (or (search prompt str) 0) (length prompt)))))
   1846 
   1847 (defun gdb-exec (cmd)
   1848   (with-temporary-file (file filename)
   1849     (write-string cmd file)
   1850     (force-output file)
   1851     (let* ((output (make-string-output-stream))
   1852            ;; gdb on sparc needs to know the executable to find the
   1853            ;; symbols.  Without this, gdb can't disassemble anything.
   1854            ;; NOTE: We assume that the first entry in
   1855            ;; lisp::*cmucl-lib* is the bin directory where lisp is
   1856            ;; located.  If this is not true, we'll have to do
   1857            ;; something better to find the lisp executable.
   1858            (lisp-path
   1859             #+sparc
   1860              (list
   1861               (namestring
   1862                (probe-file
   1863                 (merge-pathnames "lisp" (car (lisp::parse-unix-search-path
   1864                                               lisp::*cmucl-lib*))))))
   1865              #-sparc
   1866              nil)
   1867            (proc (ext:run-program *gdb-program-name*
   1868                                   `(,@lisp-path "-batch" "-x" ,filename)
   1869                                   :wait t
   1870                                   :output output)))
   1871       (assert (eq (ext:process-status proc) :exited))
   1872       (assert (eq (ext:process-exit-code proc) 0))
   1873       (get-output-stream-string output))))
   1874 
   1875 (defun foreign-frame-p (frame)
   1876   #-x86
   1877   (let ((ip (frame-ip frame)))
   1878     (and (sys:system-area-pointer-p ip)
   1879          (typep (di::frame-debug-function frame) 'di::bogus-debug-function)))
   1880   #+x86
   1881   (let ((ip (frame-ip frame)))
   1882     (and (sys:system-area-pointer-p ip)
   1883          (multiple-value-bind (pc code)
   1884              (di::compute-lra-data-from-pc ip)
   1885            (declare (ignore pc))
   1886            (not code)))))
   1887 
   1888 (defun foreign-frame-source-location (frame)
   1889   (let ((ip (sys:sap-int (frame-ip frame))))
   1890     (cond ((probe-file *gdb-program-name*)
   1891            (parse-gdb-line-info (gdb-command "info line *0x~x" ip)))
   1892           (t `(:error "no srcloc available for ~a" frame)))))
   1893 
   1894 ;; The output of gdb looks like:
   1895 ;; Line 215 of "../../src/lisp/x86-assem.S"
   1896 ;;    starts at address 0x805318c <Ldone+11>
   1897 ;;    and ends at 0x805318e <Ldone+13>.
   1898 ;; The ../../ are fixed up with the "target:" search list which might
   1899 ;; be wrong sometimes.
   1900 (defun parse-gdb-line-info (string)
   1901   (with-input-from-string (*standard-input* string)
   1902     (let ((w1 (read-word)))
   1903       (cond ((equal w1 "Line")
   1904              (let ((line (read-word)))
   1905                (assert (equal (read-word) "of"))
   1906                (let* ((file (read-from-string (read-word)))
   1907                       (pathname
   1908                        (or (probe-file file)
   1909                            (probe-file (format nil "target:lisp/~a" file))
   1910                            file)))
   1911                  (make-location (list :file (unix-truename pathname))
   1912                                 (list :line (parse-integer line))))))
   1913             (t
   1914              `(:error ,string))))))
   1915 
   1916 (defun read-word (&optional (stream *standard-input*))
   1917   (peek-char t stream)
   1918   (concatenate 'string (loop until (whitespacep (peek-char nil stream))
   1919                              collect (read-char stream))))
   1920 
   1921 (defun whitespacep (char)
   1922   (member char '(#\space #\newline)))
   1923 
   1924 
   1925 ;;;; Inspecting
   1926 
   1927 (defconstant +lowtag-symbols+
   1928   '(vm:even-fixnum-type
   1929     vm:function-pointer-type
   1930     vm:other-immediate-0-type
   1931     vm:list-pointer-type
   1932     vm:odd-fixnum-type
   1933     vm:instance-pointer-type
   1934     vm:other-immediate-1-type
   1935     vm:other-pointer-type)
   1936   "Names of the constants that specify type tags.
   1937 The `symbol-value' of each element is a type tag.")
   1938 
   1939 (defconstant +header-type-symbols+
   1940   (labels ((suffixp (suffix string)
   1941              (and (>= (length string) (length suffix))
   1942                   (string= string suffix :start1 (- (length string)
   1943                                                     (length suffix)))))
   1944            (header-type-symbol-p (x)
   1945              (and (suffixp "-TYPE" (symbol-name x))
   1946                   (not (member x +lowtag-symbols+))
   1947                   (boundp x)
   1948                   (typep (symbol-value x) 'fixnum))))
   1949     (remove-if-not #'header-type-symbol-p
   1950                    (append (apropos-list "-TYPE" "VM")
   1951                            (apropos-list "-TYPE" "BIGNUM"))))
   1952   "A list of names of the type codes in boxed objects.")
   1953 
   1954 (defimplementation describe-primitive-type (object)
   1955   (with-output-to-string (*standard-output*)
   1956     (let* ((lowtag (kernel:get-lowtag object))
   1957            (lowtag-symbol (find lowtag +lowtag-symbols+ :key #'symbol-value)))
   1958       (format t "lowtag: ~A" lowtag-symbol)
   1959       (when (member lowtag (list vm:other-pointer-type
   1960                                  vm:function-pointer-type
   1961                                  vm:other-immediate-0-type
   1962                                  vm:other-immediate-1-type
   1963                                  ))
   1964         (let* ((type (kernel:get-type object))
   1965                (type-symbol (find type +header-type-symbols+
   1966                                   :key #'symbol-value)))
   1967           (format t ", type: ~A" type-symbol))))))
   1968 
   1969 (defmethod emacs-inspect ((o t))
   1970   (cond ((di::indirect-value-cell-p o)
   1971          `("Value: " (:value ,(c:value-cell-ref o))))
   1972         ((alien::alien-value-p o)
   1973          (inspect-alien-value o))
   1974 	(t
   1975          (cmucl-inspect o))))
   1976 
   1977 (defun cmucl-inspect (o)
   1978   (destructuring-bind (text labeledp . parts) (inspect::describe-parts o)
   1979     (list* (format nil "~A~%" text)
   1980            (if labeledp
   1981                (loop for (label . value) in parts
   1982                      append (label-value-line label value))
   1983                (loop for value in parts  for i from 0
   1984                      append (label-value-line i value))))))
   1985 
   1986 (defmethod emacs-inspect ((o function))
   1987   (let ((header (kernel:get-type o)))
   1988     (cond ((= header vm:function-header-type)
   1989            (append (label-value-line*
   1990                     ("Self" (kernel:%function-self o))
   1991                     ("Next" (kernel:%function-next o))
   1992                     ("Name" (kernel:%function-name o))
   1993                     ("Arglist" (kernel:%function-arglist o))
   1994                     ("Type" (kernel:%function-type o))
   1995                     ("Code" (kernel:function-code-header o)))
   1996                    (list
   1997                     (with-output-to-string (s)
   1998                       (disassem:disassemble-function o :stream s)))))
   1999           ((= header vm:closure-header-type)
   2000            (list* (format nil "~A is a closure.~%" o)
   2001                   (append
   2002                    (label-value-line "Function" (kernel:%closure-function o))
   2003                    `("Environment:" (:newline))
   2004                    (loop for i from 0 below (1- (kernel:get-closure-length o))
   2005                          append (label-value-line
   2006                                  i (kernel:%closure-index-ref o i))))))
   2007           ((eval::interpreted-function-p o)
   2008            (cmucl-inspect o))
   2009           (t
   2010            (call-next-method)))))
   2011 
   2012 (defmethod emacs-inspect ((o kernel:funcallable-instance))
   2013   (append (label-value-line*
   2014            (:function (kernel:%funcallable-instance-function o))
   2015            (:lexenv  (kernel:%funcallable-instance-lexenv o))
   2016            (:layout  (kernel:%funcallable-instance-layout o)))
   2017           (cmucl-inspect o)))
   2018 
   2019 (defmethod emacs-inspect ((o kernel:code-component))
   2020   (append
   2021    (label-value-line*
   2022     ("code-size" (kernel:%code-code-size o))
   2023     ("entry-points" (kernel:%code-entry-points o))
   2024     ("debug-info" (kernel:%code-debug-info o))
   2025     ("trace-table-offset" (kernel:code-header-ref
   2026                            o vm:code-trace-table-offset-slot)))
   2027    `("Constants:" (:newline))
   2028    (loop for i from vm:code-constants-offset
   2029          below (kernel:get-header-data o)
   2030          append (label-value-line i (kernel:code-header-ref o i)))
   2031    `("Code:"
   2032      (:newline)
   2033      , (with-output-to-string (*standard-output*)
   2034          (cond ((c::compiled-debug-info-p (kernel:%code-debug-info o))
   2035                 (disassem:disassemble-code-component o))
   2036                ((or
   2037                  (c::debug-info-p (kernel:%code-debug-info o))
   2038                  (consp (kernel:code-header-ref
   2039                          o vm:code-trace-table-offset-slot)))
   2040                 (c:disassem-byte-component o))
   2041                (t
   2042                 (disassem:disassemble-memory
   2043                  (disassem::align
   2044                   (+ (logandc2 (kernel:get-lisp-obj-address o)
   2045                                vm:lowtag-mask)
   2046                      (* vm:code-constants-offset vm:word-bytes))
   2047                   (ash 1 vm:lowtag-bits))
   2048                  (ash (kernel:%code-code-size o) vm:word-shift))))))))
   2049 
   2050 (defmethod emacs-inspect ((o kernel:fdefn))
   2051   (label-value-line*
   2052    ("name" (kernel:fdefn-name o))
   2053    ("function" (kernel:fdefn-function o))
   2054    ("raw-addr" (sys:sap-ref-32
   2055                 (sys:int-sap (kernel:get-lisp-obj-address o))
   2056                 (* vm:fdefn-raw-addr-slot vm:word-bytes)))))
   2057 
   2058 #+(or)
   2059 (defmethod emacs-inspect ((o array))
   2060   (if (typep o 'simple-array)
   2061       (call-next-method)
   2062       (label-value-line*
   2063        (:header (describe-primitive-type o))
   2064        (:rank (array-rank o))
   2065        (:fill-pointer (kernel:%array-fill-pointer o))
   2066        (:fill-pointer-p (kernel:%array-fill-pointer-p o))
   2067        (:elements (kernel:%array-available-elements o))
   2068        (:data (kernel:%array-data-vector o))
   2069        (:displacement (kernel:%array-displacement o))
   2070        (:displaced-p (kernel:%array-displaced-p o))
   2071        (:dimensions (array-dimensions o)))))
   2072 
   2073 (defmethod emacs-inspect ((o simple-vector))
   2074   (append
   2075    (label-value-line*
   2076     (:header (describe-primitive-type o))
   2077     (:length (c::vector-length o)))
   2078    (loop for i below (length o)
   2079          append (label-value-line i (aref o i)))))
   2080 
   2081 (defun inspect-alien-record (alien)
   2082   (with-struct (alien::alien-value- sap type) alien
   2083     (with-struct (alien::alien-record-type- kind name fields) type
   2084       (append
   2085        (label-value-line*
   2086         (:sap sap)
   2087         (:kind kind)
   2088         (:name name))
   2089        (loop for field in fields
   2090              append (let ((slot (alien::alien-record-field-name field)))
   2091                       (declare (optimize (speed 0)))
   2092                       (label-value-line slot (alien:slot alien slot))))))))
   2093 
   2094 (defun inspect-alien-pointer (alien)
   2095   (with-struct (alien::alien-value- sap type) alien
   2096     (label-value-line*
   2097      (:sap sap)
   2098      (:type type)
   2099      (:to (alien::deref alien)))))
   2100 
   2101 (defun inspect-alien-value (alien)
   2102   (typecase (alien::alien-value-type alien)
   2103     (alien::alien-record-type (inspect-alien-record alien))
   2104     (alien::alien-pointer-type (inspect-alien-pointer alien))
   2105     (t (cmucl-inspect alien))))
   2106 
   2107 (defimplementation eval-context (obj)
   2108   (cond ((typep (class-of obj) 'structure-class)
   2109          (let* ((dd (kernel:layout-info (kernel:layout-of obj)))
   2110                 (slots (kernel:dd-slots dd)))
   2111            (list* (cons '*package*
   2112                         (symbol-package (if slots
   2113                                             (kernel:dsd-name (car slots))
   2114                                             (kernel:dd-name dd))))
   2115                   (loop for slot in slots collect
   2116                         (cons (kernel:dsd-name slot)
   2117                               (funcall (kernel:dsd-accessor slot) obj))))))))
   2118 
   2119 
   2120 ;;;; Profiling
   2121 (defimplementation profile (fname)
   2122   (eval `(profile:profile ,fname)))
   2123 
   2124 (defimplementation unprofile (fname)
   2125   (eval `(profile:unprofile ,fname)))
   2126 
   2127 (defimplementation unprofile-all ()
   2128   (eval `(profile:unprofile))
   2129   "All functions unprofiled.")
   2130 
   2131 (defimplementation profile-report ()
   2132   (eval `(profile:report-time)))
   2133 
   2134 (defimplementation profile-reset ()
   2135   (eval `(profile:reset-time))
   2136   "Reset profiling counters.")
   2137 
   2138 (defimplementation profiled-functions ()
   2139   profile:*timed-functions*)
   2140 
   2141 (defimplementation profile-package (package callers methods)
   2142   (profile:profile-all :package package
   2143                        :callers-p callers
   2144                        :methods methods))
   2145 
   2146 
   2147 ;;;; Multiprocessing
   2148 
   2149 #+mp
   2150 (progn
   2151   (defimplementation initialize-multiprocessing (continuation)
   2152     (mp::init-multi-processing)
   2153     (mp:make-process continuation :name "slynk")
   2154     ;; Threads magic: this never returns! But top-level becomes
   2155     ;; available again.
   2156     (unless mp::*idle-process*
   2157       (mp::startup-idle-and-top-level-loops)))
   2158 
   2159   (defimplementation spawn (fn &key name)
   2160     (mp:make-process fn :name (or name "Anonymous")))
   2161 
   2162   (defvar *thread-id-counter* 0)
   2163 
   2164   (defimplementation thread-id (thread)
   2165     (or (getf (mp:process-property-list thread) 'id)
   2166         (setf (getf (mp:process-property-list thread) 'id)
   2167               (incf *thread-id-counter*))))
   2168 
   2169   (defimplementation find-thread (id)
   2170     (find id (all-threads)
   2171           :key (lambda (p) (getf (mp:process-property-list p) 'id))))
   2172 
   2173   (defimplementation thread-name (thread)
   2174     (mp:process-name thread))
   2175 
   2176   (defimplementation thread-status (thread)
   2177     (mp:process-whostate thread))
   2178 
   2179   (defimplementation current-thread ()
   2180     mp:*current-process*)
   2181 
   2182   (defimplementation all-threads ()
   2183     (copy-list mp:*all-processes*))
   2184 
   2185   (defimplementation interrupt-thread (thread fn)
   2186     (mp:process-interrupt thread fn))
   2187 
   2188   (defimplementation kill-thread (thread)
   2189     (mp:destroy-process thread))
   2190 
   2191   (defvar *mailbox-lock* (mp:make-lock "mailbox lock"))
   2192 
   2193   (defstruct (mailbox (:conc-name mailbox.))
   2194     (mutex (mp:make-lock "process mailbox"))
   2195     (queue '() :type list))
   2196 
   2197   (defun mailbox (thread)
   2198     "Return THREAD's mailbox."
   2199     (mp:with-lock-held (*mailbox-lock*)
   2200       (or (getf (mp:process-property-list thread) 'mailbox)
   2201           (setf (getf (mp:process-property-list thread) 'mailbox)
   2202                 (make-mailbox)))))
   2203 
   2204   (defimplementation send (thread message)
   2205     (check-sly-interrupts)
   2206     (let* ((mbox (mailbox thread)))
   2207       (mp:with-lock-held ((mailbox.mutex mbox))
   2208         (setf (mailbox.queue mbox)
   2209               (nconc (mailbox.queue mbox) (list message))))))
   2210 
   2211   (defimplementation receive-if (test &optional timeout)
   2212     (let ((mbox (mailbox mp:*current-process*)))
   2213       (assert (or (not timeout) (eq timeout t)))
   2214       (loop
   2215        (check-sly-interrupts)
   2216        (mp:with-lock-held ((mailbox.mutex mbox))
   2217          (let* ((q (mailbox.queue mbox))
   2218                 (tail (member-if test q)))
   2219            (when tail
   2220              (setf (mailbox.queue mbox)
   2221                    (nconc (ldiff q tail) (cdr tail)))
   2222              (return (car tail)))))
   2223        (when (eq timeout t) (return (values nil t)))
   2224        (mp:process-wait-with-timeout
   2225         "receive-if" 0.5
   2226         (lambda () (some test (mailbox.queue mbox)))))))
   2227 
   2228 
   2229   ) ;; #+mp
   2230 
   2231 
   2232 
   2233 ;;;; GC hooks
   2234 ;;;
   2235 ;;; Display GC messages in the echo area to avoid cluttering the
   2236 ;;; normal output.
   2237 ;;;
   2238 
   2239 ;; this should probably not be here, but where else?
   2240 (defun background-message (message)
   2241   (funcall (find-symbol (string :background-message) :slynk)
   2242            message))
   2243 
   2244 (defun print-bytes (nbytes &optional stream)
   2245   "Print the number NBYTES to STREAM in KB, MB, or GB units."
   2246   (let ((names '((0 bytes) (10 kb) (20 mb) (30 gb) (40 tb) (50 eb))))
   2247     (multiple-value-bind (power name)
   2248 	(loop for ((p1 n1) (p2 n2)) on names
   2249               while n2 do
   2250               (when (<= (expt 2 p1) nbytes (1- (expt 2 p2)))
   2251 		(return (values p1 n1))))
   2252       (cond (name
   2253              (format stream "~,1F ~A" (/ nbytes (expt 2 power)) name))
   2254             (t
   2255              (format stream "~:D bytes" nbytes))))))
   2256 
   2257 (defconstant gc-generations 6)
   2258 
   2259 #+gencgc
   2260 (defun generation-stats ()
   2261   "Return a string describing the size distribution among the generations."
   2262   (let* ((alloc (loop for i below gc-generations
   2263                       collect (lisp::gencgc-stats i)))
   2264          (sum (coerce (reduce #'+ alloc) 'float)))
   2265     (format nil "~{~3F~^/~}"
   2266             (mapcar (lambda (size) (/ size sum))
   2267                     alloc))))
   2268 
   2269 (defvar *gc-start-time* 0)
   2270 
   2271 (defun pre-gc-hook (bytes-in-use)
   2272   (setq *gc-start-time* (get-internal-real-time))
   2273   (let ((msg (format nil "[Commencing GC with ~A in use.]"
   2274                      (print-bytes bytes-in-use))))
   2275     (background-message msg)))
   2276 
   2277 (defun post-gc-hook (bytes-retained bytes-freed trigger)
   2278   (declare (ignore trigger))
   2279   (let* ((seconds (/ (- (get-internal-real-time) *gc-start-time*)
   2280                      internal-time-units-per-second))
   2281          (msg (format nil "[GC done. ~A freed  ~A retained  ~A  ~4F sec]"
   2282                      (print-bytes bytes-freed)
   2283                      (print-bytes bytes-retained)
   2284                      #+gencgc(generation-stats)
   2285                      #-gencgc""
   2286                      seconds)))
   2287     (background-message msg)))
   2288 
   2289 (defun install-gc-hooks ()
   2290   (setq ext:*gc-notify-before* #'pre-gc-hook)
   2291   (setq ext:*gc-notify-after* #'post-gc-hook))
   2292 
   2293 (defun remove-gc-hooks ()
   2294   (setq ext:*gc-notify-before* #'lisp::default-gc-notify-before)
   2295   (setq ext:*gc-notify-after* #'lisp::default-gc-notify-after))
   2296 
   2297 (defvar *install-gc-hooks* t
   2298   "If non-nil install GC hooks")
   2299 
   2300 (defimplementation emacs-connected ()
   2301   (when *install-gc-hooks*
   2302     (install-gc-hooks)))
   2303 
   2304 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   2305 ;;Trace implementations
   2306 ;;In CMUCL, we have:
   2307 ;; (trace <name>)
   2308 ;; (trace (method <name> <qualifier>? (<specializer>+)))
   2309 ;; (trace :methods t '<name>) ;;to trace all methods of the gf <name>
   2310 ;; <name> can be a normal name or a (setf name)
   2311 
   2312 (defun tracedp (spec)
   2313   (member spec (eval '(trace)) :test #'equal))
   2314 
   2315 (defun toggle-trace-aux (spec &rest options)
   2316   (cond ((tracedp spec)
   2317          (eval `(untrace ,spec))
   2318          (format nil "~S is now untraced." spec))
   2319         (t
   2320          (eval `(trace ,spec ,@options))
   2321          (format nil "~S is now traced." spec))))
   2322 
   2323 (defimplementation toggle-trace (spec)
   2324   (ecase (car spec)
   2325     ((setf)
   2326      (toggle-trace-aux spec))
   2327     ((:defgeneric)
   2328      (let ((name (second spec)))
   2329        (toggle-trace-aux name :methods name)))
   2330     ((:defmethod)
   2331      (cond ((fboundp `(method ,@(cdr spec)))
   2332             (toggle-trace-aux `(method ,(cdr spec))))
   2333            ;; Man, is this ugly
   2334            ((fboundp `(pcl::fast-method ,@(cdr spec)))
   2335             (toggle-trace-aux `(pcl::fast-method ,@(cdr spec))))
   2336            (t
   2337             (error 'undefined-function :name (cdr spec)))))
   2338     ((:call)
   2339      (destructuring-bind (caller callee) (cdr spec)
   2340        (toggle-trace-aux (process-fspec callee)
   2341                          :wherein (list (process-fspec caller)))))
   2342     ;; doesn't work properly
   2343     ;; ((:labels :flet) (toggle-trace-aux (process-fspec spec)))
   2344     ))
   2345 
   2346 (defun process-fspec (fspec)
   2347   (cond ((consp fspec)
   2348          (ecase (first fspec)
   2349            ((:defun :defgeneric) (second fspec))
   2350            ((:defmethod)
   2351             `(method ,(second fspec) ,@(third fspec) ,(fourth fspec)))
   2352            ((:labels) `(labels ,(third fspec) ,(process-fspec (second fspec))))
   2353            ((:flet) `(flet ,(third fspec) ,(process-fspec (second fspec))))))
   2354         (t
   2355          fspec)))
   2356 
   2357 ;;; Weak datastructures
   2358 
   2359 (defimplementation make-weak-key-hash-table (&rest args)
   2360   (apply #'make-hash-table :weak-p t args))
   2361 
   2362 
   2363 ;;; Save image
   2364 
   2365 (defimplementation save-image (filename &optional restart-function)
   2366   (multiple-value-bind (pid error) (unix:unix-fork)
   2367     (when (not pid) (error "fork: ~A" (unix:get-unix-error-msg error)))
   2368     (cond ((= pid 0)
   2369            (apply #'ext:save-lisp
   2370                   filename
   2371                   (if restart-function
   2372                       `(:init-function ,restart-function))))
   2373           (t
   2374            (let ((status (waitpid pid)))
   2375              (destructuring-bind (&key exited? status &allow-other-keys) status
   2376                (assert (and exited? (equal status 0)) ()
   2377                        "Invalid exit status: ~a" status)))))))
   2378 
   2379 (defun waitpid (pid)
   2380   (alien:with-alien ((status c-call:int))
   2381     (let ((code (alien:alien-funcall
   2382                  (alien:extern-alien
   2383                   waitpid (alien:function c-call:int c-call:int
   2384                                           (* c-call:int) c-call:int))
   2385                  pid (alien:addr status) 0)))
   2386       (cond ((= code -1) (error "waitpid: ~A" (unix:get-unix-error-msg)))
   2387             (t (assert (= code pid))
   2388                (decode-wait-status status))))))
   2389 
   2390 (defun decode-wait-status (status)
   2391   (let ((output (with-output-to-string (s)
   2392                   (call-program (list (process-status-program)
   2393                                       (format nil "~d" status))
   2394                                 :output s))))
   2395     (read-from-string output)))
   2396 
   2397 (defun call-program (args &key output)
   2398   (destructuring-bind (program &rest args) args
   2399     (let ((process (ext:run-program program args :output output)))
   2400       (when (not program) (error "fork failed"))
   2401       (unless (and (eq (ext:process-status process) :exited)
   2402                    (= (ext:process-exit-code process) 0))
   2403         (error "Non-zero exit status")))))
   2404 
   2405 (defvar *process-status-program* nil)
   2406 
   2407 (defun process-status-program ()
   2408   (or *process-status-program*
   2409       (setq *process-status-program*
   2410             (compile-process-status-program))))
   2411 
   2412 (defun compile-process-status-program ()
   2413   (let ((infile (system::pick-temporary-file-name
   2414                  "/tmp/process-status~d~c.c")))
   2415     (with-open-file (stream infile :direction :output :if-exists :supersede)
   2416       (format stream "
   2417 #include <stdio.h>
   2418 #include <stdlib.h>
   2419 #include <sys/types.h>
   2420 #include <sys/wait.h>
   2421 #include <assert.h>
   2422 
   2423 #define FLAG(value) (value ? \"t\" : \"nil\")
   2424 
   2425 int main (int argc, char** argv) {
   2426   assert (argc == 2);
   2427   {
   2428     char* endptr = NULL;
   2429     char* arg = argv[1];
   2430     long int status = strtol (arg, &endptr, 10);
   2431     assert (endptr != arg && *endptr == '\\0');
   2432     printf (\"(:exited? %s :status %d :signal? %s :signal %d :coredump? %s\"
   2433             \" :stopped? %s :stopsig %d)\\n\",
   2434             FLAG(WIFEXITED(status)), WEXITSTATUS(status),
   2435             FLAG(WIFSIGNALED(status)), WTERMSIG(status),
   2436             FLAG(WCOREDUMP(status)),
   2437             FLAG(WIFSTOPPED(status)), WSTOPSIG(status));
   2438     fflush (NULL);
   2439     return 0;
   2440   }
   2441 }
   2442 ")
   2443       (finish-output stream))
   2444     (let* ((outfile (system::pick-temporary-file-name))
   2445            (args (list "cc" "-o" outfile infile)))
   2446       (warn "Running cc: ~{~a ~}~%" args)
   2447       (call-program args :output t)
   2448       (delete-file infile)
   2449       outfile)))
   2450 
   2451 ;; FIXME: lisp:unicode-complete introduced in version 20d.
   2452 #+#.(slynk-backend:with-symbol 'unicode-complete 'lisp)
   2453 (defun match-semi-standard (prefix matchp)
   2454   ;; Handle the CMUCL's short character names.
   2455   (loop for name in lisp::char-name-alist
   2456      when (funcall matchp prefix (car name))
   2457      collect (car name)))
   2458 
   2459 #+#.(slynk-backend:with-symbol 'unicode-complete 'lisp)
   2460 (defimplementation character-completion-set (prefix matchp)
   2461   (let ((names (lisp::unicode-complete prefix)))
   2462     ;; Match prefix against semistandard names.  If there's a match,
   2463     ;; add it to our list of matches.
   2464     (let ((semi-standard (match-semi-standard prefix matchp)))
   2465       (when semi-standard
   2466         (setf names (append semi-standard names))))
   2467     (setf names (mapcar #'string-capitalize names))
   2468     (loop for n in names
   2469        when (funcall matchp prefix n)
   2470        collect n)))
   2471 
   2472 (defimplementation codepoint-length (string)
   2473   "Return the number of code points in the string.  The string MUST be
   2474   a valid UTF-16 string."
   2475   (do ((len (length string))
   2476        (index 0 (1+ index))
   2477        (count 0 (1+ count)))
   2478       ((>= index len)
   2479        count)
   2480     (multiple-value-bind (codepoint wide)
   2481 	(lisp:codepoint string index)
   2482       (declare (ignore codepoint))
   2483       (when wide (incf index)))))