~ chicken-core (master) /c-backend.scm
Trap1;;; c-backend.scm - C-generating backend for the CHICKEN compiler
2;
3; Copyright (c) 2008-2022, The CHICKEN Team
4; Copyright (c) 2000-2007, Felix L. Winkelmann
5; All rights reserved.
6;
7; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
8; conditions are met:
9;
10; Redistributions of source code must retain the above copyright notice, this list of conditions and the following
11; disclaimer.
12; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
13; disclaimer in the documentation and/or other materials provided with the distribution.
14; Neither the name of the author nor the names of its contributors may be used to endorse or promote
15; products derived from this software without specific prior written permission.
16;
17; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
18; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
20; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25; POSSIBILITY OF SUCH DAMAGE.
26
27
28(declare
29 (unit c-backend)
30 (uses data-structures extras c-platform compiler internal support))
31
32(module chicken.compiler.c-backend
33 (generate-code
34 ;; For "foreign" (aka chicken-ffi-syntax):
35 foreign-type-declaration)
36
37(import scheme
38 chicken.base
39 chicken.bitwise
40 chicken.fixnum
41 chicken.flonum
42 chicken.foreign
43 chicken.format
44 chicken.internal
45 chicken.keyword
46 chicken.platform
47 chicken.sort
48 chicken.string
49 chicken.time
50 chicken.compiler.core
51 chicken.compiler.c-platform
52 chicken.compiler.support)
53(import (only (scheme base) open-output-string get-output-string))
54
55(include "mini-srfi-1.scm")
56
57;;; Write atoms to output-port:
58
59(define output #f)
60
61(define (gen . data)
62 (for-each
63 (lambda (x)
64 (cond ((eq? #t x) (newline output))
65 (else (display x output) ) ))
66 data) )
67
68(define (gen-list lst)
69 (for-each
70 (lambda (x) (display x output))
71 (intersperse lst #\space) ) )
72
73;; Hacky procedures to make certain names more suitable for use in C.
74(define (backslashify s) (string-translate* (->string s) '(("\\" . "\\\\"))))
75(define (uncommentify s) (string-translate* (->string s) '(("*/" . "*_/"))))
76(define (c-identifier s) (string->c-identifier (->string s)))
77
78;; Generate a sorted alist out of a symbol table
79(define (table->sorted-alist t)
80 (let ((alist '()))
81 (hash-table-for-each
82 (lambda (id ll)
83 (set! alist
84 (cons (cons id ll) alist)))
85 t)
86
87 (sort! alist (lambda (p1 p2) (string<? (symbol->string (car p1))
88 (symbol->string (car p2)))))))
89
90
91;;; Generate target code:
92
93(define (generate-code literals lliterals lambda-table out source-file user-supplied-options dynamic db dbg-info-table)
94 (let ((lambda-table* (table->sorted-alist lambda-table)) ;; sort the symbol table to make the compiler output deterministic.
95 (non-av-proc #f))
96
97 ;; Don't truncate floating-point precision!
98 (flonum-print-precision (+ flonum-maximum-decimal-exponent 1))
99
100 ;; Some helper procedures
101
102 (define (find-lambda id)
103 (or (hash-table-ref lambda-table id)
104 (bomb "can't find lambda" id) ) )
105
106 ;; Compile a single expression
107 (define (expression node temps ll)
108
109 (define (expr n i)
110 (let ((subs (node-subexpressions n))
111 (params (node-parameters n)) )
112 (case (node-class n)
113
114 ((##core#immediate)
115 (case (first params)
116 ((bool) (gen (if (second params) "C_SCHEME_TRUE" "C_SCHEME_FALSE")))
117 ((char) (gen "C_make_character(" (char->integer (second params)) #\)))
118 ((nil) (gen "C_SCHEME_END_OF_LIST"))
119 ((fix) (gen "C_fix(" (second params) #\)))
120 ((eof) (gen "C_SCHEME_END_OF_FILE"))
121 ((bwp) (gen "C_SCHEME_BROKEN_WEAK_PTR"))
122 (else (bomb "bad immediate")) ) )
123
124 ((##core#literal)
125 (let ((lit (first params)))
126 (if (vector? lit)
127 (gen "((C_word)li" (vector-ref lit 0) ")")
128 (gen "lf[" (first params) #\])) ) )
129
130 ((##core#float)
131 (let ((n (first params)))
132 (gen "(double)")
133 (cond ((nan? n) (gen "NAN"))
134 ((infinite? n)
135 (when (negative? n) (gen #\-))
136 (gen "INFINITY"))
137 (else (gen n)))))
138
139 ((if)
140 (gen #t "if(C_truep(")
141 (expr (car subs) i)
142 (gen ")){")
143 (expr (cadr subs) i)
144 (gen #\} #t "else{")
145 (expr (caddr subs) i)
146 (gen #\}) )
147
148 ((##core#proc)
149 (gen "(C_word)" (first params)) )
150
151 ((##core#bind)
152 (let loop ((bs subs) (i i) (count (first params)))
153 (cond [(> count 0)
154 (gen #t #\t i #\=)
155 (expr (car bs) i)
156 (gen #\;)
157 (loop (cdr bs) (add1 i) (sub1 count)) ]
158 [else (expr (car bs) i)] ) ) )
159
160 ((##core#let_float)
161 (let ((fi (first params)))
162 (gen #t #\f fi #\=)
163 (expr (first subs) i)
164 (gen #\;)
165 (expr (second subs) i)))
166
167 ((##core#float-variable)
168 (gen #\f (first params)))
169
170 ((##core#unbox_float)
171 (gen "C_flonum_magnitude(")
172 (expr (first subs) i)
173 (gen ")"))
174
175 ((##core#box_float)
176 (gen "C_flonum(&a,")
177 (expr (first subs) i)
178 (gen ")"))
179
180 ((##core#ref)
181 (gen "((C_word*)")
182 (expr (car subs) i)
183 (gen ")[" (+ (first params) 1) #\]) )
184
185 ((##core#rest-car)
186 (let* ((n (lambda-literal-argument-count ll))
187 (depth (second params))
188 (have-av? (not (or (lambda-literal-customizable ll)
189 (lambda-literal-direct ll)))))
190 (if have-av?
191 (gen "C_get_rest_arg(c," (+ depth n) ",av," n ",t0)")
192 (gen "C_u_i_list_ref(t" (sub1 n) "," depth ")"))))
193
194 ((##core#rest-null?)
195 (let* ((n (lambda-literal-argument-count ll))
196 (depth (second params))
197 (have-av? (not (or (lambda-literal-customizable ll)
198 (lambda-literal-direct ll)))))
199 (if have-av?
200 (gen "C_rest_nullp(c," (+ depth n) ")")
201 (gen "C_mk_bool(C_unfix(C_i_length(t" (sub1 n) ")) >= " depth ")"))))
202
203 ((##core#rest-length)
204 (let* ((n (lambda-literal-argument-count ll))
205 (depth (second params))
206 (have-av? (not (or (lambda-literal-customizable ll)
207 (lambda-literal-direct ll)))))
208 (if have-av?
209 (gen "C_fix(c - " (+ depth n) ")")
210 (gen "C_u_i_length(t" (sub1 n) ")"))))
211
212 ((##core#unbox)
213 (gen "((C_word*)")
214 (expr (car subs) i)
215 (gen ")[1]") )
216
217 ((##core#update_i)
218 (gen "C_set_block_item(")
219 (expr (car subs) i)
220 (gen #\, (first params) #\,)
221 (expr (cadr subs) i)
222 (gen #\)) )
223
224 ((##core#update)
225 (gen "C_mutate(((C_word *)")
226 (expr (car subs) i)
227 (gen ")+" (+ (first params) 1) ",")
228 (expr (cadr subs) i)
229 (gen #\)) )
230
231 ((##core#updatebox_i)
232 (gen "C_set_block_item(")
233 (expr (car subs) i)
234 (gen ",0,")
235 (expr (cadr subs) i)
236 (gen #\)) )
237
238 ((##core#updatebox)
239 (gen "C_mutate(((C_word *)")
240 (expr (car subs) i)
241 (gen ")+1,")
242 (expr (cadr subs) i)
243 (gen #\)) )
244
245 ((##core#closure)
246 (let ((n (first params)))
247 (gen "(*a=C_CLOSURE_TYPE|" n #\,)
248 (for-each
249 (lambda (x j)
250 (gen "a[" j "]=")
251 (expr x i)
252 (gen #\,) )
253 subs (list-tabulate n add1))
254 (gen "tmp=(C_word)a,a+=" (add1 n) ",tmp)") ) )
255
256 ((##core#box)
257 (gen "(*a=C_VECTOR_TYPE|1,a[1]=")
258 (expr (car subs) i)
259 (gen ",tmp=(C_word)a,a+=2,tmp)") )
260
261 ((##core#local) (gen #\t (first params)))
262
263 ((##core#setlocal)
264 (gen #\t (first params) #\=)
265 (expr (car subs) i) )
266
267 ((##core#global)
268 (let ((index (first params))
269 (safe (second params))
270 (block (third params)) )
271 (cond [block
272 (if safe
273 (gen "lf[" index "]")
274 (gen "C_retrieve2(lf[" index "],C_text("
275 (c-ify-string (##sys#symbol->string/shared
276 (fourth params))) "))"))]
277 [safe (gen "*((C_word*)lf[" index "]+1)")]
278 [else (gen "C_fast_retrieve(lf[" index "])")] ) ) )
279
280 ((##core#setglobal)
281 (let ((index (first params))
282 (block (second params))
283 (var (third params)))
284 (if block
285 (gen "C_mutate(&lf[" index "]")
286 (gen "C_mutate((C_word*)lf[" index "]+1"))
287 (gen " /* (set! " (uncommentify (##sys#symbol->string/shared var)) " ...) */,")
288 (expr (car subs) i)
289 (gen #\)) ) )
290
291 ((##core#setglobal_i)
292 (let ((index (first params))
293 (block (second params))
294 (var (third params)) )
295 (cond [block
296 (gen "lf[" index "] /* "
297 (uncommentify (##sys#symbol->string/shared var)) " */ =")
298 (expr (car subs) i)
299 (gen #\;) ]
300 [else
301 (gen "C_set_block_item(lf[" index "] /* "
302 (uncommentify (##sys#symbol->string/shared var)) " */,0,")
303 (expr (car subs) i)
304 (gen #\)) ] ) ) )
305
306 ((##core#undefined) (gen "C_SCHEME_UNDEFINED"))
307
308 ((##core#call)
309 (let* ((args (cdr subs))
310 (n (length args))
311 (nc i)
312 (nf (add1 n))
313 (dbi (first params))
314 (safe-to-call (second params))
315 (p2 (pair? (cddr params)))
316 (name (and p2 (third params)))
317 (name-str (source-info->string name))
318 (call-id (and p2 (pair? (cdddr params)) (fourth params)))
319 (customizable (and call-id (fifth params)))
320 (empty-closure (and customizable (zero? (lambda-literal-closure-size (find-lambda call-id)))))
321 (fn (car subs)) )
322 (when name
323 (if emit-trace-info
324 (gen #t "C_trace(C_text(\"" (backslashify name-str) "\"));")
325 (gen #t "/* " (uncommentify name-str) " */"))
326 (when (and emit-debug-info dbi)
327 (gen #t "C_debugger(&(C_debug_info[" dbi "]),"
328 (if non-av-proc "0,NULL" "c,av") ");")))
329 (cond ((eq? '##core#proc (node-class fn))
330 (gen #\{)
331 (push-args args i "0")
332 (let ([fpars (node-parameters fn)])
333 (gen #t (first fpars) #\( nf ",av2);}") ))
334 (call-id
335 (cond ((and (eq? call-id (lambda-literal-id ll))
336 (lambda-literal-looping ll) )
337 (let* ((temps (lambda-literal-temporaries ll))
338 (ts (list-tabulate n (lambda (i) (+ temps nf i)))))
339 (for-each
340 (lambda (arg tr)
341 (gen #t #\t tr #\=)
342 (expr arg i)
343 (gen #\;) )
344 args ts)
345 (for-each
346 (lambda (from to) (gen #t #\t to "=t" from #\;))
347 ts (list-tabulate n add1))
348 (unless customizable (gen #t "c=" nf #\;))
349 (gen #t "goto loop;") ) )
350 (else
351 (unless empty-closure
352 (gen #t #\t nc #\=)
353 (expr fn i)
354 (gen #\;) )
355 (cond (customizable
356 (gen #t call-id #\()
357 (unless empty-closure (gen #\t nc #\,))
358 (expr-args args i)
359 (gen ");") )
360 (else
361 (gen #\{)
362 (push-args args i (and (not empty-closure) (string-append "t" (number->string nc))))
363 (gen #t call-id #\()
364 (unless customizable (gen nf #\,))
365 (gen "av2);}") ) ) )))
366 ((and (eq? '##core#global (node-class fn))
367 (not unsafe)
368 (not no-procedure-checks)
369 (not safe-to-call))
370 (let* ((gparams (node-parameters fn))
371 (index (first gparams))
372 (safe (second gparams))
373 (block (third gparams))
374 (carg #f))
375 (gen #t "{C_proc tp=(C_proc)")
376 (cond (no-global-procedure-checks
377 (set! carg
378 (if block
379 (string-append "lf[" (number->string index) "]")
380 (string-append "*((C_word*)lf[" (number->string index) "]+1)")))
381 (gen "(void*)(*((C_word*)(" carg ")+1))"))
382 (block
383 (set! carg (string-append "lf[" (number->string index) "]"))
384 (if safe
385 (gen "C_fast_retrieve_proc(" carg ")")
386 (gen "C_retrieve2_symbol_proc(" carg ",C_text("
387 (c-ify-string (##sys#symbol->string/shared (fourth gparams))) "))")))
388 (safe
389 (set! carg
390 (string-append "*((C_word*)lf[" (number->string index) "]+1)"))
391 (gen "C_fast_retrieve_proc(" carg ")"))
392 (else
393 (set! carg
394 (string-append "*((C_word*)lf[" (number->string index) "]+1)"))
395 (gen "C_fast_retrieve_symbol_proc(lf[" index "])") ))
396 (gen #\;)
397 (push-args args i carg)
398 (gen #t "tp(" nf ",av2);}")))
399 (else
400 (gen #t #\t nc #\=)
401 (expr fn i)
402 (gen ";{")
403 (push-args args i (string-append "t" (number->string nc)))
404 (gen #t "((C_proc)")
405 (if (or unsafe no-procedure-checks safe-to-call)
406 (gen "(void*)(*((C_word*)t" nc "+1))")
407 (gen "C_fast_retrieve_proc(t" nc ")") )
408 (gen ")(" nf ",av2);}") ) ) ) )
409
410 ((##core#recurse)
411 (let* ([n (length subs)]
412 [nf (add1 n)]
413 [tailcall (first params)]
414 [call-id (second params)]
415 [empty-closure (zero? (lambda-literal-closure-size ll))] )
416 (cond (tailcall
417 (let* ((temps (lambda-literal-temporaries ll))
418 (ts (list-tabulate n (cut + temps nf <>))))
419 (for-each
420 (lambda (arg tr)
421 (gen #t #\t tr #\=)
422 (expr arg i)
423 (gen #\;) )
424 subs ts)
425 (for-each
426 (lambda (from to) (gen #t #\t to "=t" from #\;))
427 ts (list-tabulate n add1))
428 (gen #t "goto loop;") ) )
429 (else
430 (gen call-id #\()
431 (unless empty-closure (gen "t0,"))
432 (expr-args subs i)
433 (gen #\)) ) ) ) )
434
435 ((##core#direct_call)
436 (let* ((args (cdr subs))
437 (n (length args))
438 (nf (add1 n))
439 (dbi (first params))
440 ;; (safe-to-call (second params))
441 (name (third params))
442 (name-str (source-info->string name))
443 (call-id (fourth params))
444 (demand (fifth params))
445 (allocating (not (zero? demand)))
446 (empty-closure (zero? (lambda-literal-closure-size (find-lambda call-id))))
447 (fn (car subs)) )
448 (gen #\()
449 (when name
450 (if emit-trace-info
451 (gen #t "C_trace(\"" (backslashify name-str) "\"),")
452 (gen #t "/* " (uncommentify name-str) " */"))
453 (when (and emit-debug-info dbi)
454 (gen #t "C_debugger(&(C_debug_info[" dbi "]),"
455 (if non-av-proc "0,NULL" "c,av") "),")))
456 (gen #t " " call-id #\()
457 (when allocating
458 (gen "C_a_i(&a," demand #\))
459 (when (or (not empty-closure) (pair? args)) (gen #\,)) )
460 (unless empty-closure
461 (expr fn i)
462 (when (pair? args) (gen #\,)) )
463 (when (pair? args) (expr-args args i))
464 (gen #\)) ; function call
465 (gen #t #\)))) ; complete expression
466
467 ((##core#provide)
468 (gen "C_a_i_provide(&a,1,lf[" (first params) "])"))
469
470 ((##core#callunit)
471 ;; The code generated here does not use the extra temporary needed for standard calls, so we have
472 ;; one unused variable:
473 (let* ((n (length subs))
474 (nf (+ n 1)) )
475 (gen #\{)
476 (push-args subs i "C_SCHEME_UNDEFINED")
477 (gen #t "C_" (toplevel (first params)) "(" nf ",av2);}")))
478
479 ((##core#return)
480 (gen #t "return(")
481 (expr (first subs) i)
482 (gen ");") )
483
484 ((##core#inline)
485 (gen (first params) #\()
486 (expr-args subs i)
487 (gen #\)) )
488
489 ((##core#debug-event)
490 (gen "C_debugger(&(C_debug_info[" (first params) "]),"
491 (if non-av-proc "0,NULL" "c,av") ")"))
492
493 ((##core#inline_allocate)
494 (gen (first params) "(&a," (length subs))
495 (if (pair? subs)
496 (begin
497 (gen #\,)
498 (expr-args subs i) ) )
499 (gen #\)) )
500
501 ((##core#inline_ref)
502 (gen (foreign-result-conversion (second params) "a") (first params) #\)) )
503
504 ((##core#inline_update)
505 (let ([t (second params)])
506 (gen #\( (first params) "=(" (foreign-type-declaration t "") #\) (foreign-argument-conversion t))
507 (expr (first subs) i)
508 (gen "),C_SCHEME_UNDEFINED)") ) )
509
510 ((##core#inline_loc_ref)
511 (let ([t (first params)])
512 (gen (foreign-result-conversion t "a") "*((" (foreign-type-declaration t "") "*)C_data_pointer(")
513 (expr (first subs) i)
514 (gen ")))") ) )
515
516 ((##core#inline_loc_update)
517 (let ([t (first params)])
518 (gen "((*(" (foreign-type-declaration t "") "*)C_data_pointer(")
519 (expr (first subs) i)
520 (gen "))=" (foreign-argument-conversion t))
521 (expr (second subs) i)
522 (gen "),C_SCHEME_UNDEFINED)") ) )
523
524 ((##core#switch)
525 (gen #t "switch(")
526 (expr (first subs) i)
527 (gen "){")
528 (do ([j (first params) (sub1 j)]
529 [ps (cdr subs) (cddr ps)] )
530 ((zero? j)
531 (gen #t "default:")
532 (expr (car ps) i)
533 (gen #\}) )
534 (gen #t "case ")
535 (expr (car ps) i)
536 (gen #\:)
537 (expr (cadr ps) i) ) )
538
539 ((##core#cond)
540 (gen "(C_truep(")
541 (expr (first subs) i)
542 (gen ")?")
543 (expr (second subs) i)
544 (gen #\:)
545 (expr (third subs) i)
546 (gen #\)) )
547
548 (else (bomb "bad form" (node-class n))) ) ) )
549
550 (define (expr-args args i)
551 (let loop ((xs args))
552 (unless (null? xs)
553 (unless (eq? xs args) (gen #\,))
554 (expr (car xs) i)
555 (loop (cdr xs)))))
556
557 (define (contains-restop? args)
558 (let loop ((args args))
559 (if (null? args)
560 #f
561 (let ((node (car args)))
562 ;; Only rest-car accesses av
563 (or (eq? (node-class node) '##core#rest-car)
564 (contains-restop? (node-subexpressions node))
565 (loop (cdr args)))))))
566
567 (define (push-args args i selfarg)
568 (let* ((n (length args))
569 (avl (+ n (if selfarg 1 0)))
570 (caller-has-av? (not (or (lambda-literal-customizable ll)
571 (lambda-literal-direct ll))))
572 (caller-argcount (lambda-literal-argument-count ll))
573 (caller-rest-mode (lambda-literal-rest-argument-mode ll)))
574 ;; Try to re-use argvector from current function if it is
575 ;; large enough. push-args gets used only for functions in
576 ;; CPS context, so callee never returns to current function.
577 ;; And even so, av[] is already copied into temporaries.
578 (cond
579 ((or (not caller-has-av?) ; Argvec missing or
580 (and (< caller-argcount avl) ; known to be too small?
581 (eq? caller-rest-mode 'none))
582 (contains-restop? args)) ; Restops work on original av
583 (gen #t "C_word av2[" avl "];"))
584 ((>= caller-argcount avl) ; Argvec known to be re-usable?
585 (gen #t "C_word *av2=av;")) ; Re-use our own argvector
586 (else ; Need to determine dynamically. This is slower.
587 (gen #t "C_word *av2;")
588 (gen #t "if(c >= " avl ") {")
589 (gen #t " av2=av;") ; Re-use our own argvector
590 (gen #t "} else {")
591 (gen #t " av2=C_alloc(" avl ");")
592 (gen #t "}")))
593 (when selfarg (gen #t "av2[0]=" selfarg ";"))
594 (do ((j (if selfarg 1 0) (add1 j))
595 (args args (cdr args)))
596 ((null? args))
597 (gen #t "av2[" j "]=")
598 (expr (car args) i)
599 (gen ";"))))
600
601 (expr node temps) )
602
603 (define (header)
604 (gen "/* Generated from " source-file " by the CHICKEN compiler" #t
605 " http://www.call-cc.org" #t
606 (string-intersperse
607 (map (cut string-append " " <> "\n")
608 (string-split (chicken-version #t) "\n") )
609 "")
610 " command line: ")
611 (gen-list user-supplied-options)
612 (unless (not unit-name)
613 (gen #t " unit: " unit-name))
614 (unless (null? used-units)
615 (gen #t " uses: ")
616 (gen-list used-units))
617 (gen #t "*/")
618 (gen #t "#include \"" target-include-file "\"")
619 (when external-protos-first
620 (generate-foreign-callback-stub-prototypes foreign-callback-stubs) )
621 (when (pair? foreign-declarations)
622 (gen #t)
623 (for-each (lambda (decl) (gen #t decl)) foreign-declarations) )
624 (unless external-protos-first
625 (generate-foreign-callback-stub-prototypes foreign-callback-stubs) ) )
626
627 (define (trailer)
628 (gen #t #t "/*" #t
629 (uncommentify
630 (get-output-string
631 collected-debugging-output))
632 "*/"
633 #t "/* end of file */" #t))
634
635 (define (declarations)
636 (let ((n (length literals)))
637 (gen #t #t "static C_PTABLE_ENTRY *create_ptable(void);")
638 (for-each
639 (lambda (uu)
640 (gen #t "C_noret_decl(C_" uu ")"
641 #t "C_extern void C_ccall C_" uu "(C_word c,C_word *av) C_noret;"))
642 (map toplevel used-units))
643 (unless (zero? n)
644 (gen #t #t "static C_word lf[" n "];") )
645 (gen #t "static double C_possibly_force_alignment;")
646 (do ((i 0 (add1 i))
647 (llits lliterals (cdr llits)))
648 ((null? llits))
649 (let* ((ll (car llits))
650 (llen (##sys#size ll)))
651 (gen #t "static C_char li" i "[] C_aligned={C_lihdr("
652 (arithmetic-shift llen -16) #\,
653 (bitwise-and #xff (arithmetic-shift llen -8)) #\,
654 (bitwise-and #xff llen)
655 #\))
656 (do ((n 0 (add1 n)))
657 ((>= n llen))
658 (gen #\, (##sys#byte ll n)))
659 (do ((n (- (bitwise-and #xfffff8 (+ llen 7)) llen) (sub1 n))) ; fill up with zeros to align following entry
660 ((zero? n))
661 (gen ",0") )
662 (gen "};")))))
663
664 (define (prototypes)
665 (gen #t)
666 (for-each
667 (lambda (p)
668 (let* ((id (car p))
669 (ll (cdr p))
670 (n (lambda-literal-argument-count ll))
671 (customizable (lambda-literal-customizable ll))
672 (empty-closure (and customizable (zero? (lambda-literal-closure-size ll))))
673 (varlist (intersperse (make-variable-list (if empty-closure (sub1 n) n) "t") #\,))
674 (direct (lambda-literal-direct ll))
675 (allocated (lambda-literal-allocated ll)) )
676 (gen #t)
677 (cond ((not (eq? 'toplevel id))
678 (gen "C_noret_decl(" id ")" #t)
679 (gen "static ")
680 (gen (if direct "C_word " "void "))
681 (unless customizable (gen "C_ccall "))
682 (gen id) )
683 (else
684 (let ((uname (toplevel unit-name)))
685 (gen "C_noret_decl(C_" uname ")" #t) ;XXX what's this for?
686 (gen "C_extern void C_ccall ")
687 (gen "C_" uname) ) ) )
688 (gen #\()
689 (unless customizable (gen "C_word c,"))
690 (when (and direct (not (zero? allocated)))
691 (gen "C_word *a")
692 (when (pair? varlist) (gen #\,)) )
693 (if (or customizable direct)
694 (apply gen varlist)
695 (gen "C_word *av"))
696 (gen #\))
697 (unless direct (gen " C_noret"))
698 (gen #\;) ))
699 lambda-table*) )
700
701 (define (trampolines)
702 (let ([ns '()]
703 [nsr '()]
704 [nsrv '()] )
705
706 (define (restore n)
707 (do ((i 0 (add1 i))
708 (j (sub1 n) (sub1 j)))
709 ((>= i n))
710 (gen #t "C_word t" i "=av[" j "];")))
711
712 (for-each
713 (lambda (p)
714 (let* ([id (car p)]
715 [ll (cdr p)]
716 [argc (lambda-literal-argument-count ll)]
717 [customizable (lambda-literal-customizable ll)]
718 [empty-closure (and customizable (zero? (lambda-literal-closure-size ll)))] )
719 (when empty-closure (set! argc (sub1 argc)))
720 (when (and (not (lambda-literal-direct ll)) customizable)
721 (gen #t #t "C_noret_decl(tr" id ")"
722 #t "static void C_ccall tr" id "(C_word c,C_word *av) C_noret;")
723 (gen #t "static void C_ccall tr" id "(C_word c,C_word *av){")
724 (restore argc)
725 (gen #t id #\()
726 (let ([al (make-argument-list argc "t")])
727 (apply gen (intersperse al #\,)) )
728 (gen ");}") )))
729 lambda-table*)))
730
731 (define (literal-frame)
732 (do ([i 0 (add1 i)]
733 [lits literals (cdr lits)] )
734 ((null? lits))
735 (gen-lit (car lits) (sprintf "lf[~s]" i)) ) )
736
737 (define (bad-literal lit)
738 (bomb "type of literal not supported" lit) )
739
740 (define (literal-size lit)
741 (cond ((immediate? lit) 0)
742 ((big-fixnum? lit) 2) ; immediate if fixnum, bignum see below
743 ((string? lit) 0) ; statically allocated
744 ((bignum? lit) 2) ; internal vector statically allocated
745 ((flonum? lit) words-per-flonum)
746 ((symbol? lit) 7) ; size of symbol, and possibly a bucket
747 ((keyword? lit) 7) ; size of keyword (symbol), and possibly a bucket
748 ((pair? lit) (+ 3 (literal-size (car lit)) (literal-size (cdr lit))))
749 ((vector? lit)
750 (+ 1 (vector-length lit)
751 (foldl + 0 (map literal-size (vector->list lit)))))
752 ((block-variable-literal? lit) 0) ; excluded from generated code
753 ((##sys#immediate? lit) (bad-literal lit))
754 ((##core#inline "C_lambdainfop" lit) 0) ; statically allocated
755 ((##sys#bytevector? lit) (+ 2 (bytes->words (##sys#size lit))) ) ; drops "permanent" property!
756 ((##sys#generic-structure? lit)
757 (let ([n (##sys#size lit)])
758 (let loop ([i 0] [s (+ 2 n)])
759 (if (>= i n)
760 s
761 (loop (add1 i) (+ s (literal-size (##sys#slot lit i)))) ) ) ) )
762 ;; We could access rat/cplx slots directly, but let's not.
763 ((ratnum? lit) (+ (##sys#size lit)
764 (literal-size (numerator lit))
765 (literal-size (denominator lit))))
766 ((cplxnum? lit) (+ (##sys#size lit)
767 (literal-size (real-part lit))
768 (literal-size (imag-part lit))))
769 (else (bad-literal lit))) )
770
771 (define (gen-lit lit to)
772 ;; we do simple immediate literals directly to avoid a function call:
773 (cond ((and (fixnum? lit) (not (big-fixnum? lit)))
774 (gen #t to "=C_fix(" lit ");") )
775 ((block-variable-literal? lit))
776 ((eq? lit (void))
777 (gen #t to "=C_SCHEME_UNDEFINED;") )
778 ((boolean? lit)
779 (gen #t to #\= (if lit "C_SCHEME_TRUE" "C_SCHEME_FALSE") #\;) )
780 ((char? lit)
781 (gen #t to "=C_make_character(" (char->integer lit) ");") )
782 ((or (keyword? lit) (symbol? lit)) ; handled slightly specially (see C_h_intern_in)
783 (let* ((str (##sys#symbol->string/shared lit))
784 (cstr (c-ify-string str))
785 (len (fx- (##sys#size (##sys#slot lit 1)) 1))
786 (intern (if (keyword? lit)
787 "C_h_intern_kw"
788 "C_h_intern")))
789 (gen #t to "=")
790 (gen intern "(&" to #\, len ", C_text(" cstr "));")))
791 ((null? lit)
792 (gen #t to "=C_SCHEME_END_OF_LIST;") )
793 ((and (not (##sys#immediate? lit)) ; nop
794 (##core#inline "C_lambdainfop" lit)))
795 ((or (fixnum? lit) (not (##sys#immediate? lit)))
796 (gen #t to "=C_decode_literal(C_heaptop,C_text(\"")
797 (gen (encode-literal lit))
798 (gen "\"));"))
799 (else (bad-literal lit))))
800
801 (define (procedures)
802 (for-each
803 (lambda (p)
804 (let* ((id (car p))
805 (ll (cdr p))
806 (n (lambda-literal-argument-count ll))
807 (rname (real-name id db))
808 (demand (lambda-literal-allocated ll))
809 (max-av (apply max 0 (lambda-literal-callee-signatures ll)))
810 (rest (lambda-literal-rest-argument ll))
811 (customizable (lambda-literal-customizable ll))
812 (empty-closure (and customizable (zero? (lambda-literal-closure-size ll))))
813 (nec (- n (if empty-closure 1 0)))
814 (vlist0 (make-variable-list n "t"))
815 (alist0 (make-argument-list n "t"))
816 (varlist (intersperse (if empty-closure (cdr vlist0) vlist0) #\,))
817 (arglist (intersperse (if empty-closure (cdr alist0) alist0) #\,))
818 (external (lambda-literal-external ll))
819 (looping (lambda-literal-looping ll))
820 (direct (lambda-literal-direct ll))
821 (rest-mode (lambda-literal-rest-argument-mode ll))
822 (temps (lambda-literal-temporaries ll))
823 (ftemps (lambda-literal-float-temporaries ll))
824 (topname (toplevel unit-name)))
825 (when empty-closure (debugging 'o "dropping unused closure argument" id))
826 (gen #t #t)
827 (gen "/* " (cleanup rname) " */" #t)
828 (cond [(not (eq? 'toplevel id))
829 (gen "static ")
830 (gen (if direct "C_word " "void "))
831 (unless customizable (gen "C_ccall "))
832 (gen id) ]
833 [else
834 (gen "static int toplevel_initialized=0;")
835 (unless unit-name
836 (gen #t "C_main_entry_point") )
837 (gen #t #t "void C_ccall C_" topname) ] )
838 (gen #\()
839 (unless customizable (gen "C_word c,"))
840 (when (and direct (not (zero? demand)))
841 (gen "C_word *a")
842 (when (pair? varlist) (gen #\,)) )
843 (if (or customizable direct)
844 (apply gen varlist)
845 (gen "C_word *av"))
846 (gen "){")
847 (when (eq? rest-mode 'none) (set! rest #f))
848 (gen #t "C_word tmp;")
849 (unless (or customizable direct)
850 (do ((i 0 (add1 i)))
851 ((>= i n))
852 (gen #t "C_word t" i "=av[" i "];")))
853 (if rest
854 (gen #t "C_word t" n #\;) ; To hold rest-list if demand is met
855 (begin
856 (do ([i n (add1 i)]
857 [j (+ temps (if looping (sub1 n) 0)) (sub1 j)] )
858 ((zero? j))
859 (gen #t "C_word t" i #\;))
860 (for-each
861 (lambda (i)
862 (gen #t "double f" i #\;))
863 ftemps)))
864 (cond ((eq? 'toplevel id)
865 (let ([ldemand (foldl (lambda (n lit) (+ n (literal-size lit))) 0 literals)]
866 [llen (length literals)] )
867 (gen #t "C_word *a;"
868 #t "if(toplevel_initialized) {C_kontinue(t1,C_SCHEME_UNDEFINED);}"
869 #t "else C_toplevel_entry(C_text(\"" (or unit-name topname) "\"));")
870 (when emit-debug-info
871 (gen #t "C_register_debug_info(C_debug_info);"))
872 (when disable-stack-overflow-checking
873 (gen #t "C_disable_overflow_check=1;") )
874 (unless unit-name
875 (when target-heap-size
876 (gen #t "C_set_or_change_heap_size(" target-heap-size ",1);"
877 #t "C_heap_size_is_fixed=1;"))
878 (when target-stack-size
879 (gen #t "C_resize_stack(" target-stack-size ");") ) )
880 (gen #t "C_check_nursery_minimum(C_calculate_demand(" demand ",c," max-av "));"
881 #t "if(C_unlikely(!C_demand(C_calculate_demand(" demand ",c," max-av ")))){"
882 #t "C_save_and_reclaim((void*)C_" topname ",c,av);}"
883 #t "toplevel_initialized=1;"
884 #t "if(C_unlikely(!C_demand_2(" ldemand "))){"
885 #t "C_save(t1);"
886 #t "C_rereclaim2(" ldemand "*sizeof(C_word),1);"
887 #t "t1=C_restore;}"
888 #t "a=C_alloc(" demand ");")
889 (when (not (zero? llen))
890 (gen #t "C_initialize_lf(lf," llen ");")
891 (literal-frame)
892 (gen #t "C_register_lf2(lf," llen ",create_ptable());"))
893 (gen #\{)))
894 (rest
895 (gen #t "C_word *a;")
896 (when (and (not unsafe) (not no-argc-checks) (> n 2) (not empty-closure))
897 (gen #t "if(c<" n ") C_bad_min_argc_2(c," n ",t0);") )
898 (when insert-timer-checks (gen #t "C_check_for_interrupt;"))
899 (gen #t "if(C_unlikely(!C_demand(C_calculate_demand((c-" n ")*C_SIZEOF_PAIR +" demand ",c," max-av ")))){"))
900 (else
901 (unless direct (gen #t "C_word *a;"))
902 (when (and direct (not unsafe) (not disable-stack-overflow-checking))
903 (gen #t "C_stack_overflow_check;"))
904 (when looping (gen #t "loop:"))
905 (when (and external (not unsafe) (not no-argc-checks) (not customizable))
906 ;; (not customizable) implies empty-closure
907 (if (eq? rest-mode 'none)
908 (when (> n 2) (gen #t "if(c<" n ") C_bad_min_argc_2(c," n ",t0);"))
909 (gen #t "if(c!=" n ") C_bad_argc_2(c," n ",t0);") ) )
910 (cond ((not direct)
911 ;; The interrupt handler may fill the stack, so we only
912 ;; check for an interrupt when the procedure is restartable
913 (when insert-timer-checks (gen #t "C_check_for_interrupt;"))
914 (gen #t "if(C_unlikely(!C_demand(C_calculate_demand("
915 demand
916 (if customizable ",0," ",c,")
917 max-av ")))){"))
918 (else
919 (gen #\{)))))
920 (cond ((and (not (eq? 'toplevel id)) (not direct))
921 (when (and looping (not customizable))
922 ;; Loop will update t_n copy of av[n]; refresh av.
923 (do ((i 0 (add1 i)))
924 ((>= i n))
925 (gen #t "av[" i "]=t" i ";")))
926 (cond (rest
927 (gen #t "C_save_and_reclaim((void*)" id ",c,av);}"
928 #t "a=C_alloc((c-" n ")*C_SIZEOF_PAIR+" demand ");")
929 (gen #t "t" n "=C_build_rest(&a,c," n ",av);")
930 (do ((i (+ n 1) (+ i 1))
931 (j temps (- j 1)))
932 ((zero? j))
933 (gen #t "C_word t" i #\;)))
934 (else
935 (cond ((and customizable (> nec 0))
936 (gen #t "C_save_and_reclaim_args((void *)tr" id #\, nec #\,)
937 (apply gen arglist)
938 (gen ");}"))
939 (else
940 (gen #t "C_save_and_reclaim((void *)" id ",c,av);}")))
941 (when (> demand 0)
942 (gen #t "a=C_alloc(" demand ");")))))
943 (else (gen #\})))
944 (set! non-av-proc customizable)
945 (expression
946 (lambda-literal-body ll)
947 (if rest
948 (add1 n) ; One temporary is needed to hold the rest-list
949 n)
950 ll)
951 (gen #\}) ) )
952 lambda-table*) )
953
954 (debugging 'p "code generation phase...")
955 (set! output out)
956 (header)
957 (declarations)
958 (generate-external-variables external-variables)
959 (generate-foreign-stubs foreign-lambda-stubs db)
960 (prototypes)
961 (generate-foreign-callback-stubs foreign-callback-stubs db)
962 (trampolines)
963 (when emit-debug-info
964 (emit-debug-table dbg-info-table))
965 (procedures)
966 (emit-procedure-table lambda-table* source-file)
967 (trailer) ) )
968
969
970;;; Emit global tables for debug-info
971
972(define (emit-debug-table dbg-info-table)
973 (gen #t #t "static C_DEBUG_INFO C_debug_info[]={")
974 (for-each
975 (lambda (info)
976 (gen #t "{" (second info) ",0,")
977 (for-each
978 (lambda (x)
979 (if (not x)
980 (gen "NULL,")
981 (gen "C_text(\"" (backslashify (->string x)) "\"),")))
982 (cddr info))
983 (gen "},"))
984 (sort dbg-info-table (lambda (i1 i2) (< (car i1) (car i2)))))
985 (gen #t "{0,0,NULL,NULL}};\n"))
986
987
988;;; Emit procedure table:
989
990(define (emit-procedure-table lambda-table* sf)
991 (gen #t #t "#ifdef C_ENABLE_PTABLES"
992 #t "static C_PTABLE_ENTRY ptable[" (add1 (length lambda-table*)) "] = {")
993 (for-each
994 (lambda (p)
995 (let ((id (car p))
996 (ll (cdr p)))
997 (gen #t "{C_text(\"" id #\: (string->c-identifier sf) "\"),(void*)")
998 (if (eq? 'toplevel id)
999 (gen "C_" (toplevel unit-name) "},")
1000 (gen id "},") ) ) )
1001 lambda-table*)
1002 (gen #t "{NULL,NULL}};")
1003 (gen #t "#endif")
1004 (gen #t #t "static C_PTABLE_ENTRY *create_ptable(void)")
1005 (gen "{" #t "#ifdef C_ENABLE_PTABLES"
1006 #t "return ptable;"
1007 #t "#else"
1008 #t "return NULL;"
1009 #t "#endif"
1010 #t "}") )
1011
1012
1013;;; Generate top-level procedure name:
1014
1015(define (toplevel name)
1016 (if (not name)
1017 "toplevel"
1018 (string-append (c-identifier name) "_toplevel")))
1019
1020
1021;;; Create name that is safe for C comments:
1022
1023(define (cleanup s)
1024 (let ([s2 #f]
1025 [len (string-length s)] )
1026 (let loop ([i 0])
1027 (if (>= i len)
1028 (or s2 s)
1029 (let ([c (string-ref s i)])
1030 (if (or (char<? c #\space)
1031 (char>? c #\~)
1032 (and (char=? c #\*) (< i (sub1 len)) (char=? #\/ (string-ref s (add1 i)))) )
1033 (begin
1034 (unless s2 (set! s2 (string-copy s)))
1035 (string-set! s2 i #\~) )
1036 (when s2 (string-set! s2 i c)) )
1037 (loop (add1 i)) ) ) ) ) )
1038
1039
1040;;; Create list of variables/parameters, interspersed with a special token:
1041
1042(define (make-variable-list n prefix)
1043 (list-tabulate
1044 n
1045 (lambda (i) (string-append "C_word " prefix (number->string i))) ) )
1046
1047(define (make-argument-list n prefix)
1048 (list-tabulate
1049 n
1050 (lambda (i) (string-append prefix (number->string i))) ) )
1051
1052
1053;;; Generate external variable declarations:
1054
1055(define (generate-external-variables vars)
1056 (gen #t)
1057 (for-each
1058 (lambda (v)
1059 (let ((name (vector-ref v 0))
1060 (type (vector-ref v 1))
1061 (exported (vector-ref v 2)) )
1062 (gen #t (if exported "" "static ") (foreign-type-declaration type name) #\;) ) )
1063 vars) )
1064
1065
1066;;; Generate foreign stubs:
1067
1068(define (generate-foreign-callback-stub-prototypes stubs)
1069 (for-each
1070 (lambda (stub)
1071 (gen #t)
1072 (generate-foreign-callback-header "C_extern " stub)
1073 (gen #\;) )
1074 stubs) )
1075
1076(define (generate-foreign-stubs stubs db)
1077 (for-each
1078 (lambda (stub)
1079 (let* ([id (foreign-stub-id stub)]
1080 [rname (real-name2 id db)]
1081 [types (foreign-stub-argument-types stub)]
1082 [n (length types)]
1083 [rtype (foreign-stub-return-type stub)]
1084 [sname (foreign-stub-name stub)]
1085 [body (foreign-stub-body stub)]
1086 [names (or (foreign-stub-argument-names stub) (make-list n #f))]
1087 [rconv (foreign-result-conversion rtype "C_a")]
1088 [cps (foreign-stub-cps stub)]
1089 [callback (foreign-stub-callback stub)] )
1090 (gen #t)
1091 (when rname
1092 (gen #t "/* from " (cleanup rname) " */") )
1093 (when body
1094 (gen #t "#define return(x) C_cblock C_r = (" rconv
1095 "(x))); goto C_ret; C_cblockend"))
1096 (cond (cps
1097 (gen #t "C_noret_decl(" id ")"
1098 #t "static void C_ccall " id "(C_word C_c,C_word *C_av){"
1099 #t "C_word C_k=C_av[1],C_buf=C_av[2];")
1100 (do ((i 0 (add1 i)))
1101 ((>= i n))
1102 (gen #t "C_word C_a" i "=C_av[" (+ i 3) "];")))
1103 (else
1104 (gen #t "C_regparm static C_word " id #\()
1105 (apply gen (intersperse (cons "C_word C_buf" (make-variable-list n "C_a")) #\,))
1106 (gen "){")))
1107 (gen #t "C_word C_r=C_SCHEME_UNDEFINED,*C_a=(C_word*)C_buf;")
1108 (for-each
1109 (lambda (type index name)
1110 (gen #t
1111 (foreign-type-declaration
1112 type
1113 (if name (symbol->string name) (sprintf "t~a" index)) )
1114 "=(" (foreign-type-declaration type "") #\)
1115 (foreign-argument-conversion type) "C_a" index ");") )
1116 types (iota n) names)
1117 (when callback (gen #t "int C_level=C_save_callback_continuation(&C_a,C_k);"))
1118 (cond [body
1119 (gen #t body
1120 #t "C_ret:")
1121 (gen #t "#undef return" #t)
1122 (cond [callback
1123 (gen #t "C_k=C_restore_callback_continuation2(C_level);"
1124 #t "C_kontinue(C_k,C_r);") ]
1125 [cps (gen #t "C_kontinue(C_k,C_r);")]
1126 [else (gen #t "return C_r;")] ) ]
1127 [else
1128 (if (not (eq? rtype 'void))
1129 (gen #t "C_r=" rconv)
1130 (gen #t) )
1131 (gen sname #\()
1132 (apply gen (intersperse (make-argument-list n "t") #\,))
1133 (unless (eq? rtype 'void) (gen #\)))
1134 (gen ");")
1135 (cond [callback
1136 (gen #t "C_k=C_restore_callback_continuation2(C_level);"
1137 #t "C_kontinue(C_k,C_r);") ]
1138 [cps (gen "C_kontinue(C_k,C_r);")]
1139 [else (gen #t "return C_r;")] ) ] )
1140 (gen #\}) ) )
1141 stubs) )
1142
1143(define (generate-foreign-callback-stubs stubs db)
1144 (for-each
1145 (lambda (stub)
1146 (let* ((id (foreign-callback-stub-id stub))
1147 (rname (real-name2 id db))
1148 (rtype (foreign-callback-stub-return-type stub))
1149 (argtypes (foreign-callback-stub-argument-types stub))
1150 (n (length argtypes))
1151 (vlist (make-argument-list n "t")) )
1152
1153 (define (compute-size type var ns)
1154 (case type
1155 ((char int int32 short bool void unsigned-short scheme-object unsigned-char unsigned-int unsigned-int32
1156 byte unsigned-byte)
1157 ns)
1158 ((float double c-pointer nonnull-c-pointer
1159 c-string-list c-string-list*)
1160 (string-append ns "+3") )
1161 ((complex cplxnum)
1162 (string-append ns "+5") )
1163 ((unsigned-integer unsigned-integer32 long integer integer32
1164 unsigned-long number)
1165 (string-append ns "+C_SIZEOF_FIX_BIGNUM"))
1166 ((unsigned-integer64 integer64 size_t ssize_t)
1167 ;; On 32-bit systems, needs 2 digits
1168 (string-append ns "+C_SIZEOF_BIGNUM(2)"))
1169 ((c-string c-string* unsigned-c-string unsigned-c-string unsigned-c-string*)
1170 (string-append ns "+2+(" var "==NULL?1:C_bytestowords(C_strlen(" var ")))") )
1171 ((nonnull-c-string nonnull-c-string* nonnull-unsigned-c-string nonnull-unsigned-c-string* symbol)
1172 (string-append ns "+2+C_bytestowords(C_strlen(" var "))") )
1173 (else
1174 (cond ((and (symbol? type) (lookup-foreign-type type))
1175 => (lambda (t) (compute-size (vector-ref t 0) var ns) ) )
1176 ((pair? type)
1177 (case (car type)
1178 ((ref pointer c-pointer nonnull-pointer nonnull-c-pointer function instance
1179 nonnull-instance instance-ref)
1180 (string-append ns "+3") )
1181 ((const) (compute-size (cadr type) var ns))
1182 (else ns) ) )
1183 (else ns) ) ) ) )
1184
1185 (let ((sizestr (let loop ((types argtypes) (vars vlist) (ns "0"))
1186 (if (null? types)
1187 ns
1188 (loop (cdr types) (cdr vars)
1189 (compute-size (car types) (car vars) ns))))))
1190 (gen #t)
1191 (when rname
1192 (gen #t "/* from " (cleanup rname) " */") )
1193 (generate-foreign-callback-header "" stub)
1194 (gen #\{ #t "C_word x,s=" sizestr ",*a="
1195 (if (string=? "0" sizestr) "C_stack_pointer;" "C_alloc(s);"))
1196 (gen #t "C_callback_adjust_stack(a,s);") ; make sure content is below stack_bottom as well
1197 (for-each
1198 (lambda (v t)
1199 (gen #t "x=" (foreign-result-conversion t "a") v ");"
1200 #t "C_save(x);") )
1201 (reverse vlist)
1202 (reverse argtypes))
1203 (unless (eq? 'void rtype)
1204 (gen #t "return " (foreign-argument-conversion rtype)) )
1205 (gen "C_callback_wrapper((void *)" id #\, n #\))
1206 (unless (eq? 'void rtype) (gen #\)))
1207 (gen ";}") ) ) )
1208 stubs) )
1209
1210(define (generate-foreign-callback-header cls stub)
1211 (let* ((name (foreign-callback-stub-name stub))
1212 (quals (foreign-callback-stub-qualifiers stub))
1213 (rtype (foreign-callback-stub-return-type stub))
1214 (argtypes (foreign-callback-stub-argument-types stub))
1215 (n (length argtypes))
1216 (vlist (make-argument-list n "t")) )
1217 (gen #t cls #\space (foreign-type-declaration rtype "") quals #\space name #\()
1218 (let loop ((vs vlist) (ts argtypes))
1219 (unless (null? vs)
1220 (gen (foreign-type-declaration (car ts) (car vs)))
1221 (when (pair? (cdr vs)) (gen #\,))
1222 (loop (cdr vs) (cdr ts))))
1223 (gen #\)) ) )
1224
1225
1226;; Create type declarations
1227
1228(define (foreign-type-declaration type target)
1229 (let ((err (lambda () (quit-compiling "illegal foreign type `~A'" type)))
1230 (str (lambda (ts) (string-append ts " " target))) )
1231 (case type
1232 ((scheme-object) (str "C_word"))
1233 ((char byte) (str "C_char"))
1234 ((unsigned-char unsigned-byte) (str "unsigned C_char"))
1235 ((unsigned-int unsigned-integer) (str "unsigned int"))
1236 ((unsigned-int32 unsigned-integer32) (str "C_u32"))
1237 ((int integer bool) (str "int"))
1238 ((size_t) (str "size_t"))
1239 ((ssize_t) (str "ssize_t"))
1240 ((int32 integer32) (str "C_s32"))
1241 ((integer64) (str "C_s64"))
1242 ((unsigned-integer64) (str "C_u64"))
1243 ((short) (str "short"))
1244 ((long) (str "long"))
1245 ((unsigned-short) (str "unsigned short"))
1246 ((unsigned-long) (str "unsigned long"))
1247 ((float) (str "float"))
1248 ((double number) (str "double"))
1249 ((complex cplxnum) (str "double complex"))
1250 ((c-pointer nonnull-c-pointer scheme-pointer nonnull-scheme-pointer) (str "void *"))
1251 ((c-string-list c-string-list*) "C_char **")
1252 ((bytevector nonnull-bytevector u8vector nonnull-u8vector) (str "unsigned char *"))
1253 ((blob nonnull-blob) (str "unsigned char *")) ; DEPRECATED
1254 ((u16vector nonnull-u16vector) (str "unsigned short *"))
1255 ((s8vector nonnull-s8vector) (str "signed char *"))
1256 ((u32vector nonnull-u32vector) (str "unsigned int *")) ;; C_u32?
1257 ((u64vector nonnull-u64vector) (str "C_u64 *"))
1258 ((s16vector nonnull-s16vector) (str "short *"))
1259 ((s32vector nonnull-s32vector) (str "int *")) ;; C_s32?
1260 ((s64vector nonnull-s64vector) (str "C_s64 *"))
1261 ((f32vector nonnull-f32vector) (str "float *"))
1262 ((f64vector nonnull-f64vector) (str "double *"))
1263 ((pointer-vector nonnull-pointer-vector) (str "void **"))
1264 ((nonnull-c-string c-string nonnull-c-string* c-string* symbol)
1265 (str "char *"))
1266 ((nonnull-unsigned-c-string nonnull-unsigned-c-string* unsigned-c-string unsigned-c-string*)
1267 (str "unsigned char *"))
1268 ((void) (str "void"))
1269 (else
1270 (cond ((and (symbol? type) (lookup-foreign-type type))
1271 => (lambda (t)
1272 (foreign-type-declaration (vector-ref t 0) target)) )
1273 ((string? type) (str type))
1274 ((list? type)
1275 (let ((len (length type)))
1276 (cond
1277 ((and (= 2 len)
1278 (memq (car type) '(pointer nonnull-pointer c-pointer
1279 scheme-pointer nonnull-scheme-pointer
1280 nonnull-c-pointer) ) )
1281 (foreign-type-declaration (cadr type) (string-append "*" target)) )
1282 ((and (= 2 len)
1283 (eq? 'ref (car type)))
1284 (foreign-type-declaration (cadr type) (string-append "&" target)) )
1285 ((and (> len 2)
1286 (eq? 'template (car type)))
1287 (str
1288 (string-append
1289 (foreign-type-declaration (cadr type) "")
1290 "<"
1291 (string-intersperse
1292 (map (cut foreign-type-declaration <> "") (cddr type))
1293 ",")
1294 "> ") ) )
1295 ((and (= len 2) (eq? 'const (car type)))
1296 (string-append "const " (foreign-type-declaration (cadr type) target)))
1297 ((and (= len 2) (eq? 'struct (car type)))
1298 (if (list? (cadr type))
1299 (string-append (->string (caadr type)) " " target)
1300 (string-append "struct " (->string (cadr type)) " " target)))
1301 ((and (= len 2) (eq? 'union (car type)))
1302 (if (list? (cadr type))
1303 (string-append (->string (caadr type)) " " target)
1304 (string-append "union " (->string (cadr type)) " " target)))
1305 ((and (= len 2) (eq? 'enum (car type)))
1306 (string-append "enum " (->string (cadr type)) " " target))
1307 ((and (= len 3) (memq (car type) '(instance nonnull-instance)))
1308 (string-append (->string (cadr type)) "*" target))
1309 ((and (= len 3) (eq? 'instance-ref (car type)))
1310 (string-append (->string (cadr type)) "&" target))
1311 ((and (>= len 3) (eq? 'function (car type)))
1312 (let ((rtype (cadr type))
1313 (argtypes (caddr type))
1314 (callconv (optional (cdddr type) "")))
1315 (string-append
1316 (foreign-type-declaration rtype "")
1317 callconv
1318 " (*" target ")("
1319 (string-intersperse
1320 (map (lambda (at)
1321 (if (eq? '... at)
1322 "..."
1323 (foreign-type-declaration at "") ) )
1324 argtypes)
1325 ",")
1326 ")" ) ) )
1327 (else (err)) ) ) )
1328 (else (err)) ) ) ) ) )
1329
1330
1331;; Generate expression to convert argument from Scheme data
1332
1333(define (foreign-argument-conversion type)
1334 (let ((err (lambda ()
1335 (quit-compiling "illegal foreign argument type `~A'" type))))
1336 (case type
1337 ((scheme-object) "(")
1338 ((char unsigned-char) "C_character_code((C_word)")
1339 ((byte int int32 unsigned-int unsigned-int32 unsigned-byte) "C_unfix(")
1340 ((short) "C_unfix(")
1341 ((unsigned-short) "(unsigned short)C_unfix(")
1342 ((unsigned-long) "C_num_to_unsigned_long(")
1343 ((double number float) "C_c_double(")
1344 ((complex cplxnum) "C_c_cplxnum(")
1345 ((integer integer32) "C_num_to_int(")
1346 ((integer64) "C_num_to_int64(")
1347 ((size_t) "(size_t)C_num_to_uint64(")
1348 ((ssize_t) "(ssize_t)C_num_to_int64(")
1349 ((unsigned-integer64) "C_num_to_uint64(")
1350 ((long) "C_num_to_long(")
1351 ((unsigned-integer unsigned-integer32) "C_num_to_unsigned_int(")
1352 ((scheme-pointer) "C_data_pointer_or_null(")
1353 ((nonnull-scheme-pointer) "C_data_pointer(")
1354 ((c-pointer) "C_c_pointer_or_null(")
1355 ((nonnull-c-pointer) "C_c_pointer_nn(")
1356 ((u8vector bytevector) "C_c_bytevector_or_null(")
1357 ((nonnull-bytevector nonnull-u8vector) "C_c_bytevector(")
1358 ((blob) "C_c_bytevector_or_null(") ; DEPRECATED
1359 ((nonnull-blob) "C_c_bytevector(") ; DEPRECATED
1360 ((u16vector) "C_c_u16vector_or_null(")
1361 ((nonnull-u16vector) "C_c_u16vector(")
1362 ((u32vector) "C_c_u32vector_or_null(")
1363 ((nonnull-u32vector) "C_c_u32vector(")
1364 ((u64vector) "C_c_u64vector_or_null(")
1365 ((nonnull-u64vector) "C_c_u64vector(")
1366 ((s8vector) "C_c_s8vector_or_null(")
1367 ((nonnull-s8vector) "C_c_s8vector(")
1368 ((s16vector) "C_c_s16vector_or_null(")
1369 ((nonnull-s16vector) "C_c_s16vector(")
1370 ((s32vector) "C_c_s32vector_or_null(")
1371 ((nonnull-s32vector) "C_c_s32vector(")
1372 ((s64vector) "C_c_s64vector_or_null(")
1373 ((nonnull-s64vector) "C_c_s64vector(")
1374 ((f32vector) "C_c_f32vector_or_null(")
1375 ((nonnull-f32vector) "C_c_f32vector(")
1376 ((f64vector) "C_c_f64vector_or_null(")
1377 ((nonnull-f64vector) "C_c_f64vector(")
1378 ((pointer-vector) "C_c_pointer_vector_or_null(")
1379 ((nonnull-pointer-vector) "C_c_pointer_vector(")
1380 ((c-string c-string* unsigned-c-string unsigned-c-string*) "C_string_or_null(")
1381 ((nonnull-c-string nonnull-c-string* nonnull-unsigned-c-string
1382 nonnull-unsigned-c-string* symbol) "C_c_string(")
1383 ((bool) "C_truep(")
1384 (else
1385 (cond ((and (symbol? type) (lookup-foreign-type type))
1386 => (lambda (t)
1387 (foreign-argument-conversion (vector-ref t 0)) ) )
1388 ((and (list? type) (>= (length type) 2))
1389 (case (car type)
1390 ((c-pointer) "C_c_pointer_or_null(")
1391 ((nonnull-c-pointer) "C_c_pointer_nn(")
1392 ((instance) "C_c_pointer_or_null(")
1393 ((nonnull-instance) "C_c_pointer_nn(")
1394 ((scheme-pointer) "C_data_pointer_or_null(")
1395 ((nonnull-scheme-pointer) "C_data_pointer(")
1396 ((function) "C_c_pointer_or_null(")
1397 ((const) (foreign-argument-conversion (cadr type)))
1398 ((enum) "C_num_to_int(")
1399 ((struct union)
1400 (if (list? (cadr type))
1401 (sprintf "C_build_struct(~a," (caadr type))
1402 (sprintf "C_build_struct(~a ~a," (car type) (cadr type))))
1403 ((ref)
1404 (string-append "*(" (foreign-type-declaration (cadr type) "*")
1405 ")C_c_pointer_nn("))
1406 ((instance-ref)
1407 (string-append "*(" (cadr type) "*)C_c_pointer_nn("))
1408 (else (err)) ) )
1409 (else (err)) ) ) ) ) )
1410
1411
1412;; Generate suitable conversion of a result value into Scheme data
1413
1414(define (foreign-result-conversion type dest)
1415 (let ((err (lambda ()
1416 (quit-compiling "illegal foreign return type `~A'" type))))
1417 (case type
1418 ((char unsigned-char) "C_make_character((C_word)")
1419 ((int int32) "C_fix((C_word)")
1420 ((unsigned-int unsigned-int32) "C_fix(C_MOST_POSITIVE_FIXNUM&(C_word)")
1421 ((short) "C_fix((short)")
1422 ((unsigned-short) "C_fix(0xffff&(C_word)")
1423 ((byte) "C_fix((char)")
1424 ((unsigned-byte) "C_fix(0xff&(C_word)")
1425 ((float double) (sprintf "C_flonum(&~a," dest)) ;XXX suboptimal for int64
1426 ((complex cplxnum) (sprintf "C_inexact_cplxnum(&~a," dest))
1427 ((number) (sprintf "C_number(&~a," dest))
1428 ((nonnull-c-string c-string nonnull-c-pointer c-string* nonnull-c-string*
1429 unsigned-c-string unsigned-c-string* nonnull-unsigned-c-string
1430 nonnull-unsigned-c-string* symbol c-string-list c-string-list*)
1431 (sprintf "C_mpointer(&~a,(void*)" dest) )
1432 ((c-pointer) (sprintf "C_mpointer_or_false(&~a,(void*)" dest))
1433 ((integer integer32) (sprintf "C_int_to_num(&~a," dest))
1434 ((integer64 ssize_t) (sprintf "C_int64_to_num(&~a," dest))
1435 ((unsigned-integer64 size_t) (sprintf "C_uint64_to_num(&~a," dest))
1436 ((unsigned-integer unsigned-integer32) (sprintf "C_unsigned_int_to_num(&~a," dest))
1437 ((long) (sprintf "C_long_to_num(&~a," dest))
1438 ((unsigned-long) (sprintf "C_unsigned_long_to_num(&~a," dest))
1439 ((bool) "C_mk_bool(")
1440 ((void scheme-object) "((C_word)")
1441 (else
1442 (cond ((and (symbol? type) (lookup-foreign-type type))
1443 => (lambda (x)
1444 (foreign-result-conversion (vector-ref x 0) dest)) )
1445 ((and (list? type) (>= (length type) 2))
1446 (case (car type)
1447 ((nonnull-pointer nonnull-c-pointer)
1448 (sprintf "C_mpointer(&~A,(void*)" dest) )
1449 ((ref)
1450 (sprintf "C_mpointer(&~A,(void*)&" dest) )
1451 ((struct union)
1452 (if (list? (cadr type))
1453 (sprintf "C_a_extract_struct(&~A,~A," dest (caadr type))
1454 (sprintf "C_a_extract_struct(&~A,~A ~A," dest (car type) (cadr type))))
1455 ((instance)
1456 (sprintf "C_mpointer_or_false(&~A,(void*)" dest) )
1457 ((nonnull-instance)
1458 (sprintf "C_mpointer(&~A,(void*)" dest) )
1459 ((instance-ref)
1460 (sprintf "C_mpointer(&~A,(void*)&" dest) )
1461 ((const) (foreign-result-conversion (cadr type) dest))
1462 ((pointer c-pointer)
1463 (sprintf "C_mpointer_or_false(&~a,(void*)" dest) )
1464 ((function) (sprintf "C_mpointer(&~a,(void*)" dest))
1465 ((enum) (sprintf "C_int_to_num(&~a," dest))
1466 (else (err)) ) )
1467 (else (err)) ) ) ) ) )
1468
1469
1470;;; Encoded literals as strings, to be decoded by "C_decode_literal()"
1471;;
1472;; - everything hardcoded, using the FFI would be the ugly, but safer method.
1473
1474(define (oct n)
1475 (string-append
1476 (cond ((< n 8) "\\00")
1477 ((< n 64) "\\0")
1478 (else "\\"))
1479 (number->string n 8)))
1480
1481(define (encode-literal lit)
1482 (define getbits
1483 (foreign-lambda* int ((scheme-object lit))
1484 "
1485#ifdef C_SIXTY_FOUR
1486return((C_header_bits(lit) >> (24 + 32)) & 0xff);
1487#else
1488return((C_header_bits(lit) >> 24) & 0xff);
1489#endif
1490") )
1491 (define getsize
1492 (foreign-lambda* int ((scheme-object lit))
1493 "return(C_header_size(lit));"))
1494 (define (encode-size n)
1495 (if (fx> (fxlen n) 24)
1496 ;; Unfortunately we can't do much more to help the user.
1497 ;; Printing the literal is not helpful because it's *huge*,
1498 ;; and we have no line number information here.
1499 (quit-compiling
1500 "Encoded literal size of ~S is too large (must fit in 24 bits)" n)
1501 (string-append
1502 (oct (bitwise-and #xff (arithmetic-shift n -16)))
1503 (oct (bitwise-and #xff (arithmetic-shift n -8)))
1504 (oct (bitwise-and #xff n)))))
1505 (define (finish str) ; can be taken out at a later stage
1506 (string-append "\\376" str))
1507 (finish
1508 (cond ((eq? #t lit) "\\377\\006\\001")
1509 ((eq? #f lit) "\\377\\006\\000")
1510 ((char? lit) (string-append "\\377\\012" (encode-size (char->integer lit))))
1511 ((null? lit) "\\377\\016")
1512 ((eof-object? lit) "\\377\\076")
1513 ((eq? (void) lit) "\\377\\036")
1514 ;; The big-fixnum? check can probably be simplified
1515 ((and (fixnum? lit) (not (big-fixnum? lit)))
1516 (string-append
1517 "\\377\\001"
1518 (oct (bitwise-and #xff (arithmetic-shift lit -24)))
1519 (oct (bitwise-and #xff (arithmetic-shift lit -16)))
1520 (oct (bitwise-and #xff (arithmetic-shift lit -8)))
1521 (oct (bitwise-and #xff lit)) ) )
1522 ((exact-integer? lit)
1523 ;; Encode as hex to save space and get exact size
1524 ;; calculation. We could encode as base 32 to save more
1525 ;; space, but that makes debugging harder. The type tag is
1526 ;; a bit of a hack: we encode as "GC forwarded" string to
1527 ;; get a unique new type, as bignums don't have their own
1528 ;; type tag (they're encoded as structures).
1529 (let ((str (number->string lit 16)))
1530 (string-append "\\320" (encode-size (fx- (##sys#size (##sys#slot str 0)) 1)) str)))
1531 ((flonum? lit)
1532 (string-append "\\125" (number->string lit) "\\000") )
1533 ((keyword? lit)
1534 (let* ((str (keyword->string lit))
1535 (bv (##sys#slot str 0)))
1536 (string-append
1537 "\\001" (encode-size (fx- (##sys#size bv) 1)) "\\002"
1538 (byteblock->string bv -1)) ) )
1539 ((symbol? lit)
1540 (let* ((str (##sys#symbol->string/shared lit))
1541 (bv (##sys#slot str 0)))
1542 (string-append
1543 "\\001" (encode-size (fx- (##sys#size bv) 1)) "\\001"
1544 (byteblock->string bv -1) ) ))
1545 ((string? lit)
1546 (string-append
1547 (oct (getbits lit))
1548 (encode-size (##sys#size (##sys#slot lit 0)))
1549 (byteblock->string (##sys#slot lit 0) 0) ))
1550 ((##core#inline "C_byteblockp" lit)
1551 (string-append
1552 (oct (getbits lit))
1553 (encode-size (getsize lit))
1554 (byteblock->string lit 0) ))
1555 ((##sys#immediate? lit)
1556 (bomb "invalid literal - cannot encode" lit))
1557 (else
1558 (let ((len (getsize lit)))
1559 (string-intersperse
1560 (cons*
1561 (oct (getbits lit))
1562 (encode-size len)
1563 (list-tabulate len (lambda (i) (encode-literal (##sys#slot lit i)))))
1564 ""))))) )
1565
1566(define (byteblock->string bb mlen)
1567 (let ((out (open-output-string))
1568 (len (fx+ (##sys#size bb) mlen)))
1569 (do ((i 0 (fx+ i 1)))
1570 ((fx>= i len) (get-output-string out))
1571 (display (oct (##sys#byte bb i)) out))))
1572
1573(define (c-ify-string str)
1574 (list->string
1575 (cons
1576 #\"
1577 (let loop ((bytes (##sys#bytevector->list (##sys#slot str 0))))
1578 (if (or (null? bytes)
1579 (null? (cdr bytes)))
1580 '(#\")
1581 (let ((code (car bytes)))
1582 (if (or (< code 32)
1583 (>= code 127)
1584 (memq code '(#\" #\' #\\ #\? #\*)))
1585 (append '(#\\)
1586 (cond ((< code 8) '(#\0 #\0))
1587 ((< code 64) '(#\0))
1588 (else '()))
1589 (string->list (number->string code 8))
1590 (loop (cdr bytes)) )
1591 (cons (integer->char code)
1592 (loop (cdr bytes))))))))))
1593
1594)