PageRenderTime 63ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/local-lisp/slime/contrib/swank-kawa.scm

https://bitbucket.org/sakito/dot.emacs.d/
Scheme | 2174 lines | 1738 code | 251 blank | 185 comment | 2 complexity | d55a8867a508e1d528cdf1f8c1e0d728 MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-4.0, GPL-2.0, Unlicense
  1. ;;;; swank-kawa.scm --- Swank server for Kawa
  2. ;;;
  3. ;;; Copyright (C) 2007 Helmut Eller
  4. ;;;
  5. ;;; This file is licensed under the terms of the GNU General Public
  6. ;;; License as distributed with Emacs (press C-h C-c for details).
  7. ;;;; Installation
  8. ;;
  9. ;; 1. You need Kawa (SVN version)
  10. ;; and a Sun JVM with debugger support.
  11. ;; 2. Compile this file with:
  12. ;; kawa -e '(compile-file "swank-kawa.scm" "swank-kawa")'
  13. ;; 3. Add something like this to your .emacs:
  14. #|
  15. ;; Kawa and the debugger classes (tools.jar) must be in the classpath.
  16. ;; You also need to start the debug agent.
  17. (setq slime-lisp-implementations
  18. '((kawa ("java"
  19. "-cp" "/opt/kawa/kawa-svn:/opt/java/jdk1.6.0/lib/tools.jar"
  20. "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n"
  21. "kawa.repl" "-s")
  22. :init kawa-slime-init)))
  23. (defun kawa-slime-init (file _)
  24. (setq slime-protocol-version 'ignore)
  25. (let ((zip ".../slime/contrib/swank-kawa.zip")) ; <-- insert the right path
  26. (format "%S\n"
  27. `(begin (load ,(expand-file-name zip)) (start-swank ,file)))))
  28. |#
  29. ;; 4. Start everything with M-- M-x slime kawa
  30. ;;
  31. ;;
  32. ;;;; Module declaration
  33. (module-export start-swank create-swank-server swank-java-source-path)
  34. (module-static #t)
  35. (module-compile-options
  36. warn-invoke-unknown-method: #t
  37. warn-undefined-variable: #t
  38. )
  39. (require 'hash-table)
  40. ;;;; Macros ()
  41. (define-syntax df
  42. (syntax-rules (=>)
  43. ((df name (args ... => return-type) body ...)
  44. (define (name args ...) :: return-type body ...))
  45. ((df name (args ...) body ...)
  46. (define (name args ...) body ...))))
  47. (define-syntax fun
  48. (syntax-rules ()
  49. ((fun (args ...) body ...)
  50. (lambda (args ...) body ...))))
  51. (define-syntax fin
  52. (syntax-rules ()
  53. ((fin body handler ...)
  54. (try-finally body (seq handler ...)))))
  55. (define-syntax seq
  56. (syntax-rules ()
  57. ((seq body ...)
  58. (begin body ...))))
  59. (define-syntax esc
  60. (syntax-rules ()
  61. ((esc abort body ...)
  62. (let* ((key (<symbol>))
  63. (abort (lambda (val) (throw key val))))
  64. (catch key
  65. (lambda () body ...)
  66. (lambda (key val) val))))))
  67. (define-syntax !
  68. (syntax-rules ()
  69. ((! name obj args ...)
  70. (invoke obj 'name args ...))))
  71. (define-syntax !!
  72. (syntax-rules ()
  73. ((!! name1 name2 obj args ...)
  74. (! name1 (! name2 obj args ...)))))
  75. (define-syntax @
  76. (syntax-rules ()
  77. ((@ name obj)
  78. (field obj 'name))))
  79. (define-syntax while
  80. (syntax-rules ()
  81. ((while exp body ...)
  82. (do () ((not exp)) body ...))))
  83. (define-syntax dotimes
  84. (syntax-rules ()
  85. ((dotimes (i n result) body ...)
  86. (let ((max :: <int> n))
  87. (do ((i :: <int> 0 (as <int> (+ i 1))))
  88. ((= i max) result)
  89. body ...)))
  90. ((dotimes (i n) body ...)
  91. (dotimes (i n #f) body ...))))
  92. (define-syntax dolist
  93. (syntax-rules ()
  94. ((dolist (e list) body ... )
  95. (for ((e list)) body ...))))
  96. (define-syntax for
  97. (syntax-rules ()
  98. ((for ((var iterable)) body ...)
  99. (let ((iter (! iterator iterable)))
  100. (while (! has-next iter)
  101. ((lambda (var) body ...)
  102. (! next iter)))))))
  103. (define-syntax packing
  104. (syntax-rules ()
  105. ((packing (var) body ...)
  106. (let ((var :: <list> '()))
  107. (let ((var (lambda (v) (set! var (cons v var)))))
  108. body ...)
  109. (reverse! var)))))
  110. ;;(define-syntax loop
  111. ;; (syntax-rules (for = then collect until)
  112. ;; ((loop for var = init then step until test collect exp)
  113. ;; (packing (pack)
  114. ;; (do ((var init step))
  115. ;; (test)
  116. ;; (pack exp))))
  117. ;; ((loop while test collect exp)
  118. ;; (packing (pack) (while test (pack exp))))))
  119. (define-syntax with
  120. (syntax-rules ()
  121. ((with (vars ... (f args ...)) body ...)
  122. (f args ... (lambda (vars ...) body ...)))))
  123. (define-syntax pushf
  124. (syntax-rules ()
  125. ((pushf value var)
  126. (set! var (cons value var)))))
  127. (define-syntax ==
  128. (syntax-rules ()
  129. ((== x y)
  130. (eq? x y))))
  131. (define-syntax set
  132. (syntax-rules ()
  133. ((set x y)
  134. (let ((tmp y))
  135. (set! x tmp)
  136. tmp))
  137. ((set x y more ...)
  138. (begin (set! x y) (set more ...)))))
  139. (define-syntax assert
  140. (syntax-rules ()
  141. ((assert test)
  142. (seq
  143. (when (not test)
  144. (error "Assertion failed" 'test))
  145. 'ok))
  146. ((assert test fstring args ...)
  147. (seq
  148. (when (not test)
  149. (error "Assertion failed" 'test (format #f fstring args ...)))
  150. 'ok))))
  151. (define-syntax mif
  152. (syntax-rules (quote unquote _)
  153. ((mif ('x value) then else)
  154. (if (equal? 'x value) then else))
  155. ((mif (,x value) then else)
  156. (if (eq? x value) then else))
  157. ((mif (() value) then else)
  158. (if (eq? value '()) then else))
  159. #| This variant produces no lambdas but breaks the compiler
  160. ((mif ((p . ps) value) then else)
  161. (let ((tmp value)
  162. (fail? :: <int> 0)
  163. (result #!null))
  164. (if (instance? tmp <pair>)
  165. (let ((tmp :: <pair> tmp))
  166. (mif (p (@ car tmp))
  167. (mif (ps (@ cdr tmp))
  168. (set! result then)
  169. (set! fail? -1))
  170. (set! fail? -1)))
  171. (set! fail? -1))
  172. (if (= fail? 0) result else)))
  173. |#
  174. ((mif ((p . ps) value) then else)
  175. (let ((fail (lambda () else))
  176. (tmp value))
  177. (if (instance? tmp <pair>)
  178. (let ((tmp :: <pair> tmp))
  179. (mif (p (@ car tmp))
  180. (mif (ps (@ cdr tmp))
  181. then
  182. (fail))
  183. (fail)))
  184. (fail))))
  185. ((mif (_ value) then else)
  186. then)
  187. ((mif (var value) then else)
  188. (let ((var value)) then))
  189. ((mif (pattern value) then)
  190. (mif (pattern value) then (values)))))
  191. (define-syntax mcase
  192. (syntax-rules ()
  193. ((mcase exp (pattern body ...) more ...)
  194. (let ((tmp exp))
  195. (mif (pattern tmp)
  196. (begin body ...)
  197. (mcase tmp more ...))))
  198. ((mcase exp) (ferror "mcase failed ~s\n~a" 'exp (pprint-to-string exp)))))
  199. (define-syntax mlet
  200. (syntax-rules ()
  201. ((mlet (pattern value) body ...)
  202. (let ((tmp value))
  203. (mif (pattern tmp)
  204. (begin body ...)
  205. (error "mlet failed" tmp))))))
  206. (define-syntax mlet*
  207. (syntax-rules ()
  208. ((mlet* () body ...) (begin body ...))
  209. ((mlet* ((pattern value) ms ...) body ...)
  210. (mlet (pattern value) (mlet* (ms ...) body ...)))))
  211. (define-syntax typecase
  212. (syntax-rules (::)
  213. ((typecase var (type body ...) ...)
  214. (cond ((instance? var type)
  215. (let ((var :: type var))
  216. body ...))
  217. ...
  218. (else (error "typecase failed" var
  219. (! getClass (as <object> var))))))))
  220. (define-syntax ignore-errors
  221. (syntax-rules ()
  222. ((ignore-errors body ...)
  223. (try-catch (begin body ...)
  224. (v <java.lang.Exception> #f)))))
  225. ;;(define-syntax dc
  226. ;; (syntax-rules ()
  227. ;; ((dc name () %% (props ...) prop more ...)
  228. ;; (dc name () %% (props ... (prop <object>)) more ...))
  229. ;; ;;((dc name () %% (props ...) (prop type) more ...)
  230. ;; ;; (dc name () %% (props ... (prop type)) more ...))
  231. ;; ((dc name () %% ((prop type) ...))
  232. ;; (define-simple-class name ()
  233. ;; ((*init* (prop :: type) ...)
  234. ;; (set (field (this) 'prop) prop) ...)
  235. ;; (prop :type type) ...))
  236. ;; ((dc name () props ...)
  237. ;; (dc name () %% () props ...))))
  238. ;;;; Aliases
  239. (define-alias <server-socket> <java.net.ServerSocket>)
  240. (define-alias <socket> <java.net.Socket>)
  241. (define-alias <in> <java.io.InputStreamReader>)
  242. (define-alias <out> <java.io.OutputStreamWriter>)
  243. (define-alias <file> <java.io.File>)
  244. (define-alias <str> <java.lang.String>)
  245. (define-alias <builder> <java.lang.StringBuilder>)
  246. (define-alias <throwable> <java.lang.Throwable>)
  247. (define-alias <source-error> <gnu.text.SourceError>)
  248. (define-alias <module-info> <gnu.expr.ModuleInfo>)
  249. (define-alias <iterable> <java.lang.Iterable>)
  250. (define-alias <thread> <java.lang.Thread>)
  251. (define-alias <queue> <java.util.concurrent.LinkedBlockingQueue>)
  252. (define-alias <exchanger> <java.util.concurrent.Exchanger>)
  253. (define-alias <timeunit> <java.util.concurrent.TimeUnit>)
  254. (define-alias <vm> <com.sun.jdi.VirtualMachine>)
  255. (define-alias <mirror> <com.sun.jdi.Mirror>)
  256. (define-alias <value> <com.sun.jdi.Value>)
  257. (define-alias <thread-ref> <com.sun.jdi.ThreadReference>)
  258. (define-alias <obj-ref> <com.sun.jdi.ObjectReference>)
  259. (define-alias <array-ref> <com.sun.jdi.ArrayReference>)
  260. (define-alias <str-ref> <com.sun.jdi.StringReference>)
  261. (define-alias <meth-ref> <com.sun.jdi.Method>)
  262. (define-alias <class-ref> <com.sun.jdi.ClassType>)
  263. (define-alias <frame> <com.sun.jdi.StackFrame>)
  264. (define-alias <field> <com.sun.jdi.Field>)
  265. (define-alias <local-var> <com.sun.jdi.LocalVariable>)
  266. (define-alias <location> <com.sun.jdi.Location>)
  267. (define-alias <absent-exc> <com.sun.jdi.AbsentInformationException>)
  268. (define-alias <ref-type> <com.sun.jdi.ReferenceType>)
  269. (define-alias <event> <com.sun.jdi.event.Event>)
  270. (define-alias <exception-event> <com.sun.jdi.event.ExceptionEvent>)
  271. (define-alias <step-event> <com.sun.jdi.event.StepEvent>)
  272. (define-alias <env> <gnu.mapping.Environment>)
  273. (define-simple-class <chan> ()
  274. (owner :: <thread> init: (java.lang.Thread:currentThread))
  275. (peer :: <chan>)
  276. (queue :: <queue> init: (<queue>))
  277. (lock init: (<object>)))
  278. ;;;; Entry Points
  279. (df create-swank-server (port-number)
  280. (setup-server port-number announce-port))
  281. (df start-swank (port-file)
  282. (let ((announce (fun ((socket <server-socket>))
  283. (with (f (call-with-output-file port-file))
  284. (format f "~d\n" (! get-local-port socket))))))
  285. (spawn (fun ()
  286. (setup-server 0 announce)))))
  287. (df setup-server ((port-number <int>) announce)
  288. (! set-name (current-thread) "swank")
  289. (let ((s (<server-socket> port-number)))
  290. (announce s)
  291. (let ((c (! accept s)))
  292. (! close s)
  293. (log "connection: ~s\n" c)
  294. (fin (dispatch-events c)
  295. (log "closing socket: ~a\n" s)
  296. (! close c)))))
  297. (df announce-port ((socket <server-socket>))
  298. (log "Listening on port: ~d\n" (! get-local-port socket)))
  299. ;;;; Event dispatcher
  300. (define-variable *the-vm* #f)
  301. (define-variable *last-exception* #f)
  302. (define-variable *last-stacktrace* #f)
  303. ;; FIXME: this needs factorization. But I guess the whole idea of
  304. ;; using bidirectional channels just sucks. Mailboxes owned by a
  305. ;; single thread to which everybody can send are much easier to use.
  306. (df dispatch-events ((s <socket>))
  307. (mlet* ((charset "iso-8859-1")
  308. (ins (<in> (! getInputStream s) charset))
  309. (outs (<out> (! getOutputStream s) charset))
  310. ((in . _) (spawn/chan/catch (fun (c) (reader ins c))))
  311. ((out . _) (spawn/chan/catch (fun (c) (writer outs c))))
  312. ((dbg . _) (spawn/chan/catch vm-monitor))
  313. (user-env (interaction-environment))
  314. (x (seq
  315. (! set-flag user-env #t #|<env>:THREAD_SAFE|# 8)
  316. (! set-flag user-env #f #|<env>:DIRECT_INHERITED_ON_SET|# 16)))
  317. ((listener . _)
  318. (spawn/chan (fun (c) (listener c user-env))))
  319. (inspector #f)
  320. (threads '())
  321. (repl-thread #f)
  322. (extra '())
  323. (vm (let ((vm #f)) (fun () (or vm (rpc dbg `(get-vm)))))))
  324. (while #t
  325. (mlet ((c . event) (recv* (append (list in out dbg listener)
  326. (if inspector (list inspector) '())
  327. (map car threads)
  328. extra)))
  329. ;;(log "event: ~s\n" event)
  330. (mcase (list c event)
  331. ((_ (':emacs-rex ('|swank:debugger-info-for-emacs| from to)
  332. pkg thread id))
  333. (send dbg `(debug-info ,thread ,from ,to ,id)))
  334. ((_ (':emacs-rex ('|swank:throw-to-toplevel|) pkg thread id))
  335. (send dbg `(throw-to-toplevel ,thread ,id)))
  336. ((_ (':emacs-rex ('|swank:sldb-continue|) pkg thread id))
  337. (send dbg `(thread-continue ,thread ,id)))
  338. ((_ (':emacs-rex ('|swank:frame-source-location| frame)
  339. pkg thread id))
  340. (send dbg `(frame-src-loc ,thread ,frame ,id)))
  341. ((_ (':emacs-rex ('|swank:frame-locals-and-catch-tags| frame)
  342. pkg thread id))
  343. (send dbg `(frame-details ,thread ,frame ,id)))
  344. ((_ (':emacs-rex ('|swank:sldb-disassemble| frame)
  345. pkg thread id))
  346. (send dbg `(disassemble-frame ,thread ,frame ,id)))
  347. ((_ (':emacs-rex ('|swank:backtrace| from to) pkg thread id))
  348. (send dbg `(thread-frames ,thread ,from ,to ,id)))
  349. ((_ (':emacs-rex ('|swank:list-threads|) pkg thread id))
  350. (send dbg `(list-threads ,id)))
  351. ((_ (':emacs-rex ('|swank:debug-nth-thread| n) _ _ _))
  352. (send dbg `(debug-nth-thread ,n)))
  353. ((_ (':emacs-rex ('|swank:quit-thread-browser|) _ _ id))
  354. (send dbg `(quit-thread-browser ,id)))
  355. ((_ (':emacs-rex ('|swank:init-inspector| str . _) pkg _ id))
  356. (set inspector (make-inspector user-env (vm)))
  357. (send inspector `(init ,str ,id)))
  358. ((_ (':emacs-rex ('|swank:inspect-frame-var| frame var)
  359. pkg thread id))
  360. (mlet ((im . ex) (chan))
  361. (set inspector (make-inspector user-env (vm)))
  362. (send dbg `(get-local ,ex ,thread ,frame ,var))
  363. (send inspector `(init-mirror ,im ,id))))
  364. ((_ (':emacs-rex ('|swank:inspect-current-condition|) pkg thread id))
  365. (mlet ((im . ex) (chan))
  366. (set inspector (make-inspector user-env (vm)))
  367. (send dbg `(get-exception ,ex ,thread))
  368. (send inspector `(init-mirror ,im ,id))))
  369. ((_ (':emacs-rex ('|swank:inspect-nth-part| n) pkg _ id))
  370. (send inspector `(inspect-part ,n ,id)))
  371. ((_ (':emacs-rex ('|swank:inspector-pop|) pkg _ id))
  372. (send inspector `(pop ,id)))
  373. ((_ (':emacs-rex ('|swank:quit-inspector|) pkg _ id))
  374. (send inspector `(quit ,id)))
  375. ((_ (':emacs-interrupt id))
  376. (let* ((vm (vm))
  377. (t (find-thread id (map cdr threads) repl-thread vm)))
  378. (send dbg `(debug-thread ,t))))
  379. ((_ (':emacs-rex form _ _ id))
  380. (send listener `(,form ,id)))
  381. ((_ ('get-vm c))
  382. (send dbg `(get-vm ,c)))
  383. ((_ ('get-channel c))
  384. (mlet ((im . ex) (chan))
  385. (pushf im extra)
  386. (send c ex)))
  387. ((_ ('forward x))
  388. (send out x))
  389. ((_ ('set-listener x))
  390. (set repl-thread x))
  391. ((_ ('publish-vm vm))
  392. (set *the-vm* vm))
  393. )))))
  394. (df find-thread (id threads listener (vm <vm>))
  395. (cond ((== id ':repl-thread) listener)
  396. ((== id 't) listener
  397. ;;(if (null? threads)
  398. ;; listener
  399. ;; (vm-mirror vm (car threads)))
  400. )
  401. (#t
  402. (let ((f (find-if threads
  403. (fun (t :: <thread>)
  404. (= id (! uniqueID
  405. (as <thread-ref> (vm-mirror vm t)))))
  406. #f)))
  407. (cond (f (vm-mirror vm f))
  408. (#t listener))))))
  409. ;;;; Reader thread
  410. (df reader ((in <in>) (c <chan>))
  411. (! set-name (current-thread) "swank-net-reader")
  412. (let ((rt (gnu.kawa.lispexpr.ReadTable:createInitial))) ; ':' not special
  413. (while #t
  414. (send c (decode-message in rt)))))
  415. (df decode-message ((in <in>) (rt <gnu.kawa.lispexpr.ReadTable>) => <list>)
  416. (let* ((header (read-chunk in 6))
  417. (len (java.lang.Integer:parseInt header 16)))
  418. (call-with-input-string (read-chunk in len)
  419. (fun ((port <input-port>))
  420. (%read port rt)))))
  421. (df read-chunk ((in <in>) (len <int>) => <str>)
  422. (let ((chars (<char[]> length: len)))
  423. (let loop ((offset :: <int> 0))
  424. (cond ((= offset len) (<str> chars))
  425. (#t (let ((count (! read in chars offset (- len offset))))
  426. (assert (not (= count -1)) "partial packet")
  427. (loop (+ offset count))))))))
  428. ;;; FIXME: not thread safe
  429. (df %read ((port <gnu.mapping.InPort>) (table <gnu.kawa.lispexpr.ReadTable>))
  430. (let ((old (gnu.kawa.lispexpr.ReadTable:getCurrent)))
  431. (try-finally
  432. (seq (gnu.kawa.lispexpr.ReadTable:setCurrent table)
  433. (read port))
  434. (gnu.kawa.lispexpr.ReadTable:setCurrent old))))
  435. ;;;; Writer thread
  436. (df writer ((out <out>) (c <chan>))
  437. (! set-name (current-thread) "swank-net-writer")
  438. (while #t
  439. (encode-message out (recv c))))
  440. (df encode-message ((out <out>) (message <list>))
  441. (let ((builder (<builder> (as <int> 512))))
  442. (print-for-emacs message builder)
  443. (! write out (! toString (format "~6,'0x" (! length builder))))
  444. (! write out builder)
  445. (! flush out)))
  446. (df print-for-emacs (obj (out <builder>))
  447. (let ((pr (fun (o) (! append out (! toString (format "~s" o)))))
  448. (++ (fun ((s <string>)) (! append out (! toString s)))))
  449. (cond ((null? obj) (++ "nil"))
  450. ((string? obj) (pr obj))
  451. ((number? obj) (pr obj))
  452. ;;((keyword? obj) (++ ":") (! append out (to-str obj)))
  453. ((symbol? obj) (pr obj))
  454. ((pair? obj)
  455. (++ "(")
  456. (let loop ((obj obj))
  457. (print-for-emacs (car obj) out)
  458. (let ((cdr (cdr obj)))
  459. (cond ((null? cdr) (++ ")"))
  460. ((pair? cdr) (++ " ") (loop cdr))
  461. (#t (++ " . ") (print-for-emacs cdr out) (++ ")"))))))
  462. (#t (error "Unprintable object" obj)))))
  463. ;;;; SLIME-EVAL
  464. (df eval-for-emacs ((form <list>) env (id <int>) (c <chan>))
  465. ;;(! set-uncaught-exception-handler (current-thread)
  466. ;; (<ucex-handler> (fun (t e) (reply-abort c id))))
  467. (reply c (%eval form env) id))
  468. (define-variable *slime-funs*)
  469. (set *slime-funs* (tab))
  470. (df %eval (form env)
  471. (apply (lookup-slimefun (car form) *slime-funs*) env (cdr form)))
  472. (df lookup-slimefun ((name <symbol>) tab)
  473. ;; name looks like '|swank:connection-info|
  474. (let* ((str (symbol->string name))
  475. (sub (substring str 6 (string-length str))))
  476. (or (get tab (string->symbol sub) #f)
  477. (ferror "~a not implemented" sub))))
  478. (define-syntax defslimefun
  479. (syntax-rules ()
  480. ((defslimefun name (args ...) body ...)
  481. (seq
  482. (df name (args ...) body ...)
  483. (put *slime-funs* 'name name)))))
  484. (defslimefun connection-info ((env <env>))
  485. (let ((prop java.lang.System:getProperty))
  486. `(:pid
  487. 0
  488. :style :spawn
  489. :lisp-implementation (:type "Kawa" :name "kawa"
  490. :version ,(scheme-implementation-version))
  491. :machine (:instance ,(prop "java.vm.name") :type ,(prop "os.name")
  492. :version ,(prop "java.runtime.version"))
  493. :features ()
  494. :package (:name "??" :prompt ,(! getName env)))))
  495. ;;;; Listener
  496. (df listener ((c <chan>) (env <env>))
  497. (! set-name (current-thread) "swank-listener")
  498. (log "listener: ~s ~s ~s ~s\n"
  499. (current-thread) ((current-thread):hashCode) c env)
  500. (let ((out (make-swank-outport (rpc c `(get-channel)))))
  501. ;;(set (current-output-port) out)
  502. (let ((vm (as <vm> (rpc c `(get-vm)))))
  503. (send c `(set-listener ,(vm-mirror vm (current-thread))))
  504. (enable-uncaught-exception-events vm))
  505. (rpc c `(get-vm))
  506. (listener-loop c env out)))
  507. (df listener-loop ((c <chan>) (env <env>) port)
  508. (while (not (nul? c))
  509. ;;(log "listener-loop: ~s ~s\n" (current-thread) c)
  510. (mlet ((form id) (recv c))
  511. (let ((restart (fun ()
  512. (close-output-port port)
  513. (reply-abort c id)
  514. (send (car (spawn/chan
  515. (fun (cc)
  516. (listener (recv cc) env))))
  517. c)
  518. (set c #!null))))
  519. (! set-uncaught-exception-handler (current-thread)
  520. (<ucex-handler> (fun (t e) (restart))))
  521. (try-catch
  522. (let* ((val (%eval form env)))
  523. (force-output)
  524. (reply c val id))
  525. (ex <listener-abort>
  526. (let ((flag (java.lang.Thread:interrupted)))
  527. (log "listener-abort: ~s ~a\n" ex flag))
  528. (restart)))))))
  529. (defslimefun create-repl (env #!rest _)
  530. (list "user" "user"))
  531. (defslimefun interactive-eval (env str)
  532. (values-for-echo-area (eval (read-from-string str) env)))
  533. (defslimefun interactive-eval-region (env (s <string>))
  534. (with (port (call-with-input-string s))
  535. (values-for-echo-area
  536. (let next ((result (values)))
  537. (let ((form (read port)))
  538. (cond ((== form #!eof) result)
  539. (#t (next (eval form env)))))))))
  540. (defslimefun listener-eval (env string)
  541. (let* ((form (read-from-string string))
  542. (list (values-to-list (eval form env))))
  543. `(:values ,@(map pprint-to-string list))))
  544. (defslimefun pprint-eval (env string)
  545. (let* ((form (read-from-string string))
  546. (l (values-to-list (eval form env))))
  547. (apply cat (map pprint-to-string l))))
  548. (df call-with-abort (f)
  549. (try-catch (f) (ex <throwable> (exception-message ex))))
  550. (df exception-message ((ex <throwable>))
  551. (typecase ex
  552. (<kawa.lang.NamedException> (! to-string ex))
  553. (<throwable> (format "~a: ~a"
  554. (class-name-sans-package ex)
  555. (! getMessage ex)))))
  556. (df values-for-echo-area (values)
  557. (let ((values (values-to-list values)))
  558. (format "~:[=> ~{~s~^, ~}~;; No values~]" (null? values) values)))
  559. ;;;; Compilation
  560. (defslimefun compile-file-for-emacs (env (filename <str>) load?
  561. #!optional options)
  562. (let ((jar (cat (path-sans-extension (filepath filename)) ".jar")))
  563. (wrap-compilation
  564. (fun ((m <gnu.text.SourceMessages>))
  565. (kawa.lang.CompileFile:read filename m))
  566. jar (if (lisp-bool load?) env #f) #f)))
  567. (df wrap-compilation (f jar env delete?)
  568. (let ((start-time (current-time))
  569. (messages (<gnu.text.SourceMessages>)))
  570. (try-catch
  571. (let ((c (as <gnu.expr.Compilation> (f messages))))
  572. (set (@ explicit c) #t)
  573. (! compile-to-archive c (! get-module c) jar))
  574. (ex <throwable>
  575. (log "error during compilation: ~a\n~a" ex (! getStackTrace ex))
  576. (! error messages (as <char> #\f)
  577. (to-str (exception-message ex)) #!null)))
  578. (log "compilation done.\n")
  579. (let ((success? (zero? (! get-error-count messages))))
  580. (when (and env success?)
  581. (log "loading ...\n")
  582. (eval `(load ,jar) env)
  583. (log "loading ... done.\n"))
  584. (when delete?
  585. (ignore-errors (delete-file jar)))
  586. (let ((end-time (current-time)))
  587. (list ':compilation-result
  588. (compiler-notes-for-emacs messages)
  589. (if success? 't 'nil)
  590. (/ (- end-time start-time) 1000.0))))))
  591. (defslimefun compile-string-for-emacs (env string buffer offset dir)
  592. (wrap-compilation
  593. (fun ((m <gnu.text.SourceMessages>))
  594. (let ((c (as <gnu.expr.Compilation>
  595. (call-with-input-string
  596. string
  597. (fun ((p <gnu.mapping.InPort>))
  598. (! set-path p
  599. (format "~s"
  600. `(buffer ,buffer offset ,offset str ,string)))
  601. (kawa.lang.CompileFile:read p m))))))
  602. (let ((o (@ currentOptions c)))
  603. (! set o "warn-invoke-unknown-method" #t)
  604. (! set o "warn-undefined-variable" #t))
  605. (let ((m (! getModule c)))
  606. (! set-name m (format "<emacs>:~a/~a" buffer (current-time))))
  607. c))
  608. "/tmp/kawa-tmp.zip" env #t))
  609. (df compiler-notes-for-emacs ((messages <gnu.text.SourceMessages>))
  610. (packing (pack)
  611. (do ((e (! get-errors messages) (@ next e)))
  612. ((nul? e))
  613. (pack (source-error>elisp e)))))
  614. (df source-error>elisp ((e <source-error>) => <list>)
  615. (list ':message (to-string (@ message e))
  616. ':severity (case (integer->char (@ severity e))
  617. ((#\e #\f) ':error)
  618. ((#\w) ':warning)
  619. (else ':note))
  620. ':location (error-loc>elisp e)))
  621. (df error-loc>elisp ((e <source-error>))
  622. (cond ((nul? (@ filename e)) `(:error "No source location"))
  623. ((! starts-with (@ filename e) "(buffer ")
  624. (mlet (('buffer b 'offset o 'str s) (read-from-string (@ filename e)))
  625. `(:location (:buffer ,b)
  626. (:position ,(+ o (line>offset (1- (@ line e)) s)
  627. (1- (@ column e))))
  628. nil)))
  629. (#t
  630. `(:location (:file ,(to-string (@ filename e)))
  631. (:line ,(@ line e) ,(1- (@ column e)))
  632. nil))))
  633. (df line>offset ((line <int>) (s <str>) => <int>)
  634. (let ((offset :: <int> 0))
  635. (dotimes (i line)
  636. (set offset (! index-of s (as <char> #\newline) offset))
  637. (assert (>= offset 0))
  638. (set offset (as <int> (+ offset 1))))
  639. (log "line=~a offset=~a\n" line offset)
  640. offset))
  641. (defslimefun load-file (env filename)
  642. (format "Loaded: ~a => ~s" filename (eval `(load ,filename) env)))
  643. ;;;; Completion
  644. (defslimefun simple-completions (env (pattern <str>) _)
  645. (let* ((env (as <gnu.mapping.InheritingEnvironment> env))
  646. (matches (packing (pack)
  647. (let ((iter (! enumerate-all-locations env)))
  648. (while (! has-next iter)
  649. (let ((l (! next-location iter)))
  650. (typecase l
  651. (<gnu.mapping.NamedLocation>
  652. (let ((name (!! get-name get-key-symbol l)))
  653. (when (! starts-with name pattern)
  654. (pack name)))))))))))
  655. `(,matches ,(cond ((null? matches) pattern)
  656. (#t (fold+ common-prefix matches))))))
  657. (df common-prefix ((s1 <str>) (s2 <str>) => <str>)
  658. (let ((limit (min (! length s1) (! length s2))))
  659. (let loop ((i 0))
  660. (cond ((or (= i limit)
  661. (not (== (! char-at s1 i)
  662. (! char-at s2 i))))
  663. (! substring s1 0 i))
  664. (#t (loop (1+ i)))))))
  665. (df fold+ (f list)
  666. (let loop ((s (car list))
  667. (l (cdr list)))
  668. (cond ((null? l) s)
  669. (#t (loop (f s (car l)) (cdr l))))))
  670. ;;; Quit
  671. (defslimefun quit-lisp (env)
  672. (exit))
  673. ;;(defslimefun set-default-directory (env newdir))
  674. ;;;; Dummy defs
  675. (defslimefun buffer-first-change (#!rest y) '())
  676. (defslimefun swank-require (#!rest y) '())
  677. ;;;; arglist
  678. (defslimefun operator-arglist (env name #!rest _)
  679. (mcase (try-catch `(ok ,(eval (read-from-string name) env))
  680. (ex <throwable> 'nil))
  681. (('ok obj)
  682. (mcase (arglist obj)
  683. ('#f 'nil)
  684. ((args rtype)
  685. (format "(~a~{~^ ~a~})~a" name
  686. (map (fun (e)
  687. (if (equal (cadr e) "java.lang.Object") (car e) e))
  688. args)
  689. (if (equal rtype "java.lang.Object")
  690. ""
  691. (format " => ~a" rtype))))))
  692. (_ 'nil)))
  693. (df arglist (obj)
  694. (typecase obj
  695. (<gnu.expr.ModuleMethod>
  696. (let* ((mref (module-method>meth-ref obj)))
  697. (list (mapi (! arguments mref)
  698. (fun ((v <local-var>))
  699. (list (! name v) (! typeName v))))
  700. (! returnTypeName mref))))
  701. (<object> #f)))
  702. ;;;; M-.
  703. (defslimefun find-definitions-for-emacs (env name)
  704. (mcase (try-catch `(ok ,(eval (read-from-string name) env))
  705. (ex <throwable> `(error ,(exception-message ex))))
  706. (('ok obj) (mapi (all-definitions obj)
  707. (fun (d)
  708. `(,(format "~a" d) ,(src-loc>elisp (src-loc d))))))
  709. (('error msg) `((,name (:error ,msg))))))
  710. (define-simple-class <swank-location> (<location>)
  711. (file init: #f)
  712. (line init: #f)
  713. ((*init* file name)
  714. (set (@ file (this)) file)
  715. (set (@ line (this)) line))
  716. ((lineNumber) :: <int> (or line (absent)))
  717. ((lineNumber (s <str>)) :: int (! lineNumber (this)))
  718. ((method) :: <meth-ref> (absent))
  719. ((sourcePath) :: <str> (or file (absent)))
  720. ((sourcePath (s <str>)) :: <str> (! sourcePath (this)))
  721. ((sourceName) :: <str> (absent))
  722. ((sourceName (s <str>)) :: <str> (! sourceName (this)))
  723. ((declaringType) :: <ref-type> (absent))
  724. ((codeIndex) :: <long> -1)
  725. ((virtualMachine) :: <vm> *the-vm*)
  726. ((compareTo o) :: <int>
  727. (typecase o
  728. (<location> (- (! codeIndex (this)) (! codeIndex o))))))
  729. (df absent () (primitive-throw (<absent-exc>)))
  730. (df all-definitions (o)
  731. (typecase o
  732. (<gnu.expr.ModuleMethod> (list o))
  733. (<gnu.expr.GenericProc> (append (mappend all-definitions (gf-methods o))
  734. (let ((s (! get-setter o)))
  735. (if s (all-definitions s) '()))))
  736. (<java.lang.Class> (list o))
  737. (<gnu.mapping.Procedure> (all-definitions (! get-class o)))
  738. (<kawa.lang.Macro> (list o))
  739. (<gnu.bytecode.ObjectType> (all-definitions (! getReflectClass o)))
  740. (<java.lang.Object> '())
  741. ))
  742. (df gf-methods ((f <gnu.expr.GenericProc>))
  743. (let* ((o :: <obj-ref> (vm-mirror *the-vm* f))
  744. (f (! field-by-name (! reference-type o) "methods"))
  745. (ms (vm-demirror *the-vm* (! get-value o f))))
  746. (filter (array-to-list ms) (fun (x) (not (nul? x))))))
  747. (df src-loc (o => <location>)
  748. (typecase o
  749. (<gnu.expr.ModuleMethod> (module-method>src-loc o))
  750. (<gnu.expr.GenericProc> (<swank-location> #f #f))
  751. (<java.lang.Class> (class>src-loc o))
  752. (<kawa.lang.Macro> (<swank-location> #f #f))))
  753. (df module-method>src-loc ((f <gnu.expr.ModuleMethod>))
  754. (! location (module-method>meth-ref f)))
  755. (df module-method>meth-ref ((f <gnu.expr.ModuleMethod>) => <meth-ref>)
  756. (let ((module (! reference-type
  757. (as <obj-ref> (vm-mirror *the-vm* (@ module f)))))
  758. (name (mangled-name f)))
  759. (as <meth-ref> (1st (! methods-by-name module name)))))
  760. (df mangled-name ((f <gnu.expr.ModuleMethod>))
  761. (let ((name (gnu.expr.Compilation:mangleName (! get-name f))))
  762. (if (= (! maxArgs f) -1)
  763. (cat name "$V")
  764. name)))
  765. (df class>src-loc ((c <java.lang.Class>) => <location>)
  766. (let* ((type (! reflectedType (as <com.sun.jdi.ClassObjectReference>
  767. (vm-mirror *the-vm* c))))
  768. (locs (! all-line-locations type)))
  769. (cond ((not (! isEmpty locs)) (1st locs))
  770. (#t (<swank-location> (1st (! source-paths type #!null))
  771. #f)))))
  772. (df src-loc>elisp ((l <location>))
  773. (df src-loc>list ((l <location>))
  774. (list (ignore-errors (! source-name l))
  775. (ignore-errors (! source-path l))
  776. (ignore-errors (! line-number l))))
  777. (mcase (src-loc>list l)
  778. ((name path line)
  779. (cond ((not path)
  780. `(:error ,(call-with-abort (fun () (! source-path l)))))
  781. ((! starts-with (as <str> path) "(buffer ")
  782. (mlet (('buffer b 'offset o 'str s) (read-from-string path))
  783. `(:location (:buffer ,b)
  784. (:position ,(+ o (line>offset line s)))
  785. nil)))
  786. (#t
  787. `(:location ,(or (find-file-in-path name (source-path))
  788. (find-file-in-path path (source-path))
  789. (ferror "Can't find source-path: ~s ~s ~a"
  790. path name (source-path)))
  791. (:line ,(or line -1)) ()))))))
  792. (df src-loc>str ((l <location>))
  793. (cond ((nul? l) "<null-location>")
  794. (#t (format "~a ~a ~a"
  795. (or (ignore-errors (! source-path l))
  796. (ignore-errors (! source-name l))
  797. (ignore-errors (!! name declaring-type l)))
  798. (ignore-errors (!! name method l))
  799. (ignore-errors (! lineNumber l))))))
  800. (df ferror (fstring #!rest args)
  801. (primitive-throw (<java.lang.Error> (to-str (apply format fstring args)))))
  802. ;;;;;; class-path hacking
  803. (df find-file-in-path ((filename <str>) (path <list>))
  804. (let ((f (<file> filename)))
  805. (cond ((! isAbsolute f) `(:file ,filename))
  806. (#t (let ((result #f))
  807. (find-if path (fun (dir)
  808. (let ((x (find-file-in-dir f dir)))
  809. (set result x)))
  810. #f)
  811. result)))))
  812. (df find-file-in-dir ((file <file>) (dir <str>))
  813. (let ((filename (! getPath file)))
  814. (or (let ((child (<file> (<file> dir) filename)))
  815. (and (! exists child)
  816. `(:file ,(! getPath child))))
  817. (try-catch
  818. (and (not (nul? (! getEntry (<java.util.zip.ZipFile> dir) filename)))
  819. `(:zip ,dir ,filename))
  820. (ex <throwable> #f)))))
  821. (define swank-java-source-path
  822. (let ((jre-home (<java.lang.System>:getProperty "java.home")))
  823. (list (! get-path (<file> (! get-parent (<file> jre-home)) "src.zip"))
  824. )))
  825. (df source-path ()
  826. (mlet ((base) (search-path-prop "user.dir"))
  827. (append
  828. (list base)
  829. (map (fun ((s <str>))
  830. (let ((f (<file> s)))
  831. (cond ((! isAbsolute f) s)
  832. (#t (<file> (as <str> base) s):path))))
  833. (class-path))
  834. swank-java-source-path)))
  835. (df class-path ()
  836. (append (search-path-prop "java.class.path")
  837. (search-path-prop "sun.boot.class.path")))
  838. (df search-path-prop ((name <str>))
  839. (array-to-list (! split (java.lang.System:getProperty name)
  840. <file>:pathSeparator)))
  841. ;;;; Disassemble
  842. (defslimefun disassemble-form (env form)
  843. (mcase (read-from-string form)
  844. (('quote name)
  845. (let ((f (eval name env)))
  846. (typecase f
  847. (<gnu.expr.ModuleMethod>
  848. (disassemble (module-method>meth-ref f))))))))
  849. (df disassemble ((mr <meth-ref>) => <str>)
  850. (with-sink #f (fun (out) (disassemble-meth-ref mr out))))
  851. (df disassemble-meth-ref ((mr <meth-ref>) (out <java.io.PrintWriter>))
  852. (let* ((t (! declaring-type mr)))
  853. (disas-header mr out)
  854. (disas-code (! constant-pool t)
  855. (! constant-pool-count t)
  856. (! bytecodes mr)
  857. out)))
  858. (df disas-header ((mr <meth-ref>) (out <java.io.PrintWriter>))
  859. (let* ((++ (fun ((str <str>)) (! write out str)))
  860. (? (fun (flag str) (if flag (++ str)))))
  861. (? (! is-static mr) "static ")
  862. (? (! is-final mr) "final ")
  863. (? (! is-private mr) "private ")
  864. (? (! is-protected mr) "protected ")
  865. (? (! is-public mr) "public ")
  866. (++ (! name mr)) (++ (! signature mr)) (++ "\n")))
  867. (df disas-code ((cpool <byte[]>) (cpoolcount <int>) (bytecode <byte[]>)
  868. (out <java.io.PrintWriter>))
  869. (let* ((ct (<gnu.bytecode.ClassType> "foo"))
  870. (met (! addMethod ct "bar" 0))
  871. (ca (<gnu.bytecode.CodeAttr> met))
  872. (constants (let* ((bs (<java.io.ByteArrayOutputStream>))
  873. (s (<java.io.DataOutputStream> bs)))
  874. (! write-short s cpoolcount)
  875. (! write s cpool)
  876. (! flush s)
  877. (! toByteArray bs))))
  878. (vm-set-slot *the-vm* ct "constants"
  879. (<gnu.bytecode.ConstantPool>
  880. (<java.io.DataInputStream>
  881. (<java.io.ByteArrayInputStream>
  882. constants))))
  883. (! setCode ca bytecode)
  884. (let ((w (<gnu.bytecode.ClassTypeWriter> ct out 0)))
  885. (! print ca w)
  886. (! flush w))))
  887. (df with-sink (sink (f <function>))
  888. (cond ((instance? sink <java.io.PrintWriter>) (f sink))
  889. ((== sink #t) (f (as <java.io.PrintWriter> (current-output-port))))
  890. ((== sink #f)
  891. (let* ((buffer (<java.io.StringWriter>))
  892. (out (<java.io.PrintWriter> buffer)))
  893. (f out)
  894. (! flush out)
  895. (! toString buffer)))
  896. (#t (ferror "Invalid sink designator: ~s" sink))))
  897. (df test-disas ((c <str>) (m <str>))
  898. (let* ((vm (as <vm> *the-vm*))
  899. (c (as <ref-type> (1st (! classes-by-name vm c))))
  900. (m (as <meth-ref> (1st (! methods-by-name c m)))))
  901. (with-sink #f (fun (out) (disassemble-meth-ref m out)))))
  902. ;; (test-disas "java.lang.Class" "toString")
  903. ;;;; Macroexpansion
  904. (defslimefun swank-macroexpand-1 (env s) (%swank-macroexpand s))
  905. (defslimefun swank-macroexpand (env s) (%swank-macroexpand s))
  906. (defslimefun swank-macroexpand-all (env s) (%swank-macroexpand s))
  907. (df %swank-macroexpand (string)
  908. (pprint-to-string (%macroexpand (read-from-string string))))
  909. (df %macroexpand (sexp)
  910. (let ((tr :: kawa.lang.Translator (gnu.expr.Compilation:getCurrent)))
  911. (! rewrite tr `(begin ,sexp))))
  912. ;;;; Inspector
  913. (define-simple-class <inspector-state> ()
  914. (object init: #!null)
  915. (parts :: <java.util.ArrayList> init: (<java.util.ArrayList>) )
  916. (stack :: <list> init: '())
  917. (content :: <list> init: '()))
  918. (df make-inspector (env (vm <vm>) => <chan>)
  919. (car (spawn/chan (fun (c) (inspector c env vm)))))
  920. (df inspector ((c <chan>) env (vm <vm>))
  921. (! set-name (current-thread) "inspector")
  922. (let ((state :: <inspector-state> (<inspector-state>))
  923. (open #t))
  924. (while open
  925. (mcase (recv c)
  926. (('init str id)
  927. (set state (<inspector-state>))
  928. (let ((obj (try-catch (eval (read-from-string str) env)
  929. (ex <throwable> ex))))
  930. (reply c (inspect-object obj state vm) id)))
  931. (('init-mirror cc id)
  932. (set state (<inspector-state>))
  933. (let* ((mirror (recv cc))
  934. (obj (vm-demirror vm mirror)))
  935. (reply c (inspect-object obj state vm) id)))
  936. (('inspect-part n id)
  937. (let ((part (! get (@ parts state) n)))
  938. (reply c (inspect-object part state vm) id)))
  939. (('pop id)
  940. (reply c (inspector-pop state vm) id))
  941. (('quit id)
  942. (reply c 'nil id)
  943. (set open #f))))))
  944. (df inspect-object (obj (state <inspector-state>) (vm <vm>))
  945. (set (@ object state) obj)
  946. (set (@ parts state) (<java.util.ArrayList>))
  947. (pushf obj (@ stack state))
  948. (set (@ content state) (inspector-content
  949. `("class: " (:value ,(! getClass obj)) "\n"
  950. ,@(inspect obj vm))
  951. state))
  952. (cond ((nul? obj) (list ':title "#!null" ':id 0 ':content `()))
  953. (#t
  954. (list ':title (pprint-to-string obj)
  955. ':id (assign-index obj state)
  956. ':content (let ((c (@ content state)))
  957. (content-range c 0 (len c)))))))
  958. (df inspect (obj vm)
  959. (let* ((obj (as <obj-ref> (vm-mirror vm obj))))
  960. (packing (pack)
  961. (typecase obj
  962. (<array-ref>
  963. (let ((i 0))
  964. (iter (! getValues obj)
  965. (fun ((v <value>))
  966. (pack (format "~d: " i))
  967. (set i (1+ i))
  968. (pack `(:value ,(vm-demirror vm v)))
  969. (pack "\n")))))
  970. (<obj-ref>
  971. (let* ((type (! referenceType obj))
  972. (fields (! allFields type))
  973. (values (! getValues obj fields)))
  974. (iter fields
  975. (fun ((f <field>))
  976. (let ((val (as <value> (! get values f))))
  977. (when (! is-static f)
  978. (pack "static "))
  979. (pack (! name f)) (pack ": ")
  980. (pack `(:value ,(vm-demirror vm val)))
  981. (pack "\n"))))))))))
  982. (df inspector-content (content (state <inspector-state>))
  983. (map (fun (part)
  984. (mcase part
  985. ((':value val)
  986. `(:value ,(pprint-to-string val) ,(assign-index val state)))
  987. (x (to-string x))))
  988. content))
  989. (df assign-index (obj (state <inspector-state>) => <int>)
  990. (! add (@ parts state) obj)
  991. (1- (! size (@ parts state))))
  992. (df content-range (l start end)
  993. (let* ((len (length l)) (end (min len end)))
  994. (list (subseq l start end) len start end)))
  995. (df inspector-pop ((state <inspector-state>) vm)
  996. (cond ((<= 2 (len (@ stack state)))
  997. (let ((obj (cadr (@ stack state))))
  998. (set (@ stack state) (cddr (@ stack state)))
  999. (inspect-object obj state vm)))
  1000. (#t 'nil)))
  1001. ;;;; IO redirection
  1002. (define-simple-class <swank-writer> (<java.io.Writer>)
  1003. (q :: <queue> init: (<queue> (as <int> 100)))
  1004. ((*init*) (invoke-special <java.io.Writer> (this) '*init*))
  1005. ((write (buffer <char[]>) (from <int>) (to <int>)) :: <void>
  1006. (synchronized (this)
  1007. (assert (not (== q #!null)))
  1008. (! put q `(write ,(<str> buffer from to)))))
  1009. ((close) :: <void>
  1010. (synchronized (this)
  1011. (! put q 'close)
  1012. (set! q #!null)))
  1013. ((flush) :: <void>
  1014. (synchronized (this)
  1015. (assert (not (== q #!null)))
  1016. (let ((ex (<exchanger>)))
  1017. (! put q `(flush ,ex))
  1018. (! exchange ex #!null)))))
  1019. (df swank-writer ((in <chan>) (q <queue>))
  1020. (! set-name (current-thread) "swank-redirect-thread")
  1021. (let* ((out (as <chan> (recv in)))
  1022. (builder (<builder>))
  1023. (flush (fun ()
  1024. (unless (zero? (! length builder))
  1025. (send out `(forward (:write-string ,(<str> builder))))
  1026. (set! builder:length 0)))) ; pure magic
  1027. (closed #f))
  1028. (while (not closed)
  1029. (mcase (! poll q 200 <timeunit>:MILLISECONDS)
  1030. ('#!null (flush))
  1031. (('write s)
  1032. (! append builder (as <str> s))
  1033. (when (> (! length builder) 4000)
  1034. (flush)))
  1035. (('flush ex)
  1036. (flush)
  1037. (! exchange (as <exchanger> ex) #!null))
  1038. ('close
  1039. (set closed #t)
  1040. (flush))))))
  1041. (df make-swank-outport ((out <chan>))
  1042. (let ((w (<swank-writer>)))
  1043. (mlet ((in . _) (spawn/chan (fun (c) (swank-writer c (@ q w)))))
  1044. (send in out))
  1045. (<gnu.mapping.OutPort> w #t #t)))
  1046. ;;;; Monitor
  1047. (df vm-monitor ((c <chan>))
  1048. (! set-name (current-thread) "swank-vm-monitor")
  1049. (let ((vm (vm-attach)))
  1050. (log-vm-props vm)
  1051. ;;(enable-uncaught-exception-events vm)
  1052. (mlet* (((ev . _) (spawn/chan/catch
  1053. (fun (c)
  1054. (let ((q (! eventQueue vm)))
  1055. (while #t
  1056. (send c `(vm-event ,(to-list (! remove q)))))))))
  1057. (to-string (vm-to-string vm))
  1058. (state (tab)))
  1059. (send c `(publish-vm ,vm))
  1060. (while #t
  1061. (mcase (recv* (list c ev))
  1062. ((_ . ('get-vm cc))
  1063. (send cc vm))
  1064. ((,c . ('debug-info thread from to id))
  1065. (reply c (debug-info thread from to state) id))
  1066. ((,c . ('throw-to-toplevel thread id))
  1067. (set state (throw-to-toplevel thread id c state)))
  1068. ((,c . ('thread-continue thread id))
  1069. (set state (thread-continue thread id c state)))
  1070. ((,c . ('frame-src-loc thread frame id))
  1071. (reply c (frame-src-loc thread frame state) id))
  1072. ((,c . ('frame-details thread frame id))
  1073. (reply c (list (frame-locals thread frame state) '()) id))
  1074. ((,c . ('disassemble-frame thread frame id))
  1075. (reply c (disassemble-frame thread frame state) id))
  1076. ((,c . ('thread-frames thread from to id))
  1077. (reply c (thread-frames thread from to state) id))
  1078. ((,c . ('list-threads id))
  1079. (reply c (list-threads vm state) id))
  1080. ((,c . ('debug-thread ref))
  1081. (set state (debug-thread ref state c)))
  1082. ((,c . ('debug-nth-thread n))
  1083. (let ((t (nth (get state 'all-threads #f) n)))
  1084. ;;(log "thread ~d : ~a\n" n t)
  1085. (set state (debug-thread t state c))))
  1086. ((,c . ('quit-thread-browser id))
  1087. (reply c 't id)
  1088. (set state (del state 'all-threads)))
  1089. ((,ev . ('vm-event es))
  1090. ;;(log "vm-events: len=~a\n" (len es))
  1091. (for (((e <event>) (as <list> es)))
  1092. (set state (process-vm-event e c state))))
  1093. ((_ . ('get-exception from tid))
  1094. (mlet ((_ _ es) (get state tid #f))
  1095. (send from (let ((e (car es)))
  1096. (typecase e
  1097. (<exception-event> (! exception e))
  1098. (<event> e))))))
  1099. ((_ . ('get-local rc tid frame var))
  1100. (send rc (frame-local-var tid frame var state)))
  1101. )))))
  1102. (df reply ((c <chan>) value id)
  1103. (send c `(forward (:return (:ok ,value) ,id))))
  1104. (df reply-abort ((c <chan>) id)
  1105. (send c `(forward (:return (:abort) ,id))))
  1106. (df process-vm-event ((e <event>) (c <chan>) state)
  1107. (log "vm-event: ~s\n" e)
  1108. (typecase e
  1109. (<exception-event>
  1110. (log "exception-location: ~s\n" (src-loc>str (! location e)))
  1111. (log "exception-catch-location: ~s\n" (src-loc>str (! catch-location e)))
  1112. (let ((l (! catch-location e)))
  1113. (cond ((or (nul? l)
  1114. ;; (member (! source-path l) '("gnu/expr/ModuleExp.java"))
  1115. )
  1116. (process-exception e c state))
  1117. (#t
  1118. (let* ((t (! thread e))
  1119. (r (! request e))
  1120. (ex (! exception e)))
  1121. (unless (eq? *last-exception* ex)
  1122. (set *last-exception* ex)
  1123. (set *last-stacktrace* (copy-stack t)))
  1124. (! resume t))
  1125. state))))
  1126. (<step-event>
  1127. (let* ((r (! request e))
  1128. (k (! get-property r 'continuation)))
  1129. (! disable r)
  1130. (log "k: ~s\n" k)
  1131. (k e))
  1132. state)))
  1133. (df process-exception ((e <exception-event>) (c <chan>) state)
  1134. (let* ((tref (! thread e))
  1135. (tid (! uniqueID tref))
  1136. (s (get state tid #f)))
  1137. (mcase s
  1138. ('#f
  1139. ;; XXX redundant in debug-thread
  1140. (let* ((level 1)
  1141. (state (put state tid (list tref level (list e)))))
  1142. (send c `(forward (:debug ,tid ,level
  1143. ,@(debug-info tid 0 15 state))))
  1144. (send c `(forward (:debug-activate ,tid ,level)))
  1145. state))
  1146. ((_ level exs)
  1147. (send c `(forward (:debug-activate ,(! uniqueID tref) ,level)))
  1148. (put state tid (list tref (1+ level) (cons e exs)))))))
  1149. (define-simple-class <faked-frame> ()
  1150. (loc :: <location>)
  1151. (args)
  1152. (names)
  1153. (values :: <java.util.Map>)
  1154. (self)
  1155. ((*init* (loc <location>) args names (values <java.util.Map>) self)
  1156. (set (@ loc (this)) loc)
  1157. (set (@ args (this)) args)
  1158. (set (@ names (this)) names)
  1159. (set (@ values (this)) values)
  1160. (set (@ self (this)) self))
  1161. ((toString) :: <str>
  1162. (format "#<ff ~a>" (src-loc>str loc))))
  1163. (df copy-stack ((t <thread-ref>))
  1164. (packing (pack)
  1165. (iter (! frames t)
  1166. (fun ((f <frame>))
  1167. (let ((vars (ignore-errors (! visibleVariables f))))
  1168. (pack (<faked-frame>
  1169. (or (ignore-errors (! location f)) #!null)
  1170. (ignore-errors (! getArgumentValues f))
  1171. (or vars #!null)
  1172. (or (and vars (ignore-errors (! get-values f vars)))
  1173. #!null)
  1174. (ignore-errors (! thisObject f)))))))))
  1175. (define-simple-class <listener-abort> (<java.lang.Throwable>)
  1176. ((abort) :: void
  1177. (primitive-throw (this))
  1178. #!void))
  1179. (define-simple-class <break-event> (<com.sun.jdi.event.Event>)
  1180. (thread :: <thread-ref>)
  1181. ((*init* (thread :: <thread-ref>)) (set (@ thread (this)) thread))
  1182. ((request) :: <com.sun.jdi.request.EventRequest> #!null)
  1183. ((virtualMachine) :: <vm> (! virtualMachine thread)))
  1184. (df log-vm-props ((vm <vm>))
  1185. (letrec-syntax ((p (syntax-rules ()
  1186. ((p name) (log "~s: ~s\n" 'name (! name vm)))))
  1187. (p* (syntax-rules ()
  1188. ((p* n ...) (seq (p n) ...)))))
  1189. (p* canBeModified
  1190. canRedefineClasses
  1191. canAddMethod
  1192. canUnrestrictedlyRedefineClasses
  1193. canGetBytecodes
  1194. canGetConstantPool
  1195. canGetSyntheticAttribute
  1196. canGetSourceDebugExtension
  1197. canPopFrames
  1198. canForceEarlyReturn
  1199. canGetMethodReturnValues
  1200. canGetInstanceInfo
  1201. )))
  1202. ;;;;; Debugger
  1203. (df debug-thread ((tref <thread-ref>) state (c <chan>))
  1204. (! suspend tref)
  1205. (let* ((ev (<break-event> tref))
  1206. (id (! uniqueID tref))
  1207. (level 1)
  1208. (state (put state id (list tref level (list ev)))))
  1209. (send c `(forward (:debug ,id ,level ,@(debug-info id 0 10 state))))
  1210. (send c `(forward (:debug-activate ,id ,level)))
  1211. state))
  1212. (df debug-info ((tid <int>) (from <int>) to state)
  1213. (mlet ((thread-ref level evs) (get state tid #f))
  1214. (let* ((tref (as <thread-ref> thread-ref))
  1215. (vm (! virtualMachine tref))
  1216. (ev (as <event> (car evs)))
  1217. (ex (typecase ev
  1218. (<exception-event> (! exception ev))
  1219. (<break-event> (<java.lang.Exception> "Interrupt"))))
  1220. (desc (typecase ex
  1221. (<obj-ref>
  1222. ;;(log "ex: ~a ~a\n" ex (vm-demirror vm ex))
  1223. (! toString (vm-demirror vm ex)))
  1224. (<java.lang.Exception> (! toString ex))))
  1225. (type (format " [type ~a]"
  1226. (typecase ex
  1227. (<obj-ref> (! name (! referenceType ex)))
  1228. (<object> (!! getName getClass ex)))))
  1229. (bt (thread-frames tid from to state)))
  1230. `((,desc ,type nil) (("quit" "terminate current thread")) ,bt ()))))
  1231. (df thread-frames ((tid <int>) (from <int>) to state)
  1232. (mlet ((thread level evs) (get state tid #f))
  1233. (let* ((thread (as <thread-ref> thread))
  1234. (fcount (! frameCount thread))
  1235. (stacktrace (event-stacktrace (car evs)))
  1236. (missing (cond ((zero? (len stacktrace)) 0)
  1237. (#t (- (len stacktrace) fcount))))
  1238. (fstart (max (- from missing) 0))
  1239. (flen (max (- to from missing) 0))
  1240. (frames (! frames thread fstart (min flen (- fcount fstart)))))
  1241. (packing (pack)
  1242. (let ((i from))
  1243. (dotimes (_ (max (- missing from) 0))
  1244. (pack (list i (format "~a" (stacktrace i))))
  1245. (set i (1+ i)))
  1246. (iter frames (fun ((f <frame>))
  1247. (let ((s (frame-to-string f)))
  1248. (pack (list i s))
  1249. (set i (1+ i))))))))))
  1250. (df event-stacktrace ((ev <event>))
  1251. (typecase ev
  1252. (<exception-event>
  1253. (let ((r (! request ev))
  1254. (vm (! virtualMachine ev)))
  1255. (cond ((== (vm-demirror vm (! exception ev))
  1256. (ignore-errors (vm-demirror vm *last-exception*)))
  1257. *last-stacktrace*)
  1258. (#t
  1259. (! getStackTrace
  1260. (as <throwable> (vm-demirror vm (! exception ev))))))))
  1261. (<event> (<java.lang.StackTraceElement[]>))))
  1262. (df frame-to-string ((f <frame>))
  1263. (let ((loc (! location f))
  1264. (vm (! virtualMachine f)))
  1265. (format "~a (~a)" (!! name method loc)
  1266. (call-with-abort
  1267. (fun () (format "~{~a~^ ~}"
  1268. (mapi (! getArgumentValues f)
  1269. (fun (arg)
  1270. (pprint-to-string
  1271. (vm-demirror vm arg))))))))))
  1272. (df frame-src-loc ((tid <int>) (n <int>) state)
  1273. (try-catch
  1274. (mlet* (((frame vm) (nth-frame tid n state))
  1275. (vm (as <vm> vm)))
  1276. (src-loc>elisp
  1277. (typecase frame
  1278. (<frame> (! location frame))
  1279. (<faked-frame> (@ loc frame))
  1280. (<java.lang.StackTraceElement>
  1281. (let* ((classname (! getClassName frame))
  1282. (classes (! classesByName vm classname))
  1283. (t (as <ref-type> (1st classes))))
  1284. (1st (! locationsOfLine t (! getLineNumber frame))))))))
  1285. (ex <throwable>
  1286. (let ((msg (! getMessage ex)))
  1287. `(:error ,(if (== msg #!null)
  1288. (! toString ex)
  1289. msg))))))
  1290. (df nth-frame ((tid <int>) (n <int>) state)
  1291. (mlet ((tref level evs) (get state tid #f))
  1292. (let* ((thread (as <thread-ref> tref))
  1293. (fcount (! frameCount thread))
  1294. (stacktrace (event-stacktrace (car evs)))
  1295. (missing (cond ((zero? (len stacktrace)) 0)
  1296. (#t (- (len stacktrace) fcount))))
  1297. (vm (! virtualMachine thread))
  1298. (frame (cond ((< n missing)
  1299. (stacktrace n))
  1300. (#t (! frame thread (- n missing))))))
  1301. (list frame vm))))
  1302. ;;;;; Locals
  1303. (df frame-locals ((tid <int>) (n <int>) state)
  1304. (mlet ((thread _ _) (get state tid #f))
  1305. (let* ((thread (as <thread-ref> thread))
  1306. (vm (! virtualMachine thread))
  1307. (p (fun (x) (pprint-to-string
  1308. (call-with-abort (fun () (vm-demirror vm x)))))))
  1309. (map (fun (x)
  1310. (mlet ((name value) x)
  1311. (list ':name name ':value (p value) ':id 0)))
  1312. (%frame-locals tid n state)))))
  1313. (df frame-local-var ((tid <int>) (frame <int>) (var <int>) state => <mirror>)
  1314. (cadr (nth (%frame-locals tid frame state) var)))
  1315. (df %frame-locals ((tid <int>) (n <int>) state)
  1316. (mlet ((frame _) (nth-frame tid n state))
  1317. (typecase frame
  1318. (<frame>
  1319. (let* ((visible (try-catch (! visibleVariables frame)
  1320. (ex <com.sun.jdi.AbsentInformationException>
  1321. '())))
  1322. (map (! getValues frame visible))
  1323. (p (fun (x) x)))
  1324. (packing (pack)
  1325. (let ((self (ignore-errors (! thisObject frame))))
  1326. (when self
  1327. (pack (list "this" (p self)))))
  1328. (iter (! entrySet map)
  1329. (fun ((e <java.util.Map$Entry>))
  1330. (let ((var (as <local-var> (! getKey e)))
  1331. (val (as <value> (! getValue e))))
  1332. (pack (list (! name var) (p val)))))))))
  1333. (<faked-frame>
  1334. (packing (pack)
  1335. (when (@ self frame)
  1336. (pack (list "this" (@ self frame))))
  1337. (iter (! entrySet (@ values frame))
  1338. (fun ((e <java.util.Map$Entry>))
  1339. (let ((var (as <local-var> (! getKey e)))
  1340. (val (as <value> (! getValue e))))
  1341. (pack (list (! name var) val)))))))
  1342. (<java.lang.StackTraceElement> '()))))
  1343. (df disassemble-frame ((tid <int>) (frame <int>) state)
  1344. (mlet ((frame _) (nth-frame tid frame state))
  1345. (typecase frame
  1346. (<java.lang.StackTraceElement> "<??>")
  1347. (<frame>
  1348. (let* ((l (! location frame))
  1349. (m (! method l))
  1350. (c (! declaringType l)))
  1351. (disassemble m))))))
  1352. ;;;;; Restarts
  1353. (df throw-to-toplevel ((tid <int>) (id <int>) (c <chan>) state)
  1354. (mlet ((tref level exc) (get state tid #f))
  1355. (let* ((t (as <thread-ref> tref))
  1356. (ev (car exc)))
  1357. (typecase ev
  1358. (<exception-event>
  1359. (! resume t)
  1360. (reply-abort c id)
  1361. (do ((level level (1- level))
  1362. (exc exc (cdr exc)))
  1363. ((null? exc))
  1364. (send c `(forward (:debug-return ,tid ,level nil))))
  1365. (del state tid))
  1366. (<break-event>
  1367. ;; XXX race condition?
  1368. (let ((vm (! virtualMachine t)))
  1369. (reply-abort c id)
  1370. (! stop t (vm-mirror vm (<listener-abort>)))
  1371. (! interrupt t)
  1372. (! resume t)
  1373. (! interrupt t)
  1374. (do ((level level (1- level))
  1375. (exc exc (cdr exc)))
  1376. ((null? exc))
  1377. (send c `(forward (:debug-return ,tid ,level nil))))
  1378. (del state tid)))))))
  1379. (df thread-continue ((tid <int>) (id <int>) (c <chan>) state)
  1380. (mlet ((tref level exc) (get state tid #f))
  1381. (let* ((t (as <thread-ref> tref)))
  1382. (! resume t))
  1383. (reply-abort c id)
  1384. (do ((level level (1- level))
  1385. (exc exc (cdr exc)))
  1386. ((null? exc))
  1387. (send c `(forward (:debug-return ,tid ,level nil))))
  1388. (del state tid)))
  1389. (df thread-step ((t <thread-ref>) k)
  1390. (let* ((vm (! virtual-machine t))
  1391. (erm (! eventRequestManager vm))
  1392. (<sr> <com.sun.jdi.request.StepRequest>)
  1393. (req (! createStepRequest erm t <sr>:STEP_MIN <sr>:STEP_OVER)))
  1394. (! setSuspendPolicy req (@ SUSPEND_EVENT_THREAD req))
  1395. (! addCountFilter req 1)
  1396. (! put-property req 'continuation k)
  1397. (! enable req)))
  1398. (df eval-in-thread ((t <thread-ref>) sexp
  1399. #!optional (env :: <env> (<env>:current)))
  1400. (let* ((vm (! virtualMachine t))
  1401. (sc :: <class-ref>
  1402. (1st (! classes-by-name vm "kawa.standard.Scheme")))
  1403. (ev :: <meth-ref>
  1404. (1st (! methods-by-name sc "eval"
  1405. (cat "(Ljava/lang/Object;Lgnu/mapping/Environment;)"
  1406. "Ljava/lang/Object;")))))
  1407. (! invokeMethod sc t ev (list sexp env) sc:INVOKE_SINGLE_THREADED)))
  1408. ;;;;; Threads
  1409. (df list-threads (vm :: <vm> state)
  1410. (let* ((threads (! allThreads vm)))
  1411. (put state 'all-threads threads)
  1412. (packing (pack)
  1413. (iter threads (fun ((t <thread-ref>))
  1414. (pack (list (! name t)
  1415. (let ((s (thread-status t)))
  1416. (if (! is-suspended t)
  1417. (cat "SUSPENDED/" s)
  1418. s))
  1419. (! uniqueID t))))))))
  1420. (df thread-status (t :: <thread-ref>)
  1421. (let ((s (! status t)))
  1422. (cond ((= s t:THREAD_STATUS_UNKNOWN) "UNKNOWN")
  1423. ((= s t:THREAD_STATUS_ZOMBIE) "ZOMBIE")
  1424. ((= s t:THREAD_STATUS_RUNNING) "RUNNING")
  1425. ((= s t:THREAD_STATUS_SLEEPING) "SLEEPING")
  1426. ((= s t:THREAD_STATUS_MONITOR) "MONITOR")
  1427. ((= s t:THREAD_STATUS_WAIT) "WAIT")
  1428. ((= s t:THREAD_STATUS_NOT_STARTED) "NOT_STARTED")
  1429. (#t "<bug>"))))
  1430. ;;;;; Bootstrap
  1431. (df vm-attach (=> <vm>)
  1432. (attach (getpid) 20))
  1433. (df attach (pid timeout)
  1434. (log "attaching: ~a ~a\n" pid timeout)
  1435. (let* ((<ac> <com.sun.jdi.connect.AttachingConnector>)
  1436. (<arg> <com.sun.jdi.connect.Connector$Argument>)
  1437. (vmm (com.sun.jdi.Bootstrap:virtualMachineManager))
  1438. (pa (as <ac>
  1439. (or
  1440. (find-if (! attaching-connectors vmm)
  1441. (fun (x :: <ac>)
  1442. (! equals (! name x) "com.sun.jdi.ProcessAttach"))
  1443. #f)
  1444. (error "ProcessAttach connector not found"))))
  1445. (args (! default-arguments pa)))
  1446. (! set-value (as <arg> (! get args (to-str "pid"))) pid)
  1447. (when timeout
  1448. (! set-value (as <arg> (! get args (to-str "timeout"))) timeout))
  1449. (log "attaching2: ~a ~a\n" pa args)
  1450. (! attach pa args)))
  1451. (df getpid ()
  1452. (let ((p (make-process (command-parse "echo $PPID") #!null)))
  1453. (! waitFor p)
  1454. (! read-line (<java.io.BufferedReader> (<in> (! get-input-stream p))))))
  1455. (df enable-uncaught-exception-events ((vm <vm>))
  1456. (let* ((erm (! eventRequestManager vm))
  1457. (req (! createExceptionRequest erm #!null #f #t)))
  1458. (! setSuspendPolicy req (@ SUSPEND_EVENT_THREAD req))
  1459. (! addThreadFilter req (vm-mirror vm (current-thread)))
  1460. (! enable req))
  1461. (let* ((erm (! eventRequestManager vm))
  1462. (req (! createExceptionRequest erm #!null #t #f)))
  1463. (! setSuspendPolicy req (@ SUSPEND_EVENT_THREAD req))
  1464. (! addThreadFilter req (vm-mirror vm (current-thread)))
  1465. (! addClassExclusionFilter req "java.lang.ClassLoader")
  1466. (! addClassExclusionFilter req "java.net.URLClassLoader")
  1467. (! addClassExclusionFilter req "java.net.URLClassLoader$1")
  1468. (! enable req))
  1469. #!void
  1470. )
  1471. (df set-stacktrace-recording ((vm <vm>) (flag <boolean>))
  1472. (for (((e <com.sun.jdi.request.ExceptionRequest>)
  1473. (!! exceptionRequests eventRequestManager vm)))
  1474. (when (! notify-caught e)
  1475. (! setEnabled e flag))))
  1476. ;; (set-stacktrace-recording *the-vm* #f)
  1477. (df vm-to-string ((vm <vm>))
  1478. (let* ((obj (as <ref-type> (1st (! classesByName vm "java.lang.Object"))))
  1479. (met (as <meth-ref> (1st (! methodsByName obj "toString")))))
  1480. (fun ((o <obj-ref>) (t <thread-ref>))
  1481. (! value
  1482. (as <str-ref>
  1483. (! invokeMethod o t met '() o:INVOKE_SINGLE_THREADED))))))
  1484. (define-simple-class <swank-global-variable> ()
  1485. (var allocation: 'static))
  1486. (define-variable *global-get-mirror* #!null)
  1487. (define-variable *global-set-mirror* #!null)
  1488. (define-variable *global-get-raw* #!null)
  1489. (define-variable *global-set-raw* #!null)
  1490. (df init-global-field ((vm <vm>))
  1491. (when (nul? *global-get-mirror*)
  1492. (set <swank-global-variable>:var #!null) ; prepare class
  1493. (let* ((c (as <com.sun.jdi.ClassType>
  1494. (1st (! classes-by-name vm "swank$Mnglobal$Mnvariable"))))
  1495. (f (! fieldByName c "var")))
  1496. (set *global-get-mirror* (fun () (! getValue c f)))
  1497. (set *global-set-mirror* (fun ((v <obj-ref>)) (! setValue c f v))))
  1498. (set *global-get-raw* (fun () <swank-global-variable>:var))
  1499. (set *global-set-raw* (fun (x) (set <swank-global-variable>:var x)))))
  1500. (df vm-mirror ((vm <vm>) obj)
  1501. (synchronized vm
  1502. (init-global-field vm)
  1503. (*global-set-raw* obj)
  1504. (*global-get-mirror*)))
  1505. (df vm-demirror ((vm <vm>) (v <value>))
  1506. (synchronized vm
  1507. (if (== v #!null)
  1508. #!null
  1509. (typecase v
  1510. (<obj-ref> (init-global-field vm)
  1511. (*global-set-mirror* v)
  1512. (*global-get-raw*))
  1513. (<com.sun.jdi.IntegerValue> (! value v))
  1514. (<com.sun.jdi.LongValue> (! value v))
  1515. (<com.sun.jdi.CharValue> (! value v))
  1516. (<com.sun.jdi.ByteValue> (! value v))
  1517. (<com.sun.jdi.BooleanValue> (! value v))
  1518. (<com.sun.jdi.ShortValue> (! value v))
  1519. (<com.sun.jdi.FloatValue> (! value v))
  1520. (<com.sun.jdi.DoubleValue> (! value v))))))
  1521. (df vm-set-slot ((vm <vm>) (o <object>) (name <str>) value)
  1522. (let* ((o (as <obj-ref> (vm-mirror vm o)))
  1523. (t (! reference-type o))
  1524. (f (! field-by-name t name)))
  1525. (! set-value o f (vm-mirror vm value))))
  1526. (define-simple-class <ucex-handler>
  1527. (<java.lang.Thread$UncaughtExceptionHandler>)
  1528. (f :: <gnu.mapping.Procedure>)
  1529. ((*init* (f :: <gnu.mapping.Procedure>)) (set (@ f (this)) f))
  1530. ((uncaughtException (t <thread>) (e <throwable>))
  1531. :: <void>
  1532. ;;(! println (java.lang.System:.err) (to-str "uhexc:::"))
  1533. (! apply2 f t e)
  1534. #!void))
  1535. ;;;; Channels
  1536. (df spawn (f)
  1537. (let ((thread (<thread> (%%runnable f))))
  1538. (! start thread)
  1539. thread))
  1540. (df %%runnable (f => <java.lang.Runnable>)
  1541. ;;(<runnable> f)
  1542. (<gnu.mapping.RunnableClosure> f)
  1543. )
  1544. #|
  1545. (df %runnable (f => <java.lang.Runnable>)
  1546. (<runnable>
  1547. (fun ()
  1548. (try-catch (f)
  1549. (ex <throwable>
  1550. (log "exception in thread ~s: ~s" (current-thread)
  1551. ex)
  1552. (! printStackTrace ex))))))
  1553. |#
  1554. (df chan ()
  1555. (let ((lock (<object>))
  1556. (im (<chan>))
  1557. (ex (<chan>)))
  1558. (set (@ lock im) lock)
  1559. (set (@ lock ex) lock)
  1560. (set (@ peer im) ex)
  1561. (set (@ peer ex) im)
  1562. (cons im ex)))
  1563. (df immutable? (obj)
  1564. (or (== obj #!null)
  1565. (symbol? obj)
  1566. (number? obj)
  1567. (char? obj)
  1568. (instance? obj <str>)
  1569. (null? obj)))
  1570. (df send ((c <chan>) value => <void>)
  1571. (df pass (obj)
  1572. (cond ((immutable? obj) obj)
  1573. ((string? obj) (! to-string obj))
  1574. ((pair? obj)
  1575. (let loop ((r (list (pass (car obj))))
  1576. (o (cdr obj)))
  1577. (cond ((null? o) (reverse! r))
  1578. ((pair? o) (loop (cons (pass (car o)) r) (cdr o)))
  1579. (#t (append (reverse! r) (pass o))))))
  1580. ((instance? obj <chan>)
  1581. (let ((o :: <chan> obj))
  1582. (assert (== (@ owner o) (current-thread)))
  1583. (synchronized (@ lock c)
  1584. (set (@ owner o) (@ owner (@ peer c))))
  1585. o))
  1586. ((or (instance? obj <env>)
  1587. (instance? obj <mirror>))
  1588. ;; those can be shared, for pragmatic reasons
  1589. obj
  1590. )
  1591. (#t (error "can't send" obj (class-name-sans-package obj)))))
  1592. ;;(log "send: ~s ~s -> ~s\n" value (@ owner c) (@ owner (@ peer c)))
  1593. (assert (== (@ owner c) (current-thread)))
  1594. ;;(log "lock: ~s send\n" (@ owner (@ peer c)))
  1595. (synchronized (@ owner (@ peer c))
  1596. (! put (@ queue (@ peer c)) (pass value))
  1597. (! notify (@ owner (@ peer c))))
  1598. ;;(log "unlock: ~s send\n" (@ owner (@ peer c)))
  1599. )
  1600. (df recv ((c <chan>))
  1601. (cdr (recv/timeout (list c) 0)))
  1602. (df recv* ((cs <iterable>))
  1603. (recv/timeout cs 0))
  1604. (df recv/timeout ((cs <iterable>) (timeout <long>))
  1605. (let ((self (current-thread))
  1606. (end (if (zero? timeout)
  1607. 0
  1608. (+ (current-time) timeout))))
  1609. ;;(log "lock: ~s recv\n" self)
  1610. (synchronized self
  1611. (let loop ()
  1612. ;;(log "receive-loop: ~s\n" self)
  1613. (let ((ready (find-if cs
  1614. (fun ((c <chan>))
  1615. (not (! is-empty (@ queue c))))
  1616. #f)))
  1617. (cond (ready
  1618. ;;(log "unlock: ~s recv\n" self)
  1619. (cons ready (! take (@ queue (as <chan> ready)))))
  1620. ((zero? timeout)
  1621. ;;(log "wait: ~s recv\n" self)
  1622. (! wait self) (loop))
  1623. (#t
  1624. (let ((now (current-time)))
  1625. (cond ((<= end now)
  1626. 'timeout)
  1627. (#t
  1628. ;;(log "wait: ~s recv\n" self)
  1629. (! wait self (- end now))
  1630. (loop)))))))))))
  1631. (df rpc ((c <chan>) msg)
  1632. (mlet* (((im . ex) (chan))
  1633. ((op . args) msg))
  1634. (send c `(,op ,ex . ,args))
  1635. (recv im)))
  1636. (df spawn/chan (f)
  1637. (mlet ((im . ex) (chan))
  1638. (let ((thread (<thread> (%%runnable (fun () (f ex))))))
  1639. (set (@ owner ex) thread)
  1640. (! start thread)
  1641. (cons im thread))))
  1642. (df spawn/chan/catch (f)
  1643. (spawn/chan
  1644. (fun (c)
  1645. (try-catch
  1646. (f c)
  1647. (ex <throwable>
  1648. (send c `(error ,(! toString ex)
  1649. ,(class-name-sans-package ex)
  1650. ,(map (fun (e) (! to-string e))
  1651. (array-to-list (! get-stack-trace ex))))))))))
  1652. #|
  1653. (define-simple-class <runnable> (<gnu.mapping.RunnableClosure>)
  1654. (f :: <gnu.mapping.Procedure>)
  1655. ((*init* (f <gnu.mapping.Procedure>))
  1656. (invoke-special <gnu.mapping.RunnableClosure> (this) '*init* f)
  1657. (set (@ f (this)) f))
  1658. ((run) :: void
  1659. (! set-environment-raw (<gnu.mapping.CallContext>:getInstance)
  1660. (@ environment (this)))
  1661. (! apply0 f)))
  1662. |#
  1663. ;;;; Logging
  1664. (define swank-log-port (current-error-port))
  1665. (df log (fstr #!rest args)
  1666. (synchronized swank-log-port
  1667. (apply format swank-log-port fstr args)
  1668. (force-output swank-log-port))
  1669. #!void)
  1670. ;;;; Random helpers
  1671. (df 1+ (x) (+ x 1))
  1672. (df 1- (x) (- x 1))
  1673. (df len (x => <int>)
  1674. (typecase x
  1675. (<list> (length x))
  1676. (<str> (! length x))
  1677. (<string> (string-length x))
  1678. (<vector> (vector-length x))
  1679. (<java.util.List> (! size x))
  1680. (<object[]> (@ length x))))
  1681. (df put (tab key value) (hash-table-set! tab key value) tab)
  1682. (df get (tab key default) (hash-table-ref/default tab key default))
  1683. (df del (tab key) (hash-table-delete! tab key) tab)
  1684. (df tab () (make-hash-table))
  1685. (df equal (x y => <boolean>) (equal? x y))
  1686. (df current-thread (=> <thread>) (java.lang.Thread:currentThread))
  1687. (df current-time (=> <long>) (java.lang.System:currentTimeMillis))
  1688. (df nul? (x) (== x #!null))
  1689. (df read-from-string (str)
  1690. (call-with-input-string str read))
  1691. ;;(df print-to-string (obj) (call-with-output-string (fun (p) (write obj p))))
  1692. (df pprint-to-string (obj)
  1693. (let* ((w (<java.io.StringWriter>))
  1694. (p (<gnu.mapping.OutPort> w #t #f)))
  1695. (try-catch (write obj p)
  1696. (ex <throwable>
  1697. (format p "#<error while printing ~a ~a>"
  1698. ex (class-name-sans-package ex))))
  1699. (! flush p)
  1700. (to-string (! getBuffer w))))
  1701. (define cat string-append)
  1702. (df values-to-list (values)
  1703. (typecase values
  1704. (<gnu.mapping.Values> (array-to-list (! getValues values)))
  1705. (<object> (list values))))
  1706. ;; (to-list (as-list (values 1 2 2)))
  1707. (df array-to-list ((array <object[]>) => <list>)
  1708. (packing (pack)
  1709. (dotimes (i (@ length array))
  1710. (pack (array i)))))
  1711. (df lisp-bool (obj)
  1712. (cond ((== obj 'nil) #f)
  1713. ((== obj 't) #t)
  1714. (#t (error "Can't map lisp boolean" obj))))
  1715. (df path-sans-extension ((p path) => <string>)
  1716. (let ((ex (! get-extension p))
  1717. (str (! to-string p)))
  1718. (to-string (cond ((not ex) str)
  1719. (#t (! substring str 0 (- (len str) (len ex) 1)))))))
  1720. (df class-name-sans-package ((obj <object>))
  1721. (cond ((nul? obj) "<#!null>")
  1722. (#t
  1723. (let* ((c (! get-class obj)) (n (! get-simple-name c)))
  1724. (cond ((equal n "") (! get-name c))
  1725. (#t n))))))
  1726. (df list-env (#!optional (env :: <env> (<env>:current)))
  1727. (let ((enum (! enumerateAllLocations env)))
  1728. (packing (pack)
  1729. (while (! hasMoreElements enum)
  1730. (pack (! nextLocation enum))))))
  1731. (df list-file (filename)
  1732. (with (port (call-with-input-file filename))
  1733. (let* ((lang (gnu.expr.Language:getDefaultLanguage))
  1734. (messages (<gnu.text.SourceMessages>))
  1735. (comp (! parse lang (as <gnu.mapping.InPort> port) messages 0)))
  1736. (! get-module comp))))
  1737. (df list-decls (file)
  1738. (let* ((module (as <gnu.expr.ModuleExp> (list-file file))))
  1739. (do ((decl :: <gnu.expr.Declaration>
  1740. (! firstDecl module) (! nextDecl decl)))
  1741. ((nul? decl))
  1742. (format #t "~a ~a:~d:~d\n" decl
  1743. (! getFileName decl)
  1744. (! getLineNumber decl)
  1745. (! getColumnNumber decl)
  1746. ))))
  1747. (df %time (f)
  1748. (define-alias <mf> <java.lang.management.ManagementFactory>)
  1749. (define-alias <gc> <java.lang.management.GarbageCollectorMXBean>)
  1750. (let* ((gcs (<mf>:getGarbageCollectorMXBeans))
  1751. (mem (<mf>:getMemoryMXBean))
  1752. (jit (<mf>:getCompilationMXBean))
  1753. (oldjit (! getTotalCompilationTime jit))
  1754. (oldgc (packing (pack)
  1755. (iter gcs (fun ((gc <gc>))
  1756. (pack (cons gc
  1757. (list (! getCollectionCount gc)
  1758. (! getCollectionTime gc))))))))
  1759. (heap (!! getUsed getHeapMemoryUsage mem))
  1760. (nonheap (!! getUsed getNonHeapMemoryUsage mem))
  1761. (start (java.lang.System:nanoTime))
  1762. (values (f))
  1763. (end (java.lang.System:nanoTime))
  1764. (newheap (!! getUsed getHeapMemoryUsage mem))
  1765. (newnonheap (!! getUsed getNonHeapMemoryUsage mem)))
  1766. (format #t "~&")
  1767. (let ((njit (! getTotalCompilationTime jit)))
  1768. (format #t "; JIT compilation: ~:d ms (~:d)\n" (- njit oldjit) njit))
  1769. (iter gcs (fun ((gc <gc>))
  1770. (mlet ((_ count time) (assoc gc oldgc))
  1771. (format #t "; GC ~a: ~:d ms (~d)\n"
  1772. (! getName gc)
  1773. (- (! getCollectionTime gc) time)
  1774. (- (! getCollectionCount gc) count)))))
  1775. (format #t "; Heap: ~@:d (~:d)\n" (- newheap heap) newheap)
  1776. (format #t "; Non-Heap: ~@:d (~:d)\n" (- newnonheap nonheap) newnonheap)
  1777. (format #t "; Elapsed time: ~:d us\n" (/ (- end start) 1000))
  1778. values))
  1779. (define-syntax time
  1780. (syntax-rules ()
  1781. ((time form)
  1782. (%time (lambda () form)))))
  1783. (df gc ()
  1784. (let* ((mem (java.lang.management.ManagementFactory:getMemoryMXBean))
  1785. (oheap (!! getUsed getHeapMemoryUsage mem))
  1786. (onheap (!! getUsed getNonHeapMemoryUsage mem))
  1787. (_ (! gc mem))
  1788. (heap (!! getUsed getHeapMemoryUsage mem))
  1789. (nheap (!! getUsed getNonHeapMemoryUsage mem)))
  1790. (format #t "; heap: ~@:d (~:d) non-heap: ~@:d (~:d)\n"
  1791. (- heap oheap) heap (- onheap nheap) nheap)))
  1792. (df room ()
  1793. (let* ((pools (java.lang.management.ManagementFactory:getMemoryPoolMXBeans))
  1794. (mem (java.lang.management.ManagementFactory:getMemoryMXBean))
  1795. (heap (!! getUsed getHeapMemoryUsage mem))
  1796. (nheap (!! getUsed getNonHeapMemoryUsage mem)))
  1797. (iter pools (fun ((p <java.lang.management.MemoryPoolMXBean>))
  1798. (format #t "~&; ~a~1,16t: ~10:d\n"
  1799. (! getName p)
  1800. (!! getUsed getUsage p))))
  1801. (format #t "; Heap~1,16t: ~10:d\n" heap)
  1802. (format #t "; Non-Heap~1,16t: ~10:d\n" nheap)))
  1803. ;; (df javap (class #!key method signature)
  1804. ;; (let* ((<is> <java.io.ByteArrayInputStream>)
  1805. ;; (bytes
  1806. ;; (typecase class
  1807. ;; (<string> (read-bytes (<java.io.FileInputStream> (to-str class))))
  1808. ;; (<byte[]> class)
  1809. ;; (<symbol> (read-class-file class))))
  1810. ;; (cdata (<sun.tools.javap.ClassData> (<is> bytes)))
  1811. ;; (p (<sun.tools.javap.JavapPrinter>
  1812. ;; (<is> bytes)
  1813. ;; (current-output-port)
  1814. ;; (<sun.tools.javap.JavapEnvironment>))))
  1815. ;; (cond (method
  1816. ;; (dolist ((m <sun.tools.javap.MethodData>)
  1817. ;; (array-to-list (! getMethods cdata)))
  1818. ;; (when (and (equal (to-str method) (! getName m))
  1819. ;; (or (not signature)
  1820. ;; (equal signature (! getInternalSig m))))
  1821. ;; (! printMethodSignature p m (! getAccess m))
  1822. ;; (! printExceptions p m)
  1823. ;; (newline)
  1824. ;; (! printVerboseHeader p m)
  1825. ;; (! printcodeSequence p m))))
  1826. ;; (#t (p:print)))
  1827. ;; (values)))
  1828. (df read-bytes ((is <java.io.InputStream>) => <byte[]>)
  1829. (let ((os (<java.io.ByteArrayOutputStream>)))
  1830. (let loop ()
  1831. (let ((c (! read is)))
  1832. (cond ((= c -1))
  1833. (#t (! write os c) (loop)))))
  1834. (! to-byte-array os)))
  1835. (df read-class-file ((name <symbol>) => <byte[]>)
  1836. (let ((f (cat (! replace (to-str name) (as <char> #\.) (as <char> #\/))
  1837. ".class")))
  1838. (mcase (find-file-in-path f (class-path))
  1839. ('#f (ferror "Can't find classfile for ~s" name))
  1840. ((:zip zipfile entry)
  1841. (let* ((z (<java.util.zip.ZipFile> (as <str> zipfile)))
  1842. (e (z:getEntry (as <str> entry))))
  1843. (read-bytes (z:getInputStream e))))
  1844. ((:file s) (read-bytes (<java.io.FileInputStream> (as <str> s)))))))
  1845. (df all-instances ((vm <vm>) (classname <str>))
  1846. (mappend (fun ((c <class-ref>)) (to-list (! instances c 9999)))
  1847. (%all-subclasses vm classname)))
  1848. (df %all-subclasses ((vm <vm>) (classname <str>))
  1849. (mappend (fun ((c <class-ref>)) (cons c (to-list (! subclasses c))))
  1850. (to-list (! classes-by-name vm classname))))
  1851. (df with-output-to-string (thunk => <str>)
  1852. (call-with-output-string
  1853. (fun (s) (parameterize ((current-output-port s)) (thunk)))))
  1854. (df find-if ((i <iterable>) test default)
  1855. (let ((iter (! iterator i))
  1856. (found #f))
  1857. (while (and (not found) (! has-next iter))
  1858. (let ((e (! next iter)))
  1859. (when (test e)
  1860. (set found #t)
  1861. (set default e))))
  1862. default))
  1863. (df filter ((i <iterable>) test => <list>)
  1864. (packing (pack)
  1865. (for ((e i))
  1866. (when (test e)
  1867. (pack e)))))
  1868. (df iter ((i <iterable>) f)
  1869. (for ((e i)) (f e)))
  1870. (df mapi ((i <iterable>) f => <list>)
  1871. (packing (pack) (for ((e i)) (pack (f e)))))
  1872. (df nth ((i <iterable>) (n <int>))
  1873. (let ((iter (! iterator i)))
  1874. (dotimes (i n)
  1875. (! next iter))
  1876. (! next iter)))
  1877. (df 1st ((i <iterable>)) (!! next iterator i))
  1878. (df to-list ((i <iterable>) => <list>)
  1879. (packing (pack) (for ((e i)) (pack e))))
  1880. (df as-list ((o <java.lang.Object[]>) => <java.util.List>)
  1881. (java.util.Arrays:asList o))
  1882. (df mappend (f list)
  1883. (apply append (map f list)))
  1884. (df subseq (s from to)
  1885. (typecase s
  1886. (<list> (apply list (! sub-list s from to)))
  1887. (<vector> (apply vector (! sub-list s from to)))
  1888. (<str> (! substring s from to))
  1889. (<byte[]> (let* ((len (as <int> (- to from)))
  1890. (t (<byte[]> length: len)))
  1891. (java.lang.System:arraycopy s from t 0 len)
  1892. t))))
  1893. (df to-string (obj => <string>)
  1894. (cond ((instance? obj <str>) (<gnu.lists.FString> (as <str> obj)))
  1895. ((string? obj) obj)
  1896. ((symbol? obj) (symbol->string obj))
  1897. ((instance? obj <java.lang.StringBuffer>)
  1898. (<gnu.lists.FString> (as <java.lang.StringBuffer> obj)))
  1899. ((instance? obj <java.lang.StringBuilder>)
  1900. (<gnu.lists.FString> (as <java.lang.StringBuilder> obj)))
  1901. (#t (error "Not a string designator" obj
  1902. (class-name-sans-package obj)))))
  1903. (df to-str (obj => <str>)
  1904. (cond ((instance? obj <str>) obj)
  1905. ((string? obj) (! toString obj))
  1906. ((symbol? obj) (! getName (as <gnu.mapping.Symbol> obj)))
  1907. (#t (error "Not a string designator" obj
  1908. (class-name-sans-package obj)))))
  1909. ;; Local Variables:
  1910. ;; mode: goo
  1911. ;; compile-command:"kawa -e '(compile-file \"swank-kawa.scm\"\"swank-kawa.zip\")'"
  1912. ;; End: