Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2504 lines
87 KiB

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