~ chicken-core (chicken-5) /core.scm


   1;;;; core.scm - The CHICKEN Scheme compiler (core module)
   2;
   3;
   4; "This is insane. What we clearly want to do is not exactly clear, and is rooted in NCOMPLR."
   5;
   6;
   7;--------------------------------------------------------------------------------------------
   8; Copyright (c) 2008-2022, The CHICKEN Team
   9; Copyright (c) 2000-2007, Felix L. Winkelmann
  10; All rights reserved.
  11;
  12; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
  13; conditions are met:
  14;
  15;   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
  16;     disclaimer.
  17;   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
  18;     disclaimer in the documentation and/or other materials provided with the distribution.
  19;   Neither the name of the author nor the names of its contributors may be used to endorse or promote
  20;     products derived from this software without specific prior written permission.
  21;
  22; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
  23; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  24; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
  25; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  26; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  27; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  29; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30; POSSIBILITY OF SUCH DAMAGE.
  31;
  32;
  33; Supported syntax:
  34;
  35; - Declaration specifiers:
  36;
  37; ([not] extended-bindings {<name>})
  38; ([not] inline {<var>})
  39; ([not] safe)
  40; ([not] standard-bindings {<name>})
  41; ([not] usual-integrations {<name>})
  42; (local {<name> ...})
  43; ([not] inline-global {<name>})
  44; ([number-type] <type>)
  45; (always-bound {<name>})
  46; (block)
  47; (block-global {<name>})
  48; (bound-to-procedure {<var>})
  49; (compile-syntax)
  50; (disable-interrupts)
  51; (emit-import-library {<module> | (<module> <filename>)})
  52; (emit-types-file [<filename>])
  53; (export {<name>})
  54; (fixnum-arithmetic)
  55; (foreign-declare {<string>})
  56; (hide {<name>})
  57; (inline-limit <limit>)
  58; (unroll-limit <limit>)
  59; (keep-shadowed-macros)
  60; (no-argc-checks)
  61; (no-bound-checks)
  62; (no-procedure-checks)
  63; (no-procedure-checks-for-usual-bindings)
  64; (no-procedure-checks-for-toplevel-bindings)
  65; (profile <symbol> ...)
  66; (safe-globals)
  67; (separate)
  68; (type (<symbol> <typespec>) ...)
  69; (unit <unitname>)
  70; (unsafe)
  71; (unused <symbol> ...)
  72; (uses {<unitname>})
  73; (strict-types)
  74; (specialize)
  75; (enforce-argument-types [<symbol> ...])
  76;
  77;   <type> = fixnum | generic
  78
  79; - Global symbol properties:
  80;
  81;   ##compiler#always-bound -> BOOL
  82;   ##compiler#always-bound-to-procedure -> BOOL
  83;   ##compiler#local -> BOOL
  84;   ##compiler#visibility -> #f | 'hidden | 'exported
  85;   ##compiler#constant -> BOOL                             defined as constant
  86;   ##compiler#intrinsic -> #f | 'standard | 'extended
  87;   ##compiler#inline -> 'no | 'yes
  88;   ##compiler#inline-global -> 'yes | 'no | <node>
  89;   ##compiler#profile -> BOOL
  90;   ##compiler#unused -> BOOL
  91;   ##compiler#foldable -> BOOL
  92;   ##compiler#pure -> BOOL                                 referentially transparent
  93;   ##compiler#clean -> BOOL                                does not modify local state
  94;   ##compiler#type -> TYPE
  95;   ##compiler#type-source -> 'db | 'local | 'inference
  96
  97; - Source language:
  98;
  99; <variable>
 100; <constant>
 101; (##core#declare {<spec>})
 102; (##core#local-specialization <variable> <alias> {<spec>})
 103; (##core#immutable <exp>)
 104; (##core#quote <exp>)
 105; (##core#syntax <exp>)
 106; (##core#if <exp> <exp> [<exp>])
 107; (##core#let <variable> ({(<variable> <exp>)}) <body>)
 108; (##core#let ({(<variable> <exp>)}) <body>)
 109; (##core#letrec ({(<variable> <exp>)}) <body>)
 110; (##core#letrec* ({(<variable> <exp>)}) <body>)
 111; (##core#let-location <symbol> <type> [<init>] <exp>)
 112; (##core#lambda <variable> <body>)
 113; (##core#lambda ({<variable>}+ [. <variable>]) <body>)
 114; (##core#set! <variable> <exp>)
 115; (##core#ensure-toplevel-definition <variable>)
 116; (##core#begin <exp> ...)
 117; (##core#include <string> <string> | #f [<body>])
 118; (##core#loop-lambda <llist> <body>)
 119; (##core#undefined)
 120; (##core#primitive <name>)
 121; (##core#provide <id>)
 122; (##core#inline {<op>} <exp>)
 123; (##core#inline_allocate (<op> <words>) {<exp>})
 124; (##core#inline_ref (<name> <type>))
 125; (##core#inline_update (<name> <type>) <exp>)
 126; (##core#inline_loc_ref (<type>) <exp>)
 127; (##core#inline_loc_update (<type>) <exp> <exp>)
 128; (##core#compiletimetoo <exp>)
 129; (##core#compiletimeonly <exp>)
 130; (##core#elaborationtimetoo <exp>)
 131; (##core#elaborationtimeonly <exp>)
 132; (##core#define-foreign-variable <symbol> <type> [<string>])
 133; (##core#define-foreign-type <symbol> <type> [<proc1> [<proc2>]])
 134; (##core#foreign-lambda <type> <string> {<type>})
 135; (##core#foreign-lambda* <type> ({(<type> <var>)})) {<string>})
 136; (##core#foreign-safe-lambda <type> <string> {<type>})
 137; (##core#foreign-safe-lambda* <type> ({(<type> <var>)})) {<string>})
 138; (##core#foreign-primitive <type> ({(<type> <var>)}) {<string>})
 139; (##core#define-inline <name> <exp>)
 140; (##core#define-constant <name> <exp*>)
 141; (##core#foreign-callback-wrapper '<name> <qualifiers> '<type> '({<type>}) <exp>)
 142; (##core#define-external-variable <name> <type> <bool> [<symbol>])
 143; (##core#check <exp>)
 144; (##core#require-for-syntax <id>)
 145; (##core#require <id> [<id>])
 146; (##core#app <exp> {<exp>})
 147; (##core#define-syntax <symbol> <expr>)
 148; (##core#define-compiler-syntax <symbol> <expr>)
 149; (##core#let-compiler-syntax ((<symbol> <expr>) ...) <expr> ...)
 150; (##core#module <symbol> #t | (<name> | (<name> ...) ...) <body>)
 151; (##core#let-module-alias ((<alias> <name>) ...) <body>)
 152; (##core#the <type> <strict?> <exp>)
 153; (##core#typecase <info> <exp> (<type> <body>) ... [(else <body>)])
 154; (##core#debug-event {<event> <loc>})
 155; (##core#with-forbidden-refs (<var> ...) <loc> <expr>)
 156; (<exp> {<exp>})
 157
 158; - Core language:
 159;
 160; [##core#variable {<variable>}]
 161; [##core#float-variable {<index>}]
 162; [if {} <exp> <exp> <exp>)]
 163; [quote {<const>}]
 164; [##core#float {<const>}]
 165; [let {<variable>} <exp-v> <exp>]
 166; [##core#lambda {<id> <mode> (<variable>... [. <variable>]) <size>} <exp>]
 167; [set! {<variable> [always-immediate?]} <exp>]
 168; [##core#undefined {}]
 169; [##core#primitive {<name>}]
 170; [##core#let_float {<index>} <exp> <exp>]
 171; [##core#box_float {} <exp>]
 172; [##core#unbox_float {} <exp>]
 173; [##core#inline {<op>} <exp>...]
 174; [##core#inline_allocate {<op> <words>} <exp>...]
 175; [##core#inline_ref {<name> <type>}]
 176; [##core#inline_update {<name> <type>} <exp>]
 177; [##core#inline_loc_ref {<type>} <exp>]
 178; [##core#inline_loc_update {<type>} <exp> <exp>]
 179; [##core#debug-event {<event> <loc> <ln>}]
 180; [##core#call {<safe-flag> [<debug-info>]} <exp-f> <exp>...]
 181; [##core#callunit {<unitname>} <exp>...]
 182; [##core#switch {<count>} <exp> <const1> <body1> ... <defaultbody>]
 183; [##core#rest-car {restvar depth [<debug-info>]}]
 184; [##core#rest-cdr {restvar depth [<debug-info>]}]
 185; [##core#rest-null? {restvar depth [<debug-info>]}]
 186; [##core#rest-length {restvar depth [<debug-info>]}]
 187; [##core#cond <exp> <exp> <exp>]
 188; [##core#provide <id>]
 189; [##core#recurse {<tail-flag>} <exp1> ...]
 190; [##core#return <exp>]
 191; [##core#direct_call {<safe-flag> <debug-info> <call-id> <words>} <exp-f> <exp>...]
 192; [##core#direct_lambda {<id> <mode> (<variable>... [. <variable>]) <size>} <exp>]
 193; [##core#the {<type> <strict>} <exp>]
 194; [##core#the/result {<typelist>} <exp>]
 195; [##core#typecase {<info> (<type> ...)} <exp> <body1> ... [<elsebody>]]
 196
 197; - Closure converted/prepared language:
 198;
 199; [if {} <exp> <exp> <exp>]
 200; [quote {<exp>}]
 201; [##core#float {<const>}]
 202; [##core#bind {<count>} <exp-v>... <exp>]
 203; [##core#float-variable {<index>}]
 204; [##core#undefined {}]
 205; [##core#let_float {<index>} <exp> <exp>]
 206; [##core#box_float {} <exp>]
 207; [##core#unbox_float {} <exp>]
 208; [##core#inline {<op>} <exp>...]
 209; [##core#inline_allocate {<op <words>} <exp>...]
 210; [##core#inline_ref {<name> <type>}]
 211; [##core#inline_update {<name> <type>} <exp>]
 212; [##core#inline_loc_ref {<type>} <exp>]
 213; [##core#inline_loc_update {<type>} <exp> <exp>]
 214; [##core#debug-event {<index> <event> <loc> <ln>}]
 215; [##core#closure {<count>} <exp>...]
 216; [##core#box {} <exp>]
 217; [##core#unbox {} <exp>]
 218; [##core#ref {<index>} <exp>]
 219; [##core#update {<index>} <exp> <exp>]
 220; [##core#updatebox {} <exp> <exp>]
 221; [##core#update_i {<index>} <exp> <exp>]
 222; [##core#updatebox_i {} <exp> <exp>]
 223; [##core#call {<dbg-info-index> <safe-flag> [<debug-info> [<call-id> <customizable-flag>]]} <exp-f> <exp>...]
 224; [##core#callunit {<unitname>} <exp>...]
 225; [##core#cond <exp> <exp> <exp>]
 226; [##core#local {<index>}]
 227; [##core#setlocal {<index>} <exp>]
 228; [##core#global {<literal> <safe-flag> <block-mode> [<name>]}]
 229; [##core#setglobal {<literal> <block-mode> <name>} <exp>]
 230; [##core#setglobal_i {<literal> <block-mode> <name>} <exp>]
 231; [##core#literal {<literal>}]
 232; [##core#immediate {<type> [<immediate>]}]     - type: bool/fix/nil/char/bwp
 233; [##core#proc {<name> [<non-internal>]}]
 234; [##core#provide <literal>]
 235; [##core#recurse {<tail-flag> <call-id>} <exp1> ...]
 236; [##core#return <exp>]
 237; [##core#direct_call {<dbg-info-index> <safe-flag> <debug-info> <call-id> <words>} <exp-f> <exp>...]
 238
 239; Analysis database entries:
 240;
 241; <variable>:
 242;
 243;   captured -> <boolean>                    If true: variable is used outside it's home-scope
 244;   global -> <boolean>                      If true: variable does not occur in any lambda-list
 245;   call-sites -> ((<lambda-id> <node>) ...) Known call-nodes of a named procedure
 246;   home -> <lambda-id>                      Procedure which introduces this variable
 247;   unknown -> <boolean>                     If true: variable cannot have a known value
 248;   assigned -> <boolean>                    If true: variable is assigned somewhere
 249;   assigned-locally -> <boolean>            If true: variable has been assigned inside user lambda
 250;   undefined -> <boolean>                   If true: variable is unknown yet but can be known later
 251;   value -> <node>                          Variable has a known value
 252;   local-value -> <node>                    Variable is declared local and has value
 253;   potential-values -> (<node> ...)         Global variable was assigned this value (used for lambda-info)
 254;   references -> (<node> ...)               Nodes that are accesses of this variable (##core#variable nodes)
 255;   boxed -> <boolean>                       If true: variable has to be boxed after closure-conversion
 256;   contractable -> <boolean>                If true: variable names contractable procedure
 257;   inlinable -> <boolean>                   If true: variable names potentially inlinable procedure
 258;   collapsable -> <boolean>                 If true: variable refers to collapsable constant
 259;   removable -> <boolean>                   If true: variable is not used
 260;   replacable -> <variable>                 Variable can be replaced by another variable
 261;   replacing -> <boolean>                   If true: variable can replace another variable (don't remove)
 262;   standard-binding -> <boolean>            If true: variable names a standard binding
 263;   extended-binding -> <boolean>            If true: variable names an extended binding
 264;   unused -> <boolean>                      If true: variable is a formal parameter that is never used
 265;   rest-parameter -> #f | 'list             If true: variable holds rest-argument list
 266;   consed-rest-arg -> <boolean>             If true: variable is a rest variable in a procedure called with consed rest list
 267;   rest-cdr -> (rvar . n)                   Variable references the cdr of rest list rvar after n cdrs (0 = rest list itself)
 268;   rest-null? -> (rvar . n)                 Variable checks if the cdr of rest list rvar after n cdrs is empty (0 = rest list itself)
 269;   derived-rest-vars -> (v1 v2 ...)         Other variables aliasing or referencing cdrs of a rest variable
 270;   constant -> <boolean>                    If true: variable has fixed value
 271;   hidden-refs -> <boolean>                 If true: procedure that refers to hidden global variables
 272;   inline-transient -> <boolean>            If true: was introduced during inlining
 273;
 274; <lambda-id>:
 275;
 276;   contains -> (<lambda-id> ...)            Procedures contained in this lambda
 277;   contained-in -> <lambda-id>              Procedure containing this lambda
 278;   has-unused-parameters -> <boolean>       If true: procedure has unused formal parameters
 279;   use-expr -> (<lambda-id> ...)            Marks non-direct use-sites of common subexpression
 280;   closure-size -> <integer>                Number of free variables stored in a closure
 281;   customizable -> <boolean>                If true: all call sites are known, procedure does not escape
 282;   simple -> <boolean>                      If true: procedure only calls its continuation
 283;   explicit-rest -> <boolean>               If true: procedure is called with consed rest list
 284;   captured-variables -> (<var> ...)        List of closed over variables
 285;   inline-target -> <boolean>               If true: was target of an inlining operation
 286
 287
 288(declare
 289 (unit compiler)
 290 (uses eval extras expand data-structures scrutinizer support))
 291
 292(module chicken.compiler.core
 293    (analyze-expression canonicalize-expression compute-database-statistics
 294     initialize-compiler perform-closure-conversion perform-cps-conversion
 295     prepare-for-code-generation build-toplevel-procedure
 296
 297     ;; Various ugly global boolean flags that get set by the (batch) driver
 298     all-import-libraries preserve-unchanged-import-libraries
 299     bootstrap-mode compiler-syntax-enabled
 300     emit-closure-info emit-profile enable-inline-files explicit-use-flag
 301     first-analysis no-bound-checks compile-module-registration
 302     optimize-leaf-routines standalone-executable undefine-shadowed-macros
 303     verbose-mode local-definitions enable-specialization block-compilation
 304     inline-locally inline-substitutions-enabled strict-variable-types
 305     static-extensions emit-link-file types-output-file
 306
 307     ;; These are set by the (batch) driver, and read by the (c) backend
 308     disable-stack-overflow-checking emit-trace-info external-protos-first
 309     external-variables insert-timer-checks no-argc-checks
 310     no-global-procedure-checks no-procedure-checks emit-debug-info
 311
 312     ;; Other, non-boolean, flags set by (batch) driver
 313     profiled-procedures import-libraries inline-max-size
 314     unroll-limit
 315     extended-bindings standard-bindings
 316
 317     ;; Non-booleans set and read by the (batch) driver
 318     required-extensions linked-libraries used-libraries
 319
 320     ;; non-booleans set by the (batch) driver, and read by the (c) backend
 321     target-heap-size target-stack-size unit-name used-units
 322
 323     ;; bindings, set by the (c) platform
 324     default-extended-bindings default-standard-bindings internal-bindings
 325
 326     ;; Only read or called by the (c) backend
 327     foreign-declarations foreign-lambda-stubs foreign-stub-argument-types
 328     foreign-stub-argument-names foreign-stub-body foreign-stub-callback
 329     foreign-stub-cps foreign-stub-id foreign-stub-name foreign-stub-return-type
 330     lambda-literal-id lambda-literal-external lambda-literal-argument-count
 331     lambda-literal-rest-argument lambda-literal-rest-argument-mode
 332     lambda-literal-temporaries lambda-literal-float-temporaries
 333     lambda-literal-callee-signatures lambda-literal-allocated
 334     lambda-literal-closure-size lambda-literal-looping
 335     lambda-literal-customizable lambda-literal-body lambda-literal-direct
 336
 337     ;; Tables and databases that really should not be exported
 338     constant-table immutable-constants inline-table line-number-database-2
 339     line-number-database-size)
 340
 341(import scheme
 342	chicken.base
 343	chicken.condition
 344	chicken.compiler.scrutinizer
 345	chicken.compiler.support
 346	chicken.eval
 347	chicken.fixnum
 348	chicken.file
 349	chicken.foreign
 350	chicken.format
 351	chicken.internal
 352	chicken.io
 353	chicken.keyword
 354	chicken.load
 355	chicken.platform
 356	chicken.pretty-print
 357	chicken.pathname
 358	chicken.string
 359	chicken.syntax
 360	chicken.type)
 361
 362(define (d arg1 . more)
 363  (when (##sys#debug-mode?)
 364    (if (null? more)
 365	(pp arg1)
 366	(apply print arg1 more))))
 367
 368(define-syntax d (syntax-rules () ((_ . _) (void))))
 369
 370(include "tweaks")
 371(include "mini-srfi-1.scm")
 372
 373(define-inline (gensym-f-id) (gensym 'f_))
 374
 375(define-constant initial-analysis-database-size 3001)
 376(define-constant default-line-number-database-size 997)
 377(define-constant inline-table-size 301)
 378(define-constant constant-table-size 301)
 379(define-constant default-inline-max-size 20)
 380(define-constant default-unroll-limit 1)
 381
 382
 383;;; Global variables containing compilation parameters:
 384
 385(define unit-name #f)
 386(define standard-bindings '())
 387(define extended-bindings '())
 388(define insert-timer-checks #t)
 389(define used-units '())
 390(define foreign-declarations '())
 391(define emit-trace-info #f)
 392(define emit-debug-info #f)
 393(define block-compilation #f)
 394(define line-number-database-size default-line-number-database-size)
 395(define target-heap-size #f)
 396(define target-stack-size #f)
 397(define optimize-leaf-routines #f)
 398(define emit-profile #f)
 399(define no-bound-checks #f)
 400(define no-argc-checks #f)
 401(define no-procedure-checks #f)
 402(define no-global-procedure-checks #f)
 403(define safe-globals-flag #f)
 404(define explicit-use-flag #f)
 405(define disable-stack-overflow-checking #f)
 406(define external-protos-first #f)
 407(define inline-max-size default-inline-max-size)
 408(define unroll-limit default-unroll-limit)
 409(define emit-closure-info #t)
 410(define undefine-shadowed-macros #t)
 411(define profiled-procedures #f)
 412(define import-libraries '())
 413(define all-import-libraries #f)
 414(define preserve-unchanged-import-libraries #t)
 415(define compile-module-registration #f) ; 'no | 'yes
 416(define standalone-executable #t)
 417(define local-definitions #f)
 418(define inline-locally #f)
 419(define enable-inline-files #f)
 420(define compiler-syntax-enabled #t)
 421(define bootstrap-mode #f)
 422(define strict-variable-types #f)
 423(define enable-specialization #f)
 424(define static-extensions #f)
 425(define emit-link-file #f)
 426(define types-output-file #f) ; #t | <filename>
 427
 428;;; Other global variables:
 429
 430(define verbose-mode #f)
 431(define original-program-size #f)
 432(define current-program-size 0)
 433(define current-analysis-database-size initial-analysis-database-size)
 434(define line-number-database-2 #f)
 435(define immutable-constants '())
 436(define inline-table #f)
 437(define constant-table #f)
 438(define inline-substitutions-enabled #f)
 439(define direct-call-ids '())
 440(define first-analysis #t)
 441(define foreign-variables '())
 442(define foreign-lambda-stubs '())
 443(define external-variables '())
 444(define external-to-pointer '())
 445(define location-pointer-map '())
 446(define pending-canonicalizations '())
 447(define defconstant-bindings '())
 448(define callback-names '())
 449(define toplevel-scope #t)
 450(define toplevel-lambda-id #f)
 451(define required-extensions '())
 452(define linked-libraries '())
 453(define used-libraries '())
 454
 455(define unlikely-variables '(unquote unquote-splicing))
 456
 457;;; Initial bindings.  These are supplied (set!) by the (c-)platform
 458(define default-extended-bindings '())
 459(define default-standard-bindings '())
 460(define internal-bindings '())
 461
 462;;; Initialize globals:
 463
 464(define (initialize-compiler)
 465  (if line-number-database-2
 466      (vector-fill! line-number-database-2 '())
 467      (set! line-number-database-2 (make-vector line-number-database-size '())) )
 468  (if inline-table
 469      (vector-fill! inline-table '())
 470      (set! inline-table (make-vector inline-table-size '())) )
 471  (if constant-table
 472      (vector-fill! constant-table '())
 473      (set! constant-table (make-vector constant-table-size '())) )
 474  (reset-profile-info-vector-name!)
 475  (clear-real-name-table!)
 476  (clear-foreign-type-table!) )
 477
 478
 479;;; Compute general statistics from analysis database:
 480;
 481; - Returns:
 482;
 483;   current-program-size
 484;   original-program-size
 485;   number of known variables
 486;   number of known procedures
 487;   number of global variables
 488;   number of known call-sites
 489;   number of database entries
 490;   average bucket load
 491
 492(define (compute-database-statistics db)
 493  (let ((nprocs 0)
 494	(nvars 0)
 495	(nglobs 0)
 496	(entries 0)
 497	(nsites 0) )
 498    (hash-table-for-each
 499     (lambda (sym plist)
 500       (for-each
 501	(lambda (prop)
 502	  (set! entries (+ entries 1))
 503	  (case (car prop)
 504	    ((global) (set! nglobs (+ nglobs 1)))
 505	    ((value)
 506	     (set! nvars (+ nvars 1))
 507	     (if (eq? '##core#lambda (node-class (cdr prop)))
 508		 (set! nprocs (+ nprocs 1)) ) )
 509	    ((call-sites) (set! nsites (+ nsites (length (cdr prop))))) ) )
 510	plist) )
 511     db)
 512    (values current-program-size
 513	    original-program-size
 514	    nvars
 515	    nprocs
 516	    nglobs
 517	    nsites
 518	    entries) ) )
 519
 520;;; Expand macros and canonicalize expressions:
 521
 522(define (canonicalize-expression exp)
 523  (let ((compiler-syntax '())
 524        (forbidden-refs '()))
 525
 526  (define (find-id id se)		; ignores macro bindings
 527    (cond ((null? se) #f)
 528	  ((and (eq? id (caar se)) (symbol? (cdar se))) (cdar se))
 529	  (else (find-id id (cdr se)))))
 530
 531  (define (lookup id)
 532    (cond ((find-id id (##sys#current-environment)))
 533	  ((##sys#get id '##core#macro-alias) symbol? => values)
 534	  (else id)))
 535
 536  (define (macro-alias var)
 537    (let ((alias (gensym var)))
 538      (##sys#put! alias '##core#macro-alias (lookup var))
 539      alias) )
 540
 541  (define (handle-expansion-result outer-ln)
 542    (lambda (input output)
 543      (and-let* (((not (eq? input output)))
 544		 (ln (or (get-line-number input) outer-ln)))
 545	(##sys#update-line-number-database! output ln))
 546      output))
 547
 548  (define (canonicalize-body/ln ln body cs?)
 549    (fluid-let ((chicken.syntax#expansion-result-hook
 550		 (handle-expansion-result ln)))
 551      (##sys#canonicalize-body body (##sys#current-environment) cs?)))
 552
 553  (define (set-real-names! as ns)
 554    (for-each (lambda (a n) (set-real-name! a n)) as ns) )
 555
 556  (define (write-to-string x)
 557    (let ([out (open-output-string)])
 558      (write x out)
 559      (get-output-string out) ) )
 560
 561  (define (unquotify x)
 562    (if (and (list? x)
 563	     (= 2 (length x))
 564	     (symbol? (car x))
 565	     (eq? 'quote (lookup (car x))))
 566	(cadr x)
 567	x) )
 568
 569  (define (resolve-variable x0 e dest ldest h outer-ln)
 570    (when (memq x0 unlikely-variables)
 571      (warning
 572       (sprintf "reference to variable `~s' possibly unintended" x0) ))
 573    (let ((x (lookup x0)))
 574      (d `(RESOLVE-VARIABLE: ,x0 ,x ,(map (lambda (x) (car x)) (##sys#current-environment))))
 575      (cond ((not (symbol? x)) x0)	; syntax?
 576	    ((hash-table-ref constant-table x)
 577	     => (lambda (val) (walk val e dest ldest h #f #f)))
 578	    ((hash-table-ref inline-table x)
 579	     => (lambda (val) (walk val e dest ldest h #f #f)))
 580	    ((assq x foreign-variables)
 581	     => (lambda (fv)
 582		  (let* ((t (second fv))
 583			 (ft (final-foreign-type t))
 584			 (body `(##core#inline_ref (,(third fv) ,t))))
 585		    (walk
 586		     (foreign-type-convert-result
 587		      (finish-foreign-result ft body)
 588		      t)
 589		     e dest ldest h #f #f))))
 590	    ((assq x location-pointer-map)
 591	     => (lambda (a)
 592		  (let* ((t (third a))
 593			 (ft (final-foreign-type t))
 594			 (body `(##core#inline_loc_ref (,t) ,(second a))))
 595		    (walk
 596		     (foreign-type-convert-result
 597		      (finish-foreign-result ft body)
 598		      t)
 599		     e dest ldest h #f #f))))
 600	    ((not (memq x e)) (##sys#alias-global-hook x #f (cons h outer-ln))) ; only if global
 601            ((assq x forbidden-refs) =>
 602             (lambda (a)
 603               (let ((ln (cdr a)))
 604                 (quit-compiling
 605                   "~acyclical reference in LETREC binding for variable `~a'"
 606                   (if ln (sprintf "(~a) - " ln) "")
 607                   (get-real-name x)))))
 608	    (else x))))
 609
 610  (define (emit-import-lib name mod il)
 611    (let* ((fname (if all-import-libraries
 612		      (string-append (symbol->string name) ".import.scm")
 613		      (cdr il)))
 614	   (imps (##sys#compiled-module-registration mod #f))
 615	   (oldimps
 616	    (and (file-exists? fname)
 617		 (call-with-input-file fname read-expressions))))
 618      (cond ((and (equal? imps oldimps) preserve-unchanged-import-libraries)
 619	     (when verbose-mode
 620	       (print "not generating import library `" fname "' for module `"
 621		      name "' because imports did not change")) )
 622	    (else
 623	     (when verbose-mode
 624	       (print "generating import library `" fname "' for module `"
 625		      name "' ..."))
 626	     (with-output-to-file fname
 627	       (lambda ()
 628		 (print ";;;; " fname " - GENERATED BY CHICKEN "
 629			(chicken-version) " -*- Scheme -*-\n")
 630		 (for-each pretty-print imps)
 631		 (print "\n;; END OF FILE"))))) ) )
 632
 633  (define (walk x e dest ldest h outer-ln tl?)
 634    (cond ((keyword? x) `(quote ,x))
 635	  ((symbol? x) (resolve-variable x e dest ldest h outer-ln))
 636	  ((not (pair? x))
 637	   (if (constant? x)
 638	       `(quote ,x)
 639	       (##sys#syntax-error/context "illegal atomic form" x)))
 640	  ((symbol? (car x))
 641	   (let ((ln (or (get-line-number x) outer-ln)))
 642	     (emit-syntax-trace-info x #f)
 643	     (unless (list? x)
 644	       (if ln
 645		   (##sys#syntax-error/context (sprintf "(~a) - malformed expression" ln) x)
 646		   (##sys#syntax-error/context "malformed expression" x)))
 647	     (set! ##sys#syntax-error-culprit x)
 648	     (let* ((name (lookup (car x)))
 649		    (xexpanded
 650		     (fluid-let ((chicken.syntax#expansion-result-hook
 651				  (handle-expansion-result ln)))
 652		       (expand x (##sys#current-environment) compiler-syntax-enabled))))
 653	       (cond ((not (eq? x xexpanded))
 654		      (walk xexpanded e dest ldest h ln tl?))
 655
 656		     ((hash-table-ref inline-table name)
 657		      => (lambda (val)
 658			   (walk (cons val (cdr x)) e dest ldest h ln #f)))
 659
 660		     (else
 661		      (case name
 662
 663			((##core#if)
 664			 `(if
 665			   ,(walk (cadr x) e #f #f h ln #f)
 666			   ,(walk (caddr x) e #f #f h ln #f)
 667			   ,(if (null? (cdddr x))
 668				'(##core#undefined)
 669				(walk (cadddr x) e #f #f h ln #f) ) ) )
 670
 671			((##core#syntax ##core#quote)
 672			 `(quote ,(strip-syntax (cadr x))))
 673
 674			((##core#check)
 675			 (if unsafe
 676			     '(quote #t)
 677			     (walk (cadr x) e dest ldest h ln tl?) ) )
 678
 679			((##core#the)
 680			 `(##core#the
 681			   ,(strip-syntax (cadr x))
 682			   ,(caddr x)
 683			   ,(walk (cadddr x) e dest ldest h ln tl?)))
 684
 685			((##core#local-specialization)
 686			 (let* ((name (resolve-variable (cadr x) e dest ldest h outer-ln))
 687				(raw-alias (caddr x))
 688				(resolved-alias (resolve-variable raw-alias e dest ldest h outer-ln))
 689				(specs (##sys#get name '##compiler#local-specializations '())))
 690			   (letrec ((resolve-alias (lambda (form)
 691						     (cond ((pair? form) (cons (resolve-alias (car form)) (resolve-alias (cdr form))))
 692							   ((eq? form raw-alias) resolved-alias)
 693							   (else form)))))
 694			     (##sys#put! name '##compiler#local-specializations (##sys#append specs (resolve-alias (cdddr x))))
 695			     '(##core#undefined))))
 696
 697			((##core#typecase)
 698			 `(##core#typecase
 699			   ,(or ln (cadr x))
 700			   ,(walk (caddr x) e #f #f h ln tl?)
 701			   ,@(map (lambda (cl)
 702				    (list (strip-syntax (car cl))
 703					  (walk (cadr cl) e dest ldest h ln tl?)))
 704				  (cdddr x))))
 705
 706			((##core#immutable)
 707			 (let ((c (cadadr x)))
 708			   (cond [(assoc c immutable-constants) => cdr]
 709				 [else
 710				  (let ([var (gensym 'c)])
 711				    (set! immutable-constants (alist-cons c var immutable-constants))
 712				    (mark-variable var '##compiler#always-bound)
 713				    (hide-variable var)
 714				    var) ] ) ) )
 715
 716			((##core#provide ##core#primitive ##core#undefined) x)
 717
 718			((##core#callunit)
 719			 (let ((unit (cadr x)))
 720			   (set! used-units (lset-adjoin/eq? used-units unit))
 721			   `(##core#callunit ,unit)))
 722
 723			((##core#inline_ref)
 724			 `(##core#inline_ref
 725			   (,(caadr x) ,(strip-syntax (cadadr x)))))
 726
 727			((##core#inline_loc_ref)
 728			 `(##core#inline_loc_ref
 729			   ,(strip-syntax (cadr x))
 730			   ,(walk (caddr x) e dest ldest h ln #f)))
 731
 732			((##core#require-for-syntax)
 733			 (chicken.load#load-extension (cadr x) #f #f)
 734			 '(##core#undefined))
 735
 736			((##core#require)
 737			 (let ((lib (cadr x))
 738			       (mod (and (pair? (cddr x)) (caddr x))))
 739			   (unless (chicken.load#core-library? lib)
 740			     (set! required-extensions (lset-adjoin/eq? required-extensions lib)))
 741			   (walk (##sys#process-require
 742				  lib mod
 743				  (if (or (memq lib linked-libraries) static-extensions)
 744				      'static
 745				      'dynamic))
 746				 e dest ldest h ln #f)))
 747
 748			((##core#let)
 749			 (let* ((bindings (cadr x))
 750				(vars (unzip1 bindings))
 751				(aliases (map gensym vars))
 752				(se2 (##sys#extend-se (##sys#current-environment) vars aliases))
 753				(ln (or (get-line-number x) outer-ln)))
 754			   (set-real-names! aliases vars)
 755			   `(let
 756			     ,(map (lambda (alias b)
 757				     (list alias (walk (cadr b) e (car b) #t h ln #f)) )
 758				   aliases bindings)
 759			     ,(parameterize ((##sys#current-environment se2))
 760				(walk (canonicalize-body/ln
 761				       ln (cddr x) compiler-syntax-enabled)
 762				      (append aliases e)
 763				      dest ldest h ln #f)) ) )  )
 764
 765			((##core#letrec*)
 766			 (let ((bindings (cadr x))
 767			       (body (cddr x)) )
 768			   (walk
 769			    `(##core#let
 770			      ,(map (lambda (b)
 771				      (list (car b) '(##core#undefined)))
 772				    bindings)
 773			      ,@(map (lambda (b)
 774				       `(##core#set! ,(car b) ,(cadr b)))
 775				     bindings)
 776			      (##core#let () ,@body) )
 777			    e dest ldest h ln #f)))
 778
 779			((##core#letrec)
 780			 (let* ((bindings (cadr x))
 781				(vars (unzip1 bindings))
 782				(tmps (map gensym vars))
 783				(body (cddr x)) )
 784			   (walk
 785			    `(##core#let
 786			      ,(map (lambda (b)
 787				      (list (car b) '(##core#undefined)))
 788				    bindings)
 789			      (##core#let
 790			       ,(map (lambda (t b)
 791                                       (list t `(##core#with-forbidden-refs
 792                                                  ,vars ,ln ,(cadr b))))
 793                                     tmps bindings)
 794			       ,@(map (lambda (v t)
 795					`(##core#set! ,v ,t))
 796				      vars tmps)
 797			       (##core#let () ,@body) ) )
 798			    e dest ldest h ln #f)))
 799
 800                        ((##core#with-forbidden-refs)
 801                         (let* ((loc (caddr x))
 802                                (vars (map (lambda (v)
 803                                             (cons (resolve-variable v e dest ldest h outer-ln)
 804                                                   loc))
 805                                        (cadr x))))
 806                           (fluid-let ((forbidden-refs
 807                                         (append vars forbidden-refs)))
 808                             (walk (cadddr x) e dest ldest h ln #f))))
 809
 810			((##core#lambda)
 811			 (let ((llist (cadr x))
 812			       (obody (cddr x)) )
 813			   (when (##sys#extended-lambda-list? llist)
 814			     (set!-values
 815			      (llist obody)
 816			      (##sys#expand-extended-lambda-list
 817			       llist obody ##sys#error (##sys#current-environment)) ) )
 818			   (##sys#decompose-lambda-list
 819			    llist
 820			    (lambda (vars argc rest)
 821			      (let* ((aliases (map gensym vars))
 822				     (ln (or (get-line-number x) outer-ln))
 823				     (se2 (##sys#extend-se (##sys#current-environment) vars aliases))
 824				     (body (parameterize ((##sys#current-environment se2))
 825					     (let ((body0 (canonicalize-body/ln
 826							   ln obody compiler-syntax-enabled)))
 827                                               (fluid-let ((forbidden-refs '()))
 828                                                 (walk
 829                                                   (if emit-debug-info
 830                                                       `(##core#begin
 831                                                          (##core#debug-event C_DEBUG_ENTRY (##core#quote ,dest))
 832                                                         ,body0)
 833                                                       body0)
 834                                                   (append aliases e)
 835                                                   #f #f dest ln #f)))))
 836				     (llist2
 837				      (build-lambda-list
 838				       aliases argc
 839				       (and rest (list-ref aliases (posq rest vars))) ) )
 840				     (l `(##core#lambda ,llist2 ,body)) )
 841				(set-real-names! aliases vars)
 842				(cond ((or (not dest)
 843					   ldest
 844					   (assq dest (##sys#current-environment))) ; not global?
 845				       l)
 846				      ((and emit-profile
 847					    (or (eq? profiled-procedures 'all)
 848						(and
 849						 (eq? profiled-procedures 'some)
 850						 (variable-mark dest '##compiler#profile))))
 851				       (expand-profile-lambda
 852					(if (memq dest e) ; should normally not be the case
 853					    e
 854					    (##sys#alias-global-hook dest #f #f))
 855					llist2 body) )
 856				      (else l)))))))
 857
 858			((##core#let-syntax)
 859			 (parameterize
 860			     ((##sys#current-environment
 861			       (append
 862				(map (lambda (b)
 863				       (list
 864					(car b)
 865					(##sys#current-environment)
 866					(##sys#ensure-transformer
 867					 (##sys#eval/meta (cadr b))
 868					 (car b))))
 869				     (cadr x) )
 870				(##sys#current-environment)) ))
 871			   (let ((ln (or (get-line-number x) outer-ln)))
 872			     (walk
 873			      (canonicalize-body/ln
 874			       ln (cddr x) compiler-syntax-enabled)
 875			      e dest ldest h ln #f)) ) )
 876
 877		       ((##core#letrec-syntax)
 878			(let* ((ms (map (lambda (b)
 879					  (list
 880					   (car b)
 881					   #f
 882					   (##sys#ensure-transformer
 883					    (##sys#eval/meta (cadr b))
 884					    (car b))))
 885					(cadr x) ) )
 886			       (se2 (append ms (##sys#current-environment)))
 887			       (ln (or (get-line-number x) outer-ln)) )
 888			  (for-each
 889			   (lambda (sb)
 890			     (set-car! (cdr sb) se2) )
 891			   ms)
 892			  (parameterize ((##sys#current-environment se2))
 893			    (walk
 894			     (canonicalize-body/ln
 895			      ln (cddr x) compiler-syntax-enabled)
 896			     e dest ldest h ln #f))))
 897
 898		       ((##core#define-syntax)
 899			(##sys#check-syntax
 900			 (car x) x
 901			 (if (pair? (cadr x))
 902			     '(_ (variable . lambda-list) . #(_ 1))
 903			     '(_ variable _) )
 904			 #f (##sys#current-environment))
 905			(let* ((var (if (pair? (cadr x)) (caadr x) (cadr x)))
 906			       (body (if (pair? (cadr x))
 907					 `(##core#lambda ,(cdadr x) ,@(cddr x))
 908					 (caddr x)))
 909			       (name (lookup var)))
 910                          (##sys#put/restore! name '##sys#override 'syntax)
 911			  (##sys#register-syntax-export name (##sys#current-module) body)
 912			  (##sys#extend-macro-environment
 913			   name
 914			   (##sys#current-environment)
 915			   (##sys#eval/meta body))
 916			  (walk
 917			   (if ##sys#enable-runtime-macros
 918			       `(##sys#extend-macro-environment
 919				 (##core#quote ,var)
 920				 (##sys#current-environment) ,body) ;XXX possibly wrong se?
 921			       '(##core#undefined) )
 922			   e dest ldest h ln #f)) )
 923
 924                       ((##core#define-compiler-syntax)
 925                        (let* ((var (cadr x))
 926                               (body (caddr x))
 927                               (name (lookup var)))
 928                          (when body
 929                            (set! compiler-syntax
 930                              (alist-cons
 931                               name
 932                               (##sys#get name '##compiler#compiler-syntax)
 933                               compiler-syntax)))
 934                          (##sys#put!
 935                           name '##compiler#compiler-syntax
 936                           (and body
 937                                (##sys#cons
 938                                 (##sys#ensure-transformer
 939                                  (##sys#eval/meta body)
 940                                  var)
 941                                 (##sys#current-environment))))
 942                          (walk
 943                           (if ##sys#enable-runtime-macros
 944                               `(##sys#put!
 945                                (##core#syntax ,name)
 946                                '##compiler#compiler-syntax
 947                                ,(and body
 948                                      `(##sys#cons
 949                                        (##sys#ensure-transformer
 950                                         ,body
 951                                         (##core#quote ,var))
 952                                        (##sys#current-environment))))
 953                               '(##core#undefined) )
 954                           e dest ldest h ln #f)))
 955
 956		       ((##core#let-compiler-syntax)
 957			(let ((bs (map
 958				   (lambda (b)
 959				     (##sys#check-syntax
 960				      'let-compiler-syntax b '(symbol . #(_ 0 1)))
 961				     (let ((name (lookup (car b))))
 962				       (list
 963					name
 964					(and (pair? (cdr b))
 965					     (cons (##sys#ensure-transformer
 966						    (##sys#eval/meta (cadr b))
 967						    (car b))
 968						   (##sys#current-environment)))
 969					(##sys#get name '##compiler#compiler-syntax) ) ) )
 970				   (cadr x)))
 971			      (ln (or (get-line-number x) outer-ln)))
 972			  (dynamic-wind
 973			      (lambda ()
 974				(for-each
 975				 (lambda (b)
 976				   (##sys#put! (car b) '##compiler#compiler-syntax (cadr b)))
 977				 bs) )
 978			      (lambda ()
 979				(walk
 980				 (canonicalize-body/ln
 981				  ln (cddr x) compiler-syntax-enabled)
 982				 e dest ldest h ln tl?) )
 983			      (lambda ()
 984				(for-each
 985				 (lambda (b)
 986				   (##sys#put!
 987				    (car b)
 988				    '##compiler#compiler-syntax (caddr b)))
 989				 bs) ) ) ) )
 990
 991		       ((##core#include)
 992                         (##sys#include-forms-from-file
 993                          (cadr x)
 994                          (caddr x)
 995                          (lambda (forms path)
 996                            (let ((code (if (pair? (cdddr x)) ; body?
 997                                            (canonicalize-body/ln
 998                                              ln
 999                                              (append forms (cadddr x))
 1000                                              compiler-syntax-enabled)
1001                                            `(##core#begin ,@forms))))
1002                              (fluid-let ((##sys#current-source-filename path))
1003                                (walk code e dest ldest h ln tl?))))))
1004
1005		       ((##core#let-module-alias)
1006			(##sys#with-module-aliases
1007			 (map (lambda (b)
1008				(##sys#check-syntax 'functor b '(symbol symbol))
1009				(strip-syntax b))
1010			      (cadr x))
1011			 (lambda ()
1012			   (walk `(##core#begin ,@(cddr x)) e dest ldest h ln #t))))
1013
1014		       ((##core#module)
1015			(let* ((name (strip-syntax (cadr x)))
1016			       (il  (or (assq name import-libraries) all-import-libraries))
1017			       (lib (and (not standalone-executable) il (or unit-name name)))
1018			       (mod (##sys#register-module
1019				     name lib
1020				     (or (eq? #t (caddr x))
1021					 (map (lambda (exp)
1022						(cond ((symbol? exp) exp)
1023						      ((and (pair? exp)
1024							    (let loop ((exp exp))
1025							      (or (null? exp)
1026								  (and (symbol? (car exp))
1027								       (loop (cdr exp))))))
1028						       exp)
1029						      (else
1030						       (##sys#syntax-error-hook
1031							'module
1032							"invalid export syntax" exp name))))
1033					      (strip-syntax (caddr x))))))
1034			       (csyntax compiler-syntax))
1035			  (when (##sys#current-module)
1036			    (##sys#syntax-error-hook
1037			     'module "modules may not be nested" name))
1038			  (let ((body (parameterize ((##sys#current-module mod)
1039						     (##sys#current-environment '())
1040						     (##sys#macro-environment
1041						      ##sys#initial-macro-environment)
1042						     (##sys#module-alias-environment
1043						      (##sys#module-alias-environment)))
1044					(##sys#with-property-restore
1045					 (lambda ()
1046					   (let loop ((body (cdddr x)) (xs '()))
1047					     (if (null? body)
1048						 (handle-exceptions ex
1049						     (begin
1050						       ;; avoid backtrace
1051						       (print-error-message ex (current-error-port))
1052						       (exit 1))
1053						   (##sys#finalize-module
1054						    mod
1055						    (lambda (id)
1056						      (cond
1057							((assq id foreign-variables)
1058							 "a foreign variable")
1059							((hash-table-ref inline-table id)
1060							 "an inlined function")
1061							((hash-table-ref constant-table id)
1062							 "a constant")
1063							((##sys#get id '##compiler#type-abbreviation)
1064							 "a type abbreviation")
1065							(else #f))))
1066						   (reverse xs))
1067						 (loop
1068						  (cdr body)
1069						  (cons (walk (car body)
1070							      e #f #f
1071							      h ln #t) ; reset to toplevel!
1072							xs)))))))))
1073			    (do ((cs compiler-syntax (cdr cs)))
1074				((eq? cs csyntax) (set! compiler-syntax csyntax))
1075			      (##sys#put! (caar cs) '##compiler#compiler-syntax (cdar cs)))
1076			    (when il
1077			      (emit-import-lib name mod il)
1078			      (when (pair? il)
1079				(set! import-libraries
1080				  (delete il import-libraries equal?))))
1081			    (canonicalize-begin-body
1082			     (append
1083			      (list (list '##core#provide (module-requirement name)))
1084			      (if (or (eq? compile-module-registration 'yes)
1085				      (and (not il) ; default behaviour
1086					   (not compile-module-registration)))
1087				  (parameterize ((##sys#macro-environment
1088						  (##sys#meta-macro-environment))
1089						 (##sys#current-environment ; ???
1090						  (##sys#current-meta-environment)))
1091				    (map (lambda (x) (walk x e #f #f h ln tl?))
1092					 (##sys#compiled-module-registration
1093					  mod
1094					  (if static-extensions 'static 'dynamic))))
1095			          '())
1096			      body)))))
1097
1098		       ((##core#loop-lambda) ;XXX is this really needed?
1099			(let* ((vars (cadr x))
1100			       (obody (cddr x))
1101			       (aliases (map gensym vars))
1102			       (se2 (##sys#extend-se (##sys#current-environment) vars aliases))
1103			       (ln (or (get-line-number x) outer-ln))
1104			       (body
1105				(parameterize ((##sys#current-environment se2))
1106				  (walk
1107				   (canonicalize-body/ln ln obody compiler-syntax-enabled)
1108				   (append aliases e)
1109				   #f #f dest ln #f)) ) )
1110			  (set-real-names! aliases vars)
1111			  `(##core#lambda ,aliases ,body) ) )
1112
1113		       ((##core#ensure-toplevel-definition)
1114                         (let* ((var0 (cadr x))
1115                                (var (lookup var0)))
1116                           (unless tl?
1117                             (let ((ln (get-line-number x)))
1118                               (quit-compiling
1119                                 "~atoplevel definition of `~s' in non-toplevel context"
1120                                (if ln (sprintf "(~a) - " ln) "")
1121                                var)))
1122                           (##sys#put/restore! var '##sys#override 'value)
1123                           '(##core#undefined)))
1124
1125		       ((##core#set!)
1126			(let* ((var0 (cadr x))
1127			       (var (lookup var0))
1128			       (ln (get-line-number x))
1129			       (val (caddr x)))
1130			  (when (memq var unlikely-variables)
1131			    (warning
1132			     (sprintf "~aassignment to variable `~s' possibly unintended"
1133			       (if ln (sprintf "(~a) - " ln) "")
1134			       var)))
1135			  (cond ((assq var foreign-variables)
1136				 => (lambda (fv)
1137				      (let ((type (second fv))
1138					    (tmp (gensym)))
1139					(walk
1140					 `(##core#let ((,tmp ,(foreign-type-convert-argument val type)))
1141					    (##core#inline_update
1142					     (,(third fv) ,type)
1143					     ,(foreign-type-check tmp type)))
1144					 e #f #f h ln #f))))
1145				((assq var location-pointer-map)
1146				 => (lambda (a)
1147				      (let* ((type (third a))
1148					     (tmp (gensym)))
1149					(walk
1150					 `(##core#let ((,tmp ,(foreign-type-convert-argument val type)))
1151					    (##core#inline_loc_update
1152					     (,type)
1153					     ,(second a)
1154					     ,(foreign-type-check tmp type)))
1155					 e #f #f h ln #f))))
1156				(else
1157				 (unless (memq var e) ; global?
1158				   (set! var (##sys#alias-global-hook var #t dest))
1159				   (when safe-globals-flag
1160				     (mark-variable var '##compiler#always-bound-to-procedure)
1161				     (mark-variable var '##compiler#always-bound))
1162				   (when emit-debug-info
1163				     (set! val
1164				       `(##core#let ((,var ,val))
1165					  (##core#debug-event C_DEBUG_GLOBAL_ASSIGN (##core#quote ,var))
1166					  ,var)))
1167				   ;; We use `var0` instead of `var` because the {macro,current}-environment
1168				   ;; are keyed by the raw and unqualified name
1169				   (cond ((##sys#macro? var0 (##sys#current-environment))
1170					  (warning
1171					   (sprintf "~aassignment to syntax `~S'"
1172					    (if ln (sprintf "(~a) - " ln) "") var0))
1173					  (when undefine-shadowed-macros
1174					    (##sys#undefine-macro! var0)
1175					    (##sys#unregister-syntax-export var0 (##sys#current-module))))
1176					 ((assq var0 (##sys#current-environment))
1177					  (warning
1178					   (sprintf "~aassignment to imported value binding `~S'"
1179					    (if ln (sprintf "(~a) - " ln) "") var0)))))
1180				 `(set! ,var ,(walk val e var0 (memq var e) h ln #f))))))
1181
1182			((##core#debug-event)
1183			 `(##core#debug-event
1184			   ,(cadr x)
1185			   ,ln ; this arg is added - from this phase on ##core#debug-event has an additional argument!
1186			   ,@(map (lambda (arg)
1187				    (unquotify (walk arg e #f #f h ln tl?)))
1188				  (cddr x))))
1189
1190			((##core#inline)
1191			 `(##core#inline
1192			   ,(unquotify (cadr x)) ,@(mapwalk (cddr x) e h ln #f)))
1193
1194			((##core#inline_allocate)
1195			 `(##core#inline_allocate
1196			   ,(map unquotify (second x))
1197			   ,@(mapwalk (cddr x) e h ln #f)))
1198
1199			((##core#inline_update)
1200			 `(##core#inline_update ,(cadr x) ,(walk (caddr x) e #f #f h ln #f)) )
1201
1202			((##core#inline_loc_update)
1203			 `(##core#inline_loc_update
1204			   ,(cadr x)
1205			   ,(walk (caddr x) e #f #f h ln #f)
1206			   ,(walk (cadddr x) e #f #f h ln #f)) )
1207
1208			((##core#compiletimetoo ##core#elaborationtimetoo)
1209			 (let ((exp (cadr x)))
1210			   (##sys#eval/meta exp)
1211			   (walk exp e dest #f h ln tl?) ) )
1212
1213			((##core#compiletimeonly ##core#elaborationtimeonly)
1214			 (##sys#eval/meta (cadr x))
1215			 '(##core#undefined) )
1216
1217			((##core#begin)
1218			 (if (pair? (cdr x))
1219			     (canonicalize-begin-body
1220			      (let fold ([xs (cdr x)])
1221				(let ([x (car xs)]
1222				      [r (cdr xs)] )
1223				  (if (null? r)
1224				      (list (walk x e dest ldest h ln tl?))
1225				      (cons (walk x e #f #f h ln tl?) (fold r)) ) ) ) )
1226			     '(##core#undefined) ) )
1227
1228			((##core#foreign-lambda)
1229			 (walk (expand-foreign-lambda x #f) e dest ldest h ln #f) )
1230
1231			((##core#foreign-safe-lambda)
1232			 (walk (expand-foreign-lambda x #t) e dest ldest h ln #f) )
1233
1234			((##core#foreign-lambda*)
1235			 (walk (expand-foreign-lambda* x #f) e dest ldest h ln #f) )
1236
1237			((##core#foreign-safe-lambda*)
1238			 (walk (expand-foreign-lambda* x #t) e dest ldest h ln #f) )
1239
1240			((##core#foreign-primitive)
1241			 (walk (expand-foreign-primitive x) e dest ldest h ln #f) )
1242
1243			((##core#define-foreign-variable)
1244			 (let* ((var (strip-syntax (second x)))
1245				(type (strip-syntax (third x)))
1246				(name (if (pair? (cdddr x))
1247					  (fourth x)
1248					  (symbol->string var))))
1249			   (set! foreign-variables
1250			     (cons (list var type name)
1251				   foreign-variables))
1252			   '(##core#undefined) ) )
1253
1254			((##core#define-foreign-type)
1255			 (let ((name (second x))
1256			       (type (strip-syntax (third x)))
1257			       (conv (cdddr x)))
1258			   (unless tl?
1259			     (quit-compiling
1260			      "~adefinition of foreign type `~s' in non-toplevel context"
1261			      (if ln (sprintf "(~a) - " ln) "")
1262			      name))
1263			   (cond [(pair? conv)
1264				  (let ([arg (gensym)]
1265					[ret (gensym)] )
1266				    (register-foreign-type! name type arg ret)
1267				    (mark-variable arg '##compiler#always-bound)
1268				    (mark-variable ret '##compiler#always-bound)
1269				    (hide-variable arg)
1270				    (hide-variable ret)
1271				    ;; NOTE: Above we already check we're in toplevel context,
1272				    ;; so we can unconditionally register the export here.
1273				    ;; TODO: Remove after fixing #1615
1274				    (##sys#register-export arg (##sys#current-module))
1275				    (##sys#register-export ret (##sys#current-module))
1276				    (walk
1277				     `(##core#begin
1278					(##core#set! ,arg ,(first conv))
1279					(##core#set!
1280					 ,ret
1281					 ,(if (pair? (cdr conv)) (second conv) '##sys#values)) )
1282				     e dest ldest h ln tl?))]
1283				 [else
1284				  (register-foreign-type! name type)
1285				  '(##core#undefined) ] ) ) )
1286
1287			((##core#define-external-variable)
1288			 (let* ((sym (second x))
1289				(ln (get-line-number x))
1290				(name (symbol->string sym))
1291				(type (third x))
1292				(exported (fourth x))
1293				(rname (make-random-name)) )
1294			   (unless tl?
1295			     (quit-compiling
1296			      "~aexternal variable definition of `~s' in non-toplevel context"
1297			      (if ln (sprintf "(~a) - " ln) "")
1298			      sym))
1299			   (unless exported (set! name (symbol->string (fifth x))))
1300			   (set! external-variables (cons (vector name type exported) external-variables))
1301			   (set! foreign-variables
1302			     (cons (list rname 'c-pointer (string-append "&" name))
1303				   foreign-variables) )
1304			   (set! external-to-pointer (alist-cons sym rname external-to-pointer))
1305			   '(##core#undefined) ) )
1306
1307			((##core#let-location)
1308			 (let* ((var (second x))
1309				(type (strip-syntax (third x)))
1310				(alias (gensym))
1311				(store (gensym))
1312				(init (and (pair? (cddddr x)) (fourth x))))
1313			   (set-real-name! alias var)
1314			   (set! location-pointer-map
1315			     (cons (list alias store type) location-pointer-map) )
1316			   (parameterize ((##sys#current-environment
1317					   (alist-cons var alias (##sys#current-environment))))
1318			    (walk
1319			     `(##core#let (,(let ((size (bytes->words (estimate-foreign-result-location-size type))))
1320				       ;; Add 2 words: 1 for the header, 1 for double-alignment:
1321				       ;; Note: C_a_i_bytevector takes number of words, not bytes
1322				       (list
1323					store
1324					`(##core#inline_allocate
1325					  ("C_a_i_bytevector" ,(+ 2 size))
1326					  ',size)) ) )
1327				(##core#begin
1328				 ,@(if init
1329				       `((##core#set! ,alias ,init))
1330				       '() )
1331				 ,(if init (fifth x) (fourth x)) ) )
1332			     e
1333			     dest ldest h ln #f)) ) )
1334
1335			((##core#define-inline)
1336			 (let* ((name (second x))
1337				(val `(##core#lambda ,@(cdaddr x)))
1338				(ln (get-line-number x)))
1339			   (unless tl?
1340			     (quit-compiling
1341			      "~ainline definition of `~s' in non-toplevel context"
1342			      (if ln (sprintf "(~a) - " ln) "")
1343			      name))
1344			     (hash-table-set! inline-table name val)
1345			     '(##core#undefined)))
1346
1347			((##core#define-constant)
1348			 (let* ((name (second x))
1349				(ln (get-line-number x))
1350				(valexp (third x))
1351				(val (handle-exceptions ex
1352					 ;; could show line number here
1353					 (quit-compiling "error in constant evaluation of ~S for named constant `~S'"
1354					       valexp name)
1355				       (if (and (not (symbol? valexp))
1356						(collapsable-literal? valexp))
1357					   valexp
1358					   (eval
1359					    `(##core#let
1360					      ,defconstant-bindings ,valexp))))))
1361			   (unless tl?
1362			     (quit-compiling
1363			      "~aconstant definition of `~s' in non-toplevel context"
1364			      (if ln (sprintf "(~a) - " ln) "")
1365			      name))
1366			   (set! defconstant-bindings
1367			     (cons (list name `(##core#quote ,val)) defconstant-bindings))
1368			   (cond ((collapsable-literal? val)
1369				  (hash-table-set! constant-table name `(##core#quote ,val))
1370				  '(##core#undefined))
1371				 ((basic-literal? val)
1372				  (let ((var (gensym "constant")))
1373				    (hash-table-set! constant-table name var)
1374				    (hide-variable var)
1375				    (mark-variable var '##compiler#constant)
1376				    (mark-variable var '##compiler#always-bound)
1377				    (walk `(define ,var (##core#quote ,val)) e #f #f h ln tl?)))
1378				 (else
1379				  (quit-compiling
1380				   "~ainvalid compile-time value for named constant `~S'"
1381				   (if ln (sprintf "(~a) - " ln) "")
1382				   name)))))
1383
1384			((##core#declare)
1385			 (walk
1386			  `(##core#begin
1387			    ,@(map (lambda (d)
1388				     (process-declaration d lookup (lambda (id) (memq (lookup id) e))))
1389				   (cdr x) ) )
1390			  e #f #f h ln #f) )
1391
1392			((##core#foreign-callback-wrapper)
1393			 (let-values ([(args lam) (split-at (cdr x) 4)])
1394			   (let* ([lam (car lam)]
1395				  [raw-c-name (cadr (first args))]
1396				  [name (##sys#alias-global-hook raw-c-name #t dest)]
1397				  [rtype (cadr (third args))]
1398				  [atypes (cadr (fourth args))]
1399				  [vars (second lam)] )
1400			     (if (valid-c-identifier? raw-c-name)
1401				 (set! callback-names
1402				   (cons (cons raw-c-name name) callback-names))
1403				 (let ((ln (get-line-number x)))
1404				   (quit-compiling
1405				    "~aname `~S' of external definition is not a valid C identifier"
1406				    (if ln (sprintf "(~a) - " ln) "")
1407				    raw-c-name)))
1408			     (when (or (not (list? vars))
1409				       (not (list? atypes))
1410				       (not (= (length vars) (length atypes))) )
1411			       (syntax-error
1412				"non-matching or invalid argument list to foreign callback-wrapper"
1413				vars atypes) )
1414			     `(##core#foreign-callback-wrapper
1415			       ,@(mapwalk args e h ln #f)
1416			       ,(walk `(##core#lambda
1417					,vars
1418					(##core#let
1419					 ,(let loop ([vars vars] [types atypes])
1420					    (if (null? vars)
1421						'()
1422						(let ([var (car vars)]
1423						      [type (car types)] )
1424						  (cons
1425						   (list
1426						    var
1427						    (foreign-type-convert-result
1428						     (finish-foreign-result
1429						      (final-foreign-type type)
1430						      var)
1431						     type) )
1432						   (loop (cdr vars) (cdr types)) ) ) ) )
1433					 ,(foreign-type-convert-argument
1434					   `(##core#let
1435					     ()
1436					     ,@(cond
1437						((member
1438						  rtype
1439						  '((const nonnull-c-string)
1440						    (const nonnull-unsigned-c-string)
1441						    nonnull-unsigned-c-string
1442						    nonnull-c-string))
1443						 `((##sys#make-c-string
1444						    (##core#let
1445						     () ,@(cddr lam))
1446						    (##core#quote ,name))))
1447						((member
1448						  rtype
1449						  '((const c-string*)
1450						    (const unsigned-c-string*)
1451						    unsigned-c-string*
1452						    c-string*
1453						    c-string-list
1454						    c-string-list*))
1455						 (syntax-error
1456						  "not a valid result type for callback procedures"
1457						  rtype
1458						  name) )
1459						((member
1460						  rtype
1461						  '(c-string
1462						    (const unsigned-c-string)
1463						    unsigned-c-string
1464						    (const c-string)) )
1465						 `((##core#let
1466						    ((r (##core#let () ,@(cddr lam))))
1467						    (,(macro-alias 'and)
1468						     r
1469						     (##sys#make-c-string r (##core#quote ,name))) ) ) )
1470						(else (cddr lam)) ) )
1471					   rtype) ) )
1472				      e #f #f h ln #f) ) ) ) )
1473
1474			((##core#location)
1475			 (let ([sym (cadr x)])
1476			   (if (symbol? sym)
1477			       (cond ((assq (lookup sym) location-pointer-map)
1478				      => (lambda (a)
1479					   (walk
1480					    `(##sys#make-locative ,(second a) 0 #f (##core#quote location))
1481					    e #f #f h ln #f) ) )
1482				     ((assq sym external-to-pointer)
1483				      => (lambda (a) (walk (cdr a) e #f #f h ln #f)) )
1484				     ((assq sym callback-names)
1485				      `(##core#inline_ref (,(symbol->string sym) c-pointer)) )
1486				     (else
1487				      (walk
1488				       `(##sys#make-locative ,sym 0 #f (##core#quote location))
1489				       e #f #f h ln #f) ) )
1490			       (walk
1491				`(##sys#make-locative ,sym 0 #f (##core#quote location))
1492				e #f #f h ln #f) ) ) )
1493
1494			(else
1495			 (let* ((x2 (fluid-let ((##sys#syntax-context
1496						 (cons name ##sys#syntax-context)))
1497				      (mapwalk x e h ln tl?)))
1498				(head2 (car x2))
1499				(old (hash-table-ref line-number-database-2 head2)))
1500			   (when ln
1501			     (hash-table-set!
1502			      line-number-database-2
1503			      head2
1504			      (cons name (alist-cons x2 ln (if old (cdr old) '()))) ) )
1505			   x2))))))))
1506
1507	  ((not (list? x))
1508	   (##sys#syntax-error/context "malformed expression" x) )
1509
1510	  ((constant? (car x))
1511	   (emit-syntax-trace-info x #f)
1512	   (warning "literal in operator position" x)
1513	   (mapwalk x e h outer-ln tl?) )
1514
1515	  (else
1516	   (emit-syntax-trace-info x #f)
1517	   (let ((tmp (gensym)))
1518	     (walk
1519	      `(##core#let
1520		((,tmp ,(car x)))
1521		(,tmp ,@(cdr x)))
1522	      e dest ldest h outer-ln #f)))))
1523
1524  (define (mapwalk xs e h ln tl?)
1525    (map (lambda (x) (walk x e #f #f h ln tl?)) xs) )
1526
1527  (when (memq 'c debugging-chicken) (newline) (pretty-print exp))
1528  (foreign-code "C_clear_trace_buffer();")
1529  ;; Process visited definitions and main expression:
1530  (walk
1531   `(##core#begin
1532     ,@(let ([p (reverse pending-canonicalizations)])
1533	 (set! pending-canonicalizations '())
1534	 p)
1535     ,(begin
1536	(set! extended-bindings (append internal-bindings extended-bindings))
1537	exp) )
1538   '() #f #f #f #f #t) ) )
1539
1540
1541(define (process-declaration spec lookup local?)
1542  (define (check-decl spec minlen . maxlen)
1543    (let ([n (length (cdr spec))])
1544      (if (or (< n minlen) (> n (optional maxlen 99999)))
1545	  (syntax-error "invalid declaration" spec) ) ) )
1546  (define (globalize var)
1547    (cond ((local? var)
1548	   (note-local var)
1549	   #f)
1550	  (else (##sys#alias-global-hook (lookup var) #t #f))))
1551  (define (globalize-all vars)
1552    (filter-map globalize vars))
1553  (define (note-local var)
1554    (##sys#notice
1555     (sprintf "ignoring declaration for locally bound variable `~a'" var)))
1556  (call-with-current-continuation
1557   (lambda (return)
1558     (unless (pair? spec)
1559       (syntax-error "invalid declaration specification" spec) )
1560     (case (strip-syntax (car spec)) ; no global aliasing
1561       ((uses)
1562	(let ((units (strip-syntax (cdr spec))))
1563	  (set! used-libraries (lset-union/eq? used-libraries units))
1564	  (set! linked-libraries (lset-union/eq? linked-libraries units))))
1565       ((unit)
1566	(check-decl spec 1 1)
1567	(let ((u (strip-syntax (cadr spec))))
1568	  (when (and unit-name (not (eq? unit-name u)))
1569	    (warning "unit was already given a name (new name is ignored)"))
1570	  (set! unit-name u)
1571	  (set! standalone-executable #f)))
1572       ((standard-bindings)
1573	(if (null? (cdr spec))
1574	    (set! standard-bindings default-standard-bindings)
1575	    (set! standard-bindings (append (globalize-all (cdr spec)) standard-bindings)) ) )
1576       ((extended-bindings)
1577	(if (null? (cdr spec))
1578	    (set! extended-bindings default-extended-bindings)
1579	    (set! extended-bindings (append (globalize-all (cdr spec)) extended-bindings)) ) )
1580       ((usual-integrations)
1581	(cond [(null? (cdr spec))
1582	       (set! standard-bindings default-standard-bindings)
1583	       (set! extended-bindings default-extended-bindings) ]
1584	      [else
1585	       (let ([syms (globalize-all (cdr spec))])
1586		 (set! standard-bindings (lset-intersection/eq? syms default-standard-bindings))
1587		 (set! extended-bindings (lset-intersection/eq? syms default-extended-bindings)))]))
1588       ((number-type)
1589	(check-decl spec 1 1)
1590	(set! number-type (strip-syntax (cadr spec))))
1591       ((fixnum fixnum-arithmetic) (set! number-type 'fixnum))
1592       ((generic) (set! number-type 'generic))
1593       ((unsafe) (set! unsafe #t))
1594       ((safe) (set! unsafe #f))
1595       ((no-bound-checks) (set! no-bound-checks #t))
1596       ((no-argc-checks) (set! no-argc-checks #t))
1597       ((no-procedure-checks) (set! no-procedure-checks #t))
1598       ((disable-interrupts) (set! insert-timer-checks #f))
1599       ((always-bound)
1600	(for-each (cut mark-variable <> '##compiler#always-bound) (cdr spec)))
1601       ((safe-globals) (set! safe-globals-flag #t))
1602       ((no-procedure-checks-for-usual-bindings)
1603	(for-each
1604	 (cut mark-variable <> '##compiler#always-bound-to-procedure)
1605	 (append default-standard-bindings default-extended-bindings))
1606	(for-each
1607	 (cut mark-variable <> '##compiler#always-bound)
1608	 (append default-standard-bindings default-extended-bindings)))
1609       ((no-procedure-checks-for-toplevel-bindings)
1610	(set! no-global-procedure-checks #t))
1611       ((bound-to-procedure)
1612	(let ((vars (globalize-all (cdr spec))))
1613	  (for-each (cut mark-variable <> '##compiler#always-bound-to-procedure) vars)
1614	  (for-each (cut mark-variable <> '##compiler#always-bound) vars)))
1615       ((foreign-declare)
1616	(let ([fds (cdr spec)])
1617	  (if (every string? fds)
1618	      (set! foreign-declarations (append foreign-declarations fds))
1619	      (syntax-error 'declare "invalid declaration" spec) ) ) )
1620       ((block) (set! block-compilation #t))
1621       ((separate) (set! block-compilation #f))
1622       ((keep-shadowed-macros) (set! undefine-shadowed-macros #f))
1623       ((unused)
1624	(for-each (cut mark-variable <> '##compiler#unused) (globalize-all (cdr spec))))
1625       ((enforce-argument-types)
1626	(for-each
1627	 (cut mark-variable <> '##compiler#enforce)
1628	 (globalize-all (cdr spec))))
1629       ((not)
1630	(check-decl spec 1)
1631	(case (strip-syntax (second spec)) ; strip all
1632	  [(standard-bindings)
1633	   (if (null? (cddr spec))
1634	       (set! standard-bindings '())
1635	       (set! standard-bindings
1636		 (lset-difference/eq? default-standard-bindings
1637				      (globalize-all (cddr spec)))))]
1638	  [(extended-bindings)
1639	   (if (null? (cddr spec))
1640	       (set! extended-bindings '())
1641	       (set! extended-bindings
1642		 (lset-difference/eq? default-extended-bindings
1643				      (globalize-all (cddr spec)))))]
1644	  [(inline)
1645	   (if (null? (cddr spec))
1646	       (set! inline-locally #f)
1647	       (for-each
1648		(cut mark-variable <> '##compiler#inline 'no)
1649		(globalize-all (cddr spec)))) ]
1650	  [(usual-integrations)
1651	   (cond [(null? (cddr spec))
1652		  (set! standard-bindings '())
1653		  (set! extended-bindings '()) ]
1654		 [else
1655		  (let ([syms (globalize-all (cddr spec))])
1656		    (set! standard-bindings (lset-difference/eq? default-standard-bindings syms))
1657		    (set! extended-bindings (lset-difference/eq? default-extended-bindings syms)))])]
1658	  ((inline-global)
1659	   (set! enable-inline-files #t)
1660	   (when (pair? (cddr spec))
1661	     (for-each
1662	      (cut mark-variable <> '##compiler#inline-global 'no)
1663	      (globalize-all (cddr spec)))))
1664	  [else
1665	   (check-decl spec 1 1)
1666	   (let ((id (strip-syntax (cadr spec))))
1667	     (case id
1668	       [(safe) (set! unsafe #t)]
1669	       [else (warning "unsupported declaration specifier" id)]))]))
1670       ((compile-syntax)
1671	(set! ##sys#enable-runtime-macros #t))
1672       ((block-global hide)
1673	(let ([syms (globalize-all (cdr spec))])
1674	  (if (null? syms)
1675	      (set! block-compilation #t)
1676	      (for-each hide-variable syms))))
1677       ((export)
1678	(set! block-compilation #t)
1679	(let ((syms (globalize-all (cdr spec))))
1680	  (for-each export-variable syms)))
1681       ((emit-external-prototypes-first)
1682	(set! external-protos-first #t) )
1683       ((inline)
1684	(if (null? (cdr spec))
1685	    (set! inline-locally #t)
1686	    (for-each
1687	     (cut mark-variable <> '##compiler#local)
1688	     (globalize-all (cdr spec)))))
1689       ((inline-limit)
1690	(check-decl spec 1 1)
1691	(let ([n (cadr spec)])
1692	  (if (number? n)
1693	      (set! inline-max-size n)
1694	      (warning
1695	       "invalid argument to `inline-limit' declaration"
1696	       spec) ) ) )
1697       ((unroll-limit)
1698	(check-decl spec 1 1)
1699	(let ((n (cadr spec)))
1700	  (if (number? n)
1701	      (set! unroll-limit n)
1702	      (warning
1703	       "invalid argument to `unroll-limit' declaration"
1704	       spec) ) ) )
1705       ((pure)
1706	(let ((syms (globalize-all (cdr spec))))
1707	  (if (every symbol? syms)
1708	      (for-each
1709	       (cut mark-variable <> '##compiler#pure #t)
1710	       (globalize-all syms))
1711	      (quit-compiling
1712	       "invalid arguments to `pure' declaration: ~S" spec))))
1713       ((emit-import-library)
1714	(set! import-libraries
1715	  (append
1716	   import-libraries
1717	   (map (lambda (il)
1718		  (cond ((symbol? il)
1719			 (cons il (string-append (symbol->string il) ".import.scm")) )
1720			((and (list? il) (= 2 (length il))
1721			      (symbol? (car il)) (string? (cadr il)))
1722			 (cons (car il) (cadr il)))
1723			(else
1724			 (quit-compiling "invalid `import-library' specification: ~S" il))))
1725		(strip-syntax (cdr spec))))))
1726	((emit-types-file)
1727	 (unless types-output-file
1728	   (set! types-output-file
1729	     (or (null? (cdr spec))
1730		 (and (string? (cadr spec)) (null? (cddr spec)) (cadr spec))
1731		 (quit-compiling "invalid `emit-types-file' declaration: ~S" spec)))))
1732       ((profile)
1733	(set! emit-profile #t)
1734	(cond ((null? (cdr spec))
1735	       (set! profiled-procedures 'all) )
1736	      (else
1737	       (set! profiled-procedures 'some)
1738	       (for-each
1739		(cut mark-variable <> '##compiler#profile)
1740		(globalize-all (cdr spec))))))
1741       ((local)
1742	(cond ((null? (cdr spec))
1743	       (set! local-definitions #t) )
1744	      (else
1745	       (for-each
1746		(cut mark-variable <> '##compiler#local)
1747		(globalize-all (cdr spec))))))
1748       ((inline-global)
1749	(set! enable-inline-files #t)
1750	(set! inline-locally #t)
1751	(when (pair? (cdr spec))
1752	  (for-each
1753	   (cut mark-variable <> '##compiler#inline-global 'yes)
1754	   (globalize-all (cdr spec)))))
1755       ((type)
1756	(for-each
1757	 (lambda (spec)
1758	   (if (not (and (list? spec)
1759			 (>= (length spec) 2)
1760			 (symbol? (car spec))))
1761	       (warning "illegal type declaration" (strip-syntax spec))
1762	       (let ((name (globalize (car spec)))
1763		     (type (strip-syntax (cadr spec))))
1764		 (if (local? (car spec))
1765		     (note-local (car spec))
1766		     (let-values (((type pred pure) (validate-type type name)))
1767		       (cond (type
1768			      ;; HACK: since `:' doesn't have access to the SE, we
1769			      ;; fixup the procedure name if type is a named procedure type
1770			      ;; Quite terrible.
1771			      (when (and (pair? type)
1772					 (eq? 'procedure (car type))
1773					 (symbol? (cadr type)))
1774				(set-car! (cdr type) name))
1775			      (mark-variable name '##compiler#type type)
1776			      (mark-variable name '##compiler#type-source 'local)
1777			      (when pure
1778				(mark-variable name '##compiler#pure #t))
1779			      (when pred
1780				(mark-variable name '##compiler#predicate pred))
1781			      (when (pair? (cddr spec))
1782				(install-specializations
1783				 name
1784				 (strip-syntax (cddr spec)))))
1785			     (else
1786			      (warning
1787			       "illegal `type' declaration"
1788			       (strip-syntax spec)))))))))
1789	 (cdr spec)))
1790       ((predicate)
1791	(for-each
1792	 (lambda (spec)
1793	   (cond ((and (list? spec) (symbol? (car spec)) (= 2 (length spec)))
1794		  (let ((name (globalize (car spec)))
1795			(type (strip-syntax (cadr spec))))
1796		    (if (local? (car spec))
1797			(note-local (car spec))
1798			(let-values (((type pred pure) (validate-type type name)))
1799			  (if (and type (not pred))
1800			      (mark-variable name '##compiler#predicate type)
1801			      (warning "illegal `predicate' declaration" spec))))))
1802		 (else
1803		  (warning "illegal `type' declaration item" spec))))
1804	 (cdr spec)))
1805       ((specialize)
1806	(set! enable-specialization #t))
1807       ((strict-types)
1808	(set! strict-variable-types #t))
1809       (else (warning "unknown declaration specifier" spec)) )
1810     '(##core#undefined) ) ) )
1811
1812
1813;;; Create entry procedure:
1814
1815(define (build-toplevel-procedure node)
1816  (make-node 'lambda '(()) (list node)))
1817
1818
1819;;; Expand "foreign-lambda"/"foreign-safe-lambda" forms and add item to stub-list:
1820
1821(define-record-type foreign-stub
1822  (make-foreign-stub id return-type name argument-types argument-names body cps callback)
1823  foreign-stub?
1824  (id foreign-stub-id)			; symbol
1825  (return-type foreign-stub-return-type)	  ; type-specifier
1826  (name foreign-stub-name)			  ; string or #f
1827  (argument-types foreign-stub-argument-types) ; (type-specifier...)
1828  (argument-names foreign-stub-argument-names) ; #f or (symbol ...)
1829  (body foreign-stub-body)		       ; #f or string
1830  (cps foreign-stub-cps)		       ; boolean
1831  (callback foreign-stub-callback))	       ; boolean
1832
1833(define (create-foreign-stub rtype sname argtypes argnames body callback cps)
1834  ;; try to describe a foreign-lambda type specification
1835  ;; eg. (type->symbol '(c-pointer (struct "point"))) => point*
1836  (define (type->symbol type-spec)
1837    (let loop ([type type-spec])
1838      (cond
1839       ((null? type) 'a)
1840       ((list? type)
1841	(case (car type)
1842	  ((c-pointer) (string->symbol (conc (loop (cdr type)) "*"))) ;; if pointer, append *
1843	  ((const struct) (loop (cdr type))) ;; ignore these
1844	  (else (loop (car type)))))
1845       ((or (symbol? type) (string? type)) type)
1846       (else 'a))))
1847  (let* ((rtype (strip-syntax rtype))
1848	 (argtypes (strip-syntax argtypes))
1849	 (params (if argnames
1850		     (map gensym argnames)
1851		     (map (o gensym type->symbol) argtypes)))
1852	 (f-id (gensym 'stub))
1853	 (bufvar (gensym))
1854	 (rsize (estimate-foreign-result-size rtype)))
1855    (when sname (set-real-name! f-id (string->symbol sname)))
1856    (set! foreign-lambda-stubs
1857      (cons (make-foreign-stub f-id rtype sname argtypes argnames body cps callback)
1858	    foreign-lambda-stubs) )
1859    (let ([rsize (if callback (+ rsize 24) rsize)] ; 24 -> has to hold cons on 64-bit platforms!
1860	  [head (if cps
1861		    `((##core#primitive ,f-id))
1862		    `(##core#inline ,f-id) ) ]
1863	  [rest (map (lambda (p t) (foreign-type-check (foreign-type-convert-argument p t) t)) params argtypes)] )
1864      `(##core#lambda ,params
1865	 ;; Do minor GC (if callback) to make room on stack:
1866	 ,@(if callback '((##sys#gc #f)) '())
1867	 ,(if (zero? rsize)
1868	      (foreign-type-convert-result (append head (cons '(##core#undefined) rest)) rtype)
1869	      (let ([ft (final-foreign-type rtype)]
1870		    [ws (bytes->words rsize)] )
1871		`(##core#let ([,bufvar (##core#inline_allocate ("C_a_i_bytevector" ,(+ 2 ws)) (##core#quote ,ws))])
1872		   ,(foreign-type-convert-result
1873		     (finish-foreign-result ft (append head (cons bufvar rest)))
1874		     rtype) ) ) ) ) ) ) )
1875
1876(define (expand-foreign-lambda exp callback?)
1877  (let* ((name (third exp))
1878	 (sname (cond ((symbol? name) (symbol->string (strip-syntax name)))
1879		      ((string? name) name)
1880		      (else (quit-compiling
1881			     "name `~s' of foreign procedure has wrong type"
1882			     name)) ) )
1883	 (rtype (second exp))
1884	 (argtypes (cdddr exp)) )
1885    (create-foreign-stub rtype sname argtypes #f #f callback? callback?) ) )
1886
1887(define (expand-foreign-lambda* exp callback?)
1888  (let* ((rtype (second exp))
1889	 (args (third exp))
1890	 (body (string-intersperse (cdddr exp) "\n"))
1891 	 (argtypes (map (lambda (x) (car x)) args))
1892	 ;; C identifiers aren't hygienically renamed inside body strings
1893	 (argnames (map cadr (strip-syntax args))))
1894    (create-foreign-stub rtype #f argtypes argnames body callback? callback?) ) )
1895
1896;; TODO: Try to fold this procedure into expand-foreign-lambda*
1897(define (expand-foreign-primitive exp)
1898  (let* ((hasrtype (and (pair? (cddr exp)) (not (string? (caddr exp)))))
1899	 (rtype (if hasrtype (second exp) 'void))
1900	 (args (strip-syntax (if hasrtype (third exp) (second exp))))
1901	 (body (string-intersperse (if hasrtype (cdddr exp) (cddr exp)) "\n"))
1902 	 (argtypes (map (lambda (x) (car x)) args))
1903	 ;; C identifiers aren't hygienically renamed inside body strings
1904	 (argnames (map cadr (strip-syntax args))))
1905    (create-foreign-stub rtype #f argtypes argnames body #f #t) ) )
1906
1907
1908;;; Convert canonicalized node-graph into continuation-passing-style:
1909
1910(define (perform-cps-conversion node)
1911  (let ((called-units '()))
1912
1913  (define (cps-lambda id llist subs k)
1914    (let ([t1 (gensym 'k)])
1915      (k (make-node
1916	  '##core#lambda (list id #t (cons t1 llist) 0)
1917	  (list (walk (car subs)
1918		      (lambda (r)
1919			(make-node '##core#call (list #t) (list (varnode t1) r)) ) ) ) ) ) ) )
1920
1921  (define (node-for-var? node var)
1922     (and (eq? (node-class node) '##core#variable)
1923	  (eq? (car (node-parameters node)) var)))
1924
1925  (define (walk n k)
1926    (let ((subs (node-subexpressions n))
1927	  (params (node-parameters n))
1928	  (class (node-class n)) )
1929      (case (node-class n)
1930	((##core#variable quote ##core#undefined ##core#primitive ##core#provide)
1931          (k n))
1932	((if) (let* ((t1 (gensym 'k))
1933		     (t2 (gensym 'r))
1934		     (k1 (lambda (r) (make-node '##core#call (list #t) (list (varnode t1) r)))) )
1935		(make-node
1936		 'let
1937		 (list t1)
1938		 (list (make-node '##core#lambda (list (gensym-f-id) #f (list t2) 0)
1939				  (list (k (varnode t2))) )
1940		       (walk (car subs)
1941			     (lambda (v)
1942			       (make-node 'if '()
1943					  (list v
1944						(walk (cadr subs) k1)
1945						(walk (caddr subs) k1) ) ) ) ) ) ) ) )
1946	((let)
1947	 (let loop ((vars params) (vals subs))
1948	   (if (null? vars)
1949	       (walk (car vals) k)
1950	       (walk (car vals)
1951		     (lambda (r)
1952		       (if (node-for-var? r (car vars)) ; Don't generate unneccessary lets
1953			   (loop (cdr vars) (cdr vals))
1954			   (make-node 'let
1955				      (list (car vars))
1956				      (list r (loop (cdr vars) (cdr vals))) )) ) ) ) ) )
1957	((lambda ##core#lambda) (cps-lambda (gensym-f-id) (first params) subs k))
1958	((set!) (let* ((t1 (gensym 't))
1959		       (immediate? (and (pair? (cdr params)) (cadr params)))
1960		       (new-params (list (first params) immediate?)))
1961		  (walk (car subs)
1962			(lambda (r)
1963			  (make-node 'let (list t1)
1964				     (list (make-node 'set! new-params (list r))
1965					   (k (varnode t1)) ) ) ) ) ) )
1966	((##core#foreign-callback-wrapper)
1967	 (let ((id (gensym-f-id))
1968	       (lam (first subs)) )
1969	   (register-foreign-callback-stub! id params)
1970	   (cps-lambda id (first (node-parameters lam)) (node-subexpressions lam) k) ) )
1971	((##core#inline ##core#inline_allocate ##core#inline_ref ##core#inline_update ##core#inline_loc_ref
1972			##core#inline_loc_update ##core#debug-event)
1973	 (walk-inline-call class params subs k) )
1974	((##core#call) (walk-call (car subs) (cdr subs) params k))
1975	((##core#callunit)
1976	 (let ((unit (first params)))
1977	   (if (memq unit called-units)
1978	       (walk (make-node '##core#undefined '() '()) k)
1979	       (fluid-let ((called-units (cons unit called-units)))
1980		 (walk-call-unit unit k)))))
1981	((##core#the ##core#the/result)
1982	 ;; remove "the" nodes, as they are not used after scrutiny
1983	 (walk (car subs) k))
1984	((##core#typecase)
1985	 ;; same here, the last clause is chosen, exp is dropped
1986	 (walk (last subs) k))
1987	(else (bomb "bad node (cps)")) ) ) )
1988
1989  (define (walk-call fn args params k)
1990    (let ((t0 (gensym 'k))
1991	  (t3 (gensym 'r)) )
1992      (make-node
1993       'let (list t0)
1994       (list (make-node '##core#lambda (list (gensym-f-id) #f (list t3) 0)
1995			(list (k (varnode t3))) )
1996	     (walk-arguments
1997	      args
1998	      (lambda (vars)
1999		(walk fn
2000		      (lambda (r)
2001			(make-node '##core#call params (cons* r (varnode t0) vars) ) ) ) ) ) ) ) ) )
2002
2003  (define (walk-call-unit unitname k)
2004    (let ((t0 (gensym 'k))
2005	  (t3 (gensym 'r)) )
2006      (make-node
2007       'let (list t0)
2008       (list (make-node '##core#lambda (list (gensym-f-id) #f (list t3) 0)
2009			(list (k (varnode t3))) )
2010	     (make-node '##core#callunit (list unitname)
2011			(list (varnode t0)) ) ) ) ) )
2012
2013  (define (walk-inline-call class op args k)
2014    (walk-arguments
2015     args
2016     (lambda (vars)
2017       (k (make-node class op vars)) ) ) )
2018
2019  (define (walk-arguments args wk)
2020    (let loop ((args args) (vars '()))
2021      (cond ((null? args) (wk (reverse vars)))
2022	    ((atomic? (car args))
2023	     (loop (cdr args) (cons (car args) vars)) )
2024	    (else
2025	     (let ((t1 (gensym 'a)))
2026	       (walk (car args)
2027		     (lambda (r)
2028		       (if (node-for-var? r t1) ; Don't generate unneccessary lets
2029			   (loop (cdr args) (cons (varnode t1) vars) )
2030			   (make-node 'let (list t1)
2031				      (list r
2032					    (loop (cdr args)
2033						  (cons (varnode t1) vars) ) ) )) ) ) ) ) ) ) )
2034
2035  (define (atomic? n)
2036    (let ((class (node-class n)))
2037      (or (memq class '(quote ##core#variable ##core#undefined))
2038	  (and (memq class '(##core#inline_allocate
2039			     ##core#inline_ref ##core#inline_update
2040			     ##core#inline_loc_ref ##core#inline_loc_update))
2041	       (every atomic? (node-subexpressions n)) ) ) ) )
2042
2043  (walk node values)))
2044
2045
2046;;; Perform source-code analysis:
2047
2048(define (analyze-expression node)
2049  ;; Avoid crowded hash tables by using previous run's size as heuristic
2050  (let* ((db-size (fx* (fxmax current-analysis-database-size 1) 3))
2051	 (db (make-vector db-size '())))
2052
2053    (define (grow n)
2054      (set! current-program-size (+ current-program-size n)) )
2055
2056    ;; fullenv is constantly (append localenv env). It's there to avoid
2057    ;; exponential behaviour by APPEND calls when compiling deeply nested LETs
2058    (define (walk n env localenv fullenv here)
2059      (let ((subs (node-subexpressions n))
2060	    (params (node-parameters n))
2061	    (class (node-class n)) )
2062	(grow 1)
2063	(case class
2064	  ((quote ##core#undefined ##core#provide ##core#proc) #f)
2065
2066	  ;; Uneliminated rest-cdr calls need to hang on to rest var
2067	  ((##core#variable ##core#rest-cdr)
2068	   (let ((var (first params)))
2069	     (ref var n)
2070	     (unless (memq var localenv)
2071	       (grow 1)
2072	       (cond ((memq var env)
2073		      (db-put! db var 'captured #t))
2074		     ((not (db-get db var 'global))
2075		      (db-put! db var 'global #t) ) ) ) ) )
2076
2077	  ((##core#callunit ##core#recurse)
2078	   (grow 1)
2079	   (walkeach subs env localenv fullenv here))
2080
2081	  ((##core#call)
2082	   (grow 1)
2083	   (let ([fun (car subs)])
2084	     (when (eq? '##core#variable (node-class fun))
2085	       (let* ((name (first (node-parameters fun)))
2086                      (val (db-get db name 'value)))
2087                 (when (and first-analysis
2088                            val
2089                            (not (db-get db name 'global))
2090                            (not (db-get db name 'unknown))
2091                            (eq? '##core#lambda (node-class val))
2092                            (not (llist-match? (third (node-parameters val))
2093                                               (cdr subs))))
2094                    (quit-compiling
2095		      "known procedure called with wrong number of arguments: `~A'"
2096	              (real-name name)))
2097		 (collect! db name 'call-sites (cons here n))))
2098	     (walk (first subs) env localenv fullenv here)
2099	     (walkeach (cdr subs) env localenv fullenv here)))
2100
2101	  ((let ##core#let)
2102	   (let ([env2 (append params fullenv)])
2103	     (let loop ([vars params] [vals subs])
2104	       (if (null? vars)
2105		   (walk (car vals) env (append params localenv) env2 here)
2106		   (let ([var (car vars)]
2107			 [val (car vals)] )
2108		     (db-put! db var 'home here)
2109		     (assign var val env2 here)
2110		     (walk val env localenv fullenv here)
2111		     (loop (cdr vars) (cdr vals)) ) ) ) ) )
2112
2113	  ((lambda) ; this is an intermediate lambda, slightly different
2114	   (grow 1) ; from '##core#lambda nodes (params = (LLIST));
2115	   (##sys#decompose-lambda-list	; CPS will convert this into ##core#lambda
2116	    (first params)
2117	    (lambda (vars argc rest)
2118	      (for-each
2119	       (lambda (var) (db-put! db var 'unknown #t))
2120	       vars)
2121	      (let ([tl toplevel-scope])
2122		(set! toplevel-scope #f)
2123		(walk (car subs) fullenv vars (append vars fullenv) #f)
2124		(set! toplevel-scope tl) ) ) ) )
2125
2126	  ((##core#lambda ##core#direct_lambda)
2127	   (grow 1)
2128	   (##sys#decompose-lambda-list
2129	    (third params)
2130	    (lambda (vars argc rest)
2131	      (let ([id (first params)]
2132		    [size0 current-program-size] )
2133		(when here
2134		  (collect! db here 'contains id)
2135		  (db-put! db id 'contained-in here) )
2136		(for-each
2137		 (lambda (var)
2138		   (db-put! db var 'home here)
2139		   (db-put! db var 'unknown #t) )
2140		 vars)
2141		(when rest
2142		  (db-put! db rest 'rest-parameter 'list)
2143		  (db-put! db rest 'rest-cdr (cons rest 0)))
2144		(when (simple-lambda-node? n) (db-put! db id 'simple #t))
2145		(let ([tl toplevel-scope])
2146		  (unless toplevel-lambda-id (set! toplevel-lambda-id id))
2147		  (when (and (second params) (not (eq? toplevel-lambda-id id)))
2148		    (set! toplevel-scope #f)) ; only if non-CPS lambda
2149		  (walk (car subs) fullenv vars (append vars fullenv) id)
2150		  (set! toplevel-scope tl)
2151		  ;; decorate ##core#call node with size
2152		  (set-car! (cdddr (node-parameters n)) (- current-program-size size0)) ) ) ) ) )
2153
2154	  ((set! ##core#set!) 		;XXX ##core#set! still used?
2155	   (let* ((var (first params))
2156		  (val (car subs)) )
2157	     (when (and first-analysis (not bootstrap-mode))
2158	       (case (variable-mark var '##compiler#intrinsic)
2159		 ((standard)
2160		  (warning "redefinition of standard binding" var) )
2161		 ((extended)
2162		  (warning "redefinition of extended binding" var) ) ))
2163	     (collect! db var 'potential-values val)
2164	     (unless (memq var localenv)
2165	       (grow 1)
2166	       (cond ((memq var env)
2167		      (db-put! db var 'captured #t))
2168		     ((not (db-get db var 'global))
2169		      (db-put! db var 'global #t) ) ) )
2170	     (assign var val fullenv here)
2171	     (unless toplevel-scope (db-put! db var 'assigned-locally #t))
2172	     (db-put! db var 'assigned #t)
2173	     (walk (car subs) env localenv fullenv here)))
2174
2175	  ((##core#primitive ##core#inline)
2176	   (let ((id (first params)))
2177	     (when (and first-analysis here (symbol? id) (get-real-name id))
2178	       (set-real-name! id here) )
2179	     (walkeach subs env localenv fullenv here)))
2180
2181	  (else (walkeach subs env localenv fullenv here)))))
2182
2183    (define (walkeach xs env lenv fenv here)
2184      (for-each (lambda (x) (walk x env lenv fenv here)) xs) )
2185
2186    (define (mark-rest-cdr var rvar depth)
2187      (db-put! db var 'rest-cdr (cons rvar depth))
2188      (collect! db rvar 'derived-rest-vars var))
2189
2190    (define (mark-rest-null? var rvar depth)
2191      (db-put! db var 'rest-null? (cons rvar depth))
2192      (collect! db rvar 'derived-rest-vars var))
2193
2194    (define (assign var val env here)
2195      ;; Propagate rest-cdr and rest-null? onto aliased variables
2196      (and-let* (((eq? '##core#variable (node-class val)))
2197		 (v (db-get db (first (node-parameters val)) 'rest-cdr)))
2198	(mark-rest-cdr var (car v) (cdr v)) )
2199
2200      (and-let* (((eq? '##core#variable (node-class val)))
2201		 (v (db-get db (first (node-parameters val)) 'rest-null?)))
2202	(mark-rest-null? var (car v) (cdr v)) )
2203
2204      (cond ((eq? '##core#undefined (node-class val))
2205	     (db-put! db var 'undefined #t) )
2206	    ((and (eq? '##core#variable (node-class val)) ; assignment to itself
2207		  (eq? var (first (node-parameters val))) ) )
2208
2209	    ;; Propagate info from ##core#rest-{cdr,null?} nodes to var
2210	    ((eq? '##core#rest-cdr (node-class val))
2211	     (let ((restvar (car (node-parameters val)))
2212		   (depth (cadr (node-parameters val))))
2213	       (mark-rest-cdr var restvar (add1 depth)) ) )
2214
2215	    ((eq? '##core#rest-null? (node-class val))
2216	     (let ((restvar (car (node-parameters val)))
2217		   (depth (cadr (node-parameters val))))
2218	       (mark-rest-null? var restvar depth) ) )
2219
2220	    ;; (##core#cond (null? r) '() (cdr r)) => result is tagged as a rest-cdr var
2221	    ((and-let* ((env (match-node val '(##core#cond ()
2222							   (##core#variable (test-var))
2223							   (quote (()))
2224							   (##core#rest-cdr (rvar depth)))
2225					 '(test-var rvar depth)))
2226			((db-get db (alist-ref 'test-var env) 'rest-null?)))
2227	       env)
2228	     => (lambda (env)
2229		  (let ((rvar (alist-ref 'rvar env))
2230			(depth (alist-ref 'depth env)))
2231		    (mark-rest-cdr var rvar (add1 depth)) ) ) )
2232
2233	    ((or (memq var env)
2234		 (variable-mark var '##compiler#constant)
2235		 (not (variable-visible? var block-compilation)))
2236	     (let ((props (db-get-all db var 'unknown 'value))
2237		   (home (db-get db var 'home)) )
2238	       (unless (assq 'unknown props)
2239		 (if (assq 'value props)
2240		     (db-put! db var 'unknown #t)
2241		     (if (or (not home) (eq? here home))
2242			 (db-put! db var 'value val)
2243			 (db-put! db var 'unknown #t) ) ) ) ) )
2244	    ((and (or local-definitions
2245		      (variable-mark var '##compiler#local))
2246		  (not (db-get db var 'unknown)))
2247	     (let ((home (db-get db var 'home)))
2248	       (cond ((db-get db var 'local-value)
2249		      (db-put! db var 'unknown #t))
2250		     ((or (not home) (eq? here home))
2251		      (db-put! db var 'local-value val)	       )
2252		     (else (db-put! db var 'unknown #t)))))
2253	    (else (db-put! db var 'unknown #t)) ) )
2254
2255    (define (ref var node)
2256      (collect! db var 'references node) )
2257
2258    (define (quick-put! plist prop val)
2259      (set-cdr! plist (alist-cons prop val (cdr plist))) )
2260
2261    ;; Walk toplevel expression-node:
2262    (debugging 'p "analysis traversal phase...")
2263    (set! current-program-size 0)
2264    (walk node '() '() '() #f)
2265
2266    ;; Complete gathered database information:
2267    (debugging 'p "analysis gathering phase...")
2268    (set! current-analysis-database-size 0)
2269    (hash-table-for-each
2270     (lambda (sym plist)
2271       (let ([unknown #f]
2272	     [value #f]
2273	     [local-value #f]
2274	     [potential-values #f]
2275	     [references '()]
2276	     [captured #f]
2277	     [call-sites '()]
2278	     [assigned #f]
2279	     [assigned-locally #f]
2280	     [undefined #f]
2281	     [global #f]
2282	     [nreferences 0]
2283	     [rest-cdr #f]
2284	     [ncall-sites 0] )
2285
2286	 (set! current-analysis-database-size (fx+ current-analysis-database-size 1))
2287
2288	 (for-each
2289	  (lambda (prop)
2290	    (case (car prop)
2291	      [(unknown) (set! unknown #t)]
2292	      [(references)
2293	       (set! references (cdr prop))
2294	       (set! nreferences (length references)) ]
2295	      [(captured) (set! captured #t)]
2296	      [(potential-values)
2297	       (set! potential-values (cdr prop))]
2298	      [(call-sites)
2299	       (set! call-sites (cdr prop))
2300	       (set! ncall-sites (length call-sites)) ]
2301	      [(assigned) (set! assigned #t)]
2302	      [(assigned-locally) (set! assigned-locally #t)]
2303	      [(undefined) (set! undefined #t)]
2304	      [(global) (set! global #t)]
2305	      [(value) (set! value (cdr prop))]
2306	      [(local-value) (set! local-value (cdr prop))]
2307	      [(rest-cdr) (set! rest-cdr (cdr prop))] ) )
2308	  plist)
2309
2310	 (set! value (and (not unknown) value))
2311	 (set! local-value (and (not unknown) local-value))
2312
2313	 ;; If this is the first analysis, register known local or potentially known global
2314	 ;;  lambda-value id's along with their names:
2315         (when first-analysis
2316	   (and-let* ((vals (or (and value (list value))
2317				(and global potential-values))))
2318	     (for-each
2319	      (lambda (val)
2320		(when (eq? (node-class val) '##core#lambda)
2321		  (set-real-name! (first (node-parameters val)) sym)))
2322	      vals)))
2323
2324	 ;; If this is the first analysis and the variable is global and has no references
2325	 ;;  and is hidden then issue warning:
2326	 (when (and first-analysis
2327		    global
2328		    (null? references)
2329		    (not (variable-mark sym '##compiler#unused))
2330		    (not (variable-hidden? sym))
2331		    (not (variable-visible? sym block-compilation))
2332		    (not (variable-mark sym '##compiler#constant)) )
2333	   (##sys#notice
2334	    (sprintf "global variable `~S' is only locally visible and never used"
2335	      sym) ) )
2336
2337 	 ;; Make 'boxed, if 'assigned & 'captured:
2338	 (when (and assigned captured)
2339	   (quick-put! plist 'boxed #t) )
2340
2341	 ;; Make 'contractable, if it has a procedure as known value, has only one use
2342	 ;;  and one call-site and if the lambda has no free non-global variables
2343	 ;;  or is an internal lambda. Make 'inlinable if
2344	 ;;  use/call count is not 1:
2345	 (cond (value
2346		(let ((valparams (node-parameters value)))
2347		  (when (and (eq? '##core#lambda (node-class value))
2348			     (or (not (second valparams))
2349				 (every
2350				  (lambda (v) (db-get db v 'global))
2351				  (nth-value 0 (scan-free-variables
2352						value block-compilation)) ) ) )
2353		    (if (and (= 1 nreferences) (= 1 ncall-sites))
2354			(quick-put! plist 'contractable #t)
2355			(quick-put! plist 'inlinable #t) ) ) ) )
2356	       (local-value
2357		;; Make 'inlinable, if it is declared local and has a value
2358		(let ((valparams (node-parameters local-value)))
2359		  (when (eq? '##core#lambda (node-class local-value))
2360		    (let-values (((vars hvars) (scan-free-variables
2361						local-value block-compilation)))
2362		      (when (and (db-get db sym 'global)
2363				 (pair? hvars))
2364			(quick-put! plist 'hidden-refs #t))
2365		      (when (or (not (second valparams))
2366				(every
2367				 (lambda (v) (db-get db v 'global))
2368				 vars))
2369			(quick-put! plist 'inlinable #t) ) ) ) ) )
2370	       ((variable-mark sym '##compiler#inline-global) =>
2371		(lambda (n)
2372		  (when (node? n)
2373		    (cond (assigned
2374			   (debugging
2375			    'i
2376			    "global inlining candidate was assigned and will not be inlined"
2377			    sym)
2378			   (mark-variable sym '##compiler#inline-global 'no))
2379			  (else
2380			   (let ((lparams (node-parameters n)))
2381			     (quick-put! plist 'inlinable #t)
2382			     (quick-put! plist 'local-value n))))))))
2383
2384	 ;; Make 'collapsable, if it has a known constant value which
2385	 ;; is either collapsable or is only referenced once:
2386	 (when (and value (eq? 'quote (node-class value)) )
2387	   (let ((val (first (node-parameters value))))
2388	     (when (or (collapsable-literal? val)
2389		       (= 1 nreferences) )
2390	       (quick-put! plist 'collapsable #t) ) ) )
2391
2392	 ;; If it has a known value that is a procedure, and if the number of call-sites is equal to the
2393	 ;;  number of references (does not escape), then make all formal parameters 'unused which are
2394	 ;;  never referenced or assigned (if no rest parameter exist):
2395	 ;;  - also marks the procedure as 'has-unused-parameters (if not in `callback-names')
2396	 ;;  - if the procedure is internal (a continuation) do NOT mark unused parameters.
2397	 ;;  - also: if procedure has rest-parameter and no unused params, mark f-id as 'explicit-rest.
2398	 (when value
2399	   (let ((has #f))
2400	     (when (and (eq? '##core#lambda (node-class value))
2401			(= nreferences ncall-sites) )
2402	       (let ((lparams (node-parameters value)))
2403		 (when (second lparams)
2404		   (##sys#decompose-lambda-list
2405		    (third lparams)
2406		    (lambda (vars argc rest)
2407		      (unless rest
2408			(for-each
2409			 (lambda (var)
2410			   (cond ((and (not (db-get db var 'references))
2411				       (not (db-get db var 'assigned)) )
2412				  (db-put! db var 'unused #t)
2413				  (set! has #t)
2414				  #t)
2415				 (else #f) ) )
2416			 vars) )
2417		      (cond ((and has (not (rassoc sym callback-names eq?)))
2418			     (db-put! db (first lparams) 'has-unused-parameters #t) )
2419			    (rest
2420			     (db-put! db (first lparams) 'explicit-rest #t)
2421			     (db-put! db rest 'consed-rest-arg #t) ) ) ) ) ) ) ) ) )
2422
2423	 ;; Make 'removable, if it has no references and is not assigned to, and one of the following:
2424	 ;; - it has either a value that does not cause any side-effects
2425	 ;; - it is 'undefined
2426	 ;; - it holds only a 'rest-cdr reference (strictly speaking, it may bomb but we don't care)
2427	 (when (and (not assigned)
2428		    (null? references)
2429		    (or (and value
2430			     (if (eq? '##core#variable (node-class value))
2431				 (let ((varname (first (node-parameters value))))
2432				   (or (not (db-get db varname 'global))
2433				       (variable-mark varname '##core#always-bound)
2434				       (intrinsic? varname)))
2435				 (not (expression-has-side-effects? value db)) ))
2436			undefined
2437			rest-cdr) )
2438	   (quick-put! plist 'removable #t) )
2439
2440	 ;; Make 'replacable, if
2441	 ;; - it has a variable as known value and
2442	 ;; - it is not a global
2443	 ;; - it is never assigned to and
2444	 ;; - if either the substitute has a known value itself or
2445	 ;;   * the substitute is never assigned to and
2446	 ;;   * we are in block-mode or the substitute is non-global
2447	 ;;
2448	 ;;  - The variable that can be substituted for the current one is marked as 'replacing.
2449	 ;;    This is done to prohibit beta-contraction of the replacing variable (It wouldn't be there, if
2450	 ;;    it was contracted).
2451	 (when (and value (not global))
2452	   (when (eq? '##core#variable (node-class value))
2453	     (let ((name (first (node-parameters value))) )
2454	       (when (and (not assigned)
2455			  (or (and (not (db-get db name 'unknown))
2456				   (db-get db name 'value))
2457			      (and (not (db-get db name 'assigned))
2458				   (or (not (variable-visible?
2459					     name block-compilation))
2460				       (not (db-get db name 'global))) ) ))
2461		 (quick-put! plist 'replacable name)
2462		 (db-put! db name 'replacing #t) ) ) ) )
2463
2464	 ;; Make 'replacable, if it has a known value of the form: '(lambda (<xvar>) (<kvar> <xvar>))' and
2465	 ;;  is an internally created procedure: (See above for 'replacing)
2466	 (when (and value (eq? '##core#lambda (node-class value)))
2467	   (let ((params (node-parameters value)))
2468	     (when (not (second params))
2469	       (let ((llist (third params))
2470		     (body (first (node-subexpressions value))) )
2471		 (when (and (pair? llist)
2472			    (null? (cdr llist))
2473			    (eq? '##core#call (node-class body)) )
2474		   (let ((subs (node-subexpressions body)))
2475		     (when (= 2 (length subs))
2476		       (let ((v1 (first subs))
2477			     (v2 (second subs)) )
2478			 (when (and (eq? '##core#variable (node-class v1))
2479				    (eq? '##core#variable (node-class v2))
2480				    (eq? (first llist) (first (node-parameters v2))) )
2481			   (let ((kvar (first (node-parameters v1))))
2482			     (quick-put! plist 'replacable kvar)
2483			     (db-put! db kvar 'replacing #t) ) ) ) ) ) ) ) ) ) ) ) )
2484
2485     db)
2486
2487    ;; Set original program-size, if this is the first analysis-pass:
2488    (unless original-program-size
2489      (set! original-program-size current-program-size) )
2490
2491    ;; return database
2492    db) )
2493
2494
2495;;; Collect unsafe global procedure calls that are assigned:
2496
2497;;; Convert closures to explicit data structures (effectively flattens function-binding
2498;   structure):
2499
2500(define (perform-closure-conversion node db)
2501  (let ((direct-calls 0)
2502	(customizable '())
2503	(lexicals '()))
2504
2505    (define (test sym item) (db-get db sym item))
2506
2507    (define (register-customizable! var id)
2508      (set! customizable (lset-adjoin/eq? customizable var))
2509      (db-put! db id 'customizable #t) )
2510
2511    (define (register-direct-call! id)
2512      (set! direct-calls (add1 direct-calls))
2513      (set! direct-call-ids (lset-adjoin/eq? direct-call-ids id)))
2514
2515    ;; Gather free-variable information:
2516    ;; (and: - register direct calls
2517    ;;       - update (by mutation) call information in "##core#call" nodes)
2518    (define (gather n here locals)
2519      (let ((subs (node-subexpressions n))
2520	    (params (node-parameters n)) )
2521	(case (node-class n)
2522
2523	  ((##core#variable ##core#rest-cdr)
2524	   (let ((var (first params)))
2525	     (if (memq var lexicals)
2526		 (list var)
2527		 '())))
2528
2529	  ((quote ##core#undefined ##core#provide ##core#proc ##core#primitive)
2530	   '())
2531
2532	  ((let)
2533	   ;;XXX remove this test later, shouldn't be needed:
2534	   (when (pair? (cdr params)) (bomb "let-node has invalid format" params))
2535	   (let ((c (gather (first subs) here locals))
2536		 (var (first params)))
2537	     (append c (delete var (gather (second subs) here (cons var locals)) eq?))))
2538
2539	  ((set!)
2540	   (let ((var (first params))
2541		 (c (gather (first subs) here locals)))
2542	     (if (memq var lexicals)
2543		 (cons var c)
2544		 c)))
2545
2546	  ((##core#call)
2547	   (let* ([fn (first subs)]
2548		  [mode (first params)]
2549		  [name (and (pair? (cdr params)) (second params))]
2550		  [varfn (eq? '##core#variable (node-class fn))] )
2551	     (node-parameters-set!
2552	      n
2553	      (cons mode
2554		    (if (or name varfn)
2555			(cons name
2556			      (if varfn
2557				  (let* ([varname (first (node-parameters fn))]
2558					 [val (and (not (test varname 'unknown))
2559						   (not (eq?
2560							 'no
2561							 (variable-mark
2562							  varname '##compiler#inline)))
2563						   ;; May not be external, see #1665
2564						   (not (node? (variable-mark varname '##compiler#inline-global)))
2565						   (or (test varname 'value)
2566						       (test varname 'local-value)))] )
2567				    (if (and val (eq? '##core#lambda (node-class val)))
2568					(let* ([params (node-parameters val)]
2569					       [llist (third params)]
2570					       [id (first params)]
2571					       [refs (test varname 'references)]
2572					       [sites (test varname 'call-sites)]
2573					       [custom
2574						(and refs sites
2575						     (= (length refs) (length sites))
2576						     (test varname 'value)
2577						     (list? llist) ) ] )
2578					  (cond ((and name
2579                                                      (not (llist-match? llist (cdr subs))))
2580                                                   '())
2581                                                (else
2582   					          (register-direct-call! id)
2583					          (when custom (register-customizable! varname id))
2584					          (list id custom) ) ) )
2585					'() ) )
2586				  '() ) )
2587			'() ) ) )
2588	     (concatenate (map (lambda (n) (gather n here locals)) subs) ) ))
2589
2590	  ((##core#lambda ##core#direct_lambda)
2591	   (##sys#decompose-lambda-list
2592	    (third params)
2593	    (lambda (vars argc rest)
2594	      (let ((id (if here (first params) 'toplevel)))
2595		(fluid-let ((lexicals (append locals lexicals)))
2596		  (let ((c (delete-duplicates (gather (first subs) id vars) eq?)))
2597		    (db-put! db id 'closure-size (length c))
2598		    (db-put! db id 'captured-variables c)
2599		    (lset-difference/eq? c locals vars)))))))
2600
2601	  (else (concatenate (map (lambda (n) (gather n here locals)) subs)) ) ) ))
2602
2603    ;; Create explicit closures:
2604    (define (transform n here closure)
2605      (let ((subs (node-subexpressions n))
2606	    (params (node-parameters n))
2607	    (class (node-class n)) )
2608	(case class
2609
2610	  ((quote ##core#undefined ##core#provide ##core#proc ##core#float
2611           ##core#float-variable)
2612            n)
2613
2614	  ((##core#variable)
2615	   (let* ((var (first params))
2616		  (val (ref-var n here closure)) )
2617	     (if (test var 'boxed)
2618		 (make-node '##core#unbox '() (list val))
2619		 val) ) )
2620
2621	  ((##core#rest-cdr ##core#rest-car ##core#rest-null? ##core#rest-length)
2622	   (let* ((val (ref-var n here closure))
2623		  (rest-var (if (eq? val n) (varnode (first params)) val)))
2624	     (unless (or (eq? val n)
2625			 (match-node val `(##core#ref (i) (##core#variable (,here))) '(i)))
2626	       ;; If it's captured, replacement in optimizer was incorrect
2627	       (bomb "Saw rest op for captured variable.  This should not happen!" class) )
2628	     ;; If rest-cdrs have not all been eliminated, restore
2629	     ;; them as regular cdr calls on the rest list variable.
2630	     ;; This can be improved, as it can actually introduce
2631	     ;; many more cdr calls than necessary.
2632	     (cond ((eq? class '##core#rest-cdr)
2633		    (transform (replace-rest-op-with-list-ops class rest-var params) here closure))
2634
2635		   ;; If n isn't val, this node was processed and the
2636		   ;; variable got replaced by a closure access.
2637		   ((not (eq? val n))
2638		    (transform (replace-rest-op-with-list-ops class rest-var params) here closure))
2639
2640		   (else val)) ) )
2641
2642	  ((if ##core#call ##core#inline ##core#inline_allocate ##core#callunit
2643	       ##core#inline_ref ##core#inline_update ##core#debug-event
2644	       ##core#switch ##core#cond ##core#direct_call ##core#recurse ##core#return
2645               ##core#let_float ##core#box_float ##core#unbox_float
2646	       ##core#inline_loc_ref
2647	       ##core#inline_loc_update)
2648	   (make-node (node-class n) params (maptransform subs here closure)) )
2649
2650	  ((let)
2651	   (let* ([var (first params)]
2652		  [boxedvar (test var 'boxed)]
2653		  [boxedalias (gensym var)] )
2654	     (if boxedvar
2655		 (make-node
2656		  'let (list boxedalias)
2657		  (list (transform (first subs) here closure)
2658			(make-node
2659			 'let (list var)
2660			 (list (make-node '##core#box '() (list (varnode boxedalias)))
2661			       (transform (second subs) here closure) ) ) ) )
2662		 (make-node
2663		  'let params
2664		  (maptransform subs here closure) ) ) ) )
2665
2666	  ((##core#lambda ##core#direct_lambda)
2667	   (let ((llist (third params)))
2668	     (##sys#decompose-lambda-list
2669	      llist
2670	      (lambda (vars argc rest)
2671		(let* ((boxedvars (filter (lambda (v) (test v 'boxed)) vars))
2672		       (boxedaliases (map cons boxedvars (map gensym boxedvars)))
2673		       (cvar (gensym 'c))
2674		       (id (if here (first params) 'toplevel))
2675		       (capturedvars (or (test id 'captured-variables) '()))
2676		       (csize (or (test id 'closure-size) 0))
2677		       (info (and emit-closure-info (second params) (pair? llist))) )
2678		  ;; If rest-parameter is boxed: mark it as 'boxed-rest
2679		  ;;  (if we don't do this than preparation will think the (boxed) alias
2680		  ;;  of the rest-parameter is never used)
2681		  (and-let* ((rest)
2682			     ((test rest 'boxed))
2683			     (rp (test rest 'rest-parameter)) )
2684		    (db-put! db (cdr (assq rest boxedaliases)) 'boxed-rest #t) )
2685		  (make-node
2686		   '##core#closure (list (+ csize (if info 2 1)))
2687		   (cons
2688		    (make-node
2689		     class
2690		     (list id
2691			   (second params)
2692			   (cons
2693			    cvar
2694			    (build-lambda-list
2695			     (map (lambda (v)
2696				    (cond ((assq v boxedaliases) => cdr)
2697					  (else v) ) )
2698				  vars)
2699			     argc
2700			     (cond ((and rest (assq rest boxedaliases)) => cdr)
2701				   (else rest) ) ) )
2702			   (fourth params) )
2703		     (list (let ((body (transform (car subs) cvar capturedvars)))
2704			     (if (pair? boxedvars)
2705				 (let loop ((aliases (unzip1 boxedaliases))
2706					    (values
2707					     (map (lambda (a)
2708						    (make-node '##core#box '() (list (varnode (cdr a)))))
2709						  boxedaliases) ))
2710				   (if (null? aliases)
2711				       body
2712				       (make-node 'let (list (car aliases))
2713						  (list (car values)
2714							(loop (cdr aliases) (cdr values))))))
2715				 body) ) ) )
2716		    (let ((cvars (map (lambda (v) (ref-var (varnode v) here closure))
2717				      capturedvars) ) )
2718		      (if info
2719			  (append
2720			   cvars
2721			   (list
2722			    (qnode
2723			     (##sys#make-lambda-info
2724			      (->string (cons (or (real-name id) '?)
2725					      ;; this is not always correct, due to optimizations
2726					      (strip-syntax (cdr llist))))))))
2727			  cvars) ) ) ) ) ) ) ) )
2728
2729	  ((set!)
2730	   (let* ((var (first params))
2731		  (val (first subs))
2732		  (cval (node-class val))
2733		  (immf (or (and (eq? 'quote cval) (immediate? (first (node-parameters val))))
2734			    (and (pair? (cdr params)) (second params))
2735			    (eq? '##core#undefined cval))))
2736	     (cond ((posq var closure)
2737		    => (lambda (i)
2738			 (if (test var 'boxed)
2739			     (make-node
2740			      (if immf '##core#updatebox_i '##core#updatebox)
2741			      '()
2742			      (list (make-node '##core#ref (list (add1 i)) (list (varnode here)))
2743				    (transform val here closure) ) )
2744			     ;; Is the following actually used???
2745			     (make-node
2746			      (if immf '##core#update_i '##core#update)
2747			      (list (add1 i))
2748			      (list (varnode here)
2749				    (transform val here closure) ) ) ) ) )
2750		   ((test var 'boxed)
2751		    (make-node
2752		     (if immf '##core#updatebox_i '##core#updatebox)
2753		     '()
2754		     (list (varnode var)
2755			   (transform val here closure) ) ) )
2756		   (else (make-node
2757			  'set! (list var immf)
2758			  (list (transform val here closure) ) ) ) ) ) )
2759
2760	  ((##core#primitive)
2761	   (make-node
2762	    '##core#closure (list (if emit-closure-info 2 1))
2763	    (cons (make-node '##core#proc (list (car params) #t) '())
2764		  (if emit-closure-info
2765		      (list (qnode (##sys#make-lambda-info (car params))))
2766		      '() ) ) ) )
2767
2768	  ((##core#ref) n)
2769
2770	  (else (bomb "bad node (closure2)")) ) ) )
2771
2772    (define (maptransform xs here closure)
2773      (map (lambda (x) (transform x here closure)) xs) )
2774
2775    (define (ref-var n here closure)
2776      (let ((var (first (node-parameters n))))
2777	(cond ((posq var closure)
2778	       => (lambda (i)
2779		    (make-node '##core#ref (list (+ i 1))
2780			       (list (varnode here)) ) ) )
2781	      (else n) ) ) )
2782
2783    (debugging 'p "closure conversion gathering phase...")
2784    (gather node #f '())
2785    (when (pair? customizable)
2786      (debugging 'o "customizable procedures" customizable))
2787    (debugging 'p "closure conversion transformation phase...")
2788    (let ((node2 (transform node #f #f)))
2789      (unless (zero? direct-calls)
2790	(debugging 'o "calls to known targets" direct-calls))
2791      node2) ) )
2792
2793
2794;;; Do some preparations before code-generation can commence:
2795
2796(define-record-type lambda-literal
2797  (make-lambda-literal id external arguments argument-count rest-argument temporaries
2798		       float-temporaries callee-signatures allocated directly-called
2799		       closure-size looping customizable rest-argument-mode body direct)
2800  lambda-literal?
2801  (id lambda-literal-id)			       ; symbol
2802  (external lambda-literal-external)		       ; boolean
2803  ;; lambda-literal-arguments is used nowhere
2804  (arguments lambda-literal-arguments)		       ; (symbol ...)
2805  (argument-count lambda-literal-argument-count)       ; integer
2806  (rest-argument lambda-literal-rest-argument)	       ; symbol | #f
2807  (temporaries lambda-literal-temporaries)	       ; integer
2808  (float-temporaries lambda-literal-float-temporaries)   ; (integer ...)
2809  (callee-signatures lambda-literal-callee-signatures) ; (integer ...)
2810  (allocated lambda-literal-allocated)		       ; integer
2811  ;; lambda-literal-directly-called is used nowhere
2812  (directly-called lambda-literal-directly-called)     ; boolean
2813  (closure-size lambda-literal-closure-size)	       ; integer
2814  (looping lambda-literal-looping)		       ; boolean
2815  (customizable lambda-literal-customizable)	       ; boolean
2816  (rest-argument-mode lambda-literal-rest-argument-mode) ; #f | LIST | NONE
2817  (body lambda-literal-body)				 ; expression
2818  (direct lambda-literal-direct))			 ; boolean
2819
2820(define (prepare-for-code-generation node db)
2821  (let ((literals '())
2822	(literal-count 0)
2823	(lambda-info-literals '())
2824	(lambda-info-literal-count 0)
2825	;; Use analysis db as optimistic heuristic for procedure table size
2826	(lambda-table (make-vector (fx* (fxmax current-analysis-database-size 1) 3) '()))
2827	(temporaries 0)
2828        (float-temporaries '())
2829	(allocated 0)
2830	(looping 0)
2831	(signatures '())
2832	(fastinits 0)
2833	(fastrefs 0)
2834	(fastsets 0)
2835	(dbg-index 0)
2836	(debug-info '()))
2837
2838    (define (walk-var var e e-count sf)
2839      (cond [(posq var e)
2840	     => (lambda (i)
2841		  (make-node '##core#local (list (fx- e-count (fx+ i 1))) '()))]
2842	    [(keyword? var) (make-node '##core#literal (list (literal var)) '())]
2843	    [else (walk-global var sf)] ) )
2844
2845    (define (walk-global var sf)
2846      (let* ([safe (or sf
2847		       no-bound-checks
2848		       unsafe
2849		       (variable-mark var '##compiler#always-bound)
2850		       (intrinsic? var))]
2851	     [blockvar (and (db-get db var 'assigned)
2852			    (not (variable-visible? var block-compilation)))])
2853	(when blockvar (set! fastrefs (add1 fastrefs)))
2854	(make-node
2855	 '##core#global
2856	 (list (if blockvar
2857		   (blockvar-literal var)
2858		   (literal var) )
2859	       safe
2860	       blockvar
2861	       var)
2862	 '() ) ) )
2863
2864    (define (walk n e e-count here boxes)
2865      (let ((subs (node-subexpressions n))
2866	    (params (node-parameters n))
2867	    (class (node-class n)) )
2868	(case class
2869
2870	  ((##core#undefined ##core#proc ##core#float) n)
2871
2872	  ((##core#variable)
2873	   (walk-var (first params) e e-count #f) )
2874
2875	  ((##core#direct_call)
2876	   (let* ((source-info (second params))
2877		  (demand (fourth params)))
2878	     (if (and emit-debug-info source-info)
2879		 (let ((info (list dbg-index 'C_DEBUG_CALL
2880				   (source-info->line source-info)
2881				   (source-info->name source-info))))
2882		   (set! params (cons dbg-index params))
2883		   (set! debug-info (cons info debug-info))
2884		   (set! dbg-index (add1 dbg-index)))
2885		 (set! params (cons #f params)))
2886	     (set! allocated (+ allocated demand))
2887	     (make-node class params (mapwalk subs e e-count here boxes))))
2888
2889	  ((##core#inline_allocate)
2890	   (set! allocated (+ allocated (second params)))
2891	   (make-node class params (mapwalk subs e e-count here boxes)) )
2892
2893          ((##core#box_float)
2894           (set! allocated (+ allocated 4)) ;; words-per-flonum
2895           (make-node class params (mapwalk subs e e-count here boxes)))
2896
2897	  ((##core#inline_ref)
2898	   (set! allocated (+ allocated (bytes->words (estimate-foreign-result-size (second params)))))
2899	   (make-node class params '()) )
2900
2901	  ((##core#inline_loc_ref)
2902	   (set! allocated (+ allocated (bytes->words (estimate-foreign-result-size (first params)))))
2903	   (make-node class params (mapwalk subs e e-count here boxes)) )
2904
2905	  ((##core#closure)
2906	   (set! allocated (+ allocated (first params) 1))
2907	   (make-node '##core#closure params (mapwalk subs e e-count here boxes)) )
2908
2909	  ((##core#box)
2910	   (set! allocated (+ allocated 2))
2911	   (make-node '##core#box params (list (walk (first subs) e e-count here boxes))) )
2912
2913	  ((##core#updatebox)
2914	   (let* ([b (first subs)]
2915		  [subs (mapwalk subs e e-count here boxes)] )
2916	     (make-node
2917	      (cond [(and (eq? '##core#variable (node-class b))
2918			  (memq (first (node-parameters b)) boxes) )
2919		     (set! fastinits (add1 fastinits))
2920		     '##core#updatebox_i]
2921		    [else class] )
2922	      '()
2923	      subs) ) )
2924
2925	  ((##core#provide)
2926	   ;; Allocate enough space for the ##core#provided property.
2927	   (let ((id (literal (first params))))
2928	     (set! allocated (+ allocated 8))
2929	     (make-node class (list id) '())))
2930
2931	  ((##core#lambda ##core#direct_lambda)
2932	   (let ((temps temporaries)
2933                 (ftemps float-temporaries)
2934		 (sigs signatures)
2935		 (lping looping)
2936		 (alc allocated)
2937		 (direct (eq? class '##core#direct_lambda)) )
2938	     (set! temporaries 0)
2939             (set! float-temporaries '())
2940	     (set! allocated 0)
2941	     (set! signatures '())
2942	     (set! looping 0)
2943	     (##sys#decompose-lambda-list
2944	      (third params)
2945	      (lambda (vars argc rest)
2946		(let* ((id (first params))
2947		       (rest-mode
2948			(and rest
2949			     (let ((rrefs (db-get db rest 'references)))
2950			       (cond ((db-get db rest 'assigned) 'list)
2951				     ((and (not (db-get db rest 'boxed-rest))
2952					   (or (not rrefs) (null? rrefs))) 'none)
2953				     (else (db-get db rest 'rest-parameter)) ) ) ) )
2954		       (body (walk
2955			      (car subs)
2956			      (##sys#fast-reverse (if (eq? 'none rest-mode)
2957						      (butlast vars)
2958						      vars))
2959			      (if (eq? 'none rest-mode)
2960				  (fx- (length vars) 1)
2961				  (length vars))
2962			      id
2963			      '()) ) )
2964		  (when (eq? rest-mode 'none)
2965		    (debugging 'o "unused rest argument" rest id))
2966		  (when (and direct rest)
2967		    (bomb "bad direct lambda" id allocated rest) )
2968		  (hash-table-set!
2969		   lambda-table
2970		   id
2971		   (make-lambda-literal
2972		    id
2973		    (second params)
2974		    vars
2975		    argc
2976		    rest
2977		    (add1 temporaries)
2978                    float-temporaries
2979		    signatures
2980		    allocated
2981		    (or direct (memq id direct-call-ids))
2982		    (or (db-get db id 'closure-size) 0)
2983		    (and (not rest)
2984			 (> looping 0)
2985			 (begin
2986			   (debugging 'o "identified direct recursive calls" id looping)
2987			   #t) )
2988		    (or direct (db-get db id 'customizable))
2989		    rest-mode
2990		    body
2991		    direct) )
2992		  (set! looping lping)
2993		  (set! temporaries temps)
2994                  (set! float-temporaries ftemps)
2995		  (set! allocated alc)
2996		  (set! signatures (lset-adjoin/eq? sigs argc))
2997		  (make-node '##core#proc (list (first params)) '()) ) ) ) ) )
2998
2999	  ((let)
3000	   (let* ([var (first params)]
3001		  [val (first subs)]
3002		  [boxvars (if (eq? '##core#box (node-class val)) (list var) '())] )
3003	     (set! temporaries (add1 temporaries))
3004	     (make-node
3005	      '##core#bind (list 1)	; is actually never used with more than 1 variable
3006	      (list (walk val e e-count here boxes)
3007		    (walk (second subs)
3008			  (append (##sys#fast-reverse params) e) (fx+ e-count 1)
3009			  here (append boxvars boxes)) ) ) ) )
3010
3011	  ((##core#let_float)
3012	   (let ((i (first params))
3013	         (val (first subs)))
3014             (set! float-temporaries (cons i float-temporaries))
3015	     (make-node
3016	      '##core#let_float params
3017	      (list (walk val e e-count here boxes)
3018		    (walk (second subs) e e-count here boxes) ) ) ) )
3019
3020	  ((set!)
3021	   (let ((var (first params))
3022		 (val (first subs)) )
3023	     (cond ((posq var e)
3024		    => (lambda (i)
3025			 (make-node '##core#setlocal
3026				    (list (fx- e-count (fx+ i 1)))
3027				    (list (walk val e e-count here boxes)) ) ) )
3028		   (else
3029		    (let* ((cval (node-class val))
3030			   (blockvar (not (variable-visible?
3031					   var block-compilation)))
3032			   (immf (or (and (eq? cval 'quote) (immediate? (first (node-parameters val))))
3033				     (and (pair? (cdr params)) (second params))
3034				     (eq? '##core#undefined cval) ) ) )
3035		      (when blockvar (set! fastsets (add1 fastsets)))
3036		      (make-node
3037		       (if immf '##core#setglobal_i '##core#setglobal)
3038		       (list (if blockvar
3039				 (blockvar-literal var)
3040				 (literal var) )
3041			     blockvar
3042			     var)
3043		       (list (walk (car subs) e e-count here boxes)) ) ) ) ) ) )
3044
3045	  ((##core#call)
3046	   (let* ((len (length (cdr subs)))
3047		  (p2 (pair? (cdr params)))
3048		  (source-info (and p2 (second params))))
3049	     (set! signatures (lset-adjoin/eq? signatures len))
3050	     (when (and (>= (length params) 3) (eq? here (third params)))
3051	       (set! looping (add1 looping)) )
3052               (if (and emit-debug-info source-info)
3053                 (let ((info (list dbg-index 'C_DEBUG_CALL
3054				   (source-info->line source-info)
3055				   (source-info->name source-info))))
3056                   (set! params (cons dbg-index params))
3057                   (set! debug-info (cons info debug-info))
3058                   (set! dbg-index (add1 dbg-index)))
3059                 (set! params (cons #f params)))
3060	     (make-node class params (mapwalk subs e e-count here boxes))))
3061
3062	  ((##core#recurse)
3063	   (when (first params) (set! looping (add1 looping)))
3064	   (make-node class params (mapwalk subs e e-count here boxes)) )
3065
3066	  ((quote)
3067	   (let ((c (first params)))
3068	     (cond ((and (fixnum? c) (not (big-fixnum? c)))
3069		    (immediate-literal c) )
3070		   ((number? c)
3071		    (cond ((eq? 'fixnum number-type)
3072			   (cond ((and (integer? c) (not (big-fixnum? c)))
3073				  (warning
3074				   (sprintf
3075				       "coerced inexact literal number `~S' to fixnum ~S"
3076				     c (inexact->exact c)))
3077				  (immediate-literal (inexact->exact c)) )
3078				 (else (quit-compiling "cannot coerce inexact literal `~S' to fixnum" c)) ) )
3079			  (else (make-node '##core#literal (list (literal c)) '())) ) )
3080		   ((immediate? c) (immediate-literal c))
3081		   (else (make-node '##core#literal (list (literal c)) '())) ) ) )
3082
3083	  ((if ##core#cond)
3084	   (let* ((test (walk (first subs) e e-count here boxes))
3085		  (t0 temporaries)
3086		  (a0 allocated)
3087		  (x1 (walk (second subs) e e-count here boxes))
3088		  (t1 temporaries)
3089		  (a1 allocated)
3090		  (x2 (walk (third subs) e e-count here boxes)))
3091	     (set! allocated (+ a0 (max (- allocated a1) (- a1 a0))))
3092	     (set! temporaries (+ t0 (max (- temporaries t1) (- t1 t0))))
3093	     (make-node class params (list test x1 x2))))
3094
3095	  ((##core#switch)
3096	   (let* ((exp (walk (first subs) e e-count here boxes))
3097		  (a0 allocated))
3098	     (make-node
3099	      class
3100	      params
3101	      (cons
3102	       exp
3103	       (let loop ((j (first params)) (subs (cdr subs)) (ma 0))
3104		 (set! allocated a0)
3105		 (if (zero? j)
3106		     (let ((def (walk (car subs) e e-count here boxes)))
3107		       (set! allocated (+ a0 (max ma (- allocated a0))))
3108		       (list def))
3109		     (let* ((const (walk (car subs) e e-count here boxes))
3110			    (body (walk (cadr subs) e e-count here boxes)))
3111		       (cons*
3112			const body
3113			(loop (sub1 j) (cddr subs) (max (- allocated a0) ma))))))))))
3114
3115	  ((##core#debug-event)
3116	   (let* ((i dbg-index)
3117		  (params (cons i params)))
3118	     (set! debug-info (cons params debug-info))
3119	     (set! dbg-index (add1 dbg-index))
3120	     (make-node class params '())))
3121
3122	  (else (make-node class params (mapwalk subs e e-count here boxes)) ) ) ) )
3123
3124    (define (mapwalk xs e e-count here boxes)
3125      (map (lambda (x) (walk x e e-count here boxes)) xs) )
3126
3127    (define (literal x)
3128      (cond [(immediate? x) (immediate-literal x)]
3129	    ;; Fixnums that don't fit in 32 bits are treated as non-immediates,
3130	    ;; that's why we do the (apparently redundant) C_blockp check here.
3131	    ((and (##core#inline "C_blockp" x) (##core#inline "C_lambdainfop" x))
3132	     (let ((i lambda-info-literal-count))
3133	       (set! lambda-info-literals (cons x lambda-info-literals))
3134	       (set! lambda-info-literal-count (add1 lambda-info-literal-count))
3135	       (vector i) ) )
3136	    [(posv x literals) => (lambda (p) (fx- literal-count (fx+ p 1)))]
3137	    [else (new-literal x)] ) )
3138
3139    (define (new-literal x)
3140      (let ([i literal-count])
3141	(set! literals (cons x literals))
3142	(set! literal-count (add1 literal-count))
3143	i) )
3144
3145    (define (blockvar-literal var)
3146      (cond
3147       ((list-index (lambda (lit)
3148		      (and (block-variable-literal? lit)
3149			   (eq? var (block-variable-literal-name lit)) ) )
3150		    literals)
3151	=> (lambda (p) (fx- literal-count (fx+ p 1))))
3152       (else (new-literal (make-block-variable-literal var))) ) )
3153
3154    (define (immediate-literal x)
3155      (if (eq? (void) x)
3156	  (make-node '##core#undefined '() '())
3157	  (make-node '##core#immediate
3158		     (cond ((fixnum? x) `(fix ,x))
3159			   ((boolean? x) `(bool ,x))
3160			   ((char? x) `(char ,x))
3161			   ((null? x) '(nil))
3162			   ((eof-object? x) '(eof))
3163			   ;; TODO: Remove once we have a bootstrapping libchicken with bwp-object?
3164			   ((##core#inline "C_bwpp" x) #;(bwp-object? x) '(bwp))
3165			   (else (bomb "bad immediate (prepare)")) )
3166		     '() ) ) )
3167
3168    (debugging 'p "preparation phase...")
3169    (let ((node2 (walk node '() 0 #f '())))
3170      (when (positive? fastinits)
3171	(debugging 'o "fast box initializations" fastinits))
3172      (when (positive? fastrefs)
3173	(debugging 'o "fast global references" fastrefs))
3174      (when (positive? fastsets)
3175	(debugging 'o "fast global assignments" fastsets))
3176      (values node2
3177	      (##sys#fast-reverse literals)
3178	      (##sys#fast-reverse lambda-info-literals)
3179	      lambda-table
3180	      (reverse debug-info) ) ) ))
3181)
Trap