~ chicken-core (chicken-5) /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
  54(include "mini-srfi-1.scm")
  55
  56;;; Write atoms to output-port:
  57
  58(define output #f)
  59
  60(define (gen . data)
  61  (for-each
  62   (lambda (x) 
  63     (if (eq? #t x)
  64	 (newline output)
  65	 (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
 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 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 var)) " */ =")
 298		      (expr (car subs) i)
 299		      (gen #\;) ]
 300		     [else
 301		      (gen "C_set_block_item(lf[" index "] /* "
 302			   (uncommentify (##sys#symbol->string 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 (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_externimport 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_TLS 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 (##sys#lambda-info->string (car llits)))
 650		 (llen (string-length ll)))
 651	    (gen #t "static C_char C_TLS 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 #\, (char->integer (string-ref 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		  (if customizable
 682		      (gen "C_fcall ")
 683		      (gen "C_ccall ") )
 684		  (gen id) )
 685		 (else
 686		  (let ((uname (toplevel unit-name)))
 687		    (gen "C_noret_decl(C_" uname ")" #t) ;XXX what's this for?
 688		    (gen "C_externexport void C_ccall ")
 689		    (gen "C_" uname) ) ) )
 690	   (gen #\()
 691	   (unless customizable (gen "C_word c,"))
 692	   (when (and direct (not (zero? allocated)))
 693	     (gen "C_word *a")
 694	     (when (pair? varlist) (gen #\,)) )
 695	   (if (or customizable direct)
 696	       (apply gen varlist)
 697	       (gen "C_word *av"))
 698	   (gen #\))
 699	   (unless direct (gen " C_noret"))
 700	   (gen #\;) ))
 701       lambda-table*) )
 702  
 703    (define (trampolines)
 704      (let ([ns '()]
 705	    [nsr '()] 
 706	    [nsrv '()] )
 707
 708	(define (restore n)
 709	  (do ((i 0 (add1 i))
 710	       (j (sub1 n) (sub1 j)))
 711	      ((>= i n))
 712	    (gen #t "C_word t" i "=av[" j "];")))
 713
 714	(for-each
 715	 (lambda (p)
 716	   (let* ([id (car p)]
 717		  [ll (cdr p)]
 718		  [argc (lambda-literal-argument-count ll)]
 719		  [customizable (lambda-literal-customizable ll)]
 720		  [empty-closure (and customizable (zero? (lambda-literal-closure-size ll)))] )
 721	     (when empty-closure (set! argc (sub1 argc)))
 722	     (when (and (not (lambda-literal-direct ll)) customizable)
 723	       (gen #t #t "C_noret_decl(tr" id ")"
 724		    #t "static void C_ccall tr" id "(C_word c,C_word *av) C_noret;")
 725	       (gen #t "static void C_ccall tr" id "(C_word c,C_word *av){")
 726	       (restore argc)
 727	       (gen #t id #\()
 728	       (let ([al (make-argument-list argc "t")])
 729		 (apply gen (intersperse al #\,)) )
 730	       (gen ");}") )))
 731	 lambda-table*)))
 732  
 733    (define (literal-frame)
 734      (do ([i 0 (add1 i)]
 735	   [lits literals (cdr lits)] )
 736	  ((null? lits))
 737	(gen-lit (car lits) (sprintf "lf[~s]" i)) ) )
 738
 739    (define (bad-literal lit)
 740      (bomb "type of literal not supported" lit) )
 741
 742    (define (literal-size lit)
 743      (cond ((immediate? lit) 0)
 744	    ((big-fixnum? lit) 2)       ; immediate if fixnum, bignum see below
 745	    ((string? lit) 0)		; statically allocated
 746	    ((bignum? lit) 2)		; internal vector statically allocated
 747	    ((flonum? lit) words-per-flonum)
 748	    ((symbol? lit) 7)           ; size of symbol, and possibly a bucket
 749	    ((keyword? lit) 7)          ; size of keyword (symbol), and possibly a bucket
 750	    ((pair? lit) (+ 3 (literal-size (car lit)) (literal-size (cdr lit))))
 751	    ((vector? lit)
 752	     (+ 1 (vector-length lit)
 753                (foldl + 0 (map literal-size (vector->list lit)))))
 754	    ((block-variable-literal? lit) 0) ; excluded from generated code
 755	    ((##sys#immediate? lit) (bad-literal lit))
 756	    ((##core#inline "C_lambdainfop" lit) 0) ; statically allocated
 757	    ((##sys#bytevector? lit) (+ 2 (bytes->words (##sys#size lit))) ) ; drops "permanent" property!
 758	    ((##sys#generic-structure? lit)
 759	     (let ([n (##sys#size lit)])
 760	       (let loop ([i 0] [s (+ 2 n)])
 761		 (if (>= i n)
 762		     s
 763		     (loop (add1 i) (+ s (literal-size (##sys#slot lit i)))) ) ) ) )
 764	    ;; We could access rat/cplx slots directly, but let's not.
 765	    ((ratnum? lit) (+ (##sys#size lit)
 766			      (literal-size (numerator lit))
 767			      (literal-size (denominator lit))))
 768	    ((cplxnum? lit) (+ (##sys#size lit)
 769			       (literal-size (real-part lit))
 770			       (literal-size (imag-part lit))))
 771	    (else (bad-literal lit))) )
 772
 773    (define (gen-lit lit to)
 774      ;; we do simple immediate literals directly to avoid a function call:
 775      (cond ((and (fixnum? lit) (not (big-fixnum? lit)))
 776	     (gen #t to "=C_fix(" lit ");") )
 777	    ((block-variable-literal? lit))
 778	    ((eq? lit (void))
 779	     (gen #t to "=C_SCHEME_UNDEFINED;") )
 780	    ((boolean? lit) 
 781	     (gen #t to #\= (if lit "C_SCHEME_TRUE" "C_SCHEME_FALSE") #\;) )
 782	    ((char? lit)
 783	     (gen #t to "=C_make_character(" (char->integer lit) ");") )
 784	    ((or (keyword? lit) (symbol? lit)) ; handled slightly specially (see C_h_intern_in)
 785	     (let* ((str (##sys#slot lit 1))
 786		    (cstr (c-ify-string str))
 787		    (len (##sys#size str))
 788		    (intern (if (keyword? lit)
 789				"C_h_intern_kw"
 790				"C_h_intern")))
 791	       (gen #t to "=")
 792	       (gen intern "(&" to #\, len ", C_text(" cstr "));")))
 793	    ((null? lit) 
 794	     (gen #t to "=C_SCHEME_END_OF_LIST;") )
 795	    ((and (not (##sys#immediate? lit)) ; nop
 796		  (##core#inline "C_lambdainfop" lit)))
 797	    ((or (fixnum? lit) (not (##sys#immediate? lit)))
 798	     (gen #t to "=C_decode_literal(C_heaptop,C_text(")
 799	     (gen-string-constant (encode-literal lit))
 800	     (gen "));"))
 801	    (else (bad-literal lit))))
 802
 803    (define (gen-string-constant str)
 804      (let* ([len (##sys#size str)]
 805	     [ns (fx/ len 80)]
 806	     [srest (modulo len 80)] )
 807	(do ([i ns (sub1 i)]
 808	     [offset 0 (+ offset 80)] )
 809	    ((zero? i)
 810	     (when (or (zero? len) (not (zero? srest)))
 811	       (gen (c-ify-string (string-like-substring str offset len))) ) )
 812	  (gen (c-ify-string (string-like-substring str offset (+ offset 80))) #t) ) ) )
 813 
 814    (define (string-like-substring s start end)
 815      (let* ([len (- end start)]
 816	     [s2 (make-string len)] )
 817	(##sys#copy-bytes s s2 start 0 len)
 818	s2) )
 819
 820    (define (procedures)
 821      (for-each
 822       (lambda (p)
 823	 (let* ((id (car p))
 824		(ll (cdr p))
 825		(n (lambda-literal-argument-count ll))
 826		(rname (real-name id db))
 827		(demand (lambda-literal-allocated ll))
 828		(max-av (apply max 0 (lambda-literal-callee-signatures ll)))
 829		(rest (lambda-literal-rest-argument ll))
 830		(customizable (lambda-literal-customizable ll))
 831		(empty-closure (and customizable (zero? (lambda-literal-closure-size ll))))
 832		(nec (- n (if empty-closure 1 0)))
 833		(vlist0 (make-variable-list n "t"))
 834		(alist0 (make-argument-list n "t"))
 835		(varlist (intersperse (if empty-closure (cdr vlist0) vlist0) #\,))
 836		(arglist (intersperse (if empty-closure (cdr alist0) alist0) #\,))
 837		(external (lambda-literal-external ll))
 838		(looping (lambda-literal-looping ll))
 839		(direct (lambda-literal-direct ll))
 840		(rest-mode (lambda-literal-rest-argument-mode ll))
 841		(temps (lambda-literal-temporaries ll))
 842                (ftemps (lambda-literal-float-temporaries ll))
 843		(topname (toplevel unit-name)))
 844	   (when empty-closure (debugging 'o "dropping unused closure argument" id))
 845	   (gen #t #t)
 846	   (gen "/* " (cleanup rname) " */" #t)
 847	   (cond [(not (eq? 'toplevel id)) 
 848		  (gen "static ")
 849		  (gen (if direct "C_word " "void "))
 850		  (if customizable
 851		      (gen "C_fcall ")
 852		      (gen "C_ccall ") )
 853		  (gen id) ]
 854		 [else
 855		  (gen "static C_TLS int toplevel_initialized=0;")
 856		  (unless unit-name
 857		    (gen #t "C_main_entry_point") )
 858		  (gen #t #t "void C_ccall C_" topname) ] )
 859	   (gen #\()
 860	   (unless customizable (gen "C_word c,"))
 861	   (when (and direct (not (zero? demand))) 
 862	     (gen "C_word *a")
 863	     (when (pair? varlist) (gen #\,)) )
 864	   (if (or customizable direct)
 865	       (apply gen varlist)
 866	       (gen "C_word *av"))
 867	   (gen "){")
 868	   (when (eq? rest-mode 'none) (set! rest #f))
 869	   (gen #t "C_word tmp;")
 870	   (unless (or customizable direct)
 871	     (do ((i 0 (add1 i)))
 872		 ((>= i n))
 873	       (gen #t "C_word t" i "=av[" i "];")))
 874	   (if rest
 875	       (gen #t "C_word t" n #\;) ; To hold rest-list if demand is met
 876	       (begin
 877		 (do ([i n (add1 i)]
 878		      [j (+ temps (if looping (sub1 n) 0)) (sub1 j)] )
 879		     ((zero? j))
 880		   (gen #t "C_word t" i #\;))
 881                 (for-each
 882                   (lambda (i)
 883                     (gen #t "double f" i #\;))
 884                   ftemps)))
 885	   (cond ((eq? 'toplevel id)
 886		  (let ([ldemand (foldl (lambda (n lit) (+ n (literal-size lit))) 0 literals)]
 887			[llen (length literals)] )
 888		    (gen #t "C_word *a;"
 889			 #t "if(toplevel_initialized) {C_kontinue(t1,C_SCHEME_UNDEFINED);}"
 890			 #t "else C_toplevel_entry(C_text(\"" (or unit-name topname) "\"));")
 891		    (when emit-debug-info
 892		      (gen #t "C_register_debug_info(C_debug_info);"))
 893		    (when disable-stack-overflow-checking
 894		      (gen #t "C_disable_overflow_check=1;") )
 895		    (unless unit-name
 896		      (when target-heap-size
 897			(gen #t "C_set_or_change_heap_size(" target-heap-size ",1);"
 898			     #t "C_heap_size_is_fixed=1;"))
 899		      (when target-stack-size
 900			(gen #t "C_resize_stack(" target-stack-size ");") ) )
 901		    (gen #t "C_check_nursery_minimum(C_calculate_demand(" demand ",c," max-av "));"
 902			 #t "if(C_unlikely(!C_demand(C_calculate_demand(" demand ",c," max-av ")))){"
 903			 #t "C_save_and_reclaim((void*)C_" topname ",c,av);}"
 904			 #t "toplevel_initialized=1;"
 905			 #t "if(C_unlikely(!C_demand_2(" ldemand "))){"
 906			 #t "C_save(t1);"
 907			 #t "C_rereclaim2(" ldemand "*sizeof(C_word),1);"
 908			 #t "t1=C_restore;}"
 909			 #t "a=C_alloc(" demand ");")
 910		    (when (not (zero? llen))
 911		      (gen #t "C_initialize_lf(lf," llen ");")
 912		      (literal-frame)
 913		      (gen #t "C_register_lf2(lf," llen ",create_ptable());"))
 914		    (gen #\{)))
 915		 (rest
 916		  (gen #t "C_word *a;")
 917		  (when (and (not unsafe) (not no-argc-checks) (> n 2) (not empty-closure))
 918		    (gen #t "if(c<" n ") C_bad_min_argc_2(c," n ",t0);") )
 919		  (when insert-timer-checks (gen #t "C_check_for_interrupt;"))
 920		  (gen #t "if(C_unlikely(!C_demand(C_calculate_demand((c-" n ")*C_SIZEOF_PAIR +" demand ",c," max-av ")))){"))
 921		 (else
 922		  (unless direct (gen #t "C_word *a;"))
 923		  (when (and direct (not unsafe) (not disable-stack-overflow-checking))
 924		    (gen #t "C_stack_overflow_check;"))
 925		  (when looping (gen #t "loop:"))
 926		  (when (and external (not unsafe) (not no-argc-checks) (not customizable))
 927		    ;; (not customizable) implies empty-closure
 928		    (if (eq? rest-mode 'none)
 929			(when (> n 2) (gen #t "if(c<" n ") C_bad_min_argc_2(c," n ",t0);"))
 930			(gen #t "if(c!=" n ") C_bad_argc_2(c," n ",t0);") ) )
 931		  (cond ((not direct)
 932			 ;; The interrupt handler may fill the stack, so we only
 933			 ;; check for an interrupt when the procedure is restartable
 934			 (when insert-timer-checks (gen #t "C_check_for_interrupt;"))
 935			 (gen #t "if(C_unlikely(!C_demand(C_calculate_demand("
 936			      demand
 937			      (if customizable ",0," ",c,")
 938			      max-av ")))){"))
 939			(else
 940			 (gen #\{)))))
 941	   (cond ((and (not (eq? 'toplevel id)) (not direct))
 942		  (when (and looping (not customizable))
 943		    ;; Loop will update t_n copy of av[n]; refresh av.
 944		    (do ((i 0 (add1 i)))
 945			((>= i n))
 946		      (gen #t "av[" i "]=t" i ";")))
 947		  (cond (rest
 948			 (gen #t "C_save_and_reclaim((void*)" id ",c,av);}"
 949			      #t "a=C_alloc((c-" n ")*C_SIZEOF_PAIR+" demand ");")
 950			 (gen #t "t" n "=C_build_rest(&a,c," n ",av);")
 951			 (do ((i (+ n 1) (+ i 1))
 952			      (j temps (- j 1)))
 953			     ((zero? j))
 954			   (gen #t "C_word t" i #\;)))
 955			(else
 956			 (cond ((and customizable (> nec 0))
 957				(gen #t "C_save_and_reclaim_args((void *)tr" id #\, nec #\,)
 958				(apply gen arglist)
 959				(gen ");}"))
 960			       (else
 961				(gen #t "C_save_and_reclaim((void *)" id ",c,av);}")))
 962			 (when (> demand 0)
 963			   (gen #t "a=C_alloc(" demand ");")))))
 964		 (else (gen #\})))
 965           (set! non-av-proc customizable)
 966	   (expression
 967	    (lambda-literal-body ll)
 968	    (if rest
 969		(add1 n) ; One temporary is needed to hold the rest-list
 970		n)
 971	    ll)
 972	   (gen #\}) ) )
 973       lambda-table*) )
 974
 975    (debugging 'p "code generation phase...")
 976    (set! output out)
 977    (header)
 978    (declarations)
 979    (generate-external-variables external-variables)
 980    (generate-foreign-stubs foreign-lambda-stubs db)
 981    (prototypes)
 982    (generate-foreign-callback-stubs foreign-callback-stubs db)
 983    (trampolines)
 984    (when emit-debug-info
 985      (emit-debug-table dbg-info-table))
 986    (procedures)
 987    (emit-procedure-table lambda-table* source-file)
 988    (trailer) ) )
 989
 990
 991;;; Emit global tables for debug-info
 992
 993(define (emit-debug-table dbg-info-table)
 994  (gen #t #t "static C_DEBUG_INFO C_debug_info[]={")
 995  (for-each
 996   (lambda (info)
 997     (gen #t "{" (second info) ",0,")
 998     (for-each
 999      (lambda (x)
 1000	(if (not x)
1001	    (gen "NULL,")
1002	    (gen "C_text(\"" (backslashify (->string x)) "\"),")))
1003      (cddr info))
1004     (gen "},"))
1005   (sort dbg-info-table (lambda (i1 i2) (< (car i1) (car i2)))))
1006  (gen #t "{0,0,NULL,NULL}};\n"))
1007
1008
1009;;; Emit procedure table:
1010
1011(define (emit-procedure-table lambda-table* sf)
1012  (gen #t #t "#ifdef C_ENABLE_PTABLES"
1013       #t "static C_PTABLE_ENTRY ptable[" (add1 (length lambda-table*)) "] = {")
1014  (for-each
1015   (lambda (p)
1016     (let ((id (car p))
1017	   (ll (cdr p)))
1018       (gen #t "{C_text(\"" id #\: (string->c-identifier sf) "\"),(void*)")
1019       (if (eq? 'toplevel id)
1020	   (gen "C_" (toplevel unit-name) "},")
1021	   (gen id "},") ) ) )
1022    lambda-table*)
1023  (gen #t "{NULL,NULL}};")
1024  (gen #t "#endif")
1025  (gen #t #t "static C_PTABLE_ENTRY *create_ptable(void)")
1026  (gen "{" #t "#ifdef C_ENABLE_PTABLES"
1027       #t "return ptable;"
1028       #t "#else"
1029       #t "return NULL;"
1030       #t "#endif"
1031       #t "}") )
1032
1033
1034;;; Generate top-level procedure name:
1035
1036(define (toplevel name)
1037  (if (not name)
1038      "toplevel"
1039      (string-append (c-identifier name) "_toplevel")))
1040
1041
1042;;; Create name that is safe for C comments:
1043
1044(define (cleanup s)
1045  (let ([s2 #f] 
1046	[len (string-length s)] )
1047    (let loop ([i 0])
1048      (if (>= i len)
1049	  (or s2 s)
1050	  (let ([c (string-ref s i)])
1051	    (if (or (char<? c #\space)
1052		    (char>? c #\~)
1053		    (and (char=? c #\*) (< i (sub1 len)) (char=? #\/ (string-ref s (add1 i)))) )
1054		(begin
1055		  (unless s2 (set! s2 (string-copy s)))
1056		  (string-set! s2 i #\~) )
1057		(when s2 (string-set! s2 i c)) ) 
1058	    (loop (add1 i)) ) ) ) ) )
1059
1060
1061;;; Create list of variables/parameters, interspersed with a special token:
1062
1063(define (make-variable-list n prefix)
1064  (list-tabulate
1065   n
1066   (lambda (i) (string-append "C_word " prefix (number->string i))) ) )
1067  
1068(define (make-argument-list n prefix)
1069  (list-tabulate
1070   n
1071   (lambda (i) (string-append prefix (number->string i))) ) )
1072
1073
1074;;; Generate external variable declarations:
1075
1076(define (generate-external-variables vars)
1077  (gen #t)
1078  (for-each
1079   (lambda (v)
1080     (let ((name (vector-ref v 0))
1081	   (type (vector-ref v 1))
1082	   (exported (vector-ref v 2)) )
1083       (gen #t (if exported "" "static ") (foreign-type-declaration type name) #\;) ) )
1084   vars) )
1085
1086
1087;;; Generate foreign stubs:
1088
1089(define (generate-foreign-callback-stub-prototypes stubs)
1090  (for-each
1091   (lambda (stub)
1092     (gen #t)
1093     (generate-foreign-callback-header "C_externexport " stub)
1094     (gen #\;) )
1095   stubs) )
1096
1097(define (generate-foreign-stubs stubs db)
1098  (for-each
1099   (lambda (stub)
1100     (let* ([id (foreign-stub-id stub)]
1101	    [rname (real-name2 id db)]
1102	    [types (foreign-stub-argument-types stub)]
1103	    [n (length types)]
1104	    [rtype (foreign-stub-return-type stub)] 
1105	    [sname (foreign-stub-name stub)] 
1106	    [body (foreign-stub-body stub)]
1107	    [names (or (foreign-stub-argument-names stub) (make-list n #f))]
1108	    [rconv (foreign-result-conversion rtype "C_a")] 
1109	    [cps (foreign-stub-cps stub)]
1110	    [callback (foreign-stub-callback stub)] )
1111       (gen #t)
1112       (when rname
1113	 (gen #t "/* from " (cleanup rname) " */") )
1114       (when body
1115	 (gen #t "#define return(x) C_cblock C_r = (" rconv 
1116	      "(x))); goto C_ret; C_cblockend"))
1117       (cond (cps
1118	      (gen #t "C_noret_decl(" id ")"
1119		   #t "static void C_ccall " id "(C_word C_c,C_word *C_av){"
1120		   #t "C_word C_k=C_av[1],C_buf=C_av[2];")
1121	      (do ((i 0 (add1 i)))
1122		  ((>= i n))
1123		(gen #t "C_word C_a" i "=C_av[" (+ i 3) "];")))
1124	     (else
1125	      (gen #t "C_regparm static C_word C_fcall " id #\()
1126	      (apply gen (intersperse (cons "C_word C_buf" (make-variable-list n "C_a")) #\,))
1127	      (gen "){")))
1128       (gen #t "C_word C_r=C_SCHEME_UNDEFINED,*C_a=(C_word*)C_buf;")
1129       (for-each
1130	(lambda (type index name)
1131	  (gen #t 
1132	       (foreign-type-declaration 
1133		type
1134		(if name (symbol->string name) (sprintf "t~a" index)) )
1135	       "=(" (foreign-type-declaration type "") #\)
1136	       (foreign-argument-conversion type) "C_a" index ");") )
1137	types (iota n) names)
1138       (when callback (gen #t "int C_level=C_save_callback_continuation(&C_a,C_k);"))
1139       (cond [body
1140	      (gen #t body
1141		   #t "C_ret:")
1142	      (gen #t "#undef return" #t)
1143	      (cond [callback
1144		     (gen #t "C_k=C_restore_callback_continuation2(C_level);"
1145			  #t "C_kontinue(C_k,C_r);") ]
1146		    [cps (gen #t "C_kontinue(C_k,C_r);")]
1147		    [else (gen #t "return C_r;")] ) ]
1148	     [else
1149	      (if (not (eq? rtype 'void))
1150		  (gen #t "C_r=" rconv)
1151		  (gen #t) )
1152	      (gen sname #\()
1153	      (apply gen (intersperse (make-argument-list n "t") #\,))
1154	      (unless (eq? rtype 'void) (gen #\)))
1155	      (gen ");")
1156	      (cond [callback
1157		     (gen #t "C_k=C_restore_callback_continuation2(C_level);"
1158			  #t "C_kontinue(C_k,C_r);") ]
1159		    [cps (gen "C_kontinue(C_k,C_r);")]
1160		    [else (gen #t "return C_r;")] ) ] )
1161       (gen #\}) ) )
1162   stubs) )
1163
1164(define (generate-foreign-callback-stubs stubs db)
1165  (for-each
1166   (lambda (stub)
1167     (let* ((id (foreign-callback-stub-id stub))
1168	    (rname (real-name2 id db))
1169	    (rtype (foreign-callback-stub-return-type stub))
1170	    (argtypes (foreign-callback-stub-argument-types stub))
1171	    (n (length argtypes))
1172	    (vlist (make-argument-list n "t")) )
1173
1174       (define (compute-size type var ns)
1175	 (case type
1176	   ((char int int32 short bool void unsigned-short scheme-object unsigned-char unsigned-int unsigned-int32
1177		  byte unsigned-byte)
1178	    ns)
1179	   ((float double c-pointer nonnull-c-pointer
1180		   c-string-list c-string-list*)
1181	    (string-append ns "+3") )
1182	   ((unsigned-integer unsigned-integer32 long integer integer32 
1183			      unsigned-long number)
1184	    (string-append ns "+C_SIZEOF_FIX_BIGNUM"))
1185	   ((unsigned-integer64 integer64 size_t ssize_t)
1186	    ;; On 32-bit systems, needs 2 digits
1187	    (string-append ns "+C_SIZEOF_BIGNUM(2)"))
1188	   ((c-string c-string* unsigned-c-string unsigned-c-string unsigned-c-string*)
1189	    (string-append ns "+2+(" var "==NULL?1:C_bytestowords(C_strlen(" var ")))") )
1190	   ((nonnull-c-string nonnull-c-string* nonnull-unsigned-c-string nonnull-unsigned-c-string* symbol)
1191	    (string-append ns "+2+C_bytestowords(C_strlen(" var "))") )
1192	   (else
1193	    (cond ((and (symbol? type) (lookup-foreign-type type)) 
1194		   => (lambda (t) (compute-size (vector-ref t 0) var ns) ) )
1195		  ((pair? type)
1196		   (case (car type)
1197		     ((ref pointer c-pointer nonnull-pointer nonnull-c-pointer function instance 
1198			   nonnull-instance instance-ref)
1199		      (string-append ns "+3") )
1200		     ((const) (compute-size (cadr type) var ns))
1201		     (else ns) ) )
1202		  (else ns) ) ) ) )
1203
1204       (let ((sizestr (let loop ((types argtypes) (vars vlist) (ns "0"))
1205			(if (null? types)
1206			    ns
1207			    (loop (cdr types) (cdr vars) 
1208				  (compute-size (car types) (car vars) ns))))))
1209	 (gen #t)
1210	 (when rname
1211	   (gen #t "/* from " (cleanup rname) " */") )
1212	 (generate-foreign-callback-header "" stub)
1213	 (gen #\{ #t "C_word x,s=" sizestr ",*a="
1214	      (if (string=? "0" sizestr) "C_stack_pointer;" "C_alloc(s);"))
1215	 (gen #t "C_callback_adjust_stack(a,s);") ; make sure content is below stack_bottom as well
1216	 (for-each
1217	  (lambda (v t)
1218	    (gen #t "x=" (foreign-result-conversion t "a") v ");"
1219		 #t "C_save(x);") )
1220	  (reverse vlist)
1221	  (reverse argtypes))
1222	 (unless (eq? 'void rtype)
1223	   (gen #t "return " (foreign-argument-conversion rtype)) )
1224	 (gen "C_callback_wrapper((void *)" id #\, n #\))
1225	 (unless (eq? 'void rtype) (gen #\)))
1226	 (gen ";}") ) ) )
1227   stubs) )
1228
1229(define (generate-foreign-callback-header cls stub)
1230  (let* ((name (foreign-callback-stub-name stub))
1231	 (quals (foreign-callback-stub-qualifiers stub))
1232	 (rtype (foreign-callback-stub-return-type stub))
1233	 (argtypes (foreign-callback-stub-argument-types stub))
1234	 (n (length argtypes))
1235	 (vlist (make-argument-list n "t")) )
1236    (gen #t cls #\space (foreign-type-declaration rtype "") quals #\space name #\()
1237    (let loop ((vs vlist) (ts argtypes))
1238      (unless (null? vs)
1239	(gen (foreign-type-declaration (car ts) (car vs)))
1240	(when (pair? (cdr vs)) (gen #\,))
1241	(loop (cdr vs) (cdr ts))))
1242    (gen #\)) ) )
1243
1244
1245;; Create type declarations
1246
1247(define (foreign-type-declaration type target)
1248  (let ((err (lambda () (quit-compiling "illegal foreign type `~A'" type)))
1249	(str (lambda (ts) (string-append ts " " target))) )
1250    (case type
1251      ((scheme-object) (str "C_word"))
1252      ((char byte) (str "C_char"))
1253      ((unsigned-char unsigned-byte) (str "unsigned C_char"))
1254      ((unsigned-int unsigned-integer) (str "unsigned int"))
1255      ((unsigned-int32 unsigned-integer32) (str "C_u32"))
1256      ((int integer bool) (str "int"))
1257      ((size_t) (str "size_t"))
1258      ((ssize_t) (str "ssize_t"))
1259      ((int32 integer32) (str "C_s32"))
1260      ((integer64) (str "C_s64"))
1261      ((unsigned-integer64) (str "C_u64"))
1262      ((short) (str "short"))
1263      ((long) (str "long"))
1264      ((unsigned-short) (str "unsigned short"))
1265      ((unsigned-long) (str "unsigned long"))
1266      ((float) (str "float"))
1267      ((double number) (str "double"))
1268      ((c-pointer nonnull-c-pointer scheme-pointer nonnull-scheme-pointer) (str "void *"))
1269      ((c-string-list c-string-list*) "C_char **")
1270      ((blob nonnull-blob u8vector nonnull-u8vector) (str "unsigned char *"))
1271      ((u16vector nonnull-u16vector) (str "unsigned short *"))
1272      ((s8vector nonnull-s8vector) (str "signed char *"))
1273      ((u32vector nonnull-u32vector) (str "unsigned int *")) ;; C_u32?
1274      ((u64vector nonnull-u64vector) (str "C_u64 *"))
1275      ((s16vector nonnull-s16vector) (str "short *"))
1276      ((s32vector nonnull-s32vector) (str "int *")) ;; C_s32?
1277      ((s64vector nonnull-s64vector) (str "C_s64 *"))
1278      ((f32vector nonnull-f32vector) (str "float *"))
1279      ((f64vector nonnull-f64vector) (str "double *"))
1280      ((pointer-vector nonnull-pointer-vector) (str "void **"))
1281      ((nonnull-c-string c-string nonnull-c-string* c-string* symbol) 
1282       (str "char *"))
1283      ((nonnull-unsigned-c-string nonnull-unsigned-c-string* unsigned-c-string unsigned-c-string*)
1284       (str "unsigned char *"))
1285      ((void) (str "void"))
1286      (else
1287       (cond ((and (symbol? type) (lookup-foreign-type type))
1288	      => (lambda (t)
1289		   (foreign-type-declaration (vector-ref t 0) target)) )
1290	     ((string? type) (str type))
1291	     ((list? type)
1292	      (let ((len (length type)))
1293		(cond 
1294		 ((and (= 2 len)
1295		       (memq (car type) '(pointer nonnull-pointer c-pointer 
1296						  scheme-pointer nonnull-scheme-pointer
1297						  nonnull-c-pointer) ) )
1298		  (foreign-type-declaration (cadr type) (string-append "*" target)) )
1299		 ((and (= 2 len)
1300		       (eq? 'ref (car type)))
1301		  (foreign-type-declaration (cadr type) (string-append "&" target)) )
1302		 ((and (> len 2)
1303		       (eq? 'template (car type)))
1304		  (str
1305		   (string-append 
1306		    (foreign-type-declaration (cadr type) "")
1307		    "<"
1308		    (string-intersperse
1309		     (map (cut foreign-type-declaration <> "") (cddr type))
1310		     ",")
1311		    "> ") ) )
1312		 ((and (= len 2) (eq? 'const (car type)))
1313		  (string-append "const " (foreign-type-declaration (cadr type) target)))
1314		 ((and (= len 2) (eq? 'struct (car type)))
1315		  (string-append "struct " (->string (cadr type)) " " target))
1316		 ((and (= len 2) (eq? 'union (car type)))
1317		  (string-append "union " (->string (cadr type)) " " target))
1318		 ((and (= len 2) (eq? 'enum (car type)))
1319		  (string-append "enum " (->string (cadr type)) " " target))
1320		 ((and (= len 3) (memq (car type) '(instance nonnull-instance)))
1321		  (string-append (->string (cadr type)) "*" target))
1322		 ((and (= len 3) (eq? 'instance-ref (car type)))
1323		  (string-append (->string (cadr type)) "&" target))
1324		 ((and (>= len 3) (eq? 'function (car type)))
1325		  (let ((rtype (cadr type))
1326			(argtypes (caddr type))
1327			(callconv (optional (cdddr type) "")))
1328		    (string-append
1329		     (foreign-type-declaration rtype "")
1330		     callconv
1331		     " (*" target ")("
1332		     (string-intersperse
1333		      (map (lambda (at)
1334			     (if (eq? '... at) 
1335				 "..."
1336				 (foreign-type-declaration at "") ) )
1337			   argtypes) 
1338		      ",")
1339		     ")" ) ) )
1340		 (else (err)) ) ) )
1341	     (else (err)) ) ) ) ) )
1342
1343
1344;; Generate expression to convert argument from Scheme data
1345
1346(define (foreign-argument-conversion type)
1347  (let ((err (lambda ()
1348	       (quit-compiling "illegal foreign argument type `~A'" type))))
1349    (case type
1350      ((scheme-object) "(")
1351      ((char unsigned-char) "C_character_code((C_word)")
1352      ((byte int int32 unsigned-int unsigned-int32 unsigned-byte) "C_unfix(")
1353      ((short) "C_unfix(")
1354      ((unsigned-short) "(unsigned short)C_unfix(")
1355      ((unsigned-long) "C_num_to_unsigned_long(")
1356      ((double number float) "C_c_double(")
1357      ((integer integer32) "C_num_to_int(")
1358      ((integer64) "C_num_to_int64(")
1359      ((size_t) "(size_t)C_num_to_uint64(")
1360      ((ssize_t) "(ssize_t)C_num_to_int64(")
1361      ((unsigned-integer64) "C_num_to_uint64(")
1362      ((long) "C_num_to_long(")
1363      ((unsigned-integer unsigned-integer32) "C_num_to_unsigned_int(")
1364      ((scheme-pointer) "C_data_pointer_or_null(")
1365      ((nonnull-scheme-pointer) "C_data_pointer(")
1366      ((c-pointer) "C_c_pointer_or_null(")
1367      ((nonnull-c-pointer) "C_c_pointer_nn(")
1368      ((blob) "C_c_bytevector_or_null(")
1369      ((nonnull-blob) "C_c_bytevector(")
1370      ((u8vector) "C_c_u8vector_or_null(")
1371      ((nonnull-u8vector) "C_c_u8vector(")
1372      ((u16vector) "C_c_u16vector_or_null(")
1373      ((nonnull-u16vector) "C_c_u16vector(")
1374      ((u32vector) "C_c_u32vector_or_null(")
1375      ((nonnull-u32vector) "C_c_u32vector(")
1376      ((u64vector) "C_c_u64vector_or_null(")
1377      ((nonnull-u64vector) "C_c_u64vector(")
1378      ((s8vector) "C_c_s8vector_or_null(")
1379      ((nonnull-s8vector) "C_c_s8vector(")
1380      ((s16vector) "C_c_s16vector_or_null(")
1381      ((nonnull-s16vector) "C_c_s16vector(")
1382      ((s32vector) "C_c_s32vector_or_null(")
1383      ((nonnull-s32vector) "C_c_s32vector(")
1384      ((s64vector) "C_c_s64vector_or_null(")
1385      ((nonnull-s64vector) "C_c_s64vector(")
1386      ((f32vector) "C_c_f32vector_or_null(")
1387      ((nonnull-f32vector) "C_c_f32vector(")
1388      ((f64vector) "C_c_f64vector_or_null(")
1389      ((nonnull-f64vector) "C_c_f64vector(")
1390      ((pointer-vector) "C_c_pointer_vector_or_null(")
1391      ((nonnull-pointer-vector) "C_c_pointer_vector(")
1392      ((c-string c-string* unsigned-c-string unsigned-c-string*) "C_string_or_null(")
1393      ((nonnull-c-string nonnull-c-string* nonnull-unsigned-c-string 
1394			 nonnull-unsigned-c-string* symbol) "C_c_string(")
1395      ((bool) "C_truep(")
1396      (else
1397       (cond ((and (symbol? type) (lookup-foreign-type type))
1398	      => (lambda (t)
1399		   (foreign-argument-conversion (vector-ref t 0)) ) )
1400	     ((and (list? type) (>= (length type) 2))
1401	      (case (car type)
1402		((c-pointer) "C_c_pointer_or_null(")
1403		((nonnull-c-pointer) "C_c_pointer_nn(")
1404		((instance) "C_c_pointer_or_null(")
1405		((nonnull-instance) "C_c_pointer_nn(")
1406		((scheme-pointer) "C_data_pointer_or_null(")
1407		((nonnull-scheme-pointer) "C_data_pointer(")
1408		((function) "C_c_pointer_or_null(")
1409		((const) (foreign-argument-conversion (cadr type)))
1410		((enum) "C_num_to_int(")
1411		((ref)
1412		 (string-append "*(" (foreign-type-declaration (cadr type) "*")
1413				")C_c_pointer_nn("))
1414		((instance-ref)
1415		 (string-append "*(" (cadr type) "*)C_c_pointer_nn("))
1416		(else (err)) ) )
1417	     (else (err)) ) ) ) ) )
1418
1419
1420;; Generate suitable conversion of a result value into Scheme data
1421	    
1422(define (foreign-result-conversion type dest)
1423  (let ((err (lambda ()
1424	       (quit-compiling "illegal foreign return type `~A'" type))))
1425    (case type
1426      ((char unsigned-char) "C_make_character((C_word)")
1427      ((int int32) "C_fix((C_word)")
1428      ((unsigned-int unsigned-int32) "C_fix(C_MOST_POSITIVE_FIXNUM&(C_word)")
1429      ((short) "C_fix((short)")
1430      ((unsigned-short) "C_fix(0xffff&(C_word)")
1431      ((byte) "C_fix((char)")
1432      ((unsigned-byte) "C_fix(0xff&(C_word)")
1433      ((float double) (sprintf "C_flonum(&~a," dest))	;XXX suboptimal for int64
1434      ((number) (sprintf "C_number(&~a," dest))
1435      ((nonnull-c-string c-string nonnull-c-pointer c-string* nonnull-c-string* 
1436			 unsigned-c-string unsigned-c-string* nonnull-unsigned-c-string
1437			 nonnull-unsigned-c-string* symbol c-string-list c-string-list*) 
1438       (sprintf "C_mpointer(&~a,(void*)" dest) )
1439      ((c-pointer) (sprintf "C_mpointer_or_false(&~a,(void*)" dest))
1440      ((integer integer32) (sprintf "C_int_to_num(&~a," dest))
1441      ((integer64 ssize_t) (sprintf "C_int64_to_num(&~a," dest))
1442      ((unsigned-integer64 size_t) (sprintf "C_uint64_to_num(&~a," dest))
1443      ((unsigned-integer unsigned-integer32) (sprintf "C_unsigned_int_to_num(&~a," dest))
1444      ((long) (sprintf "C_long_to_num(&~a," dest))
1445      ((unsigned-long) (sprintf "C_unsigned_long_to_num(&~a," dest))
1446      ((bool) "C_mk_bool(")
1447      ((void scheme-object) "((C_word)")
1448      (else
1449       (cond ((and (symbol? type) (lookup-foreign-type type))
1450	      => (lambda (x)
1451		   (foreign-result-conversion (vector-ref x 0) dest)) )
1452	     ((and (list? type) (>= (length type) 2))
1453	      (case (car type)
1454		((nonnull-pointer nonnull-c-pointer)
1455		 (sprintf "C_mpointer(&~A,(void*)" dest) )
1456		((ref)
1457		 (sprintf "C_mpointer(&~A,(void*)&" dest) )
1458		((instance)
1459		 (sprintf "C_mpointer_or_false(&~A,(void*)" dest) )
1460		((nonnull-instance)
1461		 (sprintf "C_mpointer(&~A,(void*)" dest) )
1462		((instance-ref)
1463		 (sprintf "C_mpointer(&~A,(void*)&" dest) )
1464		((const) (foreign-result-conversion (cadr type) dest))
1465		((pointer c-pointer)
1466		 (sprintf "C_mpointer_or_false(&~a,(void*)" dest) )
1467		((function) (sprintf "C_mpointer(&~a,(void*)" dest))
1468		((enum) (sprintf "C_int_to_num(&~a," dest))
1469		(else (err)) ) )
1470	     (else (err)) ) ) ) ) )
1471
1472
1473;;; Encoded literals as strings, to be decoded by "C_decode_literal()"
1474;; 
1475;; - everything hardcoded, using the FFI would be the ugly, but safer method.
1476
1477(define (encode-literal lit)
1478  (define getbits
1479    (foreign-lambda* int ((scheme-object lit))
1480      "
1481#ifdef C_SIXTY_FOUR
1482return((C_header_bits(lit) >> (24 + 32)) & 0xff);
1483#else
1484return((C_header_bits(lit) >> 24) & 0xff);
1485#endif
1486") )
1487  (define getsize
1488    (foreign-lambda* int ((scheme-object lit))
1489      "return(C_header_size(lit));"))
1490  (define (encode-size n)
1491    (if (fx> (fxlen n) 24)
1492	;; Unfortunately we can't do much more to help the user.
1493	;; Printing the literal is not helpful because it's *huge*,
1494	;; and we have no line number information here.
1495	(quit-compiling
1496	 "Encoded literal size of ~S is too large (must fit in 24 bits)" n)
1497	(string
1498	 (integer->char (bitwise-and #xff (arithmetic-shift n -16)))
1499	 (integer->char (bitwise-and #xff (arithmetic-shift n -8)))
1500	 (integer->char (bitwise-and #xff n)))))
1501  (define (finish str)		   ; can be taken out at a later stage
1502    (string-append (string #\xfe) str))
1503  (finish
1504   (cond ((eq? #t lit) "\xff\x06\x01")
1505	 ((eq? #f lit) "\xff\x06\x00")
1506	 ((char? lit) (string-append "\xff\x0a" (encode-size (char->integer lit))))
1507	 ((null? lit) "\xff\x0e")
1508	 ((eof-object? lit) "\xff\x3e")
1509	 ((eq? (void) lit) "\xff\x1e")
1510	 ;; The big-fixnum? check can probably be simplified
1511	 ((and (fixnum? lit) (not (big-fixnum? lit)))
1512	  (string-append
1513	   "\xff\x01"
1514	   (string (integer->char (bitwise-and #xff (arithmetic-shift lit -24)))
1515		   (integer->char (bitwise-and #xff (arithmetic-shift lit -16)))
1516		   (integer->char (bitwise-and #xff (arithmetic-shift lit -8)))
1517		   (integer->char (bitwise-and #xff lit)) ) ) )
1518	 ((exact-integer? lit)
1519	  ;; Encode as hex to save space and get exact size
1520	  ;; calculation.  We could encode as base 32 to save more
1521	  ;; space, but that makes debugging harder.  The type tag is
1522	  ;; a bit of a hack: we encode as "GC forwarded" string to
1523	  ;; get a unique new type, as bignums don't have their own
1524	  ;; type tag (they're encoded as structures).
1525	  (let ((str (number->string lit 16)))
1526	    (string-append "\xc2" (encode-size (string-length str)) str)))
1527	 ((flonum? lit)
1528	  (string-append "\x55" (number->string lit) "\x00") )
1529	 ((or (keyword? lit) (symbol? lit))
1530	  (let ((str (##sys#slot lit 1)))
1531	    (string-append 
1532	     "\x01"
1533	     (encode-size (string-length str))
1534	     (if (keyword? lit) "\x02" "\x01")
1535	     str) ) )
1536	 ((##sys#immediate? lit)
1537	  (bomb "invalid literal - cannot encode" lit))
1538	 ((##core#inline "C_byteblockp" lit)
1539	  (##sys#string-append ; relies on the fact that ##sys#string-append doesn't check
1540	   (string-append
1541	    (string (integer->char (getbits lit)))
1542	    (encode-size (getsize lit)) )
1543	   lit) )
1544	 (else
1545	  (let ((len (getsize lit)))
1546	    (string-intersperse
1547	     (cons*
1548	      (string (integer->char (getbits lit)))
1549	      (encode-size len)
1550	      (list-tabulate len (lambda (i) (encode-literal (##sys#slot lit i)))))
1551	     ""))))) )
1552)
Trap