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