Klimi's new dotfiles with stow.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

1070 строки
39 KiB

4 лет назад
  1. ;;;; -*- indent-tabs-mode: nil; outline-regexp: ";;;;;* "; -*-
  2. ;;;
  3. ;;; swank-allegro.lisp --- Allegro CL specific code for SLIME.
  4. ;;;
  5. ;;; Created 2003
  6. ;;;
  7. ;;; This code has been placed in the Public Domain. All warranties
  8. ;;; are disclaimed.
  9. ;;;
  10. (defpackage swank/allegro
  11. (:use cl swank/backend))
  12. (in-package swank/allegro)
  13. (eval-when (:compile-toplevel :load-toplevel :execute)
  14. (require :sock)
  15. (require :process)
  16. #+(version>= 8 2)
  17. (require 'lldb))
  18. (defimplementation gray-package-name ()
  19. '#:excl)
  20. ;;; swank-mop
  21. (import-swank-mop-symbols :clos '(:slot-definition-documentation))
  22. (defun swank-mop:slot-definition-documentation (slot)
  23. (documentation slot t))
  24. ;;;; UTF8
  25. (define-symbol-macro utf8-ef
  26. (load-time-value
  27. (excl:crlf-base-ef (excl:find-external-format :utf-8))
  28. t))
  29. (defimplementation string-to-utf8 (s)
  30. (excl:string-to-octets s :external-format utf8-ef
  31. :null-terminate nil))
  32. (defimplementation utf8-to-string (u)
  33. (excl:octets-to-string u :external-format utf8-ef))
  34. ;;;; TCP Server
  35. (defimplementation preferred-communication-style ()
  36. :spawn)
  37. (defimplementation create-socket (host port &key backlog)
  38. (socket:make-socket :connect :passive :local-port port
  39. :local-host host :reuse-address t
  40. :backlog (or backlog 5)))
  41. (defimplementation local-port (socket)
  42. (socket:local-port socket))
  43. (defimplementation close-socket (socket)
  44. (close socket))
  45. (defimplementation accept-connection (socket &key external-format buffering
  46. timeout)
  47. (declare (ignore buffering timeout))
  48. (let ((s (socket:accept-connection socket :wait t)))
  49. (when external-format
  50. (setf (stream-external-format s) external-format))
  51. s))
  52. (defimplementation socket-fd (stream)
  53. (excl::stream-input-handle stream))
  54. (defvar *external-format-to-coding-system*
  55. '((:iso-8859-1
  56. "latin-1" "latin-1-unix" "iso-latin-1-unix"
  57. "iso-8859-1" "iso-8859-1-unix")
  58. (:utf-8 "utf-8" "utf-8-unix")
  59. (:euc-jp "euc-jp" "euc-jp-unix")
  60. (:us-ascii "us-ascii" "us-ascii-unix")
  61. (:emacs-mule "emacs-mule" "emacs-mule-unix")))
  62. (defimplementation find-external-format (coding-system)
  63. (let ((e (rassoc-if (lambda (x) (member coding-system x :test #'equal))
  64. *external-format-to-coding-system*)))
  65. (and e (excl:crlf-base-ef
  66. (excl:find-external-format (car e)
  67. :try-variant t)))))
  68. ;;;; Unix signals
  69. (defimplementation getpid ()
  70. (excl::getpid))
  71. (defimplementation lisp-implementation-type-name ()
  72. "allegro")
  73. (defimplementation set-default-directory (directory)
  74. (let* ((dir (namestring (truename (merge-pathnames directory)))))
  75. (setf *default-pathname-defaults* (pathname (excl:chdir dir)))
  76. dir))
  77. (defimplementation default-directory ()
  78. (namestring (excl:current-directory)))
  79. ;;;; Misc
  80. (defimplementation arglist (symbol)
  81. (handler-case (excl:arglist symbol)
  82. (simple-error () :not-available)))
  83. (defimplementation macroexpand-all (form &optional env)
  84. (declare (ignore env))
  85. #+(version>= 8 0)
  86. (excl::walk-form form)
  87. #-(version>= 8 0)
  88. (excl::walk form))
  89. (defimplementation describe-symbol-for-emacs (symbol)
  90. (let ((result '()))
  91. (flet ((doc (kind &optional (sym symbol))
  92. (or (documentation sym kind) :not-documented))
  93. (maybe-push (property value)
  94. (when value
  95. (setf result (list* property value result)))))
  96. (maybe-push
  97. :variable (when (boundp symbol)
  98. (doc 'variable)))
  99. (maybe-push
  100. :function (if (fboundp symbol)
  101. (doc 'function)))
  102. (maybe-push
  103. :class (if (find-class symbol nil)
  104. (doc 'class)))
  105. result)))
  106. (defimplementation describe-definition (symbol namespace)
  107. (ecase namespace
  108. (:variable
  109. (describe symbol))
  110. ((:function :generic-function)
  111. (describe (symbol-function symbol)))
  112. (:class
  113. (describe (find-class symbol)))))
  114. (defimplementation type-specifier-p (symbol)
  115. (or (ignore-errors
  116. (subtypep nil symbol))
  117. (not (eq (type-specifier-arglist symbol) :not-available))))
  118. (defimplementation function-name (f)
  119. (check-type f function)
  120. (cross-reference::object-to-function-name f))
  121. ;;;; Debugger
  122. (defvar *sldb-topframe*)
  123. (defimplementation call-with-debugging-environment (debugger-loop-fn)
  124. (let ((*sldb-topframe* (find-topframe))
  125. (excl::*break-hook* nil))
  126. (funcall debugger-loop-fn)))
  127. (defimplementation sldb-break-at-start (fname)
  128. ;; :print-before is kind of mis-used but we just want to stuff our
  129. ;; break form somewhere. This does not work for setf, :before and
  130. ;; :after methods, which need special syntax in the trace call, see
  131. ;; ACL's doc/debugging.htm chapter 10.
  132. (eval `(trace (,fname
  133. :print-before
  134. ((break "Function start breakpoint of ~A" ',fname)))))
  135. `(:ok ,(format nil "Set breakpoint at start of ~S" fname)))
  136. (defun find-topframe ()
  137. (let ((magic-symbol (intern (symbol-name :swank-debugger-hook)
  138. (find-package :swank)))
  139. (top-frame (excl::int-newest-frame (excl::current-thread))))
  140. (loop for frame = top-frame then (next-frame frame)
  141. for i from 0
  142. while (and frame (< i 30))
  143. when (eq (debugger:frame-name frame) magic-symbol)
  144. return (next-frame frame)
  145. finally (return top-frame))))
  146. (defun next-frame (frame)
  147. (let ((next (excl::int-next-older-frame frame)))
  148. (cond ((not next) nil)
  149. ((debugger:frame-visible-p next) next)
  150. (t (next-frame next)))))
  151. (defun nth-frame (index)
  152. (do ((frame *sldb-topframe* (next-frame frame))
  153. (i index (1- i)))
  154. ((zerop i) frame)))
  155. (defimplementation compute-backtrace (start end)
  156. (let ((end (or end most-positive-fixnum)))
  157. (loop for f = (nth-frame start) then (next-frame f)
  158. for i from start below end
  159. while f collect f)))
  160. (defimplementation print-frame (frame stream)
  161. (debugger:output-frame stream frame :moderate))
  162. (defimplementation frame-locals (index)
  163. (let ((frame (nth-frame index)))
  164. (loop for i from 0 below (debugger:frame-number-vars frame)
  165. collect (list :name (debugger:frame-var-name frame i)
  166. :id 0
  167. :value (debugger:frame-var-value frame i)))))
  168. (defimplementation frame-var-value (frame var)
  169. (let ((frame (nth-frame frame)))
  170. (debugger:frame-var-value frame var)))
  171. (defimplementation disassemble-frame (index)
  172. (let ((frame (nth-frame index)))
  173. (multiple-value-bind (x fun xx xxx pc) (debugger::dyn-fd-analyze frame)
  174. (format t "pc: ~d (~s ~s ~s)~%fun: ~a~%" pc x xx xxx fun)
  175. (disassemble (debugger:frame-function frame)))))
  176. (defimplementation frame-source-location (index)
  177. (let* ((frame (nth-frame index)))
  178. (multiple-value-bind (x fun xx xxx pc) (debugger::dyn-fd-analyze frame)
  179. (declare (ignore x xx xxx))
  180. (cond ((and pc
  181. #+(version>= 8 2)
  182. (pc-source-location fun pc)
  183. #-(version>= 8 2)
  184. (function-source-location fun)))
  185. (t ; frames for unbound functions etc end up here
  186. (cadr (car (fspec-definition-locations
  187. (car (debugger:frame-expression frame))))))))))
  188. (defun function-source-location (fun)
  189. (cadr (car (fspec-definition-locations
  190. (xref::object-to-function-name fun)))))
  191. #+(version>= 8 2)
  192. (defun pc-source-location (fun pc)
  193. (let* ((debug-info (excl::function-source-debug-info fun)))
  194. (cond ((not debug-info)
  195. (function-source-location fun))
  196. (t
  197. (let* ((code-loc (find-if (lambda (c)
  198. (<= (- pc (sys::natural-width))
  199. (let ((x (excl::ldb-code-pc c)))
  200. (or x -1))
  201. pc))
  202. debug-info)))
  203. (cond ((not code-loc)
  204. (ldb-code-to-src-loc (aref debug-info 0)))
  205. (t
  206. (ldb-code-to-src-loc code-loc))))))))
  207. #+(version>= 8 2)
  208. (defun ldb-code-to-src-loc (code)
  209. (declare (optimize debug))
  210. (let* ((func (excl::ldb-code-func code))
  211. (debug-info (excl::function-source-debug-info func))
  212. (start (loop for i from (excl::ldb-code-index code) downto 0
  213. for bpt = (aref debug-info i)
  214. for start = (excl::ldb-code-start-char bpt)
  215. when start
  216. return (if (listp start)
  217. (first start)
  218. start)))
  219. (src-file (excl:source-file func)))
  220. (cond (start
  221. (buffer-or-file-location src-file start))
  222. (func
  223. (let* ((debug-info (excl::function-source-debug-info func))
  224. (whole (aref debug-info 0))
  225. (paths (source-paths-of (excl::ldb-code-source whole)
  226. (excl::ldb-code-source code)))
  227. (path (if paths (longest-common-prefix paths) '()))
  228. (start 0))
  229. (buffer-or-file
  230. src-file
  231. (lambda (file)
  232. (make-location `(:file ,file)
  233. `(:source-path (0 . ,path) ,start)))
  234. (lambda (buffer bstart)
  235. (make-location `(:buffer ,buffer)
  236. `(:source-path (0 . ,path)
  237. ,(+ bstart start)))))))
  238. (t
  239. nil))))
  240. (defun longest-common-prefix (sequences)
  241. (assert sequences)
  242. (flet ((common-prefix (s1 s2)
  243. (let ((diff-pos (mismatch s1 s2)))
  244. (if diff-pos (subseq s1 0 diff-pos) s1))))
  245. (reduce #'common-prefix sequences)))
  246. (defun source-paths-of (whole part)
  247. (let ((result '()))
  248. (labels ((walk (form path)
  249. (cond ((eq form part)
  250. (push (reverse path) result))
  251. ((consp form)
  252. (loop for i from 0 while (consp form) do
  253. (walk (pop form) (cons i path)))))))
  254. (walk whole '())
  255. (reverse result))))
  256. (defimplementation eval-in-frame (form frame-number)
  257. (let ((frame (nth-frame frame-number)))
  258. ;; let-bind lexical variables
  259. (let ((vars (loop for i below (debugger:frame-number-vars frame)
  260. for name = (debugger:frame-var-name frame i)
  261. if (typep name '(and symbol (not null) (not keyword)))
  262. collect `(,name ',(debugger:frame-var-value frame i)))))
  263. (debugger:eval-form-in-context
  264. `(let* ,vars ,form)
  265. (debugger:environment-of-frame frame)))))
  266. (defimplementation frame-package (frame-number)
  267. (let* ((frame (nth-frame frame-number))
  268. (exp (debugger:frame-expression frame)))
  269. (typecase exp
  270. ((cons symbol) (symbol-package (car exp)))
  271. ((cons (cons (eql :internal) (cons symbol)))
  272. (symbol-package (cadar exp))))))
  273. (defimplementation return-from-frame (frame-number form)
  274. (let ((frame (nth-frame frame-number)))
  275. (multiple-value-call #'debugger:frame-return
  276. frame (debugger:eval-form-in-context
  277. form
  278. (debugger:environment-of-frame frame)))))
  279. (defimplementation frame-restartable-p (frame)
  280. (handler-case (debugger:frame-retryable-p frame)
  281. (serious-condition (c)
  282. (funcall (read-from-string "swank::background-message")
  283. "~a ~a" frame (princ-to-string c))
  284. nil)))
  285. (defimplementation restart-frame (frame-number)
  286. (let ((frame (nth-frame frame-number)))
  287. (cond ((debugger:frame-retryable-p frame)
  288. (apply #'debugger:frame-retry frame (debugger:frame-function frame)
  289. (cdr (debugger:frame-expression frame))))
  290. (t "Frame is not retryable"))))
  291. ;;;; Compiler hooks
  292. (defvar *buffer-name* nil)
  293. (defvar *buffer-start-position*)
  294. (defvar *buffer-string*)
  295. (defvar *compile-filename* nil)
  296. (defun compiler-note-p (object)
  297. (member (type-of object) '(excl::compiler-note compiler::compiler-note)))
  298. (defun redefinition-p (condition)
  299. (and (typep condition 'style-warning)
  300. (every #'char-equal "redefin" (princ-to-string condition))))
  301. (defun compiler-undefined-functions-called-warning-p (object)
  302. (typep object 'excl:compiler-undefined-functions-called-warning))
  303. (deftype compiler-note ()
  304. `(satisfies compiler-note-p))
  305. (deftype redefinition ()
  306. `(satisfies redefinition-p))
  307. (defun signal-compiler-condition (&rest args)
  308. (apply #'signal 'compiler-condition args))
  309. (defun handle-compiler-warning (condition)
  310. (declare (optimize (debug 3) (speed 0) (space 0)))
  311. (cond ((and #-(version>= 10 0) (not *buffer-name*)
  312. (compiler-undefined-functions-called-warning-p condition))
  313. (handle-undefined-functions-warning condition))
  314. ((and (typep condition 'excl::compiler-note)
  315. (let ((format (slot-value condition 'excl::format-control)))
  316. (and (search "Closure" format)
  317. (search "will be stack allocated" format))))
  318. ;; Ignore "Closure <foo> will be stack allocated" notes.
  319. ;; That occurs often but is usually uninteresting.
  320. )
  321. (t
  322. (signal-compiler-condition
  323. :original-condition condition
  324. :severity (etypecase condition
  325. (redefinition :redefinition)
  326. (style-warning :style-warning)
  327. (warning :warning)
  328. (compiler-note :note)
  329. (reader-error :read-error)
  330. (error :error))
  331. :message (format nil "~A" condition)
  332. :location (compiler-warning-location condition)))))
  333. (defun condition-pathname-and-position (condition)
  334. (let* ((context #+(version>= 10 0)
  335. (getf (slot-value condition 'excl::plist)
  336. :source-context))
  337. (location-available (and context
  338. (excl::source-context-start-char context))))
  339. (cond (location-available
  340. (values (excl::source-context-pathname context)
  341. (when-let (start-char (excl::source-context-start-char context))
  342. (let ((position (if (listp start-char) ; HACK
  343. (first start-char)
  344. start-char)))
  345. (if (typep condition 'excl::compiler-free-reference-warning)
  346. position
  347. (1+ position))))))
  348. ((typep condition 'reader-error)
  349. (let ((pos (car (last (slot-value condition 'excl::format-arguments))))
  350. (file (pathname (stream-error-stream condition))))
  351. (when (integerp pos)
  352. (values file pos))))
  353. (t
  354. (let ((loc (getf (slot-value condition 'excl::plist) :loc)))
  355. (when loc
  356. (destructuring-bind (file . pos) loc
  357. (let ((start (if (consp pos) ; 8.2 and newer
  358. #+(version>= 10 1)
  359. (if (typep condition 'excl::compiler-inconsistent-name-usage-warning)
  360. (second pos)
  361. (first pos))
  362. #-(version>= 10 1)
  363. (first pos)
  364. pos)))
  365. (values file start)))))))))
  366. (defun compiler-warning-location (condition)
  367. (multiple-value-bind (pathname position)
  368. (condition-pathname-and-position condition)
  369. (cond (*buffer-name*
  370. (make-location
  371. (list :buffer *buffer-name*)
  372. (if position
  373. (list :offset 1 (1- position))
  374. (list :offset *buffer-start-position* 0))))
  375. (pathname
  376. (make-location
  377. (list :file (namestring (truename pathname)))
  378. #+(version>= 10 1)
  379. (list :offset 1 position)
  380. #-(version>= 10 1)
  381. (list :position (1+ position))))
  382. (t
  383. (make-error-location "No error location available.")))))
  384. ;; TODO: report it as a bug to Franz that the condition's plist
  385. ;; slot contains (:loc nil).
  386. (defun handle-undefined-functions-warning (condition)
  387. (let ((fargs (slot-value condition 'excl::format-arguments)))
  388. (loop for (fname . locs) in (car fargs) do
  389. (dolist (loc locs)
  390. (multiple-value-bind (pos file) (ecase (length loc)
  391. (2 (values-list loc))
  392. (3 (destructuring-bind
  393. (start end file) loc
  394. (declare (ignore end))
  395. (values start file))))
  396. (signal-compiler-condition
  397. :original-condition condition
  398. :severity :warning
  399. :message (format nil "Undefined function referenced: ~S"
  400. fname)
  401. :location (make-location (list :file file)
  402. #+(version>= 9 0)
  403. (list :offset 1 pos)
  404. #-(version>= 9 0)
  405. (list :position (1+ pos)))))))))
  406. (defimplementation call-with-compilation-hooks (function)
  407. (handler-bind ((warning #'handle-compiler-warning)
  408. (compiler-note #'handle-compiler-warning)
  409. (reader-error #'handle-compiler-warning))
  410. (funcall function)))
  411. (defimplementation swank-compile-file (input-file output-file
  412. load-p external-format
  413. &key policy)
  414. (declare (ignore policy))
  415. (handler-case
  416. (with-compilation-hooks ()
  417. (let ((*buffer-name* nil)
  418. (*compile-filename* input-file)
  419. #+(version>= 8 2)
  420. (compiler:save-source-level-debug-info-switch t)
  421. (excl:*load-source-file-info* t)
  422. #+(version>= 8 2)
  423. (excl:*load-source-debug-info* t))
  424. (compile-file *compile-filename*
  425. :output-file output-file
  426. :load-after-compile load-p
  427. :external-format external-format)))
  428. (reader-error () (values nil nil t))))
  429. (defun call-with-temp-file (fn)
  430. (let ((tmpname (system:make-temp-file-name)))
  431. (unwind-protect
  432. (with-open-file (file tmpname :direction :output :if-exists :error)
  433. (funcall fn file tmpname))
  434. (delete-file tmpname))))
  435. (defvar *temp-file-map* (make-hash-table :test #'equal)
  436. "A mapping from tempfile names to Emacs buffer names.")
  437. (defun write-tracking-preamble (stream file file-offset)
  438. "Instrument the top of the temporary file to be compiled.
  439. The header tells allegro that any definitions compiled in the temp
  440. file should be found in FILE exactly at FILE-OFFSET. To get Allegro
  441. to do this, this factors in the length of the inserted header itself."
  442. (with-standard-io-syntax
  443. (let* ((*package* (find-package :keyword))
  444. (source-pathname-form
  445. `(cl:eval-when (:compile-toplevel :load-toplevel :execute)
  446. (cl:setq excl::*source-pathname*
  447. (pathname ,(sys::frob-source-file file)))))
  448. (source-pathname-string (write-to-string source-pathname-form))
  449. (position-form-length-bound 160) ; should be enough for everyone
  450. (header-length (+ (length source-pathname-string)
  451. position-form-length-bound))
  452. (position-form
  453. `(cl:eval-when (:compile-toplevel :load-toplevel :execute)
  454. (cl:setq excl::*partial-source-file-p* ,(- file-offset
  455. header-length
  456. 1 ; for the newline
  457. ))))
  458. (position-form-string (write-to-string position-form))
  459. (padding-string (make-string (- position-form-length-bound
  460. (length position-form-string))
  461. :initial-element #\;)))
  462. (write-string source-pathname-string stream)
  463. (write-string position-form-string stream)
  464. (write-string padding-string stream)
  465. (write-char #\newline stream))))
  466. (defun compile-from-temp-file (string buffer offset file)
  467. (call-with-temp-file
  468. (lambda (stream filename)
  469. (when (and file offset (probe-file file))
  470. (write-tracking-preamble stream file offset))
  471. (write-string string stream)
  472. (finish-output stream)
  473. (multiple-value-bind (binary-filename warnings? failure?)
  474. (let ((sys:*source-file-types* '(nil)) ; suppress .lisp extension
  475. #+(version>= 8 2)
  476. (compiler:save-source-level-debug-info-switch t)
  477. (excl:*redefinition-warnings* nil))
  478. (compile-file filename))
  479. (declare (ignore warnings?))
  480. (when binary-filename
  481. (let ((excl:*load-source-file-info* t)
  482. #+(version>= 8 2)
  483. (excl:*load-source-debug-info* t))
  484. excl::*source-pathname*
  485. (load binary-filename))
  486. (when (and buffer offset (or (not file)
  487. (not (probe-file file))))
  488. (setf (gethash (pathname stream) *temp-file-map*)
  489. (list buffer offset)))
  490. (delete-file binary-filename))
  491. (not failure?)))))
  492. (defimplementation swank-compile-string (string &key buffer position filename
  493. policy)
  494. (declare (ignore policy))
  495. (handler-case
  496. (with-compilation-hooks ()
  497. (let ((*buffer-name* buffer)
  498. (*buffer-start-position* position)
  499. (*buffer-string* string))
  500. (compile-from-temp-file string buffer position filename)))
  501. (reader-error () nil)))
  502. ;;;; Definition Finding
  503. (defun buffer-or-file (file file-fun buffer-fun)
  504. (let* ((probe (gethash file *temp-file-map*)))
  505. (cond (probe
  506. (destructuring-bind (buffer start) probe
  507. (funcall buffer-fun buffer start)))
  508. (t (funcall file-fun (namestring (truename file)))))))
  509. (defun buffer-or-file-location (file offset)
  510. (buffer-or-file file
  511. (lambda (filename)
  512. (make-location `(:file ,filename)
  513. `(:position ,(1+ offset))))
  514. (lambda (buffer start)
  515. (make-location `(:buffer ,buffer)
  516. `(:offset ,start ,offset)))))
  517. (defun fspec-primary-name (fspec)
  518. (etypecase fspec
  519. (symbol fspec)
  520. (list (fspec-primary-name (second fspec)))))
  521. (defun find-definition-in-file (fspec type file top-level)
  522. (let* ((part
  523. (or (scm::find-definition-in-definition-group
  524. fspec type (scm:section-file :file file)
  525. :top-level top-level)
  526. (scm::find-definition-in-definition-group
  527. (fspec-primary-name fspec)
  528. type (scm:section-file :file file)
  529. :top-level top-level)))
  530. (start (and part
  531. (scm::source-part-start part)))
  532. (pos (if start
  533. (list :offset 1 start)
  534. (list :function-name (string (fspec-primary-name fspec))))))
  535. (make-location (list :file (namestring (truename file)))
  536. pos)))
  537. (defun find-fspec-location (fspec type file top-level)
  538. (handler-case
  539. (etypecase file
  540. (pathname
  541. (let ((probe (gethash file *temp-file-map*)))
  542. (cond (probe
  543. (destructuring-bind (buffer offset) probe
  544. (make-location `(:buffer ,buffer)
  545. `(:offset ,offset 0))))
  546. (t
  547. (find-definition-in-file fspec type file top-level)))))
  548. ((member :top-level)
  549. (make-error-location "Defined at toplevel: ~A"
  550. (fspec->string fspec))))
  551. (error (e)
  552. (make-error-location "Error: ~A" e))))
  553. (defun fspec->string (fspec)
  554. (typecase fspec
  555. (symbol (let ((*package* (find-package :keyword)))
  556. (prin1-to-string fspec)))
  557. (list (format nil "(~A ~A)"
  558. (prin1-to-string (first fspec))
  559. (let ((*package* (find-package :keyword)))
  560. (prin1-to-string (second fspec)))))
  561. (t (princ-to-string fspec))))
  562. (defun fspec-definition-locations (fspec)
  563. (cond
  564. ((and (listp fspec) (eq (car fspec) :internal))
  565. (destructuring-bind (_internal next _n) fspec
  566. (declare (ignore _internal _n))
  567. (fspec-definition-locations next)))
  568. (t
  569. (let ((defs (excl::find-source-file fspec)))
  570. (when (and (null defs)
  571. (listp fspec)
  572. (string= (car fspec) '#:method))
  573. ;; If methods are defined in a defgeneric form, the source location is
  574. ;; recorded for the gf but not for the methods. Therefore fall back to
  575. ;; the gf as the likely place of definition.
  576. (setq defs (excl::find-source-file (second fspec))))
  577. (if (null defs)
  578. (list
  579. (list fspec
  580. (make-error-location "Unknown source location for ~A"
  581. (fspec->string fspec))))
  582. (loop for (fspec type file top-level) in defs collect
  583. (list (list type fspec)
  584. (find-fspec-location fspec type file top-level))))))))
  585. (defimplementation find-definitions (symbol)
  586. (fspec-definition-locations symbol))
  587. (defimplementation find-source-location (obj)
  588. (first (rest (first (fspec-definition-locations obj)))))
  589. ;;;; XREF
  590. (defmacro defxref (name relation name1 name2)
  591. `(defimplementation ,name (x)
  592. (xref-result (xref:get-relation ,relation ,name1 ,name2))))
  593. (defxref who-calls :calls :wild x)
  594. (defxref calls-who :calls x :wild)
  595. (defxref who-references :uses :wild x)
  596. (defxref who-binds :binds :wild x)
  597. (defxref who-macroexpands :macro-calls :wild x)
  598. (defxref who-sets :sets :wild x)
  599. (defun xref-result (fspecs)
  600. (loop for fspec in fspecs
  601. append (fspec-definition-locations fspec)))
  602. ;; list-callers implemented by groveling through all fbound symbols.
  603. ;; Only symbols are considered. Functions in the constant pool are
  604. ;; searched recursively. Closure environments are ignored at the
  605. ;; moment (constants in methods are therefore not found).
  606. (defun map-function-constants (function fn depth)
  607. "Call FN with the elements of FUNCTION's constant pool."
  608. (do ((i 0 (1+ i))
  609. (max (excl::function-constant-count function)))
  610. ((= i max))
  611. (let ((c (excl::function-constant function i)))
  612. (cond ((and (functionp c)
  613. (not (eq c function))
  614. (plusp depth))
  615. (map-function-constants c fn (1- depth)))
  616. (t
  617. (funcall fn c))))))
  618. (defun in-constants-p (fun symbol)
  619. (map-function-constants fun
  620. (lambda (c)
  621. (when (eq c symbol)
  622. (return-from in-constants-p t)))
  623. 3))
  624. (defun function-callers (name)
  625. (let ((callers '()))
  626. (do-all-symbols (sym)
  627. (when (fboundp sym)
  628. (let ((fn (fdefinition sym)))
  629. (when (in-constants-p fn name)
  630. (push sym callers)))))
  631. callers))
  632. (defimplementation list-callers (name)
  633. (xref-result (function-callers name)))
  634. (defimplementation list-callees (name)
  635. (let ((result '()))
  636. (map-function-constants (fdefinition name)
  637. (lambda (c)
  638. (when (fboundp c)
  639. (push c result)))
  640. 2)
  641. (xref-result result)))
  642. ;;;; Profiling
  643. ;; Per-function profiling based on description in
  644. ;; http://www.franz.com/support/documentation/8.0/\
  645. ;; doc/runtime-analyzer.htm#data-collection-control-2
  646. (defvar *profiled-functions* ())
  647. (defvar *profile-depth* 0)
  648. (defmacro with-redirected-y-or-n-p (&body body)
  649. ;; If the profiler is restarted when the data from the previous
  650. ;; session is not reported yet, the user is warned via Y-OR-N-P.
  651. ;; As the CL:Y-OR-N-P question is (for some reason) not directly
  652. ;; sent to the Slime user, the function CL:Y-OR-N-P is temporarily
  653. ;; overruled.
  654. `(let* ((pkg (find-package :common-lisp))
  655. (saved-pdl (excl::package-definition-lock pkg))
  656. (saved-ynp (symbol-function 'cl:y-or-n-p)))
  657. (setf (excl::package-definition-lock pkg) nil
  658. (symbol-function 'cl:y-or-n-p)
  659. (symbol-function (read-from-string "swank:y-or-n-p-in-emacs")))
  660. (unwind-protect
  661. (progn ,@body)
  662. (setf (symbol-function 'cl:y-or-n-p) saved-ynp
  663. (excl::package-definition-lock pkg) saved-pdl))))
  664. (defun start-acl-profiler ()
  665. (with-redirected-y-or-n-p
  666. (prof:start-profiler :type :time :count t
  667. :start-sampling-p nil :verbose nil)))
  668. (defun acl-profiler-active-p ()
  669. (not (eq (prof:profiler-status :verbose nil) :inactive)))
  670. (defun stop-acl-profiler ()
  671. (prof:stop-profiler :verbose nil))
  672. (excl:def-fwrapper profile-fwrapper (&rest args)
  673. ;; Ensures sampling is done during the execution of the function,
  674. ;; taking into account recursion.
  675. (declare (ignore args))
  676. (cond ((zerop *profile-depth*)
  677. (let ((*profile-depth* (1+ *profile-depth*)))
  678. (prof:start-sampling)
  679. (unwind-protect (excl:call-next-fwrapper)
  680. (prof:stop-sampling))))
  681. (t
  682. (excl:call-next-fwrapper))))
  683. (defimplementation profile (fname)
  684. (unless (acl-profiler-active-p)
  685. (start-acl-profiler))
  686. (excl:fwrap fname 'profile-fwrapper 'profile-fwrapper)
  687. (push fname *profiled-functions*))
  688. (defimplementation profiled-functions ()
  689. *profiled-functions*)
  690. (defimplementation unprofile (fname)
  691. (excl:funwrap fname 'profile-fwrapper)
  692. (setq *profiled-functions* (remove fname *profiled-functions*)))
  693. (defimplementation profile-report ()
  694. (prof:show-flat-profile :verbose nil)
  695. (when *profiled-functions*
  696. (start-acl-profiler)))
  697. (defimplementation profile-reset ()
  698. (when (acl-profiler-active-p)
  699. (stop-acl-profiler)
  700. (start-acl-profiler))
  701. "Reset profiling counters.")
  702. ;;;; Inspecting
  703. (excl:without-redefinition-warnings
  704. (defmethod emacs-inspect ((o t))
  705. (allegro-inspect o)))
  706. (defmethod emacs-inspect ((o function))
  707. (allegro-inspect o))
  708. (defmethod emacs-inspect ((o standard-object))
  709. (allegro-inspect o))
  710. (defun allegro-inspect (o)
  711. (loop for (d dd) on (inspect::inspect-ctl o)
  712. append (frob-allegro-field-def o d)
  713. until (eq d dd)))
  714. (defun frob-allegro-field-def (object def)
  715. (with-struct (inspect::field-def- name type access) def
  716. (ecase type
  717. ((:unsigned-word :unsigned-byte :unsigned-natural
  718. :unsigned-long :unsigned-half-long
  719. :unsigned-3byte :unsigned-long32)
  720. (label-value-line name (inspect::component-ref-v object access type)))
  721. ((:lisp :value :func)
  722. (label-value-line name (inspect::component-ref object access)))
  723. (:indirect
  724. (destructuring-bind (prefix count ref set) access
  725. (declare (ignore set prefix))
  726. (loop for i below (funcall count object)
  727. append (label-value-line (format nil "~A-~D" name i)
  728. (funcall ref object i))))))))
  729. ;;;; Multithreading
  730. (defimplementation initialize-multiprocessing (continuation)
  731. (mp:start-scheduler)
  732. (funcall continuation))
  733. (defimplementation spawn (fn &key name)
  734. (mp:process-run-function name fn))
  735. (defvar *id-lock* (mp:make-process-lock :name "id lock"))
  736. (defvar *thread-id-counter* 0)
  737. (defimplementation thread-id (thread)
  738. (mp:with-process-lock (*id-lock*)
  739. (or (getf (mp:process-property-list thread) 'id)
  740. (setf (getf (mp:process-property-list thread) 'id)
  741. (incf *thread-id-counter*)))))
  742. (defimplementation find-thread (id)
  743. (find id mp:*all-processes*
  744. :key (lambda (p) (getf (mp:process-property-list p) 'id))))
  745. (defimplementation thread-name (thread)
  746. (mp:process-name thread))
  747. (defimplementation thread-status (thread)
  748. (princ-to-string (mp:process-whostate thread)))
  749. (defimplementation thread-attributes (thread)
  750. (list :priority (mp:process-priority thread)
  751. :times-resumed (mp:process-times-resumed thread)))
  752. (defimplementation make-lock (&key name)
  753. (mp:make-process-lock :name name))
  754. (defimplementation call-with-lock-held (lock function)
  755. (mp:with-process-lock (lock) (funcall function)))
  756. (defimplementation current-thread ()
  757. mp:*current-process*)
  758. (defimplementation all-threads ()
  759. (copy-list mp:*all-processes*))
  760. (defimplementation interrupt-thread (thread fn)
  761. (mp:process-interrupt thread fn))
  762. (defimplementation kill-thread (thread)
  763. (mp:process-kill thread))
  764. (defvar *mailbox-lock* (mp:make-process-lock :name "mailbox lock"))
  765. (defstruct (mailbox (:conc-name mailbox.))
  766. (lock (mp:make-process-lock :name "process mailbox"))
  767. (queue '() :type list)
  768. (gate (mp:make-gate nil)))
  769. (defun mailbox (thread)
  770. "Return THREAD's mailbox."
  771. (mp:with-process-lock (*mailbox-lock*)
  772. (or (getf (mp:process-property-list thread) 'mailbox)
  773. (setf (getf (mp:process-property-list thread) 'mailbox)
  774. (make-mailbox)))))
  775. (defimplementation send (thread message)
  776. (let* ((mbox (mailbox thread)))
  777. (mp:with-process-lock ((mailbox.lock mbox))
  778. (setf (mailbox.queue mbox)
  779. (nconc (mailbox.queue mbox) (list message)))
  780. (mp:open-gate (mailbox.gate mbox)))))
  781. (defimplementation receive-if (test &optional timeout)
  782. (let ((mbox (mailbox mp:*current-process*)))
  783. (assert (or (not timeout) (eq timeout t)))
  784. (loop
  785. (check-slime-interrupts)
  786. (mp:with-process-lock ((mailbox.lock mbox))
  787. (let* ((q (mailbox.queue mbox))
  788. (tail (member-if test q)))
  789. (when tail
  790. (setf (mailbox.queue mbox) (nconc (ldiff q tail) (cdr tail)))
  791. (return (car tail)))
  792. (mp:close-gate (mailbox.gate mbox))))
  793. (when (eq timeout t) (return (values nil t)))
  794. (mp:process-wait-with-timeout "receive-if" 0.5
  795. #'mp:gate-open-p (mailbox.gate mbox)))))
  796. (let ((alist '())
  797. (lock (mp:make-process-lock :name "register-thread")))
  798. (defimplementation register-thread (name thread)
  799. (declare (type symbol name))
  800. (mp:with-process-lock (lock)
  801. (etypecase thread
  802. (null
  803. (setf alist (delete name alist :key #'car)))
  804. (mp:process
  805. (let ((probe (assoc name alist)))
  806. (cond (probe (setf (cdr probe) thread))
  807. (t (setf alist (acons name thread alist))))))))
  808. nil)
  809. (defimplementation find-registered (name)
  810. (mp:with-process-lock (lock)
  811. (cdr (assoc name alist)))))
  812. (defimplementation set-default-initial-binding (var form)
  813. (push (cons var form)
  814. #+(version>= 9 0)
  815. excl:*required-thread-bindings*
  816. #-(version>= 9 0)
  817. excl::required-thread-bindings))
  818. (defimplementation quit-lisp ()
  819. (excl:exit 0 :quiet t))
  820. ;;Trace implementations
  821. ;;In Allegro 7.0, we have:
  822. ;; (trace <name>)
  823. ;; (trace ((method <name> <qualifier>? (<specializer>+))))
  824. ;; (trace ((labels <name> <label-name>)))
  825. ;; (trace ((labels (method <name> (<specializer>+)) <label-name>)))
  826. ;; <name> can be a normal name or a (setf name)
  827. (defimplementation toggle-trace (spec)
  828. (ecase (car spec)
  829. ((setf)
  830. (toggle-trace-aux spec))
  831. (:defgeneric (toggle-trace-generic-function-methods (second spec)))
  832. ((setf :defmethod :labels :flet)
  833. (toggle-trace-aux (process-fspec-for-allegro spec)))
  834. (:call
  835. (destructuring-bind (caller callee) (cdr spec)
  836. (toggle-trace-aux callee
  837. :inside (list (process-fspec-for-allegro caller)))))))
  838. (defun tracedp (fspec)
  839. (member fspec (eval '(trace)) :test #'equal))
  840. (defun toggle-trace-aux (fspec &rest args)
  841. (cond ((tracedp fspec)
  842. (eval `(untrace ,fspec))
  843. (format nil "~S is now untraced." fspec))
  844. (t
  845. (eval `(trace (,fspec ,@args)))
  846. (format nil "~S is now traced." fspec))))
  847. (defun toggle-trace-generic-function-methods (name)
  848. (let ((methods (mop:generic-function-methods (fdefinition name))))
  849. (cond ((tracedp name)
  850. (eval `(untrace ,name))
  851. (dolist (method methods (format nil "~S is now untraced." name))
  852. (excl:funtrace (mop:method-function method))))
  853. (t
  854. (eval `(trace (,name)))
  855. (dolist (method methods (format nil "~S is now traced." name))
  856. (excl:ftrace (mop:method-function method)))))))
  857. (defun process-fspec-for-allegro (fspec)
  858. (cond ((consp fspec)
  859. (ecase (first fspec)
  860. ((setf) fspec)
  861. ((:defun :defgeneric) (second fspec))
  862. ((:defmethod) `(method ,@(rest fspec)))
  863. ((:labels) `(labels ,(process-fspec-for-allegro (second fspec))
  864. ,(third fspec)))
  865. ((:flet) `(flet ,(process-fspec-for-allegro (second fspec))
  866. ,(third fspec)))))
  867. (t
  868. fspec)))
  869. ;;;; Weak hashtables
  870. (defimplementation make-weak-key-hash-table (&rest args)
  871. (apply #'make-hash-table :weak-keys t args))
  872. (defimplementation make-weak-value-hash-table (&rest args)
  873. (apply #'make-hash-table :values :weak args))
  874. (defimplementation hash-table-weakness (hashtable)
  875. (cond ((excl:hash-table-weak-keys hashtable) :key)
  876. ((eq (excl:hash-table-values hashtable) :weak) :value)))
  877. ;;;; Character names
  878. (defimplementation character-completion-set (prefix matchp)
  879. (loop for name being the hash-keys of excl::*name-to-char-table*
  880. when (funcall matchp prefix name)
  881. collect (string-capitalize name)))
  882. ;;;; wrap interface implementation
  883. (defimplementation wrap (spec indicator &key before after replace)
  884. (let ((allegro-spec (process-fspec-for-allegro spec)))
  885. (excl:fwrap allegro-spec
  886. indicator
  887. (excl:def-fwrapper allegro-wrapper (&rest args)
  888. (let (retlist completed)
  889. (unwind-protect
  890. (progn
  891. (when before
  892. (funcall before args))
  893. (setq retlist (multiple-value-list
  894. (if replace
  895. (funcall replace args)
  896. (excl:call-next-fwrapper))))
  897. (setq completed t)
  898. (values-list retlist))
  899. (when after
  900. (funcall after (if completed
  901. retlist
  902. :exited-non-locally)))))))
  903. allegro-spec))
  904. (defimplementation unwrap (spec indicator)
  905. (let ((allegro-spec (process-fspec-for-allegro spec)))
  906. (excl:funwrap allegro-spec indicator)
  907. allegro-spec))
  908. (defimplementation wrapped-p (spec indicator)
  909. (getf (excl:fwrap-order (process-fspec-for-allegro spec)) indicator))