~ 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 ((,(gensym) (##core#debug-event C_DEBUG_GLOBAL_ASSIGN (##core#quote ,var))))
1165					  ,val)))
1166				   ;; We use `var0` instead of `var` because the {macro,current}-environment
1167				   ;; are keyed by the raw and unqualified name
1168				   (cond ((##sys#macro? var0 (##sys#current-environment))
1169					  (warning
1170					   (sprintf "~aassignment to syntax `~S'"
1171					    (if ln (sprintf "(~a) - " ln) "") var0))
1172					  (when undefine-shadowed-macros
1173					    (##sys#undefine-macro! var0)
1174					    (##sys#unregister-syntax-export var0 (##sys#current-module))))
1175					 ((assq var0 (##sys#current-environment))
1176					  (warning
1177					   (sprintf "~aassignment to imported value binding `~S'"
1178					    (if ln (sprintf "(~a) - " ln) "") var0)))))
1179				 `(set! ,var ,(walk val e var0 (memq var e) h ln #f))))))
1180
1181			((##core#debug-event)
1182			 `(##core#debug-event
1183			   ,(cadr x)
1184			   ,ln ; this arg is added - from this phase on ##core#debug-event has an additional argument!
1185			   ,@(map (lambda (arg)
1186				    (unquotify (walk arg e #f #f h ln tl?)))
1187				  (cddr x))))
1188
1189			((##core#inline)
1190			 `(##core#inline
1191			   ,(unquotify (cadr x)) ,@(mapwalk (cddr x) e h ln #f)))
1192
1193			((##core#inline_allocate)
1194			 `(##core#inline_allocate
1195			   ,(map unquotify (second x))
1196			   ,@(mapwalk (cddr x) e h ln #f)))
1197
1198			((##core#inline_update)
1199			 `(##core#inline_update ,(cadr x) ,(walk (caddr x) e #f #f h ln #f)) )
1200
1201			((##core#inline_loc_update)
1202			 `(##core#inline_loc_update
1203			   ,(cadr x)
1204			   ,(walk (caddr x) e #f #f h ln #f)
1205			   ,(walk (cadddr x) e #f #f h ln #f)) )
1206
1207			((##core#compiletimetoo ##core#elaborationtimetoo)
1208			 (let ((exp (cadr x)))
1209			   (##sys#eval/meta exp)
1210			   (walk exp e dest #f h ln tl?) ) )
1211
1212			((##core#compiletimeonly ##core#elaborationtimeonly)
1213			 (##sys#eval/meta (cadr x))
1214			 '(##core#undefined) )
1215
1216			((##core#begin)
1217			 (if (pair? (cdr x))
1218			     (canonicalize-begin-body
1219			      (let fold ([xs (cdr x)])
1220				(let ([x (car xs)]
1221				      [r (cdr xs)] )
1222				  (if (null? r)
1223				      (list (walk x e dest ldest h ln tl?))
1224				      (cons (walk x e #f #f h ln tl?) (fold r)) ) ) ) )
1225			     '(##core#undefined) ) )
1226
1227			((##core#foreign-lambda)
1228			 (walk (expand-foreign-lambda x #f) e dest ldest h ln #f) )
1229
1230			((##core#foreign-safe-lambda)
1231			 (walk (expand-foreign-lambda x #t) e dest ldest h ln #f) )
1232
1233			((##core#foreign-lambda*)
1234			 (walk (expand-foreign-lambda* x #f) e dest ldest h ln #f) )
1235
1236			((##core#foreign-safe-lambda*)
1237			 (walk (expand-foreign-lambda* x #t) e dest ldest h ln #f) )
1238
1239			((##core#foreign-primitive)
1240			 (walk (expand-foreign-primitive x) e dest ldest h ln #f) )
1241
1242			((##core#define-foreign-variable)
1243			 (let* ((var (strip-syntax (second x)))
1244				(type (strip-syntax (third x)))
1245				(name (if (pair? (cdddr x))
1246					  (fourth x)
1247					  (symbol->string var))))
1248			   (set! foreign-variables
1249			     (cons (list var type name)
1250				   foreign-variables))
1251			   '(##core#undefined) ) )
1252
1253			((##core#define-foreign-type)
1254			 (let ((name (second x))
1255			       (type (strip-syntax (third x)))
1256			       (conv (cdddr x)))
1257			   (unless tl?
1258			     (quit-compiling
1259			      "~adefinition of foreign type `~s' in non-toplevel context"
1260			      (if ln (sprintf "(~a) - " ln) "")
1261			      name))
1262			   (cond [(pair? conv)
1263				  (let ([arg (gensym)]
1264					[ret (gensym)] )
1265				    (register-foreign-type! name type arg ret)
1266				    (mark-variable arg '##compiler#always-bound)
1267				    (mark-variable ret '##compiler#always-bound)
1268				    (hide-variable arg)
1269				    (hide-variable ret)
1270				    ;; NOTE: Above we already check we're in toplevel context,
1271				    ;; so we can unconditionally register the export here.
1272				    ;; TODO: Remove after fixing #1615
1273				    (##sys#register-export arg (##sys#current-module))
1274				    (##sys#register-export ret (##sys#current-module))
1275				    (walk
1276				     `(##core#begin
1277					(##core#set! ,arg ,(first conv))
1278					(##core#set!
1279					 ,ret
1280					 ,(if (pair? (cdr conv)) (second conv) '##sys#values)) )
1281				     e dest ldest h ln tl?))]
1282				 [else
1283				  (register-foreign-type! name type)
1284				  '(##core#undefined) ] ) ) )
1285
1286			((##core#define-external-variable)
1287			 (let* ((sym (second x))
1288				(ln (get-line-number x))
1289				(name (symbol->string sym))
1290				(type (third x))
1291				(exported (fourth x))
1292				(rname (make-random-name)) )
1293			   (unless tl?
1294			     (quit-compiling
1295			      "~aexternal variable definition of `~s' in non-toplevel context"
1296			      (if ln (sprintf "(~a) - " ln) "")
1297			      sym))
1298			   (unless exported (set! name (symbol->string (fifth x))))
1299			   (set! external-variables (cons (vector name type exported) external-variables))
1300			   (set! foreign-variables
1301			     (cons (list rname 'c-pointer (string-append "&" name))
1302				   foreign-variables) )
1303			   (set! external-to-pointer (alist-cons sym rname external-to-pointer))
1304			   '(##core#undefined) ) )
1305
1306			((##core#let-location)
1307			 (let* ((var (second x))
1308				(type (strip-syntax (third x)))
1309				(alias (gensym))
1310				(store (gensym))
1311				(init (and (pair? (cddddr x)) (fourth x))))
1312			   (set-real-name! alias var)
1313			   (set! location-pointer-map
1314			     (cons (list alias store type) location-pointer-map) )
1315			   (parameterize ((##sys#current-environment
1316					   (alist-cons var alias (##sys#current-environment))))
1317			    (walk
1318			     `(##core#let (,(let ((size (bytes->words (estimate-foreign-result-location-size type))))
1319				       ;; Add 2 words: 1 for the header, 1 for double-alignment:
1320				       ;; Note: C_a_i_bytevector takes number of words, not bytes
1321				       (list
1322					store
1323					`(##core#inline_allocate
1324					  ("C_a_i_bytevector" ,(+ 2 size))
1325					  ',size)) ) )
1326				(##core#begin
1327				 ,@(if init
1328				       `((##core#set! ,alias ,init))
1329				       '() )
1330				 ,(if init (fifth x) (fourth x)) ) )
1331			     e
1332			     dest ldest h ln #f)) ) )
1333
1334			((##core#define-inline)
1335			 (let* ((name (second x))
1336				(val `(##core#lambda ,@(cdaddr x)))
1337				(ln (get-line-number x)))
1338			   (unless tl?
1339			     (quit-compiling
1340			      "~ainline definition of `~s' in non-toplevel context"
1341			      (if ln (sprintf "(~a) - " ln) "")
1342			      name))
1343			     (hash-table-set! inline-table name val)
1344			     '(##core#undefined)))
1345
1346			((##core#define-constant)
1347			 (let* ((name (second x))
1348				(ln (get-line-number x))
1349				(valexp (third x))
1350				(val (handle-exceptions ex
1351					 ;; could show line number here
1352					 (quit-compiling "error in constant evaluation of ~S for named constant `~S'"
1353					       valexp name)
1354				       (if (and (not (symbol? valexp))
1355						(collapsable-literal? valexp))
1356					   valexp
1357					   (eval
1358					    `(##core#let
1359					      ,defconstant-bindings ,valexp))))))
1360			   (unless tl?
1361			     (quit-compiling
1362			      "~aconstant definition of `~s' in non-toplevel context"
1363			      (if ln (sprintf "(~a) - " ln) "")
1364			      name))
1365			   (set! defconstant-bindings
1366			     (cons (list name `(##core#quote ,val)) defconstant-bindings))
1367			   (cond ((collapsable-literal? val)
1368				  (hash-table-set! constant-table name `(##core#quote ,val))
1369				  '(##core#undefined))
1370				 ((basic-literal? val)
1371				  (let ((var (gensym "constant")))
1372				    (hash-table-set! constant-table name var)
1373				    (hide-variable var)
1374				    (mark-variable var '##compiler#constant)
1375				    (mark-variable var '##compiler#always-bound)
1376				    (walk `(define ,var (##core#quote ,val)) e #f #f h ln tl?)))
1377				 (else
1378				  (quit-compiling
1379				   "~ainvalid compile-time value for named constant `~S'"
1380				   (if ln (sprintf "(~a) - " ln) "")
1381				   name)))))
1382
1383			((##core#declare)
1384			 (walk
1385			  `(##core#begin
1386			    ,@(map (lambda (d)
1387				     (process-declaration d lookup (lambda (id) (memq (lookup id) e))))
1388				   (cdr x) ) )
1389			  e #f #f h ln #f) )
1390
1391			((##core#foreign-callback-wrapper)
1392			 (let-values ([(args lam) (split-at (cdr x) 4)])
1393			   (let* ([lam (car lam)]
1394				  [raw-c-name (cadr (first args))]
1395				  [name (##sys#alias-global-hook raw-c-name #t dest)]
1396				  [rtype (cadr (third args))]
1397				  [atypes (cadr (fourth args))]
1398				  [vars (second lam)] )
1399			     (if (valid-c-identifier? raw-c-name)
1400				 (set! callback-names
1401				   (cons (cons raw-c-name name) callback-names))
1402				 (let ((ln (get-line-number x)))
1403				   (quit-compiling
1404				    "~aname `~S' of external definition is not a valid C identifier"
1405				    (if ln (sprintf "(~a) - " ln) "")
1406				    raw-c-name)))
1407			     (when (or (not (list? vars))
1408				       (not (list? atypes))
1409				       (not (= (length vars) (length atypes))) )
1410			       (syntax-error
1411				"non-matching or invalid argument list to foreign callback-wrapper"
1412				vars atypes) )
1413			     `(##core#foreign-callback-wrapper
1414			       ,@(mapwalk args e h ln #f)
1415			       ,(walk `(##core#lambda
1416					,vars
1417					(##core#let
1418					 ,(let loop ([vars vars] [types atypes])
1419					    (if (null? vars)
1420						'()
1421						(let ([var (car vars)]
1422						      [type (car types)] )
1423						  (cons
1424						   (list
1425						    var
1426						    (foreign-type-convert-result
1427						     (finish-foreign-result
1428						      (final-foreign-type type)
1429						      var)
1430						     type) )
1431						   (loop (cdr vars) (cdr types)) ) ) ) )
1432					 ,(foreign-type-convert-argument
1433					   `(##core#let
1434					     ()
1435					     ,@(cond
1436						((member
1437						  rtype
1438						  '((const nonnull-c-string)
1439						    (const nonnull-unsigned-c-string)
1440						    nonnull-unsigned-c-string
1441						    nonnull-c-string))
1442						 `((##sys#make-c-string
1443						    (##core#let
1444						     () ,@(cddr lam))
1445						    (##core#quote ,name))))
1446						((member
1447						  rtype
1448						  '((const c-string*)
1449						    (const unsigned-c-string*)
1450						    unsigned-c-string*
1451						    c-string*
1452						    c-string-list
1453						    c-string-list*))
1454						 (syntax-error
1455						  "not a valid result type for callback procedures"
1456						  rtype
1457						  name) )
1458						((member
1459						  rtype
1460						  '(c-string
1461						    (const unsigned-c-string)
1462						    unsigned-c-string
1463						    (const c-string)) )
1464						 `((##core#let
1465						    ((r (##core#let () ,@(cddr lam))))
1466						    (,(macro-alias 'and)
1467						     r
1468						     (##sys#make-c-string r (##core#quote ,name))) ) ) )
1469						(else (cddr lam)) ) )
1470					   rtype) ) )
1471				      e #f #f h ln #f) ) ) ) )
1472
1473			((##core#location)
1474			 (let ([sym (cadr x)])
1475			   (if (symbol? sym)
1476			       (cond ((assq (lookup sym) location-pointer-map)
1477				      => (lambda (a)
1478					   (walk
1479					    `(##sys#make-locative ,(second a) 0 #f (##core#quote location))
1480					    e #f #f h ln #f) ) )
1481				     ((assq sym external-to-pointer)
1482				      => (lambda (a) (walk (cdr a) e #f #f h ln #f)) )
1483				     ((assq sym callback-names)
1484				      `(##core#inline_ref (,(symbol->string sym) c-pointer)) )
1485				     (else
1486				      (walk
1487				       `(##sys#make-locative ,sym 0 #f (##core#quote location))
1488				       e #f #f h ln #f) ) )
1489			       (walk
1490				`(##sys#make-locative ,sym 0 #f (##core#quote location))
1491				e #f #f h ln #f) ) ) )
1492
1493			(else
1494			 (let* ((x2 (fluid-let ((##sys#syntax-context
1495						 (cons name ##sys#syntax-context)))
1496				      (mapwalk x e h ln tl?)))
1497				(head2 (car x2))
1498				(old (hash-table-ref line-number-database-2 head2)))
1499			   (when ln
1500			     (hash-table-set!
1501			      line-number-database-2
1502			      head2
1503			      (cons name (alist-cons x2 ln (if old (cdr old) '()))) ) )
1504			   x2))))))))
1505
1506	  ((not (list? x))
1507	   (##sys#syntax-error/context "malformed expression" x) )
1508
1509	  ((constant? (car x))
1510	   (emit-syntax-trace-info x #f)
1511	   (warning "literal in operator position" x)
1512	   (mapwalk x e h outer-ln tl?) )
1513
1514	  (else
1515	   (emit-syntax-trace-info x #f)
1516	   (let ((tmp (gensym)))
1517	     (walk
1518	      `(##core#let
1519		((,tmp ,(car x)))
1520		(,tmp ,@(cdr x)))
1521	      e dest ldest h outer-ln #f)))))
1522
1523  (define (mapwalk xs e h ln tl?)
1524    (map (lambda (x) (walk x e #f #f h ln tl?)) xs) )
1525
1526  (when (memq 'c debugging-chicken) (newline) (pretty-print exp))
1527  (foreign-code "C_clear_trace_buffer();")
1528  ;; Process visited definitions and main expression:
1529  (walk
1530   `(##core#begin
1531     ,@(let ([p (reverse pending-canonicalizations)])
1532	 (set! pending-canonicalizations '())
1533	 p)
1534     ,(begin
1535	(set! extended-bindings (append internal-bindings extended-bindings))
1536	exp) )
1537   '() #f #f #f #f #t) ) )
1538
1539
1540(define (process-declaration spec lookup local?)
1541  (define (check-decl spec minlen . maxlen)
1542    (let ([n (length (cdr spec))])
1543      (if (or (< n minlen) (> n (optional maxlen 99999)))
1544	  (syntax-error "invalid declaration" spec) ) ) )
1545  (define (globalize var)
1546    (cond ((local? var)
1547	   (note-local var)
1548	   #f)
1549	  (else (##sys#alias-global-hook (lookup var) #t #f))))
1550  (define (globalize-all vars)
1551    (filter-map globalize vars))
1552  (define (note-local var)
1553    (##sys#notice
1554     (sprintf "ignoring declaration for locally bound variable `~a'" var)))
1555  (call-with-current-continuation
1556   (lambda (return)
1557     (unless (pair? spec)
1558       (syntax-error "invalid declaration specification" spec) )
1559     (case (strip-syntax (car spec)) ; no global aliasing
1560       ((uses)
1561	(let ((units (strip-syntax (cdr spec))))
1562	  (set! used-libraries (lset-union/eq? used-libraries units))
1563	  (set! linked-libraries (lset-union/eq? linked-libraries units))))
1564       ((unit)
1565	(check-decl spec 1 1)
1566	(let ((u (strip-syntax (cadr spec))))
1567	  (when (and unit-name (not (eq? unit-name u)))
1568	    (warning "unit was already given a name (new name is ignored)"))
1569	  (set! unit-name u)
1570	  (set! standalone-executable #f)))
1571       ((standard-bindings)
1572	(if (null? (cdr spec))
1573	    (set! standard-bindings default-standard-bindings)
1574	    (set! standard-bindings (append (globalize-all (cdr spec)) standard-bindings)) ) )
1575       ((extended-bindings)
1576	(if (null? (cdr spec))
1577	    (set! extended-bindings default-extended-bindings)
1578	    (set! extended-bindings (append (globalize-all (cdr spec)) extended-bindings)) ) )
1579       ((usual-integrations)
1580	(cond [(null? (cdr spec))
1581	       (set! standard-bindings default-standard-bindings)
1582	       (set! extended-bindings default-extended-bindings) ]
1583	      [else
1584	       (let ([syms (globalize-all (cdr spec))])
1585		 (set! standard-bindings (lset-intersection/eq? syms default-standard-bindings))
1586		 (set! extended-bindings (lset-intersection/eq? syms default-extended-bindings)))]))
1587       ((number-type)
1588	(check-decl spec 1 1)
1589	(set! number-type (strip-syntax (cadr spec))))
1590       ((fixnum fixnum-arithmetic) (set! number-type 'fixnum))
1591       ((generic) (set! number-type 'generic))
1592       ((unsafe) (set! unsafe #t))
1593       ((safe) (set! unsafe #f))
1594       ((no-bound-checks) (set! no-bound-checks #t))
1595       ((no-argc-checks) (set! no-argc-checks #t))
1596       ((no-procedure-checks) (set! no-procedure-checks #t))
1597       ((disable-interrupts) (set! insert-timer-checks #f))
1598       ((always-bound)
1599	(for-each (cut mark-variable <> '##compiler#always-bound) (cdr spec)))
1600       ((safe-globals) (set! safe-globals-flag #t))
1601       ((no-procedure-checks-for-usual-bindings)
1602	(for-each
1603	 (cut mark-variable <> '##compiler#always-bound-to-procedure)
1604	 (append default-standard-bindings default-extended-bindings))
1605	(for-each
1606	 (cut mark-variable <> '##compiler#always-bound)
1607	 (append default-standard-bindings default-extended-bindings)))
1608       ((no-procedure-checks-for-toplevel-bindings)
1609	(set! no-global-procedure-checks #t))
1610       ((bound-to-procedure)
1611	(let ((vars (globalize-all (cdr spec))))
1612	  (for-each (cut mark-variable <> '##compiler#always-bound-to-procedure) vars)
1613	  (for-each (cut mark-variable <> '##compiler#always-bound) vars)))
1614       ((foreign-declare)
1615	(let ([fds (cdr spec)])
1616	  (if (every string? fds)
1617	      (set! foreign-declarations (append foreign-declarations fds))
1618	      (syntax-error 'declare "invalid declaration" spec) ) ) )
1619       ((block) (set! block-compilation #t))
1620       ((separate) (set! block-compilation #f))
1621       ((keep-shadowed-macros) (set! undefine-shadowed-macros #f))
1622       ((unused)
1623	(for-each (cut mark-variable <> '##compiler#unused) (globalize-all (cdr spec))))
1624       ((enforce-argument-types)
1625	(for-each
1626	 (cut mark-variable <> '##compiler#enforce)
1627	 (globalize-all (cdr spec))))
1628       ((not)
1629	(check-decl spec 1)
1630	(case (strip-syntax (second spec)) ; strip all
1631	  [(standard-bindings)
1632	   (if (null? (cddr spec))
1633	       (set! standard-bindings '())
1634	       (set! standard-bindings
1635		 (lset-difference/eq? default-standard-bindings
1636				      (globalize-all (cddr spec)))))]
1637	  [(extended-bindings)
1638	   (if (null? (cddr spec))
1639	       (set! extended-bindings '())
1640	       (set! extended-bindings
1641		 (lset-difference/eq? default-extended-bindings
1642				      (globalize-all (cddr spec)))))]
1643	  [(inline)
1644	   (if (null? (cddr spec))
1645	       (set! inline-locally #f)
1646	       (for-each
1647		(cut mark-variable <> '##compiler#inline 'no)
1648		(globalize-all (cddr spec)))) ]
1649	  [(usual-integrations)
1650	   (cond [(null? (cddr spec))
1651		  (set! standard-bindings '())
1652		  (set! extended-bindings '()) ]
1653		 [else
1654		  (let ([syms (globalize-all (cddr spec))])
1655		    (set! standard-bindings (lset-difference/eq? default-standard-bindings syms))
1656		    (set! extended-bindings (lset-difference/eq? default-extended-bindings syms)))])]
1657	  ((inline-global)
1658	   (set! enable-inline-files #t)
1659	   (when (pair? (cddr spec))
1660	     (for-each
1661	      (cut mark-variable <> '##compiler#inline-global 'no)
1662	      (globalize-all (cddr spec)))))
1663	  [else
1664	   (check-decl spec 1 1)
1665	   (let ((id (strip-syntax (cadr spec))))
1666	     (case id
1667	       [(safe) (set! unsafe #t)]
1668	       [else (warning "unsupported declaration specifier" id)]))]))
1669       ((compile-syntax)
1670	(set! ##sys#enable-runtime-macros #t))
1671       ((block-global hide)
1672	(let ([syms (globalize-all (cdr spec))])
1673	  (if (null? syms)
1674	      (set! block-compilation #t)
1675	      (for-each hide-variable syms))))
1676       ((export)
1677	(set! block-compilation #t)
1678	(let ((syms (globalize-all (cdr spec))))
1679	  (for-each export-variable syms)))
1680       ((emit-external-prototypes-first)
1681	(set! external-protos-first #t) )
1682       ((inline)
1683	(if (null? (cdr spec))
1684	    (set! inline-locally #t)
1685	    (for-each
1686	     (cut mark-variable <> '##compiler#local)
1687	     (globalize-all (cdr spec)))))
1688       ((inline-limit)
1689	(check-decl spec 1 1)
1690	(let ([n (cadr spec)])
1691	  (if (number? n)
1692	      (set! inline-max-size n)
1693	      (warning
1694	       "invalid argument to `inline-limit' declaration"
1695	       spec) ) ) )
1696       ((unroll-limit)
1697	(check-decl spec 1 1)
1698	(let ((n (cadr spec)))
1699	  (if (number? n)
1700	      (set! unroll-limit n)
1701	      (warning
1702	       "invalid argument to `unroll-limit' declaration"
1703	       spec) ) ) )
1704       ((pure)
1705	(let ((syms (globalize-all (cdr spec))))
1706	  (if (every symbol? syms)
1707	      (for-each
1708	       (cut mark-variable <> '##compiler#pure #t)
1709	       (globalize-all syms))
1710	      (quit-compiling
1711	       "invalid arguments to `pure' declaration: ~S" spec))))
1712       ((emit-import-library)
1713	(set! import-libraries
1714	  (append
1715	   import-libraries
1716	   (map (lambda (il)
1717		  (cond ((symbol? il)
1718			 (cons il (string-append (symbol->string il) ".import.scm")) )
1719			((and (list? il) (= 2 (length il))
1720			      (symbol? (car il)) (string? (cadr il)))
1721			 (cons (car il) (cadr il)))
1722			(else
1723			 (quit-compiling "invalid `import-library' specification: ~S" il))))
1724		(strip-syntax (cdr spec))))))
1725	((emit-types-file)
1726	 (unless types-output-file
1727	   (set! types-output-file
1728	     (or (null? (cdr spec))
1729		 (and (string? (cadr spec)) (null? (cddr spec)) (cadr spec))
1730		 (quit-compiling "invalid `emit-types-file' declaration: ~S" spec)))))
1731       ((profile)
1732	(set! emit-profile #t)
1733	(cond ((null? (cdr spec))
1734	       (set! profiled-procedures 'all) )
1735	      (else
1736	       (set! profiled-procedures 'some)
1737	       (for-each
1738		(cut mark-variable <> '##compiler#profile)
1739		(globalize-all (cdr spec))))))
1740       ((local)
1741	(cond ((null? (cdr spec))
1742	       (set! local-definitions #t) )
1743	      (else
1744	       (for-each
1745		(cut mark-variable <> '##compiler#local)
1746		(globalize-all (cdr spec))))))
1747       ((inline-global)
1748	(set! enable-inline-files #t)
1749	(set! inline-locally #t)
1750	(when (pair? (cdr spec))
1751	  (for-each
1752	   (cut mark-variable <> '##compiler#inline-global 'yes)
1753	   (globalize-all (cdr spec)))))
1754       ((type)
1755	(for-each
1756	 (lambda (spec)
1757	   (if (not (and (list? spec)
1758			 (>= (length spec) 2)
1759			 (symbol? (car spec))))
1760	       (warning "illegal type declaration" (strip-syntax spec))
1761	       (let ((name (globalize (car spec)))
1762		     (type (strip-syntax (cadr spec))))
1763		 (if (local? (car spec))
1764		     (note-local (car spec))
1765		     (let-values (((type pred pure) (validate-type type name)))
1766		       (cond (type
1767			      ;; HACK: since `:' doesn't have access to the SE, we
1768			      ;; fixup the procedure name if type is a named procedure type
1769			      ;; Quite terrible.
1770			      (when (and (pair? type)
1771					 (eq? 'procedure (car type))
1772					 (symbol? (cadr type)))
1773				(set-car! (cdr type) name))
1774			      (mark-variable name '##compiler#type type)
1775			      (mark-variable name '##compiler#type-source 'local)
1776			      (when pure
1777				(mark-variable name '##compiler#pure #t))
1778			      (when pred
1779				(mark-variable name '##compiler#predicate pred))
1780			      (when (pair? (cddr spec))
1781				(install-specializations
1782				 name
1783				 (strip-syntax (cddr spec)))))
1784			     (else
1785			      (warning
1786			       "illegal `type' declaration"
1787			       (strip-syntax spec)))))))))
1788	 (cdr spec)))
1789       ((predicate)
1790	(for-each
1791	 (lambda (spec)
1792	   (cond ((and (list? spec) (symbol? (car spec)) (= 2 (length spec)))
1793		  (let ((name (globalize (car spec)))
1794			(type (strip-syntax (cadr spec))))
1795		    (if (local? (car spec))
1796			(note-local (car spec))
1797			(let-values (((type pred pure) (validate-type type name)))
1798			  (if (and type (not pred))
1799			      (mark-variable name '##compiler#predicate type)
1800			      (warning "illegal `predicate' declaration" spec))))))
1801		 (else
1802		  (warning "illegal `type' declaration item" spec))))
1803	 (cdr spec)))
1804       ((specialize)
1805	(set! enable-specialization #t))
1806       ((strict-types)
1807	(set! strict-variable-types #t))
1808       (else (warning "unknown declaration specifier" spec)) )
1809     '(##core#undefined) ) ) )
1810
1811
1812;;; Create entry procedure:
1813
1814(define (build-toplevel-procedure node)
1815  (make-node 'lambda '(()) (list node)))
1816
1817
1818;;; Expand "foreign-lambda"/"foreign-safe-lambda" forms and add item to stub-list:
1819
1820(define-record-type foreign-stub
1821  (make-foreign-stub id return-type name argument-types argument-names body cps callback)
1822  foreign-stub?
1823  (id foreign-stub-id)			; symbol
1824  (return-type foreign-stub-return-type)	  ; type-specifier
1825  (name foreign-stub-name)			  ; string or #f
1826  (argument-types foreign-stub-argument-types) ; (type-specifier...)
1827  (argument-names foreign-stub-argument-names) ; #f or (symbol ...)
1828  (body foreign-stub-body)		       ; #f or string
1829  (cps foreign-stub-cps)		       ; boolean
1830  (callback foreign-stub-callback))	       ; boolean
1831
1832(define (create-foreign-stub rtype sname argtypes argnames body callback cps)
1833  ;; try to describe a foreign-lambda type specification
1834  ;; eg. (type->symbol '(c-pointer (struct "point"))) => point*
1835  (define (type->symbol type-spec)
1836    (let loop ([type type-spec])
1837      (cond
1838       ((null? type) 'a)
1839       ((list? type)
1840	(case (car type)
1841	  ((c-pointer) (string->symbol (conc (loop (cdr type)) "*"))) ;; if pointer, append *
1842	  ((const struct) (loop (cdr type))) ;; ignore these
1843	  (else (loop (car type)))))
1844       ((or (symbol? type) (string? type)) type)
1845       (else 'a))))
1846  (let* ((rtype (strip-syntax rtype))
1847	 (argtypes (strip-syntax argtypes))
1848	 (params (if argnames
1849		     (map gensym argnames)
1850		     (map (o gensym type->symbol) argtypes)))
1851	 (f-id (gensym 'stub))
1852	 (bufvar (gensym))
1853	 (rsize (estimate-foreign-result-size rtype)))
1854    (when sname (set-real-name! f-id (string->symbol sname)))
1855    (set! foreign-lambda-stubs
1856      (cons (make-foreign-stub f-id rtype sname argtypes argnames body cps callback)
1857	    foreign-lambda-stubs) )
1858    (let ([rsize (if callback (+ rsize 24) rsize)] ; 24 -> has to hold cons on 64-bit platforms!
1859	  [head (if cps
1860		    `((##core#primitive ,f-id))
1861		    `(##core#inline ,f-id) ) ]
1862	  [rest (map (lambda (p t) (foreign-type-check (foreign-type-convert-argument p t) t)) params argtypes)] )
1863      `(##core#lambda ,params
1864	 ;; Do minor GC (if callback) to make room on stack:
1865	 ,@(if callback '((##sys#gc #f)) '())
1866	 ,(if (zero? rsize)
1867	      (foreign-type-convert-result (append head (cons '(##core#undefined) rest)) rtype)
1868	      (let ([ft (final-foreign-type rtype)]
1869		    [ws (bytes->words rsize)] )
1870		`(##core#let ([,bufvar (##core#inline_allocate ("C_a_i_bytevector" ,(+ 2 ws)) (##core#quote ,ws))])
1871		   ,(foreign-type-convert-result
1872		     (finish-foreign-result ft (append head (cons bufvar rest)))
1873		     rtype) ) ) ) ) ) ) )
1874
1875(define (expand-foreign-lambda exp callback?)
1876  (let* ((name (third exp))
1877	 (sname (cond ((symbol? name) (symbol->string (strip-syntax name)))
1878		      ((string? name) name)
1879		      (else (quit-compiling
1880			     "name `~s' of foreign procedure has wrong type"
1881			     name)) ) )
1882	 (rtype (second exp))
1883	 (argtypes (cdddr exp)) )
1884    (create-foreign-stub rtype sname argtypes #f #f callback? callback?) ) )
1885
1886(define (expand-foreign-lambda* exp callback?)
1887  (let* ((rtype (second exp))
1888	 (args (third exp))
1889	 (body (string-intersperse (cdddr exp) "\n"))
1890 	 (argtypes (map (lambda (x) (car x)) args))
1891	 ;; C identifiers aren't hygienically renamed inside body strings
1892	 (argnames (map cadr (strip-syntax args))))
1893    (create-foreign-stub rtype #f argtypes argnames body callback? callback?) ) )
1894
1895;; TODO: Try to fold this procedure into expand-foreign-lambda*
1896(define (expand-foreign-primitive exp)
1897  (let* ((hasrtype (and (pair? (cddr exp)) (not (string? (caddr exp)))))
1898	 (rtype (if hasrtype (second exp) 'void))
1899	 (args (strip-syntax (if hasrtype (third exp) (second exp))))
1900	 (body (string-intersperse (if hasrtype (cdddr exp) (cddr exp)) "\n"))
1901 	 (argtypes (map (lambda (x) (car x)) args))
1902	 ;; C identifiers aren't hygienically renamed inside body strings
1903	 (argnames (map cadr (strip-syntax args))))
1904    (create-foreign-stub rtype #f argtypes argnames body #f #t) ) )
1905
1906
1907;;; Convert canonicalized node-graph into continuation-passing-style:
1908
1909(define (perform-cps-conversion node)
1910  (let ((called-units '()))
1911
1912  (define (cps-lambda id llist subs k)
1913    (let ([t1 (gensym 'k)])
1914      (k (make-node
1915	  '##core#lambda (list id #t (cons t1 llist) 0)
1916	  (list (walk (car subs)
1917		      (lambda (r)
1918			(make-node '##core#call (list #t) (list (varnode t1) r)) ) ) ) ) ) ) )
1919
1920  (define (node-for-var? node var)
1921     (and (eq? (node-class node) '##core#variable)
1922	  (eq? (car (node-parameters node)) var)))
1923
1924  (define (walk n k)
1925    (let ((subs (node-subexpressions n))
1926	  (params (node-parameters n))
1927	  (class (node-class n)) )
1928      (case (node-class n)
1929	((##core#variable quote ##core#undefined ##core#primitive ##core#provide)
1930          (k n))
1931	((if) (let* ((t1 (gensym 'k))
1932		     (t2 (gensym 'r))
1933		     (k1 (lambda (r) (make-node '##core#call (list #t) (list (varnode t1) r)))) )
1934		(make-node
1935		 'let
1936		 (list t1)
1937		 (list (make-node '##core#lambda (list (gensym-f-id) #f (list t2) 0)
1938				  (list (k (varnode t2))) )
1939		       (walk (car subs)
1940			     (lambda (v)
1941			       (make-node 'if '()
1942					  (list v
1943						(walk (cadr subs) k1)
1944						(walk (caddr subs) k1) ) ) ) ) ) ) ) )
1945	((let)
1946	 (let loop ((vars params) (vals subs))
1947	   (if (null? vars)
1948	       (walk (car vals) k)
1949	       (walk (car vals)
1950		     (lambda (r)
1951		       (if (node-for-var? r (car vars)) ; Don't generate unneccessary lets
1952			   (loop (cdr vars) (cdr vals))
1953			   (make-node 'let
1954				      (list (car vars))
1955				      (list r (loop (cdr vars) (cdr vals))) )) ) ) ) ) )
1956	((lambda ##core#lambda) (cps-lambda (gensym-f-id) (first params) subs k))
1957	((set!) (let* ((t1 (gensym 't))
1958		       (immediate? (and (pair? (cdr params)) (cadr params)))
1959		       (new-params (list (first params) immediate?)))
1960		  (walk (car subs)
1961			(lambda (r)
1962			  (make-node 'let (list t1)
1963				     (list (make-node 'set! new-params (list r))
1964					   (k (varnode t1)) ) ) ) ) ) )
1965	((##core#foreign-callback-wrapper)
1966	 (let ((id (gensym-f-id))
1967	       (lam (first subs)) )
1968	   (register-foreign-callback-stub! id params)
1969	   (cps-lambda id (first (node-parameters lam)) (node-subexpressions lam) k) ) )
1970	((##core#inline ##core#inline_allocate ##core#inline_ref ##core#inline_update ##core#inline_loc_ref
1971			##core#inline_loc_update ##core#debug-event)
1972	 (walk-inline-call class params subs k) )
1973	((##core#call) (walk-call (car subs) (cdr subs) params k))
1974	((##core#callunit)
1975	 (let ((unit (first params)))
1976	   (if (memq unit called-units)
1977	       (walk (make-node '##core#undefined '() '()) k)
1978	       (fluid-let ((called-units (cons unit called-units)))
1979		 (walk-call-unit unit k)))))
1980	((##core#the ##core#the/result)
1981	 ;; remove "the" nodes, as they are not used after scrutiny
1982	 (walk (car subs) k))
1983	((##core#typecase)
1984	 ;; same here, the last clause is chosen, exp is dropped
1985	 (walk (last subs) k))
1986	(else (bomb "bad node (cps)")) ) ) )
1987
1988  (define (walk-call fn args params k)
1989    (let ((t0 (gensym 'k))
1990	  (t3 (gensym 'r)) )
1991      (make-node
1992       'let (list t0)
1993       (list (make-node '##core#lambda (list (gensym-f-id) #f (list t3) 0)
1994			(list (k (varnode t3))) )
1995	     (walk-arguments
1996	      args
1997	      (lambda (vars)
1998		(walk fn
1999		      (lambda (r)
2000			(make-node '##core#call params (cons* r (varnode t0) vars) ) ) ) ) ) ) ) ) )
2001
2002  (define (walk-call-unit unitname k)
2003    (let ((t0 (gensym 'k))
2004	  (t3 (gensym 'r)) )
2005      (make-node
2006       'let (list t0)
2007       (list (make-node '##core#lambda (list (gensym-f-id) #f (list t3) 0)
2008			(list (k (varnode t3))) )
2009	     (make-node '##core#callunit (list unitname)
2010			(list (varnode t0)) ) ) ) ) )
2011
2012  (define (walk-inline-call class op args k)
2013    (walk-arguments
2014     args
2015     (lambda (vars)
2016       (k (make-node class op vars)) ) ) )
2017
2018  (define (walk-arguments args wk)
2019    (let loop ((args args) (vars '()))
2020      (cond ((null? args) (wk (reverse vars)))
2021	    ((atomic? (car args))
2022	     (loop (cdr args) (cons (car args) vars)) )
2023	    (else
2024	     (let ((t1 (gensym 'a)))
2025	       (walk (car args)
2026		     (lambda (r)
2027		       (if (node-for-var? r t1) ; Don't generate unneccessary lets
2028			   (loop (cdr args) (cons (varnode t1) vars) )
2029			   (make-node 'let (list t1)
2030				      (list r
2031					    (loop (cdr args)
2032						  (cons (varnode t1) vars) ) ) )) ) ) ) ) ) ) )
2033
2034  (define (atomic? n)
2035    (let ((class (node-class n)))
2036      (or (memq class '(quote ##core#variable ##core#undefined))
2037	  (and (memq class '(##core#inline_allocate
2038			     ##core#inline_ref ##core#inline_update
2039			     ##core#inline_loc_ref ##core#inline_loc_update))
2040	       (every atomic? (node-subexpressions n)) ) ) ) )
2041
2042  (walk node values)))
2043
2044
2045;;; Perform source-code analysis:
2046
2047(define (analyze-expression node)
2048  ;; Avoid crowded hash tables by using previous run's size as heuristic
2049  (let* ((db-size (fx* (fxmax current-analysis-database-size 1) 3))
2050	 (db (make-vector db-size '())))
2051
2052    (define (grow n)
2053      (set! current-program-size (+ current-program-size n)) )
2054
2055    ;; fullenv is constantly (append localenv env). It's there to avoid
2056    ;; exponential behaviour by APPEND calls when compiling deeply nested LETs
2057    (define (walk n env localenv fullenv here)
2058      (let ((subs (node-subexpressions n))
2059	    (params (node-parameters n))
2060	    (class (node-class n)) )
2061	(grow 1)
2062	(case class
2063	  ((quote ##core#undefined ##core#provide ##core#proc) #f)
2064
2065	  ;; Uneliminated rest-cdr calls need to hang on to rest var
2066	  ((##core#variable ##core#rest-cdr)
2067	   (let ((var (first params)))
2068	     (ref var n)
2069	     (unless (memq var localenv)
2070	       (grow 1)
2071	       (cond ((memq var env)
2072		      (db-put! db var 'captured #t))
2073		     ((not (db-get db var 'global))
2074		      (db-put! db var 'global #t) ) ) ) ) )
2075
2076	  ((##core#callunit ##core#recurse)
2077	   (grow 1)
2078	   (walkeach subs env localenv fullenv here))
2079
2080	  ((##core#call)
2081	   (grow 1)
2082	   (let ([fun (car subs)])
2083	     (when (eq? '##core#variable (node-class fun))
2084	       (let* ((name (first (node-parameters fun)))
2085                      (val (db-get db name 'value)))
2086                 (when (and first-analysis
2087                            val
2088                            (not (db-get db name 'global))
2089                            (not (db-get db name 'unknown))
2090                            (eq? '##core#lambda (node-class val))
2091                            (not (llist-match? (third (node-parameters val))
2092                                               (cdr subs))))
2093                    (quit-compiling
2094		      "known procedure called with wrong number of arguments: `~A'"
2095	              (real-name name)))
2096		 (collect! db name 'call-sites (cons here n))))
2097	     (walk (first subs) env localenv fullenv here)
2098	     (walkeach (cdr subs) env localenv fullenv here)))
2099
2100	  ((let ##core#let)
2101	   (let ([env2 (append params fullenv)])
2102	     (let loop ([vars params] [vals subs])
2103	       (if (null? vars)
2104		   (walk (car vals) env (append params localenv) env2 here)
2105		   (let ([var (car vars)]
2106			 [val (car vals)] )
2107		     (db-put! db var 'home here)
2108		     (assign var val env2 here)
2109		     (walk val env localenv fullenv here)
2110		     (loop (cdr vars) (cdr vals)) ) ) ) ) )
2111
2112	  ((lambda) ; this is an intermediate lambda, slightly different
2113	   (grow 1) ; from '##core#lambda nodes (params = (LLIST));
2114	   (##sys#decompose-lambda-list	; CPS will convert this into ##core#lambda
2115	    (first params)
2116	    (lambda (vars argc rest)
2117	      (for-each
2118	       (lambda (var) (db-put! db var 'unknown #t))
2119	       vars)
2120	      (let ([tl toplevel-scope])
2121		(set! toplevel-scope #f)
2122		(walk (car subs) fullenv vars (append vars fullenv) #f)
2123		(set! toplevel-scope tl) ) ) ) )
2124
2125	  ((##core#lambda ##core#direct_lambda)
2126	   (grow 1)
2127	   (##sys#decompose-lambda-list
2128	    (third params)
2129	    (lambda (vars argc rest)
2130	      (let ([id (first params)]
2131		    [size0 current-program-size] )
2132		(when here
2133		  (collect! db here 'contains id)
2134		  (db-put! db id 'contained-in here) )
2135		(for-each
2136		 (lambda (var)
2137		   (db-put! db var 'home here)
2138		   (db-put! db var 'unknown #t) )
2139		 vars)
2140		(when rest
2141		  (db-put! db rest 'rest-parameter 'list)
2142		  (db-put! db rest 'rest-cdr (cons rest 0)))
2143		(when (simple-lambda-node? n) (db-put! db id 'simple #t))
2144		(let ([tl toplevel-scope])
2145		  (unless toplevel-lambda-id (set! toplevel-lambda-id id))
2146		  (when (and (second params) (not (eq? toplevel-lambda-id id)))
2147		    (set! toplevel-scope #f)) ; only if non-CPS lambda
2148		  (walk (car subs) fullenv vars (append vars fullenv) id)
2149		  (set! toplevel-scope tl)
2150		  ;; decorate ##core#call node with size
2151		  (set-car! (cdddr (node-parameters n)) (- current-program-size size0)) ) ) ) ) )
2152
2153	  ((set! ##core#set!) 		;XXX ##core#set! still used?
2154	   (let* ((var (first params))
2155		  (val (car subs)) )
2156	     (when (and first-analysis (not bootstrap-mode))
2157	       (case (variable-mark var '##compiler#intrinsic)
2158		 ((standard)
2159		  (warning "redefinition of standard binding" var) )
2160		 ((extended)
2161		  (warning "redefinition of extended binding" var) ) ))
2162	     (collect! db var 'potential-values val)
2163	     (unless (memq var localenv)
2164	       (grow 1)
2165	       (cond ((memq var env)
2166		      (db-put! db var 'captured #t))
2167		     ((not (db-get db var 'global))
2168		      (db-put! db var 'global #t) ) ) )
2169	     (assign var val fullenv here)
2170	     (unless toplevel-scope (db-put! db var 'assigned-locally #t))
2171	     (db-put! db var 'assigned #t)
2172	     (walk (car subs) env localenv fullenv here)))
2173
2174	  ((##core#primitive ##core#inline)
2175	   (let ((id (first params)))
2176	     (when (and first-analysis here (symbol? id) (get-real-name id))
2177	       (set-real-name! id here) )
2178	     (walkeach subs env localenv fullenv here)))
2179
2180	  (else (walkeach subs env localenv fullenv here)))))
2181
2182    (define (walkeach xs env lenv fenv here)
2183      (for-each (lambda (x) (walk x env lenv fenv here)) xs) )
2184
2185    (define (mark-rest-cdr var rvar depth)
2186      (db-put! db var 'rest-cdr (cons rvar depth))
2187      (collect! db rvar 'derived-rest-vars var))
2188
2189    (define (mark-rest-null? var rvar depth)
2190      (db-put! db var 'rest-null? (cons rvar depth))
2191      (collect! db rvar 'derived-rest-vars var))
2192
2193    (define (assign var val env here)
2194      ;; Propagate rest-cdr and rest-null? onto aliased variables
2195      (and-let* (((eq? '##core#variable (node-class val)))
2196		 (v (db-get db (first (node-parameters val)) 'rest-cdr)))
2197	(mark-rest-cdr var (car v) (cdr v)) )
2198
2199      (and-let* (((eq? '##core#variable (node-class val)))
2200		 (v (db-get db (first (node-parameters val)) 'rest-null?)))
2201	(mark-rest-null? var (car v) (cdr v)) )
2202
2203      (cond ((eq? '##core#undefined (node-class val))
2204	     (db-put! db var 'undefined #t) )
2205	    ((and (eq? '##core#variable (node-class val)) ; assignment to itself
2206		  (eq? var (first (node-parameters val))) ) )
2207
2208	    ;; Propagate info from ##core#rest-{cdr,null?} nodes to var
2209	    ((eq? '##core#rest-cdr (node-class val))
2210	     (let ((restvar (car (node-parameters val)))
2211		   (depth (cadr (node-parameters val))))
2212	       (mark-rest-cdr var restvar (add1 depth)) ) )
2213
2214	    ((eq? '##core#rest-null? (node-class val))
2215	     (let ((restvar (car (node-parameters val)))
2216		   (depth (cadr (node-parameters val))))
2217	       (mark-rest-null? var restvar depth) ) )
2218
2219	    ;; (##core#cond (null? r) '() (cdr r)) => result is tagged as a rest-cdr var
2220	    ((and-let* ((env (match-node val '(##core#cond ()
2221							   (##core#variable (test-var))
2222							   (quote (()))
2223							   (##core#rest-cdr (rvar depth)))
2224					 '(test-var rvar depth)))
2225			((db-get db (alist-ref 'test-var env) 'rest-null?)))
2226	       env)
2227	     => (lambda (env)
2228		  (let ((rvar (alist-ref 'rvar env))
2229			(depth (alist-ref 'depth env)))
2230		    (mark-rest-cdr var rvar (add1 depth)) ) ) )
2231
2232	    ((or (memq var env)
2233		 (variable-mark var '##compiler#constant)
2234		 (not (variable-visible? var block-compilation)))
2235	     (let ((props (db-get-all db var 'unknown 'value))
2236		   (home (db-get db var 'home)) )
2237	       (unless (assq 'unknown props)
2238		 (if (assq 'value props)
2239		     (db-put! db var 'unknown #t)
2240		     (if (or (not home) (eq? here home))
2241			 (db-put! db var 'value val)
2242			 (db-put! db var 'unknown #t) ) ) ) ) )
2243	    ((and (or local-definitions
2244		      (variable-mark var '##compiler#local))
2245		  (not (db-get db var 'unknown)))
2246	     (let ((home (db-get db var 'home)))
2247	       (cond ((db-get db var 'local-value)
2248		      (db-put! db var 'unknown #t))
2249		     ((or (not home) (eq? here home))
2250		      (db-put! db var 'local-value val)	       )
2251		     (else (db-put! db var 'unknown #t)))))
2252	    (else (db-put! db var 'unknown #t)) ) )
2253
2254    (define (ref var node)
2255      (collect! db var 'references node) )
2256
2257    (define (quick-put! plist prop val)
2258      (set-cdr! plist (alist-cons prop val (cdr plist))) )
2259
2260    ;; Walk toplevel expression-node:
2261    (debugging 'p "analysis traversal phase...")
2262    (set! current-program-size 0)
2263    (walk node '() '() '() #f)
2264
2265    ;; Complete gathered database information:
2266    (debugging 'p "analysis gathering phase...")
2267    (set! current-analysis-database-size 0)
2268    (hash-table-for-each
2269     (lambda (sym plist)
2270       (let ([unknown #f]
2271	     [value #f]
2272	     [local-value #f]
2273	     [potential-values #f]
2274	     [references '()]
2275	     [captured #f]
2276	     [call-sites '()]
2277	     [assigned #f]
2278	     [assigned-locally #f]
2279	     [undefined #f]
2280	     [global #f]
2281	     [nreferences 0]
2282	     [rest-cdr #f]
2283	     [ncall-sites 0] )
2284
2285	 (set! current-analysis-database-size (fx+ current-analysis-database-size 1))
2286
2287	 (for-each
2288	  (lambda (prop)
2289	    (case (car prop)
2290	      [(unknown) (set! unknown #t)]
2291	      [(references)
2292	       (set! references (cdr prop))
2293	       (set! nreferences (length references)) ]
2294	      [(captured) (set! captured #t)]
2295	      [(potential-values)
2296	       (set! potential-values (cdr prop))]
2297	      [(call-sites)
2298	       (set! call-sites (cdr prop))
2299	       (set! ncall-sites (length call-sites)) ]
2300	      [(assigned) (set! assigned #t)]
2301	      [(assigned-locally) (set! assigned-locally #t)]
2302	      [(undefined) (set! undefined #t)]
2303	      [(global) (set! global #t)]
2304	      [(value) (set! value (cdr prop))]
2305	      [(local-value) (set! local-value (cdr prop))]
2306	      [(rest-cdr) (set! rest-cdr (cdr prop))] ) )
2307	  plist)
2308
2309	 (set! value (and (not unknown) value))
2310	 (set! local-value (and (not unknown) local-value))
2311
2312	 ;; If this is the first analysis, register known local or potentially known global
2313	 ;;  lambda-value id's along with their names:
2314         (when first-analysis
2315	   (and-let* ((vals (or (and value (list value))
2316				(and global potential-values))))
2317	     (for-each
2318	      (lambda (val)
2319		(when (eq? (node-class val) '##core#lambda)
2320		  (set-real-name! (first (node-parameters val)) sym)))
2321	      vals)))
2322
2323	 ;; If this is the first analysis and the variable is global and has no references
2324	 ;;  and is hidden then issue warning:
2325	 (when (and first-analysis
2326		    global
2327		    (null? references)
2328		    (not (variable-mark sym '##compiler#unused))
2329		    (not (variable-hidden? sym))
2330		    (not (variable-visible? sym block-compilation))
2331		    (not (variable-mark sym '##compiler#constant)) )
2332	   (##sys#notice
2333	    (sprintf "global variable `~S' is only locally visible and never used"
2334	      sym) ) )
2335
2336 	 ;; Make 'boxed, if 'assigned & 'captured:
2337	 (when (and assigned captured)
2338	   (quick-put! plist 'boxed #t) )
2339
2340	 ;; Make 'contractable, if it has a procedure as known value, has only one use
2341	 ;;  and one call-site and if the lambda has no free non-global variables
2342	 ;;  or is an internal lambda. Make 'inlinable if
2343	 ;;  use/call count is not 1:
2344	 (cond (value
2345		(let ((valparams (node-parameters value)))
2346		  (when (and (eq? '##core#lambda (node-class value))
2347			     (or (not (second valparams))
2348				 (every
2349				  (lambda (v) (db-get db v 'global))
2350				  (nth-value 0 (scan-free-variables
2351						value block-compilation)) ) ) )
2352		    (if (and (= 1 nreferences) (= 1 ncall-sites))
2353			(quick-put! plist 'contractable #t)
2354			(quick-put! plist 'inlinable #t) ) ) ) )
2355	       (local-value
2356		;; Make 'inlinable, if it is declared local and has a value
2357		(let ((valparams (node-parameters local-value)))
2358		  (when (eq? '##core#lambda (node-class local-value))
2359		    (let-values (((vars hvars) (scan-free-variables
2360						local-value block-compilation)))
2361		      (when (and (db-get db sym 'global)
2362				 (pair? hvars))
2363			(quick-put! plist 'hidden-refs #t))
2364		      (when (or (not (second valparams))
2365				(every
2366				 (lambda (v) (db-get db v 'global))
2367				 vars))
2368			(quick-put! plist 'inlinable #t) ) ) ) ) )
2369	       ((variable-mark sym '##compiler#inline-global) =>
2370		(lambda (n)
2371		  (when (node? n)
2372		    (cond (assigned
2373			   (debugging
2374			    'i
2375			    "global inlining candidate was assigned and will not be inlined"
2376			    sym)
2377			   (mark-variable sym '##compiler#inline-global 'no))
2378			  (else
2379			   (let ((lparams (node-parameters n)))
2380			     (quick-put! plist 'inlinable #t)
2381			     (quick-put! plist 'local-value n))))))))
2382
2383	 ;; Make 'collapsable, if it has a known constant value which
2384	 ;; is either collapsable or is only referenced once:
2385	 (when (and value (eq? 'quote (node-class value)) )
2386	   (let ((val (first (node-parameters value))))
2387	     (when (or (collapsable-literal? val)
2388		       (= 1 nreferences) )
2389	       (quick-put! plist 'collapsable #t) ) ) )
2390
2391	 ;; If it has a known value that is a procedure, and if the number of call-sites is equal to the
2392	 ;;  number of references (does not escape), then make all formal parameters 'unused which are
2393	 ;;  never referenced or assigned (if no rest parameter exist):
2394	 ;;  - also marks the procedure as 'has-unused-parameters (if not in `callback-names')
2395	 ;;  - if the procedure is internal (a continuation) do NOT mark unused parameters.
2396	 ;;  - also: if procedure has rest-parameter and no unused params, mark f-id as 'explicit-rest.
2397	 (when value
2398	   (let ((has #f))
2399	     (when (and (eq? '##core#lambda (node-class value))
2400			(= nreferences ncall-sites) )
2401	       (let ((lparams (node-parameters value)))
2402		 (when (second lparams)
2403		   (##sys#decompose-lambda-list
2404		    (third lparams)
2405		    (lambda (vars argc rest)
2406		      (unless rest
2407			(for-each
2408			 (lambda (var)
2409			   (cond ((and (not (db-get db var 'references))
2410				       (not (db-get db var 'assigned)) )
2411				  (db-put! db var 'unused #t)
2412				  (set! has #t)
2413				  #t)
2414				 (else #f) ) )
2415			 vars) )
2416		      (cond ((and has (not (rassoc sym callback-names eq?)))
2417			     (db-put! db (first lparams) 'has-unused-parameters #t) )
2418			    (rest
2419			     (db-put! db (first lparams) 'explicit-rest #t)
2420			     (db-put! db rest 'consed-rest-arg #t) ) ) ) ) ) ) ) ) )
2421
2422	 ;; Make 'removable, if it has no references and is not assigned to, and one of the following:
2423	 ;; - it has either a value that does not cause any side-effects
2424	 ;; - it is 'undefined
2425	 ;; - it holds only a 'rest-cdr reference (strictly speaking, it may bomb but we don't care)
2426	 (when (and (not assigned)
2427		    (null? references)
2428		    (or (and value
2429			     (if (eq? '##core#variable (node-class value))
2430				 (let ((varname (first (node-parameters value))))
2431				   (or (not (db-get db varname 'global))
2432				       (variable-mark varname '##core#always-bound)
2433				       (intrinsic? varname)))
2434				 (not (expression-has-side-effects? value db)) ))
2435			undefined
2436			rest-cdr) )
2437	   (quick-put! plist 'removable #t) )
2438
2439	 ;; Make 'replacable, if
2440	 ;; - it has a variable as known value and
2441	 ;; - it is not a global
2442	 ;; - it is never assigned to and
2443	 ;; - if either the substitute has a known value itself or
2444	 ;;   * the substitute is never assigned to and
2445	 ;;   * we are in block-mode or the substitute is non-global
2446	 ;;
2447	 ;;  - The variable that can be substituted for the current one is marked as 'replacing.
2448	 ;;    This is done to prohibit beta-contraction of the replacing variable (It wouldn't be there, if
2449	 ;;    it was contracted).
2450	 (when (and value (not global))
2451	   (when (eq? '##core#variable (node-class value))
2452	     (let ((name (first (node-parameters value))) )
2453	       (when (and (not assigned)
2454			  (or (and (not (db-get db name 'unknown))
2455				   (db-get db name 'value))
2456			      (and (not (db-get db name 'assigned))
2457				   (or (not (variable-visible?
2458					     name block-compilation))
2459				       (not (db-get db name 'global))) ) ))
2460		 (quick-put! plist 'replacable name)
2461		 (db-put! db name 'replacing #t) ) ) ) )
2462
2463	 ;; Make 'replacable, if it has a known value of the form: '(lambda (<xvar>) (<kvar> <xvar>))' and
2464	 ;;  is an internally created procedure: (See above for 'replacing)
2465	 (when (and value (eq? '##core#lambda (node-class value)))
2466	   (let ((params (node-parameters value)))
2467	     (when (not (second params))
2468	       (let ((llist (third params))
2469		     (body (first (node-subexpressions value))) )
2470		 (when (and (pair? llist)
2471			    (null? (cdr llist))
2472			    (eq? '##core#call (node-class body)) )
2473		   (let ((subs (node-subexpressions body)))
2474		     (when (= 2 (length subs))
2475		       (let ((v1 (first subs))
2476			     (v2 (second subs)) )
2477			 (when (and (eq? '##core#variable (node-class v1))
2478				    (eq? '##core#variable (node-class v2))
2479				    (eq? (first llist) (first (node-parameters v2))) )
2480			   (let ((kvar (first (node-parameters v1))))
2481			     (quick-put! plist 'replacable kvar)
2482			     (db-put! db kvar 'replacing #t) ) ) ) ) ) ) ) ) ) ) ) )
2483
2484     db)
2485
2486    ;; Set original program-size, if this is the first analysis-pass:
2487    (unless original-program-size
2488      (set! original-program-size current-program-size) )
2489
2490    ;; return database
2491    db) )
2492
2493
2494;;; Collect unsafe global procedure calls that are assigned:
2495
2496;;; Convert closures to explicit data structures (effectively flattens function-binding
2497;   structure):
2498
2499(define (perform-closure-conversion node db)
2500  (let ((direct-calls 0)
2501	(customizable '())
2502	(lexicals '()))
2503
2504    (define (test sym item) (db-get db sym item))
2505
2506    (define (register-customizable! var id)
2507      (set! customizable (lset-adjoin/eq? customizable var))
2508      (db-put! db id 'customizable #t) )
2509
2510    (define (register-direct-call! id)
2511      (set! direct-calls (add1 direct-calls))
2512      (set! direct-call-ids (lset-adjoin/eq? direct-call-ids id)))
2513
2514    ;; Gather free-variable information:
2515    ;; (and: - register direct calls
2516    ;;       - update (by mutation) call information in "##core#call" nodes)
2517    (define (gather n here locals)
2518      (let ((subs (node-subexpressions n))
2519	    (params (node-parameters n)) )
2520	(case (node-class n)
2521
2522	  ((##core#variable ##core#rest-cdr)
2523	   (let ((var (first params)))
2524	     (if (memq var lexicals)
2525		 (list var)
2526		 '())))
2527
2528	  ((quote ##core#undefined ##core#provide ##core#proc ##core#primitive)
2529	   '())
2530
2531	  ((let)
2532	   ;;XXX remove this test later, shouldn't be needed:
2533	   (when (pair? (cdr params)) (bomb "let-node has invalid format" params))
2534	   (let ((c (gather (first subs) here locals))
2535		 (var (first params)))
2536	     (append c (delete var (gather (second subs) here (cons var locals)) eq?))))
2537
2538	  ((set!)
2539	   (let ((var (first params))
2540		 (c (gather (first subs) here locals)))
2541	     (if (memq var lexicals)
2542		 (cons var c)
2543		 c)))
2544
2545	  ((##core#call)
2546	   (let* ([fn (first subs)]
2547		  [mode (first params)]
2548		  [name (and (pair? (cdr params)) (second params))]
2549		  [varfn (eq? '##core#variable (node-class fn))] )
2550	     (node-parameters-set!
2551	      n
2552	      (cons mode
2553		    (if (or name varfn)
2554			(cons name
2555			      (if varfn
2556				  (let* ([varname (first (node-parameters fn))]
2557					 [val (and (not (test varname 'unknown))
2558						   (not (eq?
2559							 'no
2560							 (variable-mark
2561							  varname '##compiler#inline)))
2562						   ;; May not be external, see #1665
2563						   (not (node? (variable-mark varname '##compiler#inline-global)))
2564						   (or (test varname 'value)
2565						       (test varname 'local-value)))] )
2566				    (if (and val (eq? '##core#lambda (node-class val)))
2567					(let* ([params (node-parameters val)]
2568					       [llist (third params)]
2569					       [id (first params)]
2570					       [refs (test varname 'references)]
2571					       [sites (test varname 'call-sites)]
2572					       [custom
2573						(and refs sites
2574						     (= (length refs) (length sites))
2575						     (test varname 'value)
2576						     (list? llist) ) ] )
2577					  (cond ((and name
2578                                                      (not (llist-match? llist (cdr subs))))
2579                                                   '())
2580                                                (else
2581   					          (register-direct-call! id)
2582					          (when custom (register-customizable! varname id))
2583					          (list id custom) ) ) )
2584					'() ) )
2585				  '() ) )
2586			'() ) ) )
2587	     (concatenate (map (lambda (n) (gather n here locals)) subs) ) ))
2588
2589	  ((##core#lambda ##core#direct_lambda)
2590	   (##sys#decompose-lambda-list
2591	    (third params)
2592	    (lambda (vars argc rest)
2593	      (let ((id (if here (first params) 'toplevel)))
2594		(fluid-let ((lexicals (append locals lexicals)))
2595		  (let ((c (delete-duplicates (gather (first subs) id vars) eq?)))
2596		    (db-put! db id 'closure-size (length c))
2597		    (db-put! db id 'captured-variables c)
2598		    (lset-difference/eq? c locals vars)))))))
2599
2600	  (else (concatenate (map (lambda (n) (gather n here locals)) subs)) ) ) ))
2601
2602    ;; Create explicit closures:
2603    (define (transform n here closure)
2604      (let ((subs (node-subexpressions n))
2605	    (params (node-parameters n))
2606	    (class (node-class n)) )
2607	(case class
2608
2609	  ((quote ##core#undefined ##core#provide ##core#proc ##core#float
2610           ##core#float-variable)
2611            n)
2612
2613	  ((##core#variable)
2614	   (let* ((var (first params))
2615		  (val (ref-var n here closure)) )
2616	     (if (test var 'boxed)
2617		 (make-node '##core#unbox '() (list val))
2618		 val) ) )
2619
2620	  ((##core#rest-cdr ##core#rest-car ##core#rest-null? ##core#rest-length)
2621	   (let* ((val (ref-var n here closure))
2622		  (rest-var (if (eq? val n) (varnode (first params)) val)))
2623	     (unless (or (eq? val n)
2624			 (match-node val `(##core#ref (i) (##core#variable (,here))) '(i)))
2625	       ;; If it's captured, replacement in optimizer was incorrect
2626	       (bomb "Saw rest op for captured variable.  This should not happen!" class) )
2627	     ;; If rest-cdrs have not all been eliminated, restore
2628	     ;; them as regular cdr calls on the rest list variable.
2629	     ;; This can be improved, as it can actually introduce
2630	     ;; many more cdr calls than necessary.
2631	     (cond ((eq? class '##core#rest-cdr)
2632		    (transform (replace-rest-op-with-list-ops class rest-var params) here closure))
2633
2634		   ;; If n isn't val, this node was processed and the
2635		   ;; variable got replaced by a closure access.
2636		   ((not (eq? val n))
2637		    (transform (replace-rest-op-with-list-ops class rest-var params) here closure))
2638
2639		   (else val)) ) )
2640
2641	  ((if ##core#call ##core#inline ##core#inline_allocate ##core#callunit
2642	       ##core#inline_ref ##core#inline_update ##core#debug-event
2643	       ##core#switch ##core#cond ##core#direct_call ##core#recurse ##core#return
2644               ##core#let_float ##core#box_float ##core#unbox_float
2645	       ##core#inline_loc_ref
2646	       ##core#inline_loc_update)
2647	   (make-node (node-class n) params (maptransform subs here closure)) )
2648
2649	  ((let)
2650	   (let* ([var (first params)]
2651		  [boxedvar (test var 'boxed)]
2652		  [boxedalias (gensym var)] )
2653	     (if boxedvar
2654		 (make-node
2655		  'let (list boxedalias)
2656		  (list (transform (first subs) here closure)
2657			(make-node
2658			 'let (list var)
2659			 (list (make-node '##core#box '() (list (varnode boxedalias)))
2660			       (transform (second subs) here closure) ) ) ) )
2661		 (make-node
2662		  'let params
2663		  (maptransform subs here closure) ) ) ) )
2664
2665	  ((##core#lambda ##core#direct_lambda)
2666	   (let ((llist (third params)))
2667	     (##sys#decompose-lambda-list
2668	      llist
2669	      (lambda (vars argc rest)
2670		(let* ((boxedvars (filter (lambda (v) (test v 'boxed)) vars))
2671		       (boxedaliases (map cons boxedvars (map gensym boxedvars)))
2672		       (cvar (gensym 'c))
2673		       (id (if here (first params) 'toplevel))
2674		       (capturedvars (or (test id 'captured-variables) '()))
2675		       (csize (or (test id 'closure-size) 0))
2676		       (info (and emit-closure-info (second params) (pair? llist))) )
2677		  ;; If rest-parameter is boxed: mark it as 'boxed-rest
2678		  ;;  (if we don't do this than preparation will think the (boxed) alias
2679		  ;;  of the rest-parameter is never used)
2680		  (and-let* ((rest)
2681			     ((test rest 'boxed))
2682			     (rp (test rest 'rest-parameter)) )
2683		    (db-put! db (cdr (assq rest boxedaliases)) 'boxed-rest #t) )
2684		  (make-node
2685		   '##core#closure (list (+ csize (if info 2 1)))
2686		   (cons
2687		    (make-node
2688		     class
2689		     (list id
2690			   (second params)
2691			   (cons
2692			    cvar
2693			    (build-lambda-list
2694			     (map (lambda (v)
2695				    (cond ((assq v boxedaliases) => cdr)
2696					  (else v) ) )
2697				  vars)
2698			     argc
2699			     (cond ((and rest (assq rest boxedaliases)) => cdr)
2700				   (else rest) ) ) )
2701			   (fourth params) )
2702		     (list (let ((body (transform (car subs) cvar capturedvars)))
2703			     (if (pair? boxedvars)
2704				 (let loop ((aliases (unzip1 boxedaliases))
2705					    (values
2706					     (map (lambda (a)
2707						    (make-node '##core#box '() (list (varnode (cdr a)))))
2708						  boxedaliases) ))
2709				   (if (null? aliases)
2710				       body
2711				       (make-node 'let (list (car aliases))
2712						  (list (car values)
2713							(loop (cdr aliases) (cdr values))))))
2714				 body) ) ) )
2715		    (let ((cvars (map (lambda (v) (ref-var (varnode v) here closure))
2716				      capturedvars) ) )
2717		      (if info
2718			  (append
2719			   cvars
2720			   (list
2721			    (qnode
2722			     (##sys#make-lambda-info
2723			      (->string (cons (or (real-name id) '?)
2724					      ;; this is not always correct, due to optimizations
2725					      (strip-syntax (cdr llist))))))))
2726			  cvars) ) ) ) ) ) ) ) )
2727
2728	  ((set!)
2729	   (let* ((var (first params))
2730		  (val (first subs))
2731		  (cval (node-class val))
2732		  (immf (or (and (eq? 'quote cval) (immediate? (first (node-parameters val))))
2733			    (and (pair? (cdr params)) (second params))
2734			    (eq? '##core#undefined cval))))
2735	     (cond ((posq var closure)
2736		    => (lambda (i)
2737			 (if (test var 'boxed)
2738			     (make-node
2739			      (if immf '##core#updatebox_i '##core#updatebox)
2740			      '()
2741			      (list (make-node '##core#ref (list (add1 i)) (list (varnode here)))
2742				    (transform val here closure) ) )
2743			     ;; Is the following actually used???
2744			     (make-node
2745			      (if immf '##core#update_i '##core#update)
2746			      (list (add1 i))
2747			      (list (varnode here)
2748				    (transform val here closure) ) ) ) ) )
2749		   ((test var 'boxed)
2750		    (make-node
2751		     (if immf '##core#updatebox_i '##core#updatebox)
2752		     '()
2753		     (list (varnode var)
2754			   (transform val here closure) ) ) )
2755		   (else (make-node
2756			  'set! (list var immf)
2757			  (list (transform val here closure) ) ) ) ) ) )
2758
2759	  ((##core#primitive)
2760	   (make-node
2761	    '##core#closure (list (if emit-closure-info 2 1))
2762	    (cons (make-node '##core#proc (list (car params) #t) '())
2763		  (if emit-closure-info
2764		      (list (qnode (##sys#make-lambda-info (car params))))
2765		      '() ) ) ) )
2766
2767	  ((##core#ref) n)
2768
2769	  (else (bomb "bad node (closure2)")) ) ) )
2770
2771    (define (maptransform xs here closure)
2772      (map (lambda (x) (transform x here closure)) xs) )
2773
2774    (define (ref-var n here closure)
2775      (let ((var (first (node-parameters n))))
2776	(cond ((posq var closure)
2777	       => (lambda (i)
2778		    (make-node '##core#ref (list (+ i 1))
2779			       (list (varnode here)) ) ) )
2780	      (else n) ) ) )
2781
2782    (debugging 'p "closure conversion gathering phase...")
2783    (gather node #f '())
2784    (when (pair? customizable)
2785      (debugging 'o "customizable procedures" customizable))
2786    (debugging 'p "closure conversion transformation phase...")
2787    (let ((node2 (transform node #f #f)))
2788      (unless (zero? direct-calls)
2789	(debugging 'o "calls to known targets" direct-calls))
2790      node2) ) )
2791
2792
2793;;; Do some preparations before code-generation can commence:
2794
2795(define-record-type lambda-literal
2796  (make-lambda-literal id external arguments argument-count rest-argument temporaries
2797		       float-temporaries callee-signatures allocated directly-called
2798		       closure-size looping customizable rest-argument-mode body direct)
2799  lambda-literal?
2800  (id lambda-literal-id)			       ; symbol
2801  (external lambda-literal-external)		       ; boolean
2802  ;; lambda-literal-arguments is used nowhere
2803  (arguments lambda-literal-arguments)		       ; (symbol ...)
2804  (argument-count lambda-literal-argument-count)       ; integer
2805  (rest-argument lambda-literal-rest-argument)	       ; symbol | #f
2806  (temporaries lambda-literal-temporaries)	       ; integer
2807  (float-temporaries lambda-literal-float-temporaries)   ; (integer ...)
2808  (callee-signatures lambda-literal-callee-signatures) ; (integer ...)
2809  (allocated lambda-literal-allocated)		       ; integer
2810  ;; lambda-literal-directly-called is used nowhere
2811  (directly-called lambda-literal-directly-called)     ; boolean
2812  (closure-size lambda-literal-closure-size)	       ; integer
2813  (looping lambda-literal-looping)		       ; boolean
2814  (customizable lambda-literal-customizable)	       ; boolean
2815  (rest-argument-mode lambda-literal-rest-argument-mode) ; #f | LIST | NONE
2816  (body lambda-literal-body)				 ; expression
2817  (direct lambda-literal-direct))			 ; boolean
2818
2819(define (prepare-for-code-generation node db)
2820  (let ((literals '())
2821	(literal-count 0)
2822	(lambda-info-literals '())
2823	(lambda-info-literal-count 0)
2824	;; Use analysis db as optimistic heuristic for procedure table size
2825	(lambda-table (make-vector (fx* (fxmax current-analysis-database-size 1) 3) '()))
2826	(temporaries 0)
2827        (float-temporaries '())
2828	(allocated 0)
2829	(looping 0)
2830	(signatures '())
2831	(fastinits 0)
2832	(fastrefs 0)
2833	(fastsets 0)
2834	(dbg-index 0)
2835	(debug-info '()))
2836
2837    (define (walk-var var e e-count sf)
2838      (cond [(posq var e)
2839	     => (lambda (i)
2840		  (make-node '##core#local (list (fx- e-count (fx+ i 1))) '()))]
2841	    [(keyword? var) (make-node '##core#literal (list (literal var)) '())]
2842	    [else (walk-global var sf)] ) )
2843
2844    (define (walk-global var sf)
2845      (let* ([safe (or sf
2846		       no-bound-checks
2847		       unsafe
2848		       (variable-mark var '##compiler#always-bound)
2849		       (intrinsic? var))]
2850	     [blockvar (and (db-get db var 'assigned)
2851			    (not (variable-visible? var block-compilation)))])
2852	(when blockvar (set! fastrefs (add1 fastrefs)))
2853	(make-node
2854	 '##core#global
2855	 (list (if blockvar
2856		   (blockvar-literal var)
2857		   (literal var) )
2858	       safe
2859	       blockvar
2860	       var)
2861	 '() ) ) )
2862
2863    (define (walk n e e-count here boxes)
2864      (let ((subs (node-subexpressions n))
2865	    (params (node-parameters n))
2866	    (class (node-class n)) )
2867	(case class
2868
2869	  ((##core#undefined ##core#proc ##core#float) n)
2870
2871	  ((##core#variable)
2872	   (walk-var (first params) e e-count #f) )
2873
2874	  ((##core#direct_call)
2875	   (let* ((source-info (second params))
2876		  (demand (fourth params)))
2877	     (if (and emit-debug-info source-info)
2878		 (let ((info (list dbg-index 'C_DEBUG_CALL
2879				   (source-info->line source-info)
2880				   (source-info->name source-info))))
2881		   (set! params (cons dbg-index params))
2882		   (set! debug-info (cons info debug-info))
2883		   (set! dbg-index (add1 dbg-index)))
2884		 (set! params (cons #f params)))
2885	     (set! allocated (+ allocated demand))
2886	     (make-node class params (mapwalk subs e e-count here boxes))))
2887
2888	  ((##core#inline_allocate)
2889	   (set! allocated (+ allocated (second params)))
2890	   (make-node class params (mapwalk subs e e-count here boxes)) )
2891
2892          ((##core#box_float)
2893           (set! allocated (+ allocated 4)) ;; words-per-flonum
2894           (make-node class params (mapwalk subs e e-count here boxes)))
2895
2896	  ((##core#inline_ref)
2897	   (set! allocated (+ allocated (bytes->words (estimate-foreign-result-size (second params)))))
2898	   (make-node class params '()) )
2899
2900	  ((##core#inline_loc_ref)
2901	   (set! allocated (+ allocated (bytes->words (estimate-foreign-result-size (first params)))))
2902	   (make-node class params (mapwalk subs e e-count here boxes)) )
2903
2904	  ((##core#closure)
2905	   (set! allocated (+ allocated (first params) 1))
2906	   (make-node '##core#closure params (mapwalk subs e e-count here boxes)) )
2907
2908	  ((##core#box)
2909	   (set! allocated (+ allocated 2))
2910	   (make-node '##core#box params (list (walk (first subs) e e-count here boxes))) )
2911
2912	  ((##core#updatebox)
2913	   (let* ([b (first subs)]
2914		  [subs (mapwalk subs e e-count here boxes)] )
2915	     (make-node
2916	      (cond [(and (eq? '##core#variable (node-class b))
2917			  (memq (first (node-parameters b)) boxes) )
2918		     (set! fastinits (add1 fastinits))
2919		     '##core#updatebox_i]
2920		    [else class] )
2921	      '()
2922	      subs) ) )
2923
2924	  ((##core#provide)
2925	   ;; Allocate enough space for the ##core#provided property.
2926	   (let ((id (literal (first params))))
2927	     (set! allocated (+ allocated 8))
2928	     (make-node class (list id) '())))
2929
2930	  ((##core#lambda ##core#direct_lambda)
2931	   (let ((temps temporaries)
2932                 (ftemps float-temporaries)
2933		 (sigs signatures)
2934		 (lping looping)
2935		 (alc allocated)
2936		 (direct (eq? class '##core#direct_lambda)) )
2937	     (set! temporaries 0)
2938             (set! float-temporaries '())
2939	     (set! allocated 0)
2940	     (set! signatures '())
2941	     (set! looping 0)
2942	     (##sys#decompose-lambda-list
2943	      (third params)
2944	      (lambda (vars argc rest)
2945		(let* ((id (first params))
2946		       (rest-mode
2947			(and rest
2948			     (let ((rrefs (db-get db rest 'references)))
2949			       (cond ((db-get db rest 'assigned) 'list)
2950				     ((and (not (db-get db rest 'boxed-rest))
2951					   (or (not rrefs) (null? rrefs))) 'none)
2952				     (else (db-get db rest 'rest-parameter)) ) ) ) )
2953		       (body (walk
2954			      (car subs)
2955			      (##sys#fast-reverse (if (eq? 'none rest-mode)
2956						      (butlast vars)
2957						      vars))
2958			      (if (eq? 'none rest-mode)
2959				  (fx- (length vars) 1)
2960				  (length vars))
2961			      id
2962			      '()) ) )
2963		  (when (eq? rest-mode 'none)
2964		    (debugging 'o "unused rest argument" rest id))
2965		  (when (and direct rest)
2966		    (bomb "bad direct lambda" id allocated rest) )
2967		  (hash-table-set!
2968		   lambda-table
2969		   id
2970		   (make-lambda-literal
2971		    id
2972		    (second params)
2973		    vars
2974		    argc
2975		    rest
2976		    (add1 temporaries)
2977                    float-temporaries
2978		    signatures
2979		    allocated
2980		    (or direct (memq id direct-call-ids))
2981		    (or (db-get db id 'closure-size) 0)
2982		    (and (not rest)
2983			 (> looping 0)
2984			 (begin
2985			   (debugging 'o "identified direct recursive calls" id looping)
2986			   #t) )
2987		    (or direct (db-get db id 'customizable))
2988		    rest-mode
2989		    body
2990		    direct) )
2991		  (set! looping lping)
2992		  (set! temporaries temps)
2993                  (set! float-temporaries ftemps)
2994		  (set! allocated alc)
2995		  (set! signatures (lset-adjoin/eq? sigs argc))
2996		  (make-node '##core#proc (list (first params)) '()) ) ) ) ) )
2997
2998	  ((let)
2999	   (let* ([var (first params)]
3000		  [val (first subs)]
3001		  [boxvars (if (eq? '##core#box (node-class val)) (list var) '())] )
3002	     (set! temporaries (add1 temporaries))
3003	     (make-node
3004	      '##core#bind (list 1)	; is actually never used with more than 1 variable
3005	      (list (walk val e e-count here boxes)
3006		    (walk (second subs)
3007			  (append (##sys#fast-reverse params) e) (fx+ e-count 1)
3008			  here (append boxvars boxes)) ) ) ) )
3009
3010	  ((##core#let_float)
3011	   (let ((i (first params))
3012	         (val (first subs)))
3013             (set! float-temporaries (cons i float-temporaries))
3014	     (make-node
3015	      '##core#let_float params
3016	      (list (walk val e e-count here boxes)
3017		    (walk (second subs) e e-count here boxes) ) ) ) )
3018
3019	  ((set!)
3020	   (let ((var (first params))
3021		 (val (first subs)) )
3022	     (cond ((posq var e)
3023		    => (lambda (i)
3024			 (make-node '##core#setlocal
3025				    (list (fx- e-count (fx+ i 1)))
3026				    (list (walk val e e-count here boxes)) ) ) )
3027		   (else
3028		    (let* ((cval (node-class val))
3029			   (blockvar (not (variable-visible?
3030					   var block-compilation)))
3031			   (immf (or (and (eq? cval 'quote) (immediate? (first (node-parameters val))))
3032				     (and (pair? (cdr params)) (second params))
3033				     (eq? '##core#undefined cval) ) ) )
3034		      (when blockvar (set! fastsets (add1 fastsets)))
3035		      (make-node
3036		       (if immf '##core#setglobal_i '##core#setglobal)
3037		       (list (if blockvar
3038				 (blockvar-literal var)
3039				 (literal var) )
3040			     blockvar
3041			     var)
3042		       (list (walk (car subs) e e-count here boxes)) ) ) ) ) ) )
3043
3044	  ((##core#call)
3045	   (let* ((len (length (cdr subs)))
3046		  (p2 (pair? (cdr params)))
3047		  (source-info (and p2 (second params))))
3048	     (set! signatures (lset-adjoin/eq? signatures len))
3049	     (when (and (>= (length params) 3) (eq? here (third params)))
3050	       (set! looping (add1 looping)) )
3051               (if (and emit-debug-info source-info)
3052                 (let ((info (list dbg-index 'C_DEBUG_CALL
3053				   (source-info->line source-info)
3054				   (source-info->name source-info))))
3055                   (set! params (cons dbg-index params))
3056                   (set! debug-info (cons info debug-info))
3057                   (set! dbg-index (add1 dbg-index)))
3058                 (set! params (cons #f params)))
3059	     (make-node class params (mapwalk subs e e-count here boxes))))
3060
3061	  ((##core#recurse)
3062	   (when (first params) (set! looping (add1 looping)))
3063	   (make-node class params (mapwalk subs e e-count here boxes)) )
3064
3065	  ((quote)
3066	   (let ((c (first params)))
3067	     (cond ((and (fixnum? c) (not (big-fixnum? c)))
3068		    (immediate-literal c) )
3069		   ((number? c)
3070		    (cond ((eq? 'fixnum number-type)
3071			   (cond ((and (integer? c) (not (big-fixnum? c)))
3072				  (warning
3073				   (sprintf
3074				       "coerced inexact literal number `~S' to fixnum ~S"
3075				     c (inexact->exact c)))
3076				  (immediate-literal (inexact->exact c)) )
3077				 (else (quit-compiling "cannot coerce inexact literal `~S' to fixnum" c)) ) )
3078			  (else (make-node '##core#literal (list (literal c)) '())) ) )
3079		   ((immediate? c) (immediate-literal c))
3080		   (else (make-node '##core#literal (list (literal c)) '())) ) ) )
3081
3082	  ((if ##core#cond)
3083	   (let* ((test (walk (first subs) e e-count here boxes))
3084		  (t0 temporaries)
3085		  (a0 allocated)
3086		  (x1 (walk (second subs) e e-count here boxes))
3087		  (t1 temporaries)
3088		  (a1 allocated)
3089		  (x2 (walk (third subs) e e-count here boxes)))
3090	     (set! allocated (+ a0 (max (- allocated a1) (- a1 a0))))
3091	     (set! temporaries (+ t0 (max (- temporaries t1) (- t1 t0))))
3092	     (make-node class params (list test x1 x2))))
3093
3094	  ((##core#switch)
3095	   (let* ((exp (walk (first subs) e e-count here boxes))
3096		  (a0 allocated))
3097	     (make-node
3098	      class
3099	      params
3100	      (cons
3101	       exp
3102	       (let loop ((j (first params)) (subs (cdr subs)) (ma 0))
3103		 (set! allocated a0)
3104		 (if (zero? j)
3105		     (let ((def (walk (car subs) e e-count here boxes)))
3106		       (set! allocated (+ a0 (max ma (- allocated a0))))
3107		       (list def))
3108		     (let* ((const (walk (car subs) e e-count here boxes))
3109			    (body (walk (cadr subs) e e-count here boxes)))
3110		       (cons*
3111			const body
3112			(loop (sub1 j) (cddr subs) (max (- allocated a0) ma))))))))))
3113
3114	  ((##core#debug-event)
3115	   (let* ((i dbg-index)
3116		  (params (cons i params)))
3117	     (set! debug-info (cons params debug-info))
3118	     (set! dbg-index (add1 dbg-index))
3119	     (make-node class params '())))
3120
3121	  (else (make-node class params (mapwalk subs e e-count here boxes)) ) ) ) )
3122
3123    (define (mapwalk xs e e-count here boxes)
3124      (map (lambda (x) (walk x e e-count here boxes)) xs) )
3125
3126    (define (literal x)
3127      (cond [(immediate? x) (immediate-literal x)]
3128	    ;; Fixnums that don't fit in 32 bits are treated as non-immediates,
3129	    ;; that's why we do the (apparently redundant) C_blockp check here.
3130	    ((and (##core#inline "C_blockp" x) (##core#inline "C_lambdainfop" x))
3131	     (let ((i lambda-info-literal-count))
3132	       (set! lambda-info-literals (cons x lambda-info-literals))
3133	       (set! lambda-info-literal-count (add1 lambda-info-literal-count))
3134	       (vector i) ) )
3135	    [(posv x literals) => (lambda (p) (fx- literal-count (fx+ p 1)))]
3136	    [else (new-literal x)] ) )
3137
3138    (define (new-literal x)
3139      (let ([i literal-count])
3140	(set! literals (cons x literals))
3141	(set! literal-count (add1 literal-count))
3142	i) )
3143
3144    (define (blockvar-literal var)
3145      (cond
3146       ((list-index (lambda (lit)
3147		      (and (block-variable-literal? lit)
3148			   (eq? var (block-variable-literal-name lit)) ) )
3149		    literals)
3150	=> (lambda (p) (fx- literal-count (fx+ p 1))))
3151       (else (new-literal (make-block-variable-literal var))) ) )
3152
3153    (define (immediate-literal x)
3154      (if (eq? (void) x)
3155	  (make-node '##core#undefined '() '())
3156	  (make-node '##core#immediate
3157		     (cond ((fixnum? x) `(fix ,x))
3158			   ((boolean? x) `(bool ,x))
3159			   ((char? x) `(char ,x))
3160			   ((null? x) '(nil))
3161			   ((eof-object? x) '(eof))
3162			   ;; TODO: Remove once we have a bootstrapping libchicken with bwp-object?
3163			   ((##core#inline "C_bwpp" x) #;(bwp-object? x) '(bwp))
3164			   (else (bomb "bad immediate (prepare)")) )
3165		     '() ) ) )
3166
3167    (debugging 'p "preparation phase...")
3168    (let ((node2 (walk node '() 0 #f '())))
3169      (when (positive? fastinits)
3170	(debugging 'o "fast box initializations" fastinits))
3171      (when (positive? fastrefs)
3172	(debugging 'o "fast global references" fastrefs))
3173      (when (positive? fastsets)
3174	(debugging 'o "fast global assignments" fastsets))
3175      (values node2
3176	      (##sys#fast-reverse literals)
3177	      (##sys#fast-reverse lambda-info-literals)
3178	      lambda-table
3179	      (reverse debug-info) ) ) ))
3180)
Trap