e, a pair uses its car and ;;; cdr, a string uses its stringbuf, etc. ;;; ;;; Some things we want to add to the constant table are not actually ;;; Scheme objects: for example, stringbufs, cache cells for toplevel ;;; references, or cache cells for non-closure procedures. For these we ;;; define special record types and add instances of those record types ;;; to the table. ;;; (define-record-type (make-stringbuf string) stringbuf? (string stringbuf-string)) (define-record-type (make-static-procedure code) static-procedure? (code static-procedure-code)) (define-record-type (make-uniform-vector-backing-store bytes element-size) uniform-vector-backing-store? (bytes uniform-vector-backing-store-bytes) (element-size uniform-vector-backing-store-element-size)) (define-record-type (make-cache-cell key) cache-cell? (key cache-cell-key)) (define (simple-vector? obj) (and (vector? obj) (equal? (array-shape obj) (list (list 0 (1- (vector-length obj))))))) (define (simple-uniform-vector? obj) (and (array? obj) (symbol? (array-type obj)) (match (array-shape obj) (((0 n)) #t) (else #f)))) (define (statically-allocatable? x) "Return @code{#t} if a non-immediate constant can be allocated statically, and @code{#f} if it would need some kind of runtime allocation." (or (pair? x) (string? x) (stringbuf? x) (static-procedure? x) (array? x) (syntax? x))) (define (intern-constant asm obj) "Add an object to the constant table, and return a label that can be used to reference it. If the object is already present in the constant table, its existing label is used directly." (define (recur obj) (intern-constant asm obj)) (define (add-desc! label desc) (set-asm-inits! asm (vhash-consq label desc (asm-inits asm)))) (define (init-descriptor obj) (let ((label (recur obj))) (cond ((not label) #f) ((vhash-assq label (asm-inits asm)) => cdr) (else (let ((desc (vector #f #t '()))) (add-desc! label desc) desc))))) (define (add-patch! dst field obj) (match (init-descriptor obj) (#f #f) ((and desc #(emit-init emit-load patches)) (vector-set! desc 2 (acons dst field patches))))) (define (add-init! dst init) (add-desc! dst (vector init #f '()))) (define (intern! obj label) (define (patch! field obj) (add-patch! label field obj)) (define (init! emit-init) (add-init! label emit-init)) (cond ((pair? obj) (patch! 0 (car obj)) (patch! 1 (cdr obj))) ((simple-vector? obj) (let lp ((i 0)) (when (< i (vector-length obj)) (patch! (1+ i) (vector-ref obj i)) (lp (1+ i))))) ((syntax? obj) (patch! 1 (syntax-expression obj)) (patch! 2 (syntax-wrap obj)) (patch! 3 (syntax-module obj)) (patch! 4 (syntax-sourcev obj))) ((stringbuf? obj)) ((static-procedure? obj) ;; Special case, as we can't load the procedure's code using ;; make-non-immediate. (let* ((code (static-procedure-code obj)) (init (lambda (asm label) (emit-static-patch! asm label 1 code) #f))) (add-desc! label (vector init #t '())))) ((cache-cell? obj)) ((symbol? obj) (unless (symbol-interned? obj) (error "uninterned symbol cannot be saved to object file" obj)) (let ((str-label (recur (symbol->string obj)))) (init! (lambda (asm label) (emit-make-non-immediate asm 1 str-label) (emit-string->symbol asm 1 1) (emit-static-set! asm 1 label 0) 1)))) ((string? obj) (patch! 1 (make-stringbuf obj))) ((keyword? obj) (let ((sym-label (recur (keyword->symbol obj)))) (init! (lambda (asm label) (emit-static-ref asm 1 sym-label) (emit-symbol->keyword asm 1 1) (emit-static-set! asm 1 label 0) 1)))) ((number? obj) (let ((str-label (recur (number->string obj)))) (init! (lambda (asm label) (emit-make-non-immediate asm 1 str-label) (emit-string->number asm 1 1) (emit-static-set! asm 1 label 0) 1)))) ((uniform-vector-backing-store? obj)) ((simple-uniform-vector? obj) (let ((width (case (array-type obj) ((vu8 u8 s8) 1) ((u16 s16) 2) ;; Bitvectors are addressed in 32-bit units. ;; Although a complex number is 8 or 16 bytes wide, ;; it should be byteswapped in 4 or 8 byte units. ((u32 s32 f32 c32 b) 4) ((u64 s64 f64 c64) 8) (else (error "unhandled array type" obj))))) (patch! 2 (make-uniform-vector-backing-store (uniform-array->bytevector obj) width)))) ((array? obj) (patch! 1 (shared-array-root obj))) (else (error "don't know how to intern" obj)))) (cond ((immediate-bits asm obj) #f) ((vhash-assoc obj (asm-constants asm)) => cdr) (else (let ((label (gensym "constant"))) ;; Note that calling intern may mutate asm-constants and asm-inits. (intern! obj label) (set-asm-constants! asm (vhash-cons obj label (asm-constants asm))) label)))) (define (intern-non-immediate asm obj) "Intern a non-immediate into the constant table, and return its label." (when (immediate-bits asm obj) (error "expected a non-immediate" obj)) (intern-constant asm obj)) (define (intern-cache-cell asm key) "Intern a cache cell into the constant table, and return its label. If there is already a cache cell with the given scope and key, it is returned instead." (intern-constant asm (make-cache-cell key)))