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