;; VM Scheme -> C translation module ;; (c) 1996-1997 Sebastian Good ;; (c) 1997-2001 PLT (module vm2c mzscheme (require (lib "unitsig.ss") (lib "list.ss")) (require (lib "zodiac-sig.ss" "syntax") (lib "primitives.ss" "syntax")) (require "sig.ss") (require "../sig.ss") (provide vm2c@) (define vm2c@ (unit/sig compiler:vm2c^ (import (compiler:option : compiler:option^) compiler:library^ compiler:cstructs^ (zodiac : zodiac^) compiler:zlayer^ compiler:analyze^ compiler:const^ compiler:rep^ compiler:closure^ compiler:vehicle^ compiler:vmstructs^ compiler:driver^) (define local-vars-at-top? #f) (define (interned? sym) (eq? sym (string->symbol (symbol->string sym)))) (define vm->c:indent-by 4) (define vm->c:indent-spaces (make-string vm->c:indent-by #\space)) (define (vm->c:generate-modglob-name m s) (when (symbol? m) (compiler:get-symbol-const! #f m)) ;; generates symbol const (compiler:get-symbol-const! #f s) ;; generates symbol const (let ([mname (cond [(symbol? m) m] [(not m) '||] [else ;; try to find a useful part of the module-path-index; ;; this is just for debugging. (let-values ([(path base) (module-path-index-split m)]) (cond [(and (pair? path) (eq? 'lib (car path)) (pair? (cdr path)) (string? (cadr path))) (string->symbol (cadr path))] [else (string->symbol "MoD")]))])]) (let ([name (symbol-append 'GL (compiler:gensym) mname '_ s)]) (string->symbol (compiler:clean-string (symbol->string name)))))) (define vm->c:bucket-name (lambda (mod var) ;; Shouldn't generate any new names: (mod-glob-cname (compiler:add-global-varref! mod var #f #f #f #f)))) (define (vm->c:SYMBOLS-name) (if (compiler:multi-o-constant-pool) (format "SYMBOLS~a" (compiler:get-setup-suffix)) "SYMBOLS")) (define (vm->c:INEXACTS-name) "INEXACTS") (define (vm->c:STRING-name) "STRINGS") (define (vm->c:make-symbol-const-string sc) (format "~a[~a]" (vm->c:SYMBOLS-name) (zodiac:varref-var sc))) (define (vm->c:emit-list! port comma c-comment? table counter -symbol->string) (let ([v (make-vector counter)]) (hash-table-for-each table (lambda (sym b) (vector-set! v (string->number (symbol->string (zodiac:varref-var b))) sym))) (let loop ([i 0]) (unless (= i (vector-length v)) (fprintf port " ~s~a ~a~n" (-symbol->string (vector-ref v i)) comma (if c-comment? (format "/* ~a */" i) (format "; ~a" i))) (loop (add1 i)))))) (define (vm->c:emit-symbol-list! port comma c-comment?) (vm->c:emit-list! port comma c-comment? (const:get-symbol-table) (const:get-symbol-counter) (if c-comment? symbol->string ;; Hack: wrap with parens to indicate uninterned (lambda (s) ((if (interned? s) values list) (symbol->string s)))))) (define (vm->c:emit-symbol-length-list! port comma c-comment?) (vm->c:emit-list! port comma c-comment? (const:get-symbol-table) (const:get-symbol-counter) (lambda (s) (string-length (symbol->string s))))) (define (vm->c:emit-symbol-declarations! port) (unless (zero? (const:get-symbol-counter)) (unless (compiler:multi-o-constant-pool) (fprintf port "static const char *SYMBOL_STRS[~a] = {~n" (const:get-symbol-counter)) (vm->c:emit-symbol-list! port "," #t) (fprintf port "}; /* end of SYMBOL_STRS */~n~n") (fprintf port "static const long SYMBOL_LENS[~a] = {~n" (const:get-symbol-counter)) (vm->c:emit-symbol-length-list! port "," #t) (fprintf port "}; /* end of SYMBOL_LENS */~n~n")) (fprintf port "~aScheme_Object * ~a[~a];~n~n" (if (compiler:multi-o-constant-pool) "" "static ") (vm->c:SYMBOLS-name) (const:get-symbol-counter)))) (define (vm->c:emit-syntax-string-declarations! port) (let ([l (const:get-syntax-strings)]) (unless (null? l) (fprintf port "static Scheme_Object *SS[~a];~n~n" (length l)) (for-each (lambda (ss) (emit-string port "char" (syntax-string-str ss) (format "SYNTAX_STRING_~a" (syntax-string-id ss)))) l)))) (define (vm->c:emit-inexact-list! port comma comment?) (vm->c:emit-list! port comma comment? (const:get-inexact-table) (const:get-inexact-counter) (lambda (x) (string->number (symbol->string x))))) (define (vm->c:emit-inexact-declarations! port) (unless (zero? (const:get-inexact-counter)) (fprintf port "static const double INEXACT_NUMBERS[~a] = {~n" (const:get-inexact-counter)) (vm->c:emit-inexact-list! port "," #t) (fprintf port "}; /* end of INEXACT_NUMBERS */~n~n") (fprintf port "static Scheme_Object * ~a[~a];~n~n" (vm->c:INEXACTS-name) (const:get-inexact-counter)))) (define (emit-string-declarations! port table kind) (hash-table-for-each table (lambda (str index) (emit-string port kind str (format "STRING_~a" index))))) (define (vm->c:emit-string-declarations! port) (emit-string-declarations! port (const:get-string-table) "mzchar") (emit-string-declarations! port (const:get-bytes-table) "char")) (define emit-string (lambda (port kind str name) (let* ([len (if (string? str) (string-length str) (bytes-length str))]) (let ([friendly (if (string? str) (substring str 0 (min len 24)) (bytes->string/latin-1 (subbytes str 0 (min len 24))))]) (fprintf port "/* ~a */~n" (list->string (map (lambda (i) (cond [(eq? i #\/) #\_] [(<= 32 (char->integer i) 121) i] [else #\_])) (string->list friendly))))) (fprintf port "static const ~a ~a[~a] = {" kind name (add1 len)) (let loop ([i 0]) (unless (= i len) (when (zero? (modulo i 20)) (fprintf port "~n ")) (fprintf port "~a, " (if (string? str) (char->integer (string-ref str i)) (bytes-ref str i))) (loop (add1 i))))) (fprintf port "0 }; /* end of ~a */~n~n" name))) (define (vm->c:emit-symbol-definitions! port) (unless (zero? (const:get-symbol-counter)) (fprintf port " int i;~n") (fprintf port " for (i = ~a; i--; )~n SYMBOLS[i] = scheme_intern_exact_symbol(SYMBOL_STRS[i], SYMBOL_LENS[i]);~n" (const:get-symbol-counter)) ;; Some symbols might be uninterned... (hash-table-for-each (const:get-symbol-table) (lambda (sym b) (unless (interned? sym) (let ([pos (zodiac:varref-var b)]) (fprintf port " SYMBOLS[~a] = scheme_make_exact_symbol(SYMBOL_STRS[~a], SYMBOL_LENS[~a]); /* uninterned */~n" pos pos pos))))))) (define (vm->c:emit-syntax-string-definitions! port) (let ([l (const:get-syntax-strings)]) (unless (null? l) (for-each (lambda (ss) (let ([id (syntax-string-id ss)] [symbols (vm->c:SYMBOLS-name)]) (fprintf port " SS[~a] = scheme_load_compiled_stx_string(SYNTAX_STRING_~a, ~a);~n" id id (bytes-length (syntax-string-str ss))) ;; Reset uninterned symbols: (let loop ([uposes (syntax-string-uposes ss)][i (syntax-string-ustart ss)]) (unless (null? uposes) (fprintf port " ~a[~a] = scheme_compiled_stx_symbol(SCHEME_VEC_ELS(SS[~a])[~a]);~n" symbols (car uposes) id i) (loop (cdr uposes) (add1 i)))))) l)))) (define (vm->c:emit-inexact-definitions! port) (unless (zero? (const:get-inexact-counter)) (fprintf port " int i;~n") (fprintf port " for (i = ~a; i--; )~n INEXACTS[i] = scheme_make_double(INEXACT_NUMBERS[i]);~n" (const:get-inexact-counter)))) (define vm->c:emit-prim-ref-declarations! (lambda (port) (unless (set-empty? (compiler:get-primitive-refs)) (fprintf port "/* primitives referenced by the code */~n") (fprintf port "static struct {~n") (for-each (lambda (a) (fprintf port " Scheme_Object * ~a;~n" (vm->c:convert-symbol (vm->c:bucket-name '#%kernel a)))) (set->list (compiler:get-primitive-refs))) (fprintf port "} P;~n") (newline port)))) (define vm->c:emit-prim-ref-definitions! (lambda (port) (unless (set-empty? (compiler:get-primitive-refs)) (fprintf port " /* primitives referenced by the code */~n") (for-each (lambda (a) (fprintf port "~aP.~a = scheme_module_bucket(~a, ~a, -1, env)->val;~n" vm->c:indent-spaces (vm->c:convert-symbol (vm->c:bucket-name '#%kernel a)) (vm->c:make-symbol-const-string (compiler:get-symbol-const! #f '#%kernel)) (vm->c:make-symbol-const-string (compiler:get-symbol-const! #f a)))) (set->list (compiler:get-primitive-refs)))))) (define vm->c:emit-struct-definitions! (lambda (structs port) (fprintf port "/* compiler-written structures */~n") (for-each (lambda (struct) (fprintf port "struct ~a~n{~n" (vm->c:convert-symbol (rep:struct-name struct))) (for-each (lambda (field) (fprintf port "~a~a ~a;~n" vm->c:indent-spaces (vm->c:convert-type-definition (rep:struct-field-rep field)) (vm->c:convert-symbol (rep:struct-field-name field)))) (rep:struct-fields struct)) (fprintf port "};~n")) (reverse structs)) (newline port))) (define (compiler:any-statics?) (not (and (null? (compiler:get-static-list)) (null? (compiler:get-case-lambdas)) (null? (compiler:get-lifted-lambda-vars))))) (define (emit-static-variable-fields! port l) (unless (null? l) (fprintf port " /* Write fields as an array to help C compilers */~n") (fprintf port " /* that don't like really big records. */~n") (fprintf port " Scheme_Object * _consts_[~a];~n" (length l)) (let svloop ([l l][n 0]) (unless (null? l) (fprintf port "# define ~a _consts_[~a]~n" (vm->c:convert-symbol (car l)) n) (svloop (cdr l) (add1 n)))))) ;; when statics have binding information, this will look more like ;; emit-local-variable-declarations! (define vm->c:emit-static-declarations! (lambda (port) (unless (not (compiler:any-statics?)) (fprintf port "/* compiler-written static variables */~n") (fprintf port "static struct {~n") (emit-static-variable-fields! port (compiler:get-static-list)) (unless (null? (compiler:get-case-lambdas)) (fprintf port " mzshort *casesArities[~a];~n" (length (compiler:get-case-lambdas)))) (for-each (lambda (ll) (fprintf port " Scheme_Object * ~a;~n" (vm->c:convert-symbol (zodiac:varref-var ll)))) (compiler:get-lifted-lambda-vars)) (fprintf port "} S;~n~n")) (fprintf port "/* compiler-written per-load static variables */~n") (fprintf port "typedef struct Scheme_Per_Load_Statics {~n") (if (null? (compiler:get-per-load-static-list)) (fprintf port " int dummy;~n") (emit-static-variable-fields! port (compiler:get-per-load-static-list))) (fprintf port "} Scheme_Per_Load_Statics;~n") (newline port) (let ([ht (make-hash-table)]) ;; Gather per-invoke statics with the same invoke id (let ([l (compiler:get-per-invoke-static-list)]) (for-each (lambda (p) (let ([mi (cdr p)] [var (car p)]) (hash-table-put! ht (varref:module-invoke-id mi) (cons (cons var (varref:module-invoke-syntax? mi)) (hash-table-get ht (varref:module-invoke-id mi) (lambda () null)))))) l) ;; Make sure that every module has a struct: (let loop ([i 0]) (unless (= i (get-num-module-invokes)) (hash-table-get ht i (lambda () (hash-table-put! ht i null))) (loop (add1 i)))) (hash-table-for-each ht (lambda (id vars) (fprintf port "/* compiler-written per-invoke variables for module ~a */~n" id) (let ([vars (map car (filter (lambda (i) (not (cdr i))) vars))] [syntax-vars (map car (filter (lambda (i) (cdr i)) vars))]) (fprintf port "typedef struct Scheme_Per_Invoke_Statics_~a {~n" id) (if (null? vars) (fprintf port " int dummy;~n") (emit-static-variable-fields! port vars)) (fprintf port "} Scheme_Per_Invoke_Statics_~a;~n" id) (fprintf port "typedef struct Scheme_Per_Invoke_Syntax_Statics_~a {~n" id) (if (null? syntax-vars) (fprintf port " int dummy;~n") (emit-static-variable-fields! port syntax-vars)) (fprintf port "} Scheme_Per_Invoke_Syntax_Statics_~a;~n" id) (newline port)))))))) ;; when statics have binding information, this need only register ;; pointer declarations (define vm->c:emit-registration! (lambda (port) (fprintf port "~a/* register compiler-written static variables with GC */~n" vm->c:indent-spaces) (let ([register (lambda (v) (fprintf port "~ascheme_register_extension_global(&~a, sizeof(~a));~n" vm->c:indent-spaces v v))]) (unless (or (zero? (const:get-symbol-counter)) (compiler:multi-o-constant-pool)) (register "SYMBOLS")) (unless (zero? (const:get-inexact-counter)) (register "INEXACTS")) (unless (set-empty? (compiler:get-primitive-refs)) (register "P")) (unless (not (compiler:any-statics?)) (register "S")) (unless (null? (const:get-syntax-strings)) (register "SS"))) (newline port))) (define (vm->c:emit-case-arities-definitions! port) (fprintf port " /* arity information for compiled case-lambdas */~n") (let caloop ([l (reverse (compiler:get-case-lambdas))][pos 0]) (unless (null? l) (let* ([ast (car l)] [args (zodiac:case-lambda-form-args ast)]) (if (null? args) (fprintf port "~aS.casesArities[~a] = NULL;~n" vm->c:indent-spaces pos) (begin (fprintf port "~a{~n~a mzshort * arities;~n" vm->c:indent-spaces vm->c:indent-spaces) (fprintf port "~a arities = (mzshort *)scheme_malloc_atomic(~a * sizeof(mzshort));~n" vm->c:indent-spaces (* 2 (length args))) (let cailoop ([l args][n 0]) (unless (null? l) (let-values ([(min-arity max-arity) (compiler:formals->arity (car l))]) (fprintf port "~a arities[~a] = ~a;~n~a arities[~a] = ~a;~n" vm->c:indent-spaces (* 2 n) min-arity vm->c:indent-spaces (add1 (* 2 n)) max-arity)) (cailoop (cdr l) (add1 n)))) (fprintf port "~a S.casesArities[~a] = arities;~n" vm->c:indent-spaces pos) (fprintf port "~a}~n" vm->c:indent-spaces)))) (caloop (cdr l) (add1 pos))))) (define (vm->c:emit-top-levels! kind return? per-load? null-self-modidx? count vm-list locals-list globals-list max-arity module mod-syntax? c-port) ;; count == -1 => go to the end of the list (let tls-loop ([i 0] [n 0] [vml vm-list] [ll locals-list] [bl globals-list]) (fprintf c-port "static ~a ~a_~a(Scheme_Env * env~a~a)~n{~n" (if return? "Scheme_Object *" "void") kind i (if (or per-load? module) ", Scheme_Per_Load_Statics *PLS" "") (if module (format ", long phase_shift, Scheme_Object *self_modidx, Scheme_Per_Invoke_~aStatics_~a *PMIS" (if mod-syntax? "Syntax_" "") module) "")) (when null-self-modidx? (fprintf c-port "#define self_modidx NULL~n")) (when (> max-arity 0) (fprintf c-port "~aScheme_Object * arg[~a];~n" vm->c:indent-spaces max-arity) (fprintf c-port "~aScheme_Thread * pr = scheme_current_thread;~n" vm->c:indent-spaces) (fprintf c-port "~aScheme_Object ** tail_buf;~n" vm->c:indent-spaces)) (let loop ([c (compiler:option:max-exprs-per-top-level-set)][n n][vml vml][ll ll][bl bl]) (if (or (zero? c) (null? vml) (= n count)) (begin (unless (or (null? vml) (= n count) (not return?)) (fprintf c-port "~areturn NULL;~n" vm->c:indent-spaces)) (when null-self-modidx? (fprintf c-port "#undef self_modidx~n")) (fprintf c-port "} /* end of ~a_~a */~n~n" kind i) (if (or (null? vml) (= n count)) i (tls-loop (add1 i) n vml ll bl))) (if (not (or (and (not module) (not (vm:module-body? (car vml)))) (and module (vm:module-body? (car vml)) (is-module-invoke? (vm:module-body-invoke (car vml)) module) (eq? (vm:module-body-syntax? (car vml)) mod-syntax?)))) (loop c n (cdr vml) (cdr ll) (cdr bl)) (begin (let ([start (zodiac:zodiac-start (car vml))]) (fprintf c-port "~a{ /* [~a,~a] */~n" vm->c:indent-spaces (zodiac:location-line start) (zodiac:location-column start))) (vm->c:emit-local-variable-declarations! (car ll) (string-append vm->c:indent-spaces vm->c:indent-spaces) c-port) (vm->c:emit-local-bucket-declarations! (car bl) (string-append vm->c:indent-spaces vm->c:indent-spaces) #t c-port) (vm->c:emit-bucket-lookups! (car bl) (string-append vm->c:indent-spaces vm->c:indent-spaces) c-port) (vm->c-expression (car vml) #f c-port vm->c:indent-by #t) (fprintf c-port "~a}~n" vm->c:indent-spaces) (loop (sub1 c) (add1 n) (cdr vml) (cdr ll) (cdr bl)))))))) (define (vm->c:emit-module-glue! port id num num-syntax) (define (out syntax? n) (fprintf port "static void module_invoke~a_~a(" (if syntax? "_syntax" "") id) (fprintf port "Scheme_Env *env, long phase_shift, Scheme_Object *self_modidx, void *pls)~n") (fprintf port "{~n~aScheme_Per_Invoke_~aStatics_~a *PMIS;~n" vm->c:indent-spaces (if syntax? "Syntax_" "") id) (let ([s (format "Scheme_Per_Invoke_~aStatics_~a" (if syntax? "Syntax_" "") id)]) (fprintf port "~aPMIS = (~a *)scheme_malloc(sizeof(~a));~n" vm->c:indent-spaces s s)) (let loop ([j 0]) (unless (j . > . n) (fprintf port "~amodule_~abody_~a_~a(env, (Scheme_Per_Load_Statics *)pls, phase_shift, self_modidx, PMIS);~n" vm->c:indent-spaces (if syntax? "syntax_" "") id j) (loop (add1 j)))) (fprintf port "}~n~n")) (out #f num) (out #t num-syntax)) (define vm->c:emit-vehicle-prototype (lambda (port number) (let ([v (get-vehicle number)]) (fprintf port "static ~a vehicle_~a(~a)" "Scheme_Object *" number (cond [(procedure-vehicle? v) "void * void_param, int argc, Scheme_Object *argv[]"] [else (compiler:internal-error #f "vm->c:emit-vehicle-prototype: unknown closure kind ~a" v)]))))) (define vm->c:emit-vehicle-declaration (lambda (port number) (vm->c:emit-vehicle-prototype port number) (fprintf port "; /* ~a */ ~n" (vehicle-total-labels (get-vehicle number))))) (define vm->c:emit-vehicle-header (lambda (port number) (vm->c:emit-vehicle-prototype port number) (fprintf port "~n{~n"))) (define vm->c:emit-vehicle-prologue (lambda (port vehicle) (let ([max-arity (vehicle-max-arity vehicle)] [max-args (if (procedure-vehicle? vehicle) (procedure-vehicle-max-args vehicle) 0)]) (when (> max-arity 0) ; emit declaration of argument stack (fprintf port "~aScheme_Object * arg[~a];~n" vm->c:indent-spaces max-arity)) (when (> max-args 0) ; emit declaration of global variables for argument passing (let loop ([n 0]) (unless (= n max-args) (fprintf port "~aregister long reg~a;~n" vm->c:indent-spaces n) (loop (+ n 1))))) (when (> max-arity 0) ; tail-buffer-setup (fprintf port "~aScheme_Thread * pr = scheme_current_thread;~n" vm->c:indent-spaces) (fprintf port "~aScheme_Object ** tail_buf;~n" vm->c:indent-spaces))) (when local-vars-at-top? (for-each (lambda (L) (let ([locals (code-local-vars (get-annotation L))]) (vm->c:emit-local-variable-declarations! locals vm->c:indent-spaces port))) (vehicle-lambdas vehicle))) ; emit jump to function... (when (> (vehicle-total-labels vehicle) 1) ; emit switch dispatcher (fprintf port "~aswitch(*(unsigned int*)void_param)~n~a{ " vm->c:indent-spaces vm->c:indent-spaces ) (let loop ([n 0]) (when (and (zero? (modulo n 3)) (not (= n (compiler:get-label-number)))) (fprintf port "~n~a~a" vm->c:indent-spaces vm->c:indent-spaces)) (if (= n (sub1 (vehicle-total-labels vehicle))) (fprintf port "default: goto FGN~a;" n) (begin (fprintf port "case ~a: goto FGN~a;" n n) (loop (add1 n))))) (fprintf port "~n~a}~n" vm->c:indent-spaces)))) (define vm->c:emit-vehicle-epilogue (lambda (port number) (fprintf port "} /* end of vehicle # ~a */~n" number))) ;; Will be expanded to hold environments, perhaps, etc. (define vm->c:convert-type-definition (lambda (rep) (cond [(rep:atomic? rep) (case (rep:atomic-type rep) [(scheme-object) "Scheme_Object *"] [(scheme-bucket) "Scheme_Bucket *"] [(scheme-per-load-static) "struct Scheme_Per_Load_Statics *"] [(scheme-per-invoke-static) (let ([mi (rep:atomic/invoke-module-invoke rep)]) (format "struct Scheme_Per_Invoke_~aStatics_~a *" (if (varref:module-invoke-syntax? mi) "Syntax_" "") (varref:module-invoke-id mi)))] [(label) "int"] [(prim) "Scheme_Closed_Primitive_Proc"] [(prim-case) "Scheme_Closed_Case_Primitive_Proc"] [(begin0-saver) "_Scheme_Begin0_Rec"] [(wcm-saver) "_Scheme_WCM_Rec"] [else (compiler:internal-error #f (format "vm->c:convert-type-definition: ~a not valid atomic type" (rep:atomic-type rep)))])] [(rep:pointer? rep) (string-append (vm->c:convert-type-definition (rep:pointer-to rep)) " *")] [(rep:struct? rep) (format "struct ~a" (vm->c:convert-symbol (rep:struct-name rep)))] [else (compiler:internal-error #f (format "vm->c:convert-type-definition: ~a not a valid representation" rep))]))) ;; must handle structs as well as atomic types (define vm->c:type-definition->malloc (lambda (rep) (let ([s (if (rep:struct? rep) (string-append "struct " (vm->c:convert-symbol (rep:struct-name rep))) (vm->c:convert-type-definition rep))]) (format "(~a *)scheme_malloc(sizeof(~a))" s s)))) (define vm->c:emit-local-variable-declarations! (lambda (locals indent port) (let loop ([locals (set->list locals)]) (if (null? locals) (void) (let* ([bound (car locals)] [rep (binding-rep (get-annotation bound))]) (fprintf port "~a~a ~a;~n" indent (vm->c:convert-type-definition rep) (vm->c:convert-symbol (zodiac:binding-var bound))) (loop (cdr locals))))))) (define vm->c:emit-local-bucket-declarations! (lambda (globals indent top-level? port) (for-each (lambda (var) (cond [(const:per-load-statics-table? var) (unless top-level? (fprintf port "~aScheme_Per_Load_Statics * PLS;~n" indent))] [(varref:module-invoke? var) (unless top-level? (fprintf port "~aScheme_Per_Invoke_Statics_~a * PMIS;~n" indent (varref:module-invoke-id var)))] [else (fprintf port "~aScheme_Bucket * G~a;~n" indent (vm->c:convert-symbol (mod-glob-cname var)))])) (set->list globals)))) (define vm->c:emit-bucket-lookups! (lambda (globals indent port) (for-each (lambda (var) (unless (or (const:per-load-statics-table? var) (varref:module-invoke? var)) (let* ([name (vm->c:convert-symbol (mod-glob-cname var))] [et? (mod-glob-exp-time? var)] [ed? (mod-glob-exp-def? var)] [position (mod-glob-position var)] [mod (mod-glob-modname var)] [in-mod? (mod-glob-in-module? var)] [var (mod-glob-varname var)] [modidx (and (not (symbol? mod)) (compiler:get-module-path-constant mod))] [mod-local (and mod (not (symbol? mod)) (not modidx))] [mod-far (and mod (or (symbol? mod) modidx))]) (fprintf port "~aG~a = scheme_~a~a~a_bucket(~a~a~a, ~a~a~a);~n" indent name (if et? "exptime_" "") (if ed? "expdef_" "") (if mod-far "module" "global") (if mod-far (if (symbol? mod) (vm->c:make-symbol-const-string (compiler:get-symbol-const! #f mod)) (format "~a~a" (cond [(varref:has-attribute? modidx varref:per-load-static) "PLS->"] [(varref:has-attribute? modidx varref:per-invoke-static) "PMIS->"] [else "S."]) (vm->c:convert-symbol (zodiac:varref-var modidx)))) "") (if mod-far ", " "") (vm->c:make-symbol-const-string (compiler:get-symbol-const! #f var)) (if mod-far (or position -1) "") (if mod-far ", " "") (if (or mod-local in-mod?) "env" "SCHEME_CURRENT_ENV(pr)"))))) (set->list globals)))) (define binding-boxed? binding-mutable?) (define vm->c:extract-arguments-into-variables! (lambda (args normal? get-rep get-dest dest-boxed? get-src get-cast has-default? indent port) ; Reverse order for the sake of noticing default arguments (let loop ([args (reverse args)] [n (sub1 (length args))] [last? #t]) (unless (null? args) (let* ([has-default? (has-default? n)] [argv-n (lambda () (if has-default? (format "((argc > ~a) ? ~a : (arg_set_level = ~a, scheme_undefined))" n (get-src n) n) (get-src n)))]) (cond [(or normal? (not last?)) (fprintf port "~a~a = " indent (get-dest n)) (if (dest-boxed? n) ;; if the binding is mutable, we need to make a box and fill it with ;; the correct value (let ([rep (get-rep n)]) (fprintf port "~ascheme_malloc(sizeof(~a));~n" (get-cast n #f) (vm->c:convert-type-definition (rep:pointer-to rep))) (fprintf port "~a*(~a)~a = (~a)~a;~n" indent (vm->c:convert-type-definition rep) (get-dest n) (vm->c:convert-type-definition (rep:pointer-to rep)) (argv-n))) (fprintf port "~a~a;~n" (get-cast n #t) (argv-n))) (loop (cdr args) (sub1 n) #f)] [else ; the rest get pulled into a list (when (dest-boxed? n) (fprintf port "~a~a = ~ascheme_malloc(sizeof(Scheme_Object *));~n" indent (get-dest n) (get-cast n #f))) (fprintf port "~a~a~a = ~ascheme_build_list(argc-~a, argv+~a);~n" indent (if (dest-boxed? n) "*(Scheme_Object * *)" "") (get-dest n) (if (dest-boxed? n) "" (get-cast n #t)) n n) (loop (cdr args) (sub1 n) #f)])))))) (define vm->c:pack-global-registers! (lambda (L which indent port) (let* ([arglist (list-ref (zodiac:case-lambda-form-args L) which)] [args (zodiac:arglist-vars arglist)]) (vm->c:extract-arguments-into-variables! args (zodiac:list-arglist? arglist) (lambda (n) "") ; rep not used since never boxed (lambda (n) (format "reg~a" n)) (lambda (n) #f) ; never boxed (lambda (n) (format "argv[~a]" n)) (lambda (n deref) "(long)") (lambda (n) #f) indent port)))) (define vm->c:emit-private-box-initializations ; Currently, each is filled with undefined, but specialized representations ; will require something different (lambda (bindings indent port) (for-each (lambda (binding) (let* ([rep (binding-rep (get-annotation binding))] [derep (rep:pointer-to rep)]) (fprintf port "~a~a = (~a)~a;~n~a*(~a) = scheme_undefined;~n" indent (vm->c:convert-symbol (zodiac:binding-var binding)) (vm->c:convert-type-definition rep) (vm->c:type-definition->malloc derep) indent (vm->c:convert-symbol (zodiac:binding-var binding))))) bindings))) (define vm->c:emit-undefines (lambda (undefines indent port) (for-each (lambda (name) (fprintf port "#~aundef ~a~n" indent name)) undefines))) (define vm->c:emit-function-prologue (lambda (L port) (let* ([code (get-annotation L)] [label (closure-code-label code)]) (if (= 1 (length (zodiac:case-lambda-form-bodies L))) (values 1 #f) (begin ;; The foreign entry label (fprintf port "FGN~a:~n" label) (let loop ([args (zodiac:case-lambda-form-args L)][i 0]) (if (null? args) (begin (fprintf port "~a~ascheme_case_lambda_wrong_count(~s, argc, argv, ~a, ~a" vm->c:indent-spaces vm->c:indent-spaces (vm->c:extract-inferred-name (closure-code-name code)) (if (procedure-code-method? code) "1" "0") (length (zodiac:case-lambda-form-args L))) (let loop ([l (zodiac:case-lambda-form-args L)]) (unless (null? l) (let-values ([(min-arity max-arity) (compiler:formals->arity (car l))]) (fprintf port ", ~a, ~a" min-arity max-arity) (loop (cdr l))))) (fprintf port ");~n") (fprintf port "~a~areturn NULL;~n" vm->c:indent-spaces vm->c:indent-spaces) (values i #t)) (let ([a (car args)]) (cond [(zodiac:sym-arglist? a) (fprintf port "~a~agoto FGN~ac~a;~n" vm->c:indent-spaces vm->c:indent-spaces label i) (values (add1 i) #t)] [(zodiac:list-arglist? a) (fprintf port "~a~aif (argc == ~a) goto FGN~ac~a;~n" vm->c:indent-spaces vm->c:indent-spaces (length (zodiac:arglist-vars a)) label i) (loop (cdr args) (add1 i))] [else (fprintf port "~a~aif (argc >= ~a) goto FGN~ac~a;~n" vm->c:indent-spaces vm->c:indent-spaces (sub1 (length (zodiac:arglist-vars a))) label i) (loop (cdr args) (add1 i))]))))))))) (define vm->c:emit-extract-env-variables (lambda (code vars indent port) ;; now pull environment variables into registers ;; this is easy because of the way we've set up environments (let loop ([vars vars][undefines null]) (if (null? vars) undefines (let* ([var (if (pair? vars) (car vars) vars)] [vname (zodiac:binding-var var)] [name (vm->c:convert-symbol vname)] [fname (rep:find-field (closure-code-rep code) vname)]) (fprintf port (if (compiler:option:unpack-environments) "~a~a = env->~a;~n" "#~adefine ~a env->~a~n") indent name fname) (let ([undefines (if (compiler:option:unpack-environments) undefines (cons name undefines))]) (if (pair? vars) (loop (cdr vars) undefines) undefines))))))) (define vm->c:emit-extract-bucket-variables (lambda (code vars indent port) ;; pull bucket variables into registers (let loop ([vars vars][undefines null]) (if (null? vars) undefines (let ([var (car vars)]) (cond [(const:per-load-statics-table? var) (begin (fprintf port (if (compiler:option:unpack-environments) "~aPLS = env->pls;~n" "#~adefine PLS env->pls~n") indent) (loop (cdr vars) (if (compiler:option:unpack-environments) undefines (cons "PLS" undefines))))] [(varref:module-invoke? var) (begin (fprintf port (if (compiler:option:unpack-environments) "~aPMIS = env->pmis;~n" "#~adefine PMIS env->pmis~n") indent) (loop (cdr vars) (if (compiler:option:unpack-environments) undefines (cons "PMIS" undefines))))] [else (let* ([vname (mod-glob-cname var)] [name (vm->c:convert-symbol vname)] [fname (rep:find-field (closure-code-rep code) vname)]) (fprintf port (if (compiler:option:unpack-environments) "~aG~a = env->~a;~n" "#~adefine G~a env->~a~n") indent name fname) (loop (cdr vars) (if (compiler:option:unpack-environments) undefines (cons (string-append "G" name) undefines))))])))))) (define vm->c:emit-case-prologue (lambda (L which pre-decl lsuffix indent port) (let* ([code (get-annotation L)] [case-code (list-ref (procedure-code-case-codes code) which)] [label (closure-code-label code)] [undefines null] [used-free-set ; Only unpack anchors if they're captured (let* ([free-set (code-free-vars case-code)] [free-list (set->list free-set)] [captured-list (set->list (code-captured-vars code))] [uncaptured-anchor-set (list->set (let loop ([l free-list]) (if (null? l) null (let ([zb (car l)]) (let ([a (binding-anchor (get-annotation zb))]) (if (and a (not (member zb captured-list))) (cons a (loop (cdr l))) (loop (cdr l))))))))]) (set-minus free-set uncaptured-anchor-set))]) ; The foreign entry label (fprintf port "FGN~a~a:~n" label lsuffix) ; Pull arguments to global registers (vm->c:pack-global-registers! L which indent port) ; The local entry label (fprintf port "LOC~a~a:~n" label lsuffix) (pre-decl) (unless local-vars-at-top? (vm->c:emit-local-variable-declarations! (code-local-vars case-code) indent port)) (when (compiler:option:unpack-environments) (vm->c:emit-local-variable-declarations! used-free-set indent port) (vm->c:emit-local-bucket-declarations! (code-global-vars case-code) indent #f port)) (let ([r (closure-code-rep code)]) (when r ; (fprintf port "~aconst ~a * env;~n" indent (vm->c:convert-type-definition r)) (fprintf port "#~adefine env ((const ~a *)void_param)~n" indent (vm->c:convert-type-definition r)))) ; Registers into local vars (let* ([args (zodiac:arglist-vars (list-ref (zodiac:case-lambda-form-args L) which))]) (vm->c:extract-arguments-into-variables! args #t ; since regN already builds lists as appropriate (lambda (n) (binding-rep (get-annotation (list-ref args n)))) (lambda (n) (vm->c:convert-symbol (zodiac:binding-var (list-ref args n)))) (lambda (n) (binding-boxed? (get-annotation (list-ref args n)))) (lambda (n) (format "reg~a" n)) (lambda (n deref) (format "(~a)" (vm->c:convert-type-definition (let* ([binding (get-annotation (list-ref args n))] [rep (binding-rep binding)]) (if (and deref (binding-boxed? binding)) (rep:pointer-to rep) rep))))) (lambda (n) #f) indent port)) ; reduce register pressure by doing all the env calculations ; after the args have been done ; equate the local registers with the global argument registers ; starting with the env #| (let ([r (closure-code-rep code)]) (when r (fprintf port "~aenv = (~a *)void_param;~n" indent (vm->c:convert-type-definition r)))) |# ; now pull environment variables into registers (set! undefines (append (vm->c:emit-extract-env-variables code (set->list used-free-set) indent port) undefines)) ; pull bucket variables into registers (set! undefines (append (vm->c:emit-extract-bucket-variables code (set->list (code-global-vars case-code)) indent port) undefines)) (when (case-code-has-continue? case-code) (fprintf port "~awhile(1)~n" indent)) undefines))) (define vm->c:emit-case-epilogue (lambda (code which undefines indent port) (fprintf port "#~aundef env~n" indent) (vm->c:emit-undefines undefines indent port))) (define vm->c:emit-function-epilogue (lambda (code close port) (fprintf port "~a~a /* end of function body ~a */~n" vm->c:indent-spaces close (closure-code-label code)))) (define vm->c:convert-symbol (lambda (sym) (compiler:clean-string (symbol->string sym)))) (define vm->c:convert-char (lambda (char) (if ((char->integer char) . > . 127) (char->integer char) (format "'~a'" (cond [(char=? char #\tab) "\\t"] [(char=? char #\newline) "\\n"] [(char=? char #\return) "\\r"] [(char=? char #\space) " "] [(or (char-alphabetic? char) (char-numeric? char)) (string char)] [else (let ([text (number->string (char->integer char) 8)]) (string-append "\\" (make-string (- 3 (string-length text)) #\0) text))]))))) (define vm->c:convert-special-constant (lambda (ast) (cond [(void? (syntax-e (zodiac:zodiac-stx ast))) "scheme_void"] [(undefined? (syntax-e (zodiac:zodiac-stx ast))) "scheme_undefined"] [else (compiler:internal-error #f (format "vm->c:convert-special-constant: ~a not correct" ast))]))) (define vm->c:block-statement? (one-of vm:if? vm:sequence? vm:module-body?)) (define vm->c:extract-inferred-name (let ([nullsym (string->symbol "NULL")]) (lambda (var) (cond [(list? var) (if (= (length var) 1) (vm->c:extract-inferred-name (car var)) nullsym)] [(zodiac:binding? var) (symbol->string (zodiac:binding-orig-name var))] [(zodiac:bound-varref? var) (vm->c:extract-inferred-name (zodiac:bound-varref-binding var))] [(zodiac:varref? var) (symbol->string (zodiac:varref-var var))] [(not var) nullsym] [else (compiler:internal-error #f (format "vm->c:extract-inferred-name: bad var type: ~a" var))])))) (define single-arity? (one-of vm:global-varref? vm:local-varref? vm:static-varref? vm:primitive-varref? vm:symbol-varref? vm:struct-ref? vm:deref? vm:ref? vm:cast? vm:immediate?)) (define is-primitive? (one-of primitive? primitive-closure?)) (define vm->c-expression (lambda (ast code port indent-level no-seq-braces?) (let process ([ast ast] [indent-level indent-level] [own-line? #t] [braces? (not no-seq-braces?)]) (letrec ([emit-indentation (lambda () (display (make-string indent-level #\ ) port))] [indent (lambda () (+ indent-level vm->c:indent-by))] [emit (lambda s (apply fprintf (cons port s)))] [emit-expr (lambda s (when own-line? (emit-indentation)) (apply emit s))] [emit-macro-application (lambda (ast) (let ([args (vm:macro-apply-args ast)]) (emit "~a(" (vm:macro-apply-name ast)) (process (vm:macro-apply-primitive ast) indent-level #f #f) (for-each (lambda (a) (emit ", ~a" (vm->c:convert-symbol (zodiac:binding-var a)))) args) (emit ")")))]) (cond ;; (%sequence V ...) -> { M; ... } [(or (vm:sequence? ast) (vm:module-body? ast)) (let* ([seq ((if (vm:sequence? ast) vm:sequence-vals vm:module-body-vals) ast)]) (when braces? (emit-indentation) (emit "{~n")) (for-each (lambda (v) (process v (indent) #t #t) (unless (vm->c:block-statement? v) (emit ";~n"))) seq) (when braces? (emit-indentation) (emit "}~n")))] ;; (if R (sequence V) (sequence V)) -> ;; if (!SCHEME_FALSEP(A)) { V ... } else { V ...} [(vm:if? ast) (emit-indentation) (let iloop ([ast ast]) (let ([test (vm:if-test ast)] [then (vm:if-then ast)] [else (vm:if-else ast)]) (emit "if (") (let ([direct? (and (vm:macro-apply? test) (vm:macro-apply-bool? test))]) (if direct? (emit-macro-application test) (begin (emit "!SCHEME_FALSEP(") (process test indent-level #f #t) (emit ")")))) (emit ")~n") (process (vm:if-then ast) indent-level #t #t) (let ([else-vals (vm:sequence-vals else)]) (cond [(and (= 1 (length else-vals)) (vm:if? (car else-vals))) (emit-indentation) (emit "else ") (iloop (car else-vals))] [(not (null? else-vals)) (emit-indentation) (emit "else~n") (process (vm:if-else ast) indent-level #f #t)] [else (void)]))))] ;; begin0 stuff [(vm:begin0-mark!? ast) (let ([var (vm->c:convert-symbol (vm:local-varref-var (vm:begin0-mark!-var ast)))]) (emit-indentation) (emit "~a.val = " var) (process (vm:begin0-mark!-val ast) indent-level #f #t))] [(vm:begin0-setup!? ast) (let ([var (vm->c:convert-symbol (vm:local-varref-var (vm:begin0-setup!-var ast)))]) (emit-indentation) (emit "if (~a.val == SCHEME_MULTIPLE_VALUES) {~n" var) (emit-indentation) (emit " ~a.array = pr->ku.multiple.array;~n" var) (emit-indentation) (emit " ~a.count = pr->ku.multiple.count;~n" var) (emit-indentation) (emit " SCHEME_DETATCH_MV_BUFFER(~a.array, pr);~n" var) (emit-indentation) (emit "} else ~a.array = NULL" var))] [(vm:begin0-extract? ast) (let ([var (vm->c:convert-symbol (vm:local-varref-var (vm:begin0-extract-var ast)))]) (emit "(pr->ku.multiple.array = ~a.array," var) (emit " pr->ku.multiple.count = ~a.count, " var) (emit " ~a.val)" var))] ;; single value: (set! L R) -> L = R; ;; multiple value: [(vm:set!? ast) (let* ([process-target! (lambda (target) (let ([type (car target)] [target (cdr target)]) (cond [(eq? type target-type:lexical) (process target indent-level #f #t)] [(eq? type target-type:global) (let ([bucket-name (vm->c:convert-symbol (mod-glob-cname target))]) (emit "G~a->val" bucket-name))] [else (compiler:internal-error #f (format "~a: bad set! target type" type))])))] [process-set! (lambda (target val process-val?) (let ([mode (vm:set!-mode ast)]) (if mode (begin (emit "scheme_set_global_bucket(~s, " (car mode)) (emit "G~a, " (vm->c:convert-symbol (mod-glob-cname (cdr target)))) (if process-val? (process val indent-level #f #t) (emit val)) (emit ", ~a)" (cadr mode))) (begin (process-target! target) (emit " = ") (if process-val? (process val indent-level #f #t) (emit val))))))] [vars (vm:set!-vars ast)] [val (vm:set!-val ast)] [num-to-set (length vars)] [return-arity (or (and (single-arity? val) 1) (and (vm:apply? val) (vm:apply-prim val) (let ([proc (global-defined-value* (vm:apply-prim val))]) (and (is-primitive? proc) (primitive-result-arity proc)))) )]) (emit-indentation) (let ([return-arity-ok? (and return-arity (number? return-arity) (= return-arity num-to-set))]) (if (= num-to-set 1) (process-set! (car vars) val #t) (begin (emit "{ Scheme_Object * res = ") (process val indent-level #f #t) (emit "; ") (unless return-arity-ok? (emit "CHECK_MULTIPLE_VALUES(res, ~a);" num-to-set)) (emit "}") (if (not (null? vars)) (emit "~n")) (let aloop ([vars vars] [n 0]) (unless (null? vars) (emit-indentation) (process-set! (car vars) (format "scheme_multiple_array[~a]" n) #f) (emit ";~n") (aloop (cdr vars) (+ n 1)))) ))))] ;; (define-syntax! x R) or (define-for-syntax! x R) [(vm:syntax!? ast) (let* ([process-set! (lambda (target val process-val? return-arity-ok?) (let ([sym (vm->c:make-symbol-const-string (compiler:get-symbol-const! #f (zodiac:varref-var target)))] [in-module? (varref:has-attribute? target varref:in-module)]) (when process-val? (emit "{ Scheme_Object *mcv = ") (process val indent-level #f #t) (emit "; ")) (unless return-arity-ok? (emit " if (mcv != SCHEME_MULTIPLE_VALUES || scheme_multiple_count) {") (emit " NO_MULTIPLE_VALUES(mcv); ")) (let ([for-stx? (zodiac:top-level-varref-expdef? target)]) (emit "scheme_~a(~ascheme_global_~abucket(~a, ~a), " (if for-stx? "set_global_bucket" "install_macro") (if for-stx? "NULL, " "") (if for-stx? "" "keyword_") sym (if in-module? "env" "SCHEME_CURRENT_ENV(pr)")) (if process-val? (emit "mcv") (emit val)) (when for-stx? (emit ", 1")) (emit ")")) (when (or (not return-arity-ok?) process-val?) (emit ";")) (unless return-arity-ok? (emit " }")) (when process-val? (emit " }"))))] [vars (vm:syntax!-vars ast)] [val (vm:syntax!-val ast)] [in-mod? (vm:syntax!-in-mod? ast)] [num-to-set (length vars)] [return-arity (if (single-arity? val) 1 #f)]) (emit-indentation) (let ([return-arity-ok? (and return-arity (number? return-arity) (= return-arity num-to-set))]) (if (= num-to-set 1) (process-set! (car vars) val #t return-arity-ok?) (begin (emit "{ Scheme_Object * res = ") (process val indent-level #f #t) (emit "; ") (unless return-arity-ok? (unless in-mod? (emit "if (res != SCHEME_MULTIPLE_VALUES || scheme_multiple_count) ")) (emit "CHECK_MULTIPLE_VALUES(res, ~a);" num-to-set)) (emit "}") (if (not (null? vars)) (emit "~n")) (unless in-mod? (emit-indentation) (emit "if (scheme_multiple_count) {~n")) (let aloop ([vars vars] [n 0]) (unless (null? vars) (emit-indentation) (process-set! (car vars) (format "scheme_multiple_array[~a]" n) #f #t) (emit ";~n") (aloop (cdr vars) (+ n 1)))) (unless in-mod? (emit-indentation) (emit "}~n")) ))))] ;; (%args A ...) -> arg[0] = A; ... [(vm:args? ast) ;; skip tail_buf setup if no args (when (and (eq? arg-type:tail-arg (vm:args-type ast)) (not (null? (vm:args-vals ast)))) (emit-indentation) (emit "tail_buf = scheme_tail_apply_buffer_wp(~a, pr);~n" (length (vm:args-vals ast)))) (if (null? (vm:args-vals ast)) (emit-indentation) (let arloop ([n 0] [args (vm:args-vals ast)]) (unless (null? args) (emit-indentation) (let ([argtype (vm:args-type ast)]) (cond [(eq? arg-type:arg argtype) (emit "arg[~a] = " n)] [(eq? arg-type:tail-arg argtype) (emit "tail_buf[~a] = " n)] [(eq? arg-type:register argtype) (emit "reg~a = (long)" n)] [else (compiler:internal-error #f (format "vm->c: ~a unknown arg type" (vm:args-type ast)))])) ;; (emit "DEBUG_CHECK(") ;; DEBUGGING (process (car args) indent-level #f #t) ;; (emit ")") ;; DEBUGGING (unless (null? (cdr args)) (emit ";~n")) (arloop (add1 n) (cdr args)))))] [(vm:register-args? ast) (let ([vars (vm:register-args-vars ast)] [vals (vm:register-args-vals ast)]) (let raloop ([vars vars][vals vals]) (let ([var (car vars)] [val (car vals)]) (emit-indentation) (emit "~a = " (vm->c:convert-symbol (zodiac:binding-var var))) (process val indent-level #f #f) (unless (null? (cdr vars)) (emit ";~n") (raloop (cdr vars) (cdr vals))))))] ;; (alloc ) -> malloc ;; a bit complicated [(vm:alloc? ast) (emit (vm->c:type-definition->malloc (vm:alloc-type ast)))] ;; (make-closure) -> _scheme_make_c_closure [(vm:make-procedure-closure? ast) (emit "_scheme_make_c_proc_closure~a(vehicle_~a, " (if (vm:make-procedure-closure-empty? ast) "_empty" "") (vm:make-procedure-closure-vehicle ast)) (process (vm:make-closure-closure ast) indent-level #f #t) (emit ", ~s, ~a, ~a, ~a)" (vm->c:extract-inferred-name (vm:make-procedure-closure-name ast)) (vm:make-procedure-closure-min-arity ast) (vm:make-procedure-closure-max-arity ast) (if (vm:make-procedure-closure-method? ast) "SCHEME_PRIM_IS_METHOD" "0"))] [(vm:make-case-procedure-closure? ast) (emit "_scheme_make_c_case_proc_closure~a(vehicle_~a, " (if (vm:make-case-procedure-closure-empty? ast) "_empty" "") (vm:make-case-procedure-closure-vehicle ast)) (process (vm:make-closure-closure ast) indent-level #f #t) (emit ", ~s, ~a, S.casesArities[~a], ~a)" (vm->c:extract-inferred-name (vm:make-case-procedure-closure-name ast)) (vm:make-case-procedure-closure-num-cases ast) (vm:make-case-procedure-closure-case-arities ast) (if (vm:make-case-procedure-closure-method? ast) "SCHEME_PRIM_IS_METHOD" "0"))] [(vm:deref? ast) (emit "(*") (process (vm:deref-var ast) indent-level #f #t) (emit ")")] [(vm:ref? ast) (emit "(&") (process (vm:ref-var ast) indent-level #f #t) (emit ")")] ; optimize (*X).Y to X->Y [(vm:struct-ref? ast) (let ([var (vm:struct-ref-var ast)]) (if (vm:deref? var) (begin (process (vm:deref-var var) indent-level #f #t) (emit "->")) (begin (process (vm:struct-ref-var ast) indent-level #f #t) (emit "."))) (emit "~a" (vm->c:convert-symbol (vm:struct-ref-field ast))))] [(vm:cast? ast) (emit "(") (emit (vm->c:convert-type-definition (vm:cast-rep ast))) (emit ")(") (process (vm:cast-val ast) indent-level #f #t) (emit ")")] [(vm:check-global? ast) (emit-expr (format "CHECK_GLOBAL_BOUND(G~a)" (vm->c:convert-symbol (mod-glob-cname (vm:check-global-var ast)))))] [(vm:module-create? ast) (emit-expr "scheme_declare_module(") (process (vm:module-create-shape ast) indent-level #f #f) (emit ", module_invoke_~a, module_invoke_syntax_~a, PLS, SCHEME_CURRENT_ENV(pr)" (vm:module-create-id ast) (vm:module-create-id ast)) (emit ")")] ;; with-continuation-mark [(vm:wcm-mark!? ast) (emit-expr "scheme_set_cont_mark(") (process (vm:wcm-mark!-key ast) indent-level #f #f) (emit ", ") (process (vm:wcm-mark!-val ast) indent-level #f #f) (emit ")")] [(vm:wcm-push!? ast) (let ([var (vm->c:convert-symbol (vm:local-varref-var (vm:wcm-push!-var ast)))]) (emit-indentation) (emit "scheme_push_continuation_frame(&~a.cf)" var))] [(vm:wcm-pop!? ast) (let ([var (vm->c:convert-symbol (vm:local-varref-var (vm:wcm-pop!-var ast)))]) (emit-indentation) (emit "scheme_pop_continuation_frame(&~a.cf)" var))] [(vm:wcm-remember!? ast) (let ([var (vm->c:convert-symbol (vm:local-varref-var (vm:wcm-remember!-var ast)))]) (emit-indentation) (emit "scheme_temp_dec_mark_depth();~n") (emit-indentation) (emit "~a.val = " var) (process (vm:wcm-remember!-val ast) indent-level #f #t) (emit ";~n") (emit-indentation) (emit "scheme_temp_inc_mark_depth()"))] [(vm:wcm-extract? ast) (let ([var (vm->c:convert-symbol (vm:local-varref-var (vm:wcm-extract-var ast)))]) (emit "~a.val" var))] ;; (continue) -> continue; [(vm:continue? ast) (unless (compiler:option:disable-interrupts) (emit-expr "SCHEME_USE_FUEL(1);~n")) (emit-expr "continue")] ;; use NULL instead of tail_buf if no args ;; (tail-apply A ) -> return _scheme_tail_apply(A, argc); [(vm:tail-apply? ast) (emit-expr "return _scheme_tail_apply_no_copy_wp(") (process (vm:tail-apply-closure ast) indent-level #f #t) (let ([c (vm:tail-apply-argc ast)]) (emit ", ~a, ~a, pr)" c (if (zero? c) "NULL" 'tail_buf)))] ;; (tail-call