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