scsh-0.5/scsh/static.scm.in

914 lines
29 KiB
Scheme

#!@prefix@/lib/scsh/scshvm \
-o @prefix@/lib/scsh/scshvm -h 8000000 -i @prefix@/lib/scsh/scsh.image -lm @prefix@/lib/scsh/vm/ps-interface.scm -lm @prefix@/lib/scsh/vm/interfaces.scm -lm @prefix@/lib/scsh/vm/package-defs.scm -lm @prefix@/lib/scsh/vm/s48-package-defs.scm -dm -m static-heaps -e static-heap-linker -s
!#
#!
For testing load this at a scsh prompt
,config ,load ../vm/ps-interface.scm
,config ,load ../vm/interfaces.scm
,config ,load ../vm/package-defs.scm
,config ,load ../vm/s48-package-defs.scm
,config ,load static.scm
,load-package static-heaps
,in static-heaps
!#
;;; Static heap package for the Scheme Shell
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Copyright (c) 1995-1996 by Brian D. Carlstrom.
;;;
;;; based on Scheme48 implementation.
;;; Copyright (c) 1993, 1994 by Richard Kelsey and Jonathan Rees.
;;;
;;; The business of this package is converting a Scheme 48 bytecode
;;; image as embodied in a .image file to a C representation. This C
;;; code is then compiled and linked in with a virtual machine. One
;;; pleasant side effect of this is reduced startup times. Another
;;; good thing is that immutable parts of the image can be shared
;;; between processes.
(define-structure static-heaps
(export static-heap-linker)
(open scheme heap memory data stob struct
heap-extra
vm-architecture
formats
enumerated
signals
tables
defrec-package
scsh)
(begin
;;; static-heap-linker
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; the external entry point
;;; real work in static-heap-linker1
;;; argl is a list of the command line arguments
(define (static-heap-linker argl)
(static-heap-linker1 (parse-options argl))
(exit 0))
;;; parse-options
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; parses the command line options
;;; returns them in an options structure
(define (parse-options argl)
(let ((options (make-options)))
(let loop ((args (cdr argl)))
(cond ((null? args)
(cond ((not (options:output-executable options))
(display "error: -o is a required argument")
(newline)
(usage (car argl)))
((not (options:input-image options))
(display "error: -i is a required argument")
(newline)
(usage (car argl)))))
((equal? (car args) "-i")
(cond ((not (null? (cdr args)))
(set-options:input-image options (cadr args))
(loop (cddr args)))
(else
(display "error: -i requires argument") (newline)
(usage (car argl)))))
((equal? (car args) "-o")
(cond ((not (null? (cdr args)))
(set-options:output-executable options (cadr args))
(loop (cddr args)))
(else
(display "error: -o requires argument") (newline)
(usage (car argl)))))
((equal? (car args) "--args")
(cond ((not (null? (cdr args)))
(set-options:args-parser options (cadr args))
(loop (cddr args)))
(else
(display "error: --args requires argument") (newline)
(usage (car argl)))))
((equal? (car args) "--temp")
(cond ((not (null? (cdr args)))
(set-options:temp-dir options (cadr args))
(loop (cddr args)))
(else
(display "error: --temp requires argument") (newline)
(usage (car argl)))))
((equal? (car args) "--cc")
(cond ((not (null? (cdr args)))
(set-options:cc-command options (cadr args))
(loop (cddr args)))
(else
(display "error: --cc requires argument") (newline)
(usage (car argl)))))
((equal? (car args) "--ld")
(cond ((not (null? (cdr args)))
(set-options:ld-command options (cadr args))
(loop (cddr args)))
(else
(display "error: --ld requires argument") (newline)
(usage (car argl)))))
((equal? (car args) "--libs")
(cond ((not (null? (cdr args)))
(set-options:libraries options (cadr args))
(loop (cddr args)))
(else
(display "error: --libs requires argument") (newline)
(usage (car argl)))))
(else
(format #t "error: unknown argument ~a" (car args))
(newline)
(usage (car argl)))))
(set-options:args-parser
options
(if (options:args-parser options)
(list (options:args-parser options))
'()))
(set-options:temp-dir
options
(or (options:temp-dir options)
(getenv "TMPDIR")
"@TMPDIR@"))
(set-options:cc-command
options
(or (options:cc-command options)
(getenv "CC")
"@CC@ @CFLAGS@"))
(set-options:ld-flags
options
(or (options:ld-flags options)
(getenv "LDFLAGS")
"@LDFLAGS@"))
(set-options:libraries
options
(or (options:libraries options)
(getenv "LIBS")
"@LIBS@"))
options))
;;; usage reporting
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (usage program-name)
(format #t
(string-append
"usage: ~a ~%"
" [-i image]~%"
" [-o executable]~%"
" [--args object]~%"
" [--temp directory]~%"
" [--cc command]~%"
" [--ld command]~%"
" [--libs libraries]~%")
program-name)
(exit 1))
;;; options structure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-record options
(input-image #f) ; the input scheme image file
(output-executable #f) ; the output executable file
(args-parser #f) ; .o file for replacement process_args
(temp-dir #f) ; place for intermediate .c .o files
(cc-command #f) ; command to compile a .c file
(ld-flags #f) ; flags needed to link executable
(libraries #f) ; linbraries need to link executable
)
;;; heap structure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-record heap
(length 0)
(objects '())
)
;;; static-heap-linker1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (static-heap-linker1 options)
;;; munge some options into a more usable form
(set-options:temp-dir
options
(format #f "~a/scsh~s" (options:temp-dir options) (pid)))
(set-options:output-executable
options
(string-append (cwd) "/" (options:output-executable options)))
;;; Read the image
(let ((start ; entry point of image
(read-heap-image (options:input-image options))))
;;; Process the image
(receive (pure impure reloc externs)
(create-heaps-and-tables)
;;; Prepare for output
;;; if directory exists blow it away
;;; useful for repeated runs from within same scsh process
(if (file-exists? (options:temp-dir options))
(cond ((file-directory? (options:temp-dir otions))
(with-cwd (options:temp-dir options)
(let loop ((files (directory-files
(options:temp-dir options)
#t)))
(cond ((not (null? files))
(delete-file (car files))
(loop (cdr files))))))
(delete-directory (options:temp-dir options)))
(else
(delete-file (options:temp-dir options)))))
(create-directory (options:temp-dir options) #o755 #t)
;;; Process the info we gather to make it the output file
(with-cwd (options:temp-dir options)
(write-c-header-file pure impure externs)
(compile-main-c-file start reloc options)
(compile-c-image pure impure reloc externs options)
(link-files options)
(let loop ((files (directory-files
(options:temp-dir options) #t)))
(cond ((not (null? files))
(delete-file (car files))
(loop (cdr files))))))
(delete-directory (options:temp-dir options)))))
;;; read-heap-image
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; reads the scheme48 bytecode image into memory.
;;; returns entry point.
(define (read-heap-image infile)
(let ((bytes (file-info:size (file-info infile))))
(init (inexact->exact (floor (* 1.1 bytes))) infile)))
;; XXX the 1.1 is because we need a little extra space for find-all-xs
;;; create-heaps-and-tables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Walks over the in memory scheme 48 heap image.
;;; Returns
;;; 1.) vector of heaps describing pure heap objects
;;; 2.) vector of heaps describing impure heap objects
;;; 3.) vector of tables descibing relocations
;;; 4.) table of external references
(define (create-heaps-and-tables)
(let* ((n (nchunks)) ; number of chunks we have in image
( pure (make-vector n)) ; immutable bits of each chunk
(impure (make-vector n)) ; mutable bits of each chunk
(reloc (make-vector n)) ; relocation information
(externs (make-table))) ; external references
;; create empty heaps for each chunk
(let loop ((i 0))
(cond ((not (= i n))
(vector-set! pure i (make-heap))
(vector-set! impure i (make-heap))
(vector-set! reloc i (make-table))
(loop (+ i 1)))))
;; here is where we iterate through all the bits
;; we construct our own data structures describing the layout
(scsh-for-each-stored-object
(lambda (chunk)
(display "."))
(lambda (chunk x len)
(let* ((heap ; choose the appropriate heap
(vector-ref (if (mutable? x) impure pure) chunk)))
;; add the relocation information
(table-set! (vector-ref reloc chunk) x (heap:length heap))
;; add object reference to heap chunk
(set-heap:objects heap (cons x (heap:objects heap)))
;; update current heap chunk length
(set-heap:length heap (+ len (heap:length heap)))
;; if we have an external reference handle add it to the list
(if (= (header-type (stob-header x)) (enum stob external))
(table-set! externs
(external-value x)
(vm-string->string (external-name x))))))
(lambda (chunk) 'foo))
(newline)
;; put all the heaps in the correct order
(let loop ((i 0))
(cond ((not (= i n))
(let ((p (vector-ref pure i))
(i (vector-ref impure i)))
(set-heap:objects p (reverse (heap:objects p)))
(set-heap:objects i (reverse (heap:objects i))))
(loop (+ i 1)))))
(values pure impure reloc externs)))
;;; vm-string->string
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; converts a vm-string to a scheme one that we can handle
(define (vm-string->string x)
(cond ((vm-string? x)
(let ((len (vm-string-length x)))
(let loop ((i 0)
(l '()))
(cond ((= i len)
(list->string (reverse l)))
(else
(loop (+ i 1) (cons (vm-string-ref x i) l)))))))
(else
(message x " is not a vm-string"))))
;;; write-c-header-file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; declares the c long arrays for each heap chunk
;;; declares the extern references to other c functions
(define (write-c-header-file pure impure externs)
(call-with-output-file "static.h"
(lambda (port)
(format port "/* Static Heap File Automatically Generated~%")
(format port " * by scsh/static.scm */~%")
;; declare the long arrays for each heap chunk
(let ((n (nchunks)))
(do ((i 0 (+ i 1)))
((= i n))
(format port "extern const long p~s[~s];~%" i
(quotient (heap:length (vector-ref pure i)) 4)))
(do ((i 0 (+ i 1)))
((= i n))
(format port "extern long i~s[~s];~%" i
(quotient (heap:length (vector-ref impure i)) 4))))
;; declare the external references
(table-walk
(lambda (address name)
(format port "const extern ~a();~%" name))
externs)
)))
;;; compile-main-c-file
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; creates the top level interfaces that scheme48 wants to see
;;; p_count i_count
;;; number of chunks
;;; p_areas i_areas
;;; pointers to each chunk
;;; p_sizes i_sizes
;;; sizes of each chunk
;;; entry
;;; the starting entry point
(define (compile-main-c-file start reloc options)
(let ((n (nchunks))
(cc (append (line->list (options:cc-command options)) '(-c))))
(call-with-output-file "static.c"
(lambda (port)
(format port "#include \"static.h\"~%")
(format port "const long p_count = ~s;~%" n)
(format port "const long i_count = ~s;~%" n)
(format port "const long * const p_areas[~s] = {" n)
(do ((i 0 (+ i 1)))
((= i n))
(format port "(const long *) &p~s, " i))
(format port "};~%")
(format port "long * const i_areas[~s] = {" n)
(do ((i 0 (+ i 1)))
((= i n))
(format port "(long *) &i~s, " i))
(format port "};~%")
(format port "const long p_sizes[~s] = {" n)
(do ((i 0 (+ i 1)))
((= i n))
(format port "sizeof(p~s), " i))
(format port "};~%")
(format port "const long i_sizes[~s] = {" n)
(do ((i 0 (+ i 1)))
((= i n))
(format port "sizeof(i~s), " i))
(format port "};~%")
(display "const long entry = " port)
(scsh-emit-descriptor start reloc port)
(write-char #\; port)
(newline port)))
(let ((command (append cc '("static.c"))))
(message command)
(run (,@command)))))
;;; compile-c-image
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; responsible for writing and compiling the pure and impure heaps
(define (compile-c-image pure impure reloc externs options)
(compile-c-image1 pure "p" "const " reloc externs options)
(compile-c-image1 impure "i" "" reloc externs options))
;;; compile-c-image1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; writes and compiles the c long array
(define (compile-c-image1 heap name const reloc externs options)
(let* ((n (nchunks))
(process #f)
(cc (append (line->list (options:cc-command options)) '(-c))))
;; iterate over all the chunks for this part of heap
(let chunk-loop ((c 0))
(cond ((not (= c n))
(let ((filename (format #f "static-~a~s.c" name c)))
(call-with-output-file filename
(lambda (port)
(format port "#include \"static.h\"~%")
(format port "~a long ~a~s[]={~%" const name c)
(let ((heap (vector-ref heap c)))
;; iterate over each object
(let heap-loop ((l (heap:objects heap)))
(cond ((not (null? l))
(scsh-emit-initializer
(car l) reloc externs port)
(heap-loop (cdr l))))))
(display "};" port)
(newline port)))
;; wait for last compile before starting new one
(if process
(wait process))
(let ((command (append cc (list filename))))
(message command)
(set! process (& (,@command))))
(chunk-loop (+ 1 c))))
(else
(wait process))))))
;;; link-files
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; links the .o's from compile-c-files
;;; uses the provided flags and libraries
;;; produces outfile as executable
(define (link-files options)
(let ((n (nchunks))
(ld (append (line->list (options:cc-command options))
(line->list (options:ld-flags options))
`(-o ,(options:output-executable options))))
(libs (line->list (options:libraries options))))
(let ((command (append ld
(let loop ((i 0)
(l '()))
(cond ((not (= i n))
(loop (+ i 1)
(cons
(format #f "static-i~s.o" i)
(cons
(format #f "static-p~s.o" i)
l))))
(else
(reverse
(cons "static.o"
l)))))
(options:args-parser options)
'("-L" "@prefix@/lib/scsh" "-lscshvm")
libs)))
(message command)
(run (,@command)))))
;;; scsh-emit-initializer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; see scheme48 emit-initialize below
(define (scsh-emit-initializer x reloc externs port)
;; emit the header
(write-hex port (stob-header x))
;; handle descriptor vectors and vm-strings.
;; everything else is a byte vector
(cond ((d-vector? x)
(scsh-emit-d-vector-initializer x reloc port))
((vm-string? x)
(scsh-emit-vm-string-initializer x port))
(else
(scsh-emit-b-vector-initializer x externs port)))
(if *comments?*
(begin (display " /* " port)
(writex x port)
(display " */" port)))
(newline port))
;;; scsh-emit-d-vector
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; descriptor vectors are pretty easy given scsh-emit-descriptor
(define (scsh-emit-d-vector-initializer x reloc port)
(let ((len (d-vector-length x)))
(do ((i 0 (+ i 1)))
((= i len))
(scsh-emit-descriptor (d-vector-ref x i) reloc port)
(write-char #\, port))))
;;; scsh-emit-descriptor
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; for descrriptors we consult the relocation table
(define (scsh-emit-descriptor x reloc port)
(if (stob? x)
(let ((n (chunk-number x)))
(display "(long)(&" port)
(if (immutable? x)
(display "p" port)
(display "i" port))
(display n port)
(display "[" port)
(display (quotient (table-ref (vector-ref reloc n) x) 4) port)
(display "])+7" port))
(format port
(if (negative? x) "-0x~a" "0x~a")
(number->string (abs x) 16))))
;;; scsh-emit-vm-string-initializer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; vm-strings are converted to numbers and byte order adjusted
(define (scsh-emit-vm-string-initializer x port)
(let* ((len (vm-string-length x)) ; end is jawilson style hack
(end (- (cells->bytes (bytes->cells (+ len 1))) 4)))
(do ((i 0 (+ i 4)))
((= i end)
(case (- len end)
((0)
(write-hex port 0))
((1)
(write-hex
port
(net-to-host-32 (arithmetic-shift
(char->ascii (vm-string-ref x i)) 24))))
((2)
(write-hex
port
(net-to-host-32
(bitwise-ior
(arithmetic-shift
(char->ascii (vm-string-ref x i)) 24)
(arithmetic-shift
(char->ascii (vm-string-ref x (+ i 1))) 16)))))
((3)
(write-hex
port
(net-to-host-32
(bitwise-ior
(bitwise-ior
(arithmetic-shift
(char->ascii (vm-string-ref x i)) 24)
(arithmetic-shift
(char->ascii (vm-string-ref x (+ i 1))) 16))
(arithmetic-shift
(char->ascii (vm-string-ref x (+ i 2))) 8)))))))
(write-hex port
(net-to-host-32 (bitwise-ior
(bitwise-ior
(arithmetic-shift
(char->ascii
(vm-string-ref x i)) 24)
(arithmetic-shift
(char->ascii
(vm-string-ref x (+ i 1))) 16))
(bitwise-ior
(arithmetic-shift
(char->ascii
(vm-string-ref x (+ i 2))) 8)
(char->ascii
(vm-string-ref x (+ i 3))))))
))))
;;; scsh-emit-b-vector-initializer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; byte vectors are byte order adjusted too
(define (scsh-emit-b-vector-initializer x externs port)
(cond ((and (code-vector? x)
(table-ref externs x)) =>
(lambda (name)
(format port "(long) *~a," name)))
(else
(let* ((len (b-vector-length x)) ;end is jawilson style hack
(end (- (cells->bytes (bytes->cells (+ len 1))) 4)))
(do ((i 0 (+ i 4)))
((= i end)
(case (- len end)
((1)
(write-hex
port
(net-to-host-32
(arithmetic-shift (b-vector-ref x i) 24))))
((2)
(write-hex
port
(net-to-host-32
(bitwise-ior
(arithmetic-shift (b-vector-ref x i) 24)
(arithmetic-shift (b-vector-ref x (+ i 1)) 16)))))
((3)
(write-hex
port
(net-to-host-32
(bitwise-ior
(bitwise-ior
(arithmetic-shift (b-vector-ref x i) 24)
(arithmetic-shift (b-vector-ref x (+ i 1)) 16))
(arithmetic-shift (b-vector-ref x (+ i 2)) 8)))
))))
(write-hex
port
(net-to-host-32 (bitwise-ior
(bitwise-ior
(arithmetic-shift
(b-vector-ref x i) 24)
(arithmetic-shift
(b-vector-ref x (+ i 1)) 16))
(bitwise-ior
(arithmetic-shift
(b-vector-ref x (+ i 2)) 8)
(b-vector-ref x (+ i 3))))))))
)))
;;; scsh-for-each-stored-object
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; see scheme48 for-each-stored-object
;;; Image traversal utility
(define (scsh-for-each-stored-object chunk-start proc chunk-end)
(let ((limit (heap-pointer)))
(let chunk-loop ((addr (newspace-begin))
(i 0)
(chunk (+ (newspace-begin) *chunk-size*)))
(if (addr< addr limit)
(begin (chunk-start i)
(let loop ((addr addr))
(if (and (addr< addr limit)
(addr< addr chunk))
(let* ((d (fetch addr))
(len (addr1+ (header-a-units d))))
(if (not (header? d))
(warn "heap is in an inconsistent state" d))
(proc i
(address->stob-descriptor (addr1+ addr))
len)
(loop (addr+ addr len)))
(begin (chunk-end i)
(chunk-loop addr
(+ i 1)
(+ chunk *chunk-size*))))))))))
;;; write-hex
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; utility routine to print a scheme number as a c hex number
(define (write-hex port x)
(format port
(if (negative? x) "-0x~a," "0x~a,")
(number->string (abs x) 16)))
;;; line->list
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; utility that takes a string and break it into a list at whitespace
;;; rewrite using scsh stuff?
(define (line->list line)
(let ((len (string-length line)))
(let loop ((start 0)
(end 0)
(l '()))
(cond ((>= end len)
(if (= start end)
l
(append l (list (substring line start end)))))
((and (= start end)
(or (char=? (string-ref line start) (ascii->char 32))
(char=? (string-ref line start) (ascii->char 9))))
(loop (+ 1 start)
(+ 1 end)
l))
((or (char=? (string-ref line end) (ascii->char 32))
(char=? (string-ref line end) (ascii->char 9)))
(loop (+ 1 end)
(+ 1 end)
(append l (list (substring line start end)))))
((< end len)
(loop start
(+ 1 end)
l))
(else (error "unexpected case in line->list"))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Debugging
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define (bin n)
(number->string n 2))
(define (oct n)
(number->string n 8))
(define (dec n)
(number->string n 10))
(define (hex n)
(number->string n 16))
;;; Static Heap Code From Scheme48
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; The Scheme 48 version produced monolithic C files that even
;;; the GNU C Compiler couldn't handle, let alone standard vendor
;;; compilers...
;;; It also relied upon the C compiler to fill in some pointer
;;; information. Because I needed to break up the files, I had to
;;; calculate this information myself.
; For example:
; (do-it 100000 "~/s48/debug/little.image" "little-heap.c")
;
; The first argument to do-it should be somewhat larger than the size,
; in bytes, of the image file to be converted (which you can obtain with
; "ls -l").
;
; If the image contains 0-length stored objects, then the .c file will
; have to be compiled by gcc, since 0-length arrays aren't allowed in
; ANSI C. This wouldn't be difficult to work around.
(define *comments?* #f)
; 800,000 bytes => 200,000 words => at least 100,000 objects
; 50 chunks => 16,000 bytes per chunk => 2,000 objects per chunk
(define *chunk-size* 10000)
(define (do-it bytes infile outfile)
(let ((start (init bytes infile)))
(call-with-output-file outfile
(lambda (port)
(format port "#define D(x) (long)(&x)+7~%")
(format port "#define H unsigned long~%")
(emit-area-declarations "p" immutable? "const " port)
(emit-area-declarations "i" mutable? "" port)
(emit-area-initializers "p" immutable? "const " port)
(emit-area-initializers "i" mutable? "" port)
(display "const long entry = " port)
(emit-descriptor start port)
(write-char #\; port)
(newline port)))))
(define (init bytes infile)
(create-memory (quotient bytes 2) quiescent) ;Output of ls -l
(initialize-heap (memory-begin) (memory-size))
(let ((start (read-image infile 0)))
(message (nchunks)
" chunks")
start))
(define (nchunks) (+ (chunk-number (heap-pointer)) 1))
; emit struct declarations for areas
(define (emit-area-declarations name in-area? const port)
(for-each-stored-object
(lambda (chunk)
(message name chunk " declaration")
(display "struct " port) (display name port) (display chunk port)
(display " {" port) (newline port))
(lambda (x)
(if (in-area? x)
(emit-declaration x port)))
(lambda (chunk)
(display "};" port)
(newline port)
(display const port)
(display "extern struct " port) (display name port) (display chunk port)
(write-char #\space port) (display name port) (display chunk port)
(write-char #\; port) (newline port)
chunk)))
(define (emit-declaration x port)
(display " H x" port)
(writex x port)
(cond ((d-vector? x)
(display "; long d" port)
(writex x port)
(write-char #\[ port)
(write (d-vector-length x) port))
((vm-string? x)
(display "; char d" port)
(writex x port)
(write-char #\[ port)
;; Ensure alignment (thanks Ian)
(write (cells->bytes (bytes->cells (b-vector-length x)))
port))
(else
(display "; unsigned char d" port)
(writex x port)
(write-char #\[ port)
;; Ensure alignment
(write (cells->bytes (bytes->cells (b-vector-length x)))
port)))
(display "];" port)
(if *comments?*
(begin (display " /* " port)
(display (enumerand->name (stob-type x) stob) port)
(display " */" port)))
(newline port))
; Emit initializers for areas
(define (emit-area-initializers name in-area? const port)
(for-each-stored-object
(lambda (chunk)
(message name chunk " initializer")
(display const port)
(display "struct " port) (display name port) (write chunk port)
(write-char #\space port) (display name port) (write chunk port)
(display " =" port) (newline port)
(write-char #\{ port) (newline port))
(lambda (x)
(if (in-area? x)
(emit-initializer x port)))
(lambda (chunk)
(display "};" port) (newline port)))
(let ((n (nchunks)))
(format port "const long ~a_count = ~s;~%" name n)
(format port "~a long * const ~a_areas[~s] = {" const name n)
(do ((i 0 (+ i 1)))
((= i n))
(format port "(~a long *)&~a~s, " const name i))
(format port "};~%const long ~a_sizes[~s] = {" name n)
(do ((i 0 (+ i 1)))
((= i n))
(format port "sizeof(~a~s), " name i))
(format port "};~%")))
(define (message . stuff)
(for-each display stuff) (newline))
(define (emit-initializer x port)
(display " " port)
(write (stob-header x) port)
(write-char #\, port)
(cond ((d-vector? x)
(emit-d-vector-initializer x port))
((vm-string? x)
(write-char #\" port)
(let ((len (vm-string-length x)))
(do ((i 0 (+ i 1)))
((= i len) (write-char #\" port))
(let ((c (vm-string-ref x i)))
(cond ((or (char=? c #\") (char=? c #\\))
(write-char #\\ port))
((char=? c #\newline)
(display "\\n\\" port)))
(write-char c port)))))
(else
(write-char #\{ port)
(let ((len (b-vector-length x)))
(do ((i 0 (+ i 1)))
((= i len) (write-char #\} port))
(write (b-vector-ref x i) port)
(write-char #\, port)))))
(write-char #\, port)
(if *comments?*
(begin (display " /* " port)
(writex x port)
(display " */" port)))
(newline port))
(define (emit-d-vector-initializer x port)
(write-char #\{ port)
(let ((len (d-vector-length x)))
(do ((i 0 (+ i 1)))
((= i len) (write-char #\} port))
(emit-descriptor (d-vector-ref x i) port)
(write-char #\, port))))
(define (emit-descriptor x port)
(if (stob? x)
(begin (if (immutable? x)
(display "D(p" port)
(display "D(i" port))
(display (chunk-number x) port)
(display ".x" port)
(writex x port)
(write-char #\) port))
(write x port)))
; Foo
(define (writex x port)
(write (quotient (- (- x (memory-begin)) 7) 4) port))
(define (chunk-number x)
(quotient (- (- x (memory-begin)) 7) *chunk-size*))
; Image traversal utility
(define (for-each-stored-object chunk-start proc chunk-end)
(let ((limit (heap-pointer)))
(let chunk-loop ((addr (newspace-begin))
(i 0)
(chunk (+ (newspace-begin) *chunk-size*)))
(if (addr< addr limit)
(begin (chunk-start i)
(let loop ((addr addr))
(if (and (addr< addr limit)
(addr< addr chunk))
(let ((d (fetch addr)))
(if (not (header? d))
(warn "heap is in an inconsistent state" d))
(proc (address->stob-descriptor (addr1+ addr)))
(loop (addr1+ (addr+ addr (header-a-units d)))))
(begin (chunk-end i)
(chunk-loop addr
(+ i 1)
(+ chunk *chunk-size*))))))))))
(define (mutable? x) (not (immutable? x)))
;; End begin
))