~ chicken-core (master) /c-backend.scm


   1;;; 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)
Trap