PageRenderTime 52ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/local-lisp/slime/swank-allegro.lisp

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