#lang typed/racket/base
(require "expression-structs.rkt"
"lexical-structs.rkt"
"il-structs.rkt"
"compiler-structs.rkt"
"kernel-primitives.rkt"
"optimize-il.rkt"
"analyzer-structs.rkt"
"../parameters.rkt"
"../sets.rkt"
racket/bool
racket/list
racket/match)
(require/typed "../logger.rkt"
[log-debug (String -> Void)])
(provide (rename-out [-compile compile])
compile-general-procedure-call
append-instruction-sequences)
(: -compile (Expression Target Linkage -> (Listof Statement)))
(define (-compile exp target linkage)
(let* ([after-lam-bodies (make-label 'afterLamBodies)]
[before-pop-prompt-multiple (make-label 'beforePopPromptMultiple)]
[before-pop-prompt (make-LinkedLabel
(make-label 'beforePopPrompt)
before-pop-prompt-multiple)])
(optimize-il
(statements
(append-instruction-sequences
(make-GotoStatement (make-Label after-lam-bodies))
(compile-lambda-bodies (collect-all-lambdas-with-bodies exp))
after-lam-bodies
(make-PushControlFrame/Prompt default-continuation-prompt-tag
before-pop-prompt)
(compile exp '() 'val return-linkage/nontail)
before-pop-prompt-multiple
(make-PopEnvironment (make-Reg 'argcount) (make-Const 0))
before-pop-prompt
(if (eq? target 'val)
empty-instruction-sequence
(make-AssignImmediateStatement target (make-Reg 'val))))))))
(define-struct: lam+cenv ([lam : (U Lam CaseLam)]
[cenv : CompileTimeEnvironment]))
(: collect-all-lambdas-with-bodies (Expression -> (Listof lam+cenv)))
(define (collect-all-lambdas-with-bodies exp)
(let: loop : (Listof lam+cenv)
([exp : Expression exp]
[cenv : CompileTimeEnvironment '()])
(cond
[(Top? exp)
(loop (Top-code exp) (cons (Top-prefix exp) cenv))]
[(Module? exp)
(loop (Module-code exp) (cons (Module-prefix exp) cenv))]
[(Constant? exp)
'()]
[(LocalRef? exp)
'()]
[(ToplevelRef? exp)
'()]
[(ToplevelSet? exp)
(loop (ToplevelSet-value exp) cenv)]
[(Branch? exp)
(append (loop (Branch-predicate exp) cenv)
(loop (Branch-consequent exp) cenv)
(loop (Branch-alternative exp) cenv))]
[(Lam? exp)
(cons (make-lam+cenv exp cenv)
(loop (Lam-body exp)
(extract-lambda-cenv exp cenv)))]
[(CaseLam? exp)
(cons (make-lam+cenv exp cenv)
(apply append (map (lambda: ([lam : (U Lam EmptyClosureReference)])
(loop lam cenv))
(CaseLam-clauses exp))))]
[(EmptyClosureReference? exp)
'()]
[(Seq? exp)
(apply append (map (lambda: ([e : Expression]) (loop e cenv))
(Seq-actions exp)))]
[(Splice? exp)
(apply append (map (lambda: ([e : Expression]) (loop e cenv))
(Splice-actions exp)))]
[(Begin0? exp)
(apply append (map (lambda: ([e : Expression]) (loop e cenv))
(Begin0-actions exp)))]
[(App? exp)
(let ([new-cenv (append (build-list (length (App-operands exp)) (lambda: ([i : Natural]) '?))
cenv)])
(append (loop (App-operator exp) new-cenv)
(apply append (map (lambda: ([e : Expression]) (loop e new-cenv)) (App-operands exp)))))]
[(Let1? exp)
(append (loop (Let1-rhs exp)
(cons '? cenv))
(loop (Let1-body exp)
(cons (extract-static-knowledge (Let1-rhs exp) (cons '? cenv))
cenv)))]
[(LetVoid? exp)
(loop (LetVoid-body exp)
(append (build-list (LetVoid-count exp) (lambda: ([i : Natural]) '?))
cenv))]
[(InstallValue? exp)
(loop (InstallValue-body exp) cenv)]
[(BoxEnv? exp)
(loop (BoxEnv-body exp) cenv)]
[(LetRec? exp)
(let ([n (length (LetRec-procs exp))])
(let ([new-cenv (append (map (lambda: ([p : Lam])
(extract-static-knowledge
p
(append (build-list (length (LetRec-procs exp))
(lambda: ([i : Natural]) '?))
(drop cenv n))))
(LetRec-procs exp))
(drop cenv n))])
(append (apply append
(map (lambda: ([lam : Lam])
(loop lam new-cenv))
(LetRec-procs exp)))
(loop (LetRec-body exp) new-cenv))))]
[(WithContMark? exp)
(append (loop (WithContMark-key exp) cenv)
(loop (WithContMark-value exp) cenv)
(loop (WithContMark-body exp) cenv))]
[(ApplyValues? exp)
(append (loop (ApplyValues-proc exp) cenv)
(loop (ApplyValues-args-expr exp) cenv))]
[(DefValues? exp)
(append (loop (DefValues-rhs exp) cenv))]
[(PrimitiveKernelValue? exp)
'()]
[(VariableReference? exp)
(loop (VariableReference-toplevel exp) cenv)]
[(Require? exp)
'()])))
(: extract-lambda-cenv (Lam CompileTimeEnvironment -> CompileTimeEnvironment))
(define (extract-lambda-cenv lam cenv)
(append (map (lambda: ([d : Natural])
(list-ref cenv d))
(Lam-closure-map lam))
(build-list (if (Lam-rest? lam)
(add1 (Lam-num-parameters lam))
(Lam-num-parameters lam))
(lambda: ([i : Natural]) '?))))
(: end-with-linkage (Linkage CompileTimeEnvironment InstructionSequence -> InstructionSequence))
(define (end-with-linkage linkage cenv instruction-sequence)
(append-instruction-sequences instruction-sequence
(compile-linkage cenv linkage)))
(: compile-linkage (CompileTimeEnvironment Linkage -> InstructionSequence))
(define (compile-linkage cenv linkage)
(cond
[(ReturnLinkage? linkage)
(cond
[(ReturnLinkage-tail? linkage)
(append-instruction-sequences
(make-PopEnvironment (make-Const (length cenv))
(make-Const 0))
(make-AssignImmediateStatement 'proc (make-ControlStackLabel))
(make-PopControlFrame)
(make-GotoStatement (make-Reg 'proc)))]
[else
(append-instruction-sequences
(make-AssignImmediateStatement 'proc (make-ControlStackLabel))
(make-PopControlFrame)
(make-GotoStatement (make-Reg 'proc)))])]
[(NextLinkage? linkage)
empty-instruction-sequence]
[(LabelLinkage? linkage)
(make-GotoStatement (make-Label (LabelLinkage-label linkage)))]))
(: compile (Expression CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile exp cenv target linkage)
(cond
[(Top? exp)
(compile-top exp cenv target linkage)]
[(Module? exp)
(compile-module exp cenv target linkage)]
[(Constant? exp)
(compile-constant exp cenv target linkage)]
[(LocalRef? exp)
(compile-local-reference exp cenv target linkage)]
[(ToplevelRef? exp)
(compile-toplevel-reference exp cenv target linkage)]
[(ToplevelSet? exp)
(compile-toplevel-set exp cenv target linkage)]
[(Branch? exp)
(compile-branch exp cenv target linkage)]
[(Lam? exp)
(compile-lambda exp cenv target linkage)]
[(CaseLam? exp)
(compile-case-lambda exp cenv target linkage)]
[(EmptyClosureReference? exp)
(compile-empty-closure-reference exp cenv target linkage)]
[(Seq? exp)
(compile-sequence (Seq-actions exp)
cenv
target
linkage)]
[(Splice? exp)
(compile-splice (Splice-actions exp)
cenv
target
linkage)]
[(Begin0? exp)
(compile-begin0 (Begin0-actions exp)
cenv
target
linkage)]
[(App? exp)
(compile-application exp cenv target linkage)]
[(Let1? exp)
(compile-let1 exp cenv target linkage)]
[(LetVoid? exp)
(compile-let-void exp cenv target linkage)]
[(InstallValue? exp)
(compile-install-value exp cenv target linkage)]
[(BoxEnv? exp)
(compile-box-environment-value exp cenv target linkage)]
[(LetRec? exp)
(compile-let-rec exp cenv target linkage)]
[(WithContMark? exp)
(compile-with-cont-mark exp cenv target linkage)]
[(ApplyValues? exp)
(compile-apply-values exp cenv target linkage)]
[(DefValues? exp)
(compile-def-values exp cenv target linkage)]
[(PrimitiveKernelValue? exp)
(compile-primitive-kernel-value exp cenv target linkage)]
[(VariableReference? exp)
(compile-variable-reference exp cenv target linkage)]
[(Require? exp)
(compile-require exp cenv target linkage)]))
(: compile-top (Top CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-top top cenv target linkage)
(let*: ([names : (Listof (U False Symbol GlobalBucket ModuleVariable)) (Prefix-names (Top-prefix top))])
(end-with-linkage
linkage cenv
(append-instruction-sequences
(make-PerformStatement (make-ExtendEnvironment/Prefix! names))
(compile (Top-code top)
(cons (Top-prefix top) cenv)
'val
next-linkage/drop-multiple)
(make-AssignImmediateStatement target (make-Reg 'val))
(make-PopEnvironment (make-Const 1)
(make-Const 0))))))
(: compile-module (Module CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-module mod cenv target linkage)
(match mod
[(struct Module (name path prefix requires provides code))
(let*: ([after-module-body (make-label 'afterModuleBody)]
[module-entry (make-label 'module-entry)]
[names : (Listof (U False Symbol GlobalBucket ModuleVariable))
(Prefix-names prefix)]
[module-cenv : CompileTimeEnvironment (list prefix)])
(end-with-linkage
linkage cenv
(append-instruction-sequences
(make-PerformStatement (make-InstallModuleEntry! name path module-entry))
(make-GotoStatement (make-Label after-module-body))
module-entry
(make-PerformStatement (make-MarkModuleInvoked! path))
(apply append-instruction-sequences
(map compile-module-invoke (Module-requires mod)))
(make-PerformStatement (make-ExtendEnvironment/Prefix! names))
(make-AssignImmediateStatement (make-ModulePrefixTarget path)
(make-EnvWholePrefixReference 0))
(compile (Module-code mod)
(cons (Module-prefix mod) module-cenv)
'val
next-linkage/drop-multiple)
(make-PopEnvironment (make-Const 1) (make-Const 0))
(make-AssignImmediateStatement 'proc (make-ControlStackLabel))
(make-PopControlFrame)
(make-PerformStatement (make-FinalizeModuleInvokation! path))
(make-GotoStatement (make-Reg 'proc))
after-module-body)))]))
(: compile-require (Require CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-require exp cenv target linkage)
(end-with-linkage linkage cenv
(append-instruction-sequences
(compile-module-invoke (Require-path exp))
(make-AssignImmediateStatement target (make-Const (void))))))
(: compile-module-invoke (ModuleLocator -> InstructionSequence))
(define (compile-module-invoke a-module-name)
(cond
[(kernel-module-name? a-module-name)
empty-instruction-sequence]
[else
(let* ([linked (make-label 'linked)]
[on-return-multiple (make-label 'onReturnMultiple)]
[on-return (make-LinkedLabel (make-label 'onReturn)
on-return-multiple)])
(append-instruction-sequences
(make-TestAndJumpStatement (make-TestTrue
(make-IsModuleLinked a-module-name))
linked)
(make-DebugPrint (make-Const
(format "DEBUG: the module ~a hasn't been linked in!!!"
(ModuleLocator-name a-module-name))))
(make-GotoStatement (make-Label (LinkedLabel-label on-return)))
linked
(make-TestAndJumpStatement (make-TestTrue
(make-IsModuleInvoked a-module-name))
(LinkedLabel-label on-return))
(make-PushControlFrame/Call on-return)
(make-GotoStatement (ModuleEntry a-module-name))
on-return-multiple
(make-PopEnvironment (make-SubtractArg (make-Reg 'argcount)
(make-Const 1))
(make-Const 0))
on-return))]))
(: kernel-module-name? (ModuleLocator -> Boolean))
(define (kernel-module-name? name)
((current-kernel-module-locator?) name))
(: emit-singular-context (Linkage -> InstructionSequence))
(define (emit-singular-context linkage)
(cond [(ReturnLinkage? linkage)
empty-instruction-sequence]
[(or (NextLinkage? linkage)
(LabelLinkage? linkage))
(let ([context (linkage-context linkage)])
(cond
[(eq? context 'tail)
empty-instruction-sequence]
[(eq? context 'drop-multiple)
empty-instruction-sequence]
[(eq? context 'keep-multiple)
(make-AssignImmediateStatement 'argcount (make-Const 1))]
[(natural? context)
(if (= context 1)
empty-instruction-sequence
(append-instruction-sequences
(make-AssignImmediateStatement 'argcount (make-Const 1))
(make-PerformStatement (make-RaiseContextExpectedValuesError!
context))))]))]))
(: compile-constant (Constant CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-constant exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)])
(end-with-linkage linkage
cenv
(append-instruction-sequences
(make-AssignImmediateStatement target (make-Const (Constant-v exp)))
singular-context-check))))
(: compile-variable-reference (VariableReference CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-variable-reference exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)])
(end-with-linkage linkage
cenv
(append-instruction-sequences
(make-AssignImmediateStatement target exp)
singular-context-check))))
(: compile-local-reference (LocalRef CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-local-reference exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)])
(end-with-linkage linkage
cenv
(append-instruction-sequences
(make-AssignImmediateStatement target
(make-EnvLexicalReference (LocalRef-depth exp)
(LocalRef-unbox? exp)))
singular-context-check))))
(: compile-toplevel-reference (ToplevelRef CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-toplevel-reference exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)])
(end-with-linkage linkage
cenv
(append-instruction-sequences
(if (ToplevelRef-check-defined? exp)
(make-PerformStatement (make-CheckToplevelBound!
(ToplevelRef-depth exp)
(ToplevelRef-pos exp)))
empty-instruction-sequence)
(make-AssignImmediateStatement
target
(make-EnvPrefixReference (ToplevelRef-depth exp)
(ToplevelRef-pos exp)))
singular-context-check))))
(: compile-toplevel-set (ToplevelSet CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-toplevel-set exp cenv target linkage)
(let ([lexical-pos (make-EnvPrefixReference (ToplevelSet-depth exp)
(ToplevelSet-pos exp))])
(let ([get-value-code
(compile (ToplevelSet-value exp) cenv lexical-pos
next-linkage/expects-single)]
[singular-context-check (emit-singular-context linkage)])
(end-with-linkage
linkage
cenv
(append-instruction-sequences
get-value-code
(make-AssignImmediateStatement target (make-Const (void)))
singular-context-check)))))
(: compile-branch (Branch CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-branch exp cenv target linkage)
(let: ([f-branch : Symbol (make-label 'falseBranch)]
[after-if : Symbol (make-label 'afterIf)])
(let ([consequent-linkage
(cond
[(NextLinkage? linkage)
(let ([context (NextLinkage-context linkage)])
(make-LabelLinkage after-if context))]
[(ReturnLinkage? linkage)
linkage]
[(LabelLinkage? linkage)
linkage])])
(let ([p-code (compile (Branch-predicate exp) cenv 'val next-linkage/expects-single)]
[c-code (compile (Branch-consequent exp) cenv target consequent-linkage)]
[a-code (compile (Branch-alternative exp) cenv target linkage)])
(append-instruction-sequences
p-code
(make-TestAndJumpStatement (make-TestFalse (make-Reg 'val))
f-branch)
c-code
f-branch
a-code
after-if)))))
(: compile-sequence ((Listof Expression) CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-sequence seq cenv target linkage)
(cond [(empty? seq)
(end-with-linkage linkage cenv empty-instruction-sequence)]
[(empty? (rest seq))
(compile (first seq) cenv target linkage)]
[else
(append-instruction-sequences
(compile (first seq) cenv 'val next-linkage/drop-multiple)
(compile-sequence (rest seq) cenv target linkage))]))
(: compile-splice ((Listof Expression) CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-splice seq cenv target linkage)
(cond [(empty? seq)
(end-with-linkage linkage cenv empty-instruction-sequence)]
[(empty? (rest seq))
(let* ([on-return/multiple (make-label 'beforePromptPopMultiple)]
[on-return (make-LinkedLabel (make-label 'beforePromptPop)
on-return/multiple)])
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(make-PushControlFrame/Prompt default-continuation-prompt-tag
on-return)
(compile (first seq) cenv 'val return-linkage/nontail)
(emit-values-context-check-on-procedure-return (linkage-context linkage)
on-return/multiple
on-return)
(make-AssignImmediateStatement target (make-Reg 'val)))))]
[else
(let* ([on-return/multiple (make-label 'beforePromptPopMultiple)]
[on-return (make-LinkedLabel (make-label 'beforePromptPop)
on-return/multiple)])
(append-instruction-sequences
(make-PushControlFrame/Prompt (make-DefaultContinuationPromptTag)
on-return)
(compile (first seq) cenv 'val return-linkage/nontail)
on-return/multiple
(make-PopEnvironment (make-SubtractArg (make-Reg 'argcount)
(make-Const 1))
(make-Const 0))
on-return
(compile-splice (rest seq) cenv target linkage)))]))
(: compile-begin0 ((Listof Expression) CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-begin0 seq cenv target linkage)
(cond
[(empty? seq)
(end-with-linkage linkage cenv empty-instruction-sequence)]
[(empty? (rest seq))
(compile (first seq) cenv target linkage)]
[else
(let ([evaluate-and-save-first-expression
(let ([after-first-seq (make-label 'afterFirstSeqEvaluated)])
(append-instruction-sequences
(make-Comment "begin0")
(compile (first seq) cenv 'val next-linkage/keep-multiple-on-stack)
(make-TestAndJumpStatement (make-TestZero (make-Reg 'argcount)) after-first-seq)
(make-PushImmediateOntoEnvironment (make-Reg 'val) #f)
after-first-seq
(make-PushControlFrame/Generic)
(make-AssignImmediateStatement (make-ControlFrameTemporary 'pendingBegin0Count)
(make-Reg 'argcount))
(make-PerformStatement (make-UnspliceRestFromStack! (make-Const 0) (make-Reg 'argcount)))
(make-AssignImmediateStatement (make-ControlFrameTemporary 'pendingBegin0Values)
(make-EnvLexicalReference 0 #f))
(make-PopEnvironment (make-Const 1) (make-Const 0))))]
[reinstate-values-on-stack
(let ([after-values-reinstated (make-label 'afterValuesReinstated)])
(append-instruction-sequences
(make-PushImmediateOntoEnvironment (make-ControlFrameTemporary 'pendingBegin0Values) #f)
(make-PerformStatement (make-SpliceListIntoStack! (make-Const 0)))
(make-AssignImmediateStatement 'argcount (make-ControlFrameTemporary 'pendingBegin0Count))
(make-PopControlFrame)
(make-TestAndJumpStatement (make-TestZero (make-Reg 'argcount)) after-values-reinstated)
(make-AssignImmediateStatement 'val (make-EnvLexicalReference 0 #f))
(make-PopEnvironment (make-Const 1) (make-Const 0))
after-values-reinstated))])
(append-instruction-sequences
evaluate-and-save-first-expression
(compile-sequence (rest seq) cenv 'val next-linkage/drop-multiple)
reinstate-values-on-stack
(make-AssignImmediateStatement target (make-Reg 'val))
(cond
[(ReturnLinkage? linkage)
(cond
[(ReturnLinkage-tail? linkage)
(append-instruction-sequences
(make-PopEnvironment (make-Const (length cenv))
(make-SubtractArg (make-Reg 'argcount)
(make-Const 1)))
(make-AssignImmediateStatement 'proc (make-ControlStackLabel/MultipleValueReturn))
(make-PopControlFrame)
(make-GotoStatement (make-Reg 'proc)))]
[else
(append-instruction-sequences
(make-AssignImmediateStatement 'proc (make-ControlStackLabel/MultipleValueReturn))
(make-PopControlFrame)
(make-GotoStatement (make-Reg 'proc)))])]
[(NextLinkage? linkage)
empty-instruction-sequence]
[(LabelLinkage? linkage)
(make-GotoStatement (make-Label (LabelLinkage-label linkage)))])))]))
(: compile-lambda (Lam CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-lambda exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)])
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(make-AssignPrimOpStatement
target
(make-MakeCompiledProcedure (Lam-entry-label exp)
(Lam-arity exp)
(Lam-closure-map exp)
(Lam-name exp)))
singular-context-check))))
(: compile-empty-closure-reference (EmptyClosureReference CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-empty-closure-reference exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)])
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(make-AssignPrimOpStatement
target
(make-MakeCompiledProcedure (EmptyClosureReference-entry-label exp)
(EmptyClosureReference-arity exp)
empty
(EmptyClosureReference-name exp)))
singular-context-check))))
(: compile-case-lambda (CaseLam CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-case-lambda exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)]
[n (length (CaseLam-clauses exp))])
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(make-Comment "scratch space for case-lambda")
(make-PushEnvironment n #f)
(apply append-instruction-sequences
(map (lambda: ([lam : (U Lam EmptyClosureReference)]
[target : Target])
(make-AssignPrimOpStatement
target
(cond
[(Lam? lam)
(make-MakeCompiledProcedure (Lam-entry-label lam)
(Lam-arity lam)
(shift-closure-map (Lam-closure-map lam) n)
(Lam-name lam))]
[(EmptyClosureReference? lam)
(make-MakeCompiledProcedure (EmptyClosureReference-entry-label lam)
(EmptyClosureReference-arity lam)
'()
(EmptyClosureReference-name lam))])))
(CaseLam-clauses exp)
(build-list (length (CaseLam-clauses exp))
(lambda: ([i : Natural])
(make-EnvLexicalReference i #f)))))
(make-AssignPrimOpStatement
(adjust-target-depth target n)
(make-MakeCompiledProcedure (CaseLam-entry-label exp)
(merge-arities (map Lam-arity (CaseLam-clauses exp)))
(build-list n (lambda: ([i : Natural]) i))
(CaseLam-name exp)))
(make-PopEnvironment (make-Const n) (make-Const 0))
singular-context-check))))
(: Lam-arity ((U Lam EmptyClosureReference) -> Arity))
(define (Lam-arity lam)
(cond
[(Lam? lam)
(if (Lam-rest? lam)
(make-ArityAtLeast (Lam-num-parameters lam))
(Lam-num-parameters lam))]
[(EmptyClosureReference? lam)
(if (EmptyClosureReference-rest? lam)
(make-ArityAtLeast (EmptyClosureReference-num-parameters lam))
(EmptyClosureReference-num-parameters lam))]))
(: EmptyClosureReference-arity (EmptyClosureReference -> Arity))
(define (EmptyClosureReference-arity lam)
(if (EmptyClosureReference-rest? lam)
(make-ArityAtLeast (EmptyClosureReference-num-parameters lam))
(EmptyClosureReference-num-parameters lam)))
(: shift-closure-map ((Listof Natural) Natural -> (Listof Natural)))
(define (shift-closure-map closure-map n)
(map (lambda: ([i : Natural]) (+ i n))
closure-map))
(: merge-arities ((Listof Arity) -> Arity))
(define (merge-arities arities)
(cond [(empty? (rest arities))
(first arities)]
[else
(let ([first-arity (first arities)]
[merged-rest (merge-arities (rest arities))])
(cond
[(AtomicArity? first-arity)
(cond [(AtomicArity? merged-rest)
(list first-arity merged-rest)]
[(listof-atomic-arity? merged-rest)
(cons first-arity merged-rest)])]
[(listof-atomic-arity? first-arity)
(cond [(AtomicArity? merged-rest)
(append first-arity (list merged-rest))]
[(listof-atomic-arity? merged-rest)
(append first-arity merged-rest)])]))]))
(: compile-lambda-shell (Lam CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-lambda-shell exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)])
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(make-AssignPrimOpStatement
target
(make-MakeCompiledProcedureShell (Lam-entry-label exp)
(if (Lam-rest? exp)
(make-ArityAtLeast (Lam-num-parameters exp))
(Lam-num-parameters exp))
(Lam-name exp)))
singular-context-check))))
(: compile-lambda-body (Lam CompileTimeEnvironment -> InstructionSequence))
(define (compile-lambda-body exp cenv)
(let: ([maybe-unsplice-rest-argument : InstructionSequence
(if (Lam-rest? exp)
(make-PerformStatement
(make-UnspliceRestFromStack!
(make-Const (Lam-num-parameters exp))
(make-SubtractArg (make-Reg 'argcount)
(make-Const (Lam-num-parameters exp)))))
empty-instruction-sequence)]
[maybe-install-closure-values : InstructionSequence
(if (not (empty? (Lam-closure-map exp)))
(append-instruction-sequences
(make-Comment (format "installing closure for ~s" (Lam-name exp)))
(make-PerformStatement (make-InstallClosureValues!)))
empty-instruction-sequence)]
[lam-body-code : InstructionSequence
(compile (Lam-body exp)
(extract-lambda-cenv exp cenv)
'val
return-linkage)])
(append-instruction-sequences
(Lam-entry-label exp)
maybe-unsplice-rest-argument
maybe-install-closure-values
lam-body-code)))
(: compile-case-lambda-body (CaseLam CompileTimeEnvironment -> InstructionSequence))
(define (compile-case-lambda-body exp cenv)
(append-instruction-sequences
(CaseLam-entry-label exp)
(apply append-instruction-sequences
(map (lambda: ([lam : (U Lam EmptyClosureReference)]
[i : Natural])
(let ([not-match (make-label 'notMatch)])
(append-instruction-sequences
(make-TestAndJumpStatement (make-TestClosureArityMismatch
(make-CompiledProcedureClosureReference
(make-Reg 'proc)
i)
(make-Reg 'argcount))
not-match)
(make-AssignImmediateStatement
'proc
(make-CompiledProcedureClosureReference (make-Reg 'proc) i))
(make-GotoStatement (make-Label
(cond [(Lam? lam)
(Lam-entry-label lam)]
[(EmptyClosureReference? lam)
(EmptyClosureReference-entry-label lam)])))
not-match)))
(CaseLam-clauses exp)
(build-list (length (CaseLam-clauses exp)) (lambda: ([i : Natural]) i))))))
(: compile-lambda-bodies ((Listof lam+cenv) -> InstructionSequence))
(define (compile-lambda-bodies exps)
(cond
[(empty? exps)
empty-instruction-sequence]
[else
(let: ([lam : (U Lam CaseLam) (lam+cenv-lam (first exps))]
[cenv : CompileTimeEnvironment (lam+cenv-cenv (first exps))])
(cond
[(Lam? lam)
(append-instruction-sequences (compile-lambda-body lam
cenv)
(compile-lambda-bodies (rest exps)))]
[(CaseLam? lam)
(append-instruction-sequences
(compile-case-lambda-body lam cenv)
(compile-lambda-bodies (rest exps)))]))]))
(: extend-compile-time-environment/scratch-space (CompileTimeEnvironment Natural -> CompileTimeEnvironment))
(define (extend-compile-time-environment/scratch-space cenv n)
(append (build-list n (lambda: ([i : Natural])
'?))
cenv))
(: compile-application (App CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-application exp cenv target linkage)
(let ([extended-cenv
(extend-compile-time-environment/scratch-space
cenv
(length (App-operands exp)))])
(define (default)
(compile-general-application exp cenv target linkage))
(let: ([op-knowledge : CompileTimeEnvironmentEntry
(extract-static-knowledge (App-operator exp)
extended-cenv)])
(cond
[(eq? op-knowledge '?)
(default)]
[(PrimitiveKernelValue? op-knowledge)
(let ([id (PrimitiveKernelValue-id op-knowledge)])
(cond
[(KernelPrimitiveName/Inline? id)
(compile-kernel-primitive-application id exp cenv target linkage)]
[else
(default)]))]
[(ModuleVariable? op-knowledge)
(cond
[(symbol=? (ModuleLocator-name
(ModuleVariable-module-name op-knowledge))
'#%kernel)
(let ([op (ModuleVariable-name op-knowledge)])
(cond [(KernelPrimitiveName/Inline? op)
(compile-kernel-primitive-application
op
exp cenv target linkage)]
[else
(default)]))]
[else
(default)])]
[(StaticallyKnownLam? op-knowledge)
(compile-statically-known-lam-application op-knowledge exp cenv target linkage)]
[(Prefix? op-knowledge)
(error 'impossible)]
[(Const? op-knowledge)
(append-instruction-sequences
(make-AssignImmediateStatement 'proc op-knowledge)
(make-PerformStatement
(make-RaiseOperatorApplicationError! (make-Reg 'proc))))]))))
(: compile-general-application (App CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-general-application exp cenv target linkage)
(let* ([extended-cenv
(extend-compile-time-environment/scratch-space
cenv
(length (App-operands exp)))]
[proc-code (compile (App-operator exp)
extended-cenv
(if (empty? (App-operands exp))
'proc
(make-EnvLexicalReference
(ensure-natural (sub1 (length (App-operands exp))))
#f))
next-linkage/expects-single)]
[operand-codes (map (lambda: ([operand : Expression]
[target : Target])
(compile operand
extended-cenv
target
next-linkage/expects-single))
(App-operands exp)
(build-list (length (App-operands exp))
(lambda: ([i : Natural])
(if (< i (sub1 (length (App-operands exp))))
(make-EnvLexicalReference i #f)
'val))))])
(append-instruction-sequences
(make-Comment "scratch space for general application")
(make-PushEnvironment (length (App-operands exp)) #f)
proc-code
(juggle-operands operand-codes)
(make-AssignImmediateStatement 'argcount
(make-Const (length (App-operands exp))))
(compile-general-procedure-call cenv
(make-Const (length (App-operands exp)))
target
linkage))))
(: compile-kernel-primitive-application
(KernelPrimitiveName/Inline App CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-kernel-primitive-application kernel-op exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)])
(cond
[(andmap (lambda (op)
(or (Constant? op)
(ToplevelRef? op)
(LocalRef? op)))
(App-operands exp))
(let* ([n (length (App-operands exp))]
[operand-knowledge
(map (lambda: ([arg : Expression])
(extract-static-knowledge
arg
(extend-compile-time-environment/scratch-space
cenv n)))
(App-operands exp))]
[typechecks?
(map (lambda: ([dom : OperandDomain]
[known : CompileTimeEnvironmentEntry])
(not (redundant-check? dom known)))
(kernel-primitive-expected-operand-types kernel-op n)
operand-knowledge)]
[expected-operand-types
(kernel-primitive-expected-operand-types kernel-op n)]
[operand-poss
(simple-operands->opargs (map (lambda: ([op : Expression])
(adjust-expression-depth op n n))
(App-operands exp)))])
(end-with-linkage
linkage cenv
(append-instruction-sequences
(make-AssignPrimOpStatement target
(make-CallKernelPrimitiveProcedure
kernel-op
operand-poss
expected-operand-types
typechecks?))
singular-context-check)))]
[else
(let*-values ([(n)
(length (App-operands exp))]
[(expected-operand-types)
(kernel-primitive-expected-operand-types kernel-op n)]
[(constant-operands rest-operands)
(split-operands-by-constants
(App-operands exp))]
[(extended-cenv constant-operands rest-operands)
(values (extend-compile-time-environment/scratch-space
cenv
(length rest-operands))
(map (lambda: ([constant-operand : Expression])
(ensure-simple-expression
(adjust-expression-depth constant-operand
(length constant-operands)
n)))
constant-operands)
(map (lambda: ([rest-operand : Expression])
(adjust-expression-depth rest-operand
(length constant-operands)
n))
rest-operands))]
[(operand-knowledge)
(append (map (lambda: ([arg : Expression])
(extract-static-knowledge arg extended-cenv))
constant-operands)
(map (lambda: ([arg : Expression])
(extract-static-knowledge arg extended-cenv))
rest-operands))]
[(typechecks?)
(map (lambda: ([dom : OperandDomain]
[known : CompileTimeEnvironmentEntry])
(not (redundant-check? dom known)))
(kernel-primitive-expected-operand-types kernel-op n)
operand-knowledge)]
[(stack-pushing-code)
(make-PushEnvironment (length rest-operands)
#f)]
[(stack-popping-code)
(make-PopEnvironment (make-Const (length rest-operands))
(make-Const 0))]
[(constant-operand-poss)
(simple-operands->opargs constant-operands)]
[(rest-operand-poss)
(build-list (length rest-operands)
(lambda: ([i : Natural])
(make-EnvLexicalReference i #f)))]
[(rest-operand-code)
(apply append-instruction-sequences
(map (lambda: ([operand : Expression]
[target : Target])
(compile operand
extended-cenv
target
next-linkage/expects-single))
rest-operands
rest-operand-poss))])
(end-with-linkage
linkage cenv
(append-instruction-sequences
stack-pushing-code
rest-operand-code
(make-AssignPrimOpStatement (adjust-target-depth target (length rest-operands))
(make-CallKernelPrimitiveProcedure
kernel-op
(append constant-operand-poss rest-operand-poss)
expected-operand-types
typechecks?))
stack-popping-code
singular-context-check)))])))
(: ensure-simple-expression (Expression -> (U Constant ToplevelRef LocalRef)))
(define (ensure-simple-expression e)
(if (or (Constant? e)
(LocalRef? e)
(ToplevelRef? e))
e
(error 'ensure-simple-expression)))
(: simple-operands->opargs ((Listof Expression) -> (Listof OpArg)))
(define (simple-operands->opargs rands)
(map (lambda: ([e : Expression])
(cond
[(Constant? e)
(make-Const (Constant-v e))]
[(LocalRef? e)
(make-EnvLexicalReference (LocalRef-depth e)
(LocalRef-unbox? e))]
[(ToplevelRef? e)
(make-EnvPrefixReference (ToplevelRef-depth e)
(ToplevelRef-pos e))]
[else
(error 'all-operands-are-constant "Impossible")]))
rands))
(: redundant-check? (OperandDomain CompileTimeEnvironmentEntry -> Boolean))
(define (redundant-check? domain-type knowledge)
(cond
[(eq? domain-type 'any)
#t]
[else
(cond [(Const? knowledge)
(case domain-type
[(number)
(number? (Const-const knowledge))]
[(string)
(string? (Const-const knowledge))]
[(box)
(box? (Const-const knowledge))]
[(list)
(list? (Const-const knowledge))]
[(pair)
(pair? (Const-const knowledge))])]
[else
#f])]))
(: split-operands-by-constants
((Listof Expression) ->
(values (Listof (U Constant LocalRef ToplevelRef))
(Listof Expression))))
(define (split-operands-by-constants rands)
(let: loop : (values (Listof (U Constant LocalRef ToplevelRef)) (Listof Expression))
([rands : (Listof Expression) rands]
[constants : (Listof (U Constant LocalRef ToplevelRef))
empty])
(cond [(empty? rands)
(values (reverse constants) empty)]
[else (let ([e (first rands)])
(if (or (Constant? e)
(and (LocalRef? e) (not (LocalRef-unbox? e)))
(and (ToplevelRef? e)
(let ([prefix (ensure-prefix
(list-ref cenv (ToplevelRef-depth e)))])
(ModuleVariable?
(list-ref prefix (ToplevelRef-pos e))))))
(loop (rest rands) (cons e constants))
(values (reverse constants) rands)))])))
(define-predicate natural? Natural)
(define-predicate atomic-arity-list? (Listof (U Natural ArityAtLeast)))
(: arity-matches? (Arity Natural -> Boolean))
(define (arity-matches? an-arity n)
(cond
[(natural? an-arity)
(= an-arity n)]
[(ArityAtLeast? an-arity)
(>= n (ArityAtLeast-value an-arity))]
[(atomic-arity-list? an-arity)
(ormap (lambda: ([an-arity : (U Natural ArityAtLeast)])
(cond
[(natural? an-arity)
(= an-arity n)]
[(ArityAtLeast? an-arity)
(>= n (ArityAtLeast-value an-arity))]))
an-arity)]))
(: compile-statically-known-lam-application
(StaticallyKnownLam App CompileTimeEnvironment Target Linkage
-> InstructionSequence))
(define (compile-statically-known-lam-application static-knowledge exp cenv target linkage)
(let ([arity-check
(cond [(arity-matches? (StaticallyKnownLam-arity static-knowledge)
(length (App-operands exp)))
empty-instruction-sequence]
[else
(make-PerformStatement
(make-RaiseArityMismatchError!
(make-Reg 'proc)
(StaticallyKnownLam-arity static-knowledge)
(make-Const (length (App-operands exp)))))])])
(let* ([extended-cenv
(extend-compile-time-environment/scratch-space
cenv
(length (App-operands exp)))]
[proc-code (compile (App-operator exp)
extended-cenv
(if (empty? (App-operands exp))
'proc
(make-EnvLexicalReference
(ensure-natural (sub1 (length (App-operands exp))))
#f))
next-linkage/expects-single)]
[operand-codes (map (lambda: ([operand : Expression]
[target : Target])
(compile operand
extended-cenv
target
next-linkage/expects-single))
(App-operands exp)
(build-list (length (App-operands exp))
(lambda: ([i : Natural])
(if (< i (sub1 (length (App-operands exp))))
(make-EnvLexicalReference i #f)
'val))))])
(append-instruction-sequences
(make-Comment "scratch space for statically known lambda application")
(make-PushEnvironment (length (App-operands exp)) #f)
proc-code
(juggle-operands operand-codes)
arity-check
(compile-procedure-call/statically-known-lam static-knowledge
cenv
extended-cenv
(length (App-operands exp))
target
linkage)))))
(: juggle-operands ((Listof InstructionSequence) -> InstructionSequence))
(define (juggle-operands operand-codes)
(let: loop : InstructionSequence ([ops : (Listof InstructionSequence) operand-codes])
(cond
[(null? ops)
empty-instruction-sequence]
[(null? (rest ops))
(let: ([n : Natural (ensure-natural (sub1 (length operand-codes)))])
(append-instruction-sequences
(car ops)
(make-AssignImmediateStatement 'proc
(make-EnvLexicalReference n #f))
(make-AssignImmediateStatement (make-EnvLexicalReference n #f)
(make-Reg 'val))))]
[else
(append-instruction-sequences (car ops)
(loop (rest ops)))])))
(: linkage-context (Linkage -> ValuesContext))
(define (linkage-context linkage)
(cond
[(ReturnLinkage? linkage)
(cond [(ReturnLinkage-tail? linkage)
'tail]
[else
'drop-multiple])]
[(NextLinkage? linkage)
(NextLinkage-context linkage)]
[(LabelLinkage? linkage)
(LabelLinkage-context linkage)]))
(: compile-general-procedure-call (CompileTimeEnvironment OpArg Target Linkage
->
InstructionSequence))
(define (compile-general-procedure-call cenv number-of-arguments target linkage)
(let: ([primitive-branch : Symbol (make-label 'primitiveBranch)]
[after-call : Symbol (make-label 'afterCall)])
(let: ([compiled-linkage : Linkage (if (and (ReturnLinkage? linkage)
(ReturnLinkage-tail? linkage))
linkage
(make-LabelLinkage after-call
(linkage-context linkage)))]
[primitive-linkage : Linkage
(make-NextLinkage (linkage-context linkage))])
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(make-TestAndJumpStatement (make-TestPrimitiveProcedure
(make-Reg 'proc))
primitive-branch)
(make-PerformStatement (make-CheckClosureArity! (make-Reg 'argcount)))
(compile-compiled-procedure-application cenv
number-of-arguments
'dynamic
target
compiled-linkage)
primitive-branch
(make-PerformStatement (make-CheckPrimitiveArity! (make-Reg 'argcount)))
(compile-primitive-application cenv target primitive-linkage)
after-call)))))
(: compile-primitive-application (CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-primitive-application cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)])
(append-instruction-sequences
(make-AssignPrimOpStatement 'val (make-ApplyPrimitiveProcedure))
(make-PopEnvironment (make-Reg 'argcount)
(make-Const 0))
(if (eq? target 'val)
empty-instruction-sequence
(make-AssignImmediateStatement target (make-Reg 'val)))
singular-context-check)))
(: compile-procedure-call/statically-known-lam
(StaticallyKnownLam CompileTimeEnvironment CompileTimeEnvironment Natural Target Linkage -> InstructionSequence))
(define (compile-procedure-call/statically-known-lam static-knowledge cenv extended-cenv n target linkage)
(let*: ([after-call : Symbol (make-label 'afterCall)]
[compiled-linkage : Linkage (if (and (ReturnLinkage? linkage)
(ReturnLinkage-tail? linkage))
linkage
(make-LabelLinkage
after-call
(linkage-context linkage)))])
(append-instruction-sequences
(make-AssignImmediateStatement 'argcount
(make-Const n))
(compile-compiled-procedure-application cenv
(make-Const n)
(make-Label
(StaticallyKnownLam-entry-point static-knowledge))
target
compiled-linkage)
(end-with-linkage
linkage
cenv
after-call))))
(: compile-compiled-procedure-application (CompileTimeEnvironment OpArg (U Label 'dynamic) Target Linkage -> InstructionSequence))
(define (compile-compiled-procedure-application cenv number-of-arguments entry-point target linkage)
(let* ([entry-point-target
(cond [(Label? entry-point)
entry-point]
[(eq? entry-point 'dynamic)
(make-CompiledProcedureEntry (make-Reg 'proc))])]
[maybe-migrate-val-to-target
(cond
[(eq? target 'val)
empty-instruction-sequence]
[else
(make-AssignImmediateStatement target (make-Reg 'val))])]
[on-return/multiple (make-label 'procReturnMultiple)]
[on-return (make-LinkedLabel (make-label 'procReturn)
on-return/multiple)]
[nontail-jump-into-procedure
(append-instruction-sequences
(make-PushControlFrame/Call on-return)
(make-GotoStatement entry-point-target))])
(cond [(ReturnLinkage? linkage)
(cond
[(eq? target 'val)
(cond
[(ReturnLinkage-tail? linkage)
(let ([reuse-the-stack
(make-PopEnvironment (make-Const (length cenv))
number-of-arguments)])
(append-instruction-sequences
reuse-the-stack
(make-PerformStatement (make-SetFrameCallee! (make-Reg 'proc)))
(make-GotoStatement entry-point-target)))]
[else
(append-instruction-sequences
nontail-jump-into-procedure
on-return/multiple
(make-PopEnvironment (make-SubtractArg (make-Reg 'argcount)
(make-Const 1))
(make-Const 0))
on-return)])]
[else
(error 'compile "return linkage, target not val: ~s" target)])]
[(or (NextLinkage? linkage) (LabelLinkage? linkage))
(let* ([context (linkage-context linkage)]
[check-values-context-on-procedure-return
(emit-values-context-check-on-procedure-return context on-return/multiple on-return)]
[maybe-jump-to-label
(if (LabelLinkage? linkage)
(make-GotoStatement (make-Label (LabelLinkage-label linkage)))
empty-instruction-sequence)])
(append-instruction-sequences
nontail-jump-into-procedure
check-values-context-on-procedure-return
maybe-migrate-val-to-target
maybe-jump-to-label))])))
(: emit-values-context-check-on-procedure-return (ValuesContext Symbol LinkedLabel -> InstructionSequence))
(define (emit-values-context-check-on-procedure-return context on-return/multiple on-return)
(cond
[(eq? context 'tail)
(append-instruction-sequences on-return/multiple
on-return)]
[(eq? context 'drop-multiple)
(append-instruction-sequences
on-return/multiple
(make-PopEnvironment (SubtractArg (make-Reg 'argcount) (make-Const 1))
(make-Const 0))
on-return)]
[(eq? context 'keep-multiple)
(let ([after-return (make-label 'afterReturn)])
(append-instruction-sequences
on-return/multiple
(make-GotoStatement (make-Label after-return))
on-return
(make-AssignImmediateStatement 'argcount (make-Const 1))
after-return))]
[(natural? context)
(cond
[(= context 1)
(append-instruction-sequences
on-return/multiple
(make-PerformStatement
(make-RaiseContextExpectedValuesError! 1))
on-return)]
[else
(let ([after-value-check (make-label 'afterValueCheck)])
(append-instruction-sequences
on-return/multiple
(make-TestAndJumpStatement (make-TestZero (make-SubtractArg (make-Reg 'argcount)
(make-Const context)))
after-value-check)
on-return
(make-PerformStatement
(make-RaiseContextExpectedValuesError! context))
after-value-check))])]))
(: extract-static-knowledge (Expression CompileTimeEnvironment ->
CompileTimeEnvironmentEntry))
(define (extract-static-knowledge exp cenv)
(log-debug (format "Trying to discover information about ~s" exp))
(cond
[(Lam? exp)
(log-debug "known to be a lambda")
(make-StaticallyKnownLam (Lam-name exp)
(Lam-entry-label exp)
(if (Lam-rest? exp)
(make-ArityAtLeast (Lam-num-parameters exp))
(Lam-num-parameters exp)))]
[(and (LocalRef? exp)
(not (LocalRef-unbox? exp)))
(let ([entry (list-ref cenv (LocalRef-depth exp))])
(log-debug (format "known to be ~s" entry))
entry)]
[(ToplevelRef? exp)
(log-debug (format "toplevel reference of ~a" exp))
(when (ToplevelRef-constant? exp)
(log-debug (format "toplevel reference ~a should be known constant" exp)))
(let: ([name : (U Symbol False GlobalBucket ModuleVariable)
(list-ref (Prefix-names (ensure-prefix (list-ref cenv (ToplevelRef-depth exp))))
(ToplevelRef-pos exp))])
(cond
[(ModuleVariable? name)
(log-debug (format "toplevel reference is to ~s" name))
name]
[(GlobalBucket? name)
'?]
[else
(log-debug (format "nothing statically known about ~s" exp))
'?]))]
[(Constant? exp)
(make-Const (Constant-v exp))]
[(PrimitiveKernelValue? exp)
exp]
[else
(log-debug (format "nothing statically known about ~s" exp))
'?]))
(: compile-let1 (Let1 CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-let1 exp cenv target linkage)
(let*: ([rhs-code : InstructionSequence
(compile (Let1-rhs exp)
(cons '? cenv)
(make-EnvLexicalReference 0 #f)
next-linkage/expects-single)]
[after-body-code : Symbol (make-label 'afterLetBody)]
[extended-cenv : CompileTimeEnvironment (cons (extract-static-knowledge (Let1-rhs exp)
(cons '? cenv))
cenv)]
[let-linkage : Linkage
(cond
[(NextLinkage? linkage)
linkage]
[(ReturnLinkage? linkage)
(cond [(ReturnLinkage-tail? linkage)
linkage]
[else
(make-LabelLinkage after-body-code (linkage-context linkage))])]
[(LabelLinkage? linkage)
(make-LabelLinkage after-body-code (LabelLinkage-context linkage))])]
[body-target : Target (adjust-target-depth target 1)]
[body-code : InstructionSequence
(compile (Let1-body exp) extended-cenv body-target let-linkage)])
(end-with-linkage
linkage
extended-cenv
(append-instruction-sequences
(make-Comment "scratch space for let1")
(make-PushEnvironment 1 #f)
rhs-code
body-code
after-body-code
(make-PopEnvironment (make-Const 1) (make-Const 0))))))
(: compile-let-void (LetVoid CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-let-void exp cenv target linkage)
(let*: ([n : Natural (LetVoid-count exp)]
[after-let : Symbol (make-label 'afterLet)]
[after-body-code : Symbol (make-label 'afterLetBody)]
[extended-cenv : CompileTimeEnvironment
(append (build-list (LetVoid-count exp)
(lambda: ([i : Natural]) '?))
cenv)]
[context : ValuesContext (linkage-context linkage)]
[let-linkage : Linkage
(cond
[(NextLinkage? linkage)
linkage]
[(ReturnLinkage? linkage)
(cond
[(ReturnLinkage-tail? linkage)
linkage]
[else
(make-LabelLinkage after-body-code context)])]
[(LabelLinkage? linkage)
(make-LabelLinkage after-body-code context)])]
[body-target : Target (adjust-target-depth target n)]
[body-code : InstructionSequence
(compile (LetVoid-body exp) extended-cenv body-target let-linkage)])
(end-with-linkage
linkage
extended-cenv
(append-instruction-sequences
(make-Comment "scratch space for let-void")
(make-PushEnvironment n (LetVoid-boxes? exp))
body-code
after-body-code
(cond
[(eq? context 'tail)
empty-instruction-sequence]
[(eq? context 'drop-multiple)
(make-PopEnvironment (make-Const n)
(make-Const 0))]
[(eq? context 'keep-multiple)
(make-PopEnvironment (make-Const n)
(make-SubtractArg
(make-Reg 'argcount)
(make-Const 1)))]
[else
(cond [(= context 0)
(make-PopEnvironment (make-Const n)
(make-Const 0))]
[(= context 1)
(make-PopEnvironment (make-Const n)
(make-Const 0))]
[else
(make-PopEnvironment (make-Const n)
(make-SubtractArg
(make-Const context)
(make-Const 1)))])])
after-let))))
(: compile-let-rec (LetRec CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-let-rec exp cenv target linkage)
(let*: ([n : Natural (length (LetRec-procs exp))]
[extended-cenv : CompileTimeEnvironment
(append (map (lambda: ([p : Lam])
(extract-static-knowledge
p
(append (build-list (length (LetRec-procs exp))
(lambda: ([i : Natural])
'?))
(drop cenv n))))
(LetRec-procs exp))
(drop cenv n))]
[n : Natural (length (LetRec-procs exp))]
[after-body-code : Symbol (make-label 'afterBodyCode)]
[letrec-linkage : Linkage (cond
[(NextLinkage? linkage)
linkage]
[(ReturnLinkage? linkage)
(cond
[(ReturnLinkage-tail? linkage)
linkage]
[else
(make-LabelLinkage after-body-code
(linkage-context linkage))])]
[(LabelLinkage? linkage)
(make-LabelLinkage after-body-code
(LabelLinkage-context linkage))])])
(end-with-linkage
linkage
extended-cenv
(append-instruction-sequences
(apply append-instruction-sequences
(map (lambda: ([lam : Lam]
[i : Natural])
(compile-lambda-shell lam
extended-cenv
(make-EnvLexicalReference i #f)
next-linkage/expects-single))
(LetRec-procs exp)
(build-list n (lambda: ([i : Natural]) i))))
(apply append-instruction-sequences
(map (lambda: ([lam : Lam]
[i : Natural])
(append-instruction-sequences
(make-Comment (format "Installing shell for ~s\n" (Lam-name lam)))
(make-PerformStatement (make-FixClosureShellMap! i
(Lam-closure-map lam)))))
(LetRec-procs exp)
(build-list n (lambda: ([i : Natural]) i))))
(compile (LetRec-body exp) extended-cenv target letrec-linkage)
after-body-code))))
(: compile-install-value (InstallValue CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-install-value exp cenv target linkage)
(append-instruction-sequences
(make-Comment "install-value")
(let ([count (InstallValue-count exp)])
(cond [(= count 0)
(end-with-linkage
linkage
cenv
(compile (InstallValue-body exp)
cenv
target
(make-NextLinkage 0)))]
[(= count 1)
(append-instruction-sequences
(make-Comment (format "installing single value into ~s"
(InstallValue-depth exp)))
(end-with-linkage
linkage
cenv
(compile (InstallValue-body exp)
cenv
(make-EnvLexicalReference (InstallValue-depth exp) (InstallValue-box? exp))
(make-NextLinkage 1))))]
[else
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(make-Comment "install-value: evaluating values")
(compile (InstallValue-body exp)
cenv
'val
(make-NextLinkage count))
(apply append-instruction-sequences
(map (lambda: ([to : EnvLexicalReference]
[from : OpArg])
(append-instruction-sequences
(make-Comment "install-value: installing value")
(make-AssignImmediateStatement to from)))
(build-list count (lambda: ([i : Natural])
(make-EnvLexicalReference (+ i
(InstallValue-depth exp)
(sub1 count))
(InstallValue-box? exp))))
(cons (make-Reg 'val)
(build-list (sub1 count) (lambda: ([i : Natural])
(make-EnvLexicalReference i #f))))))
(make-PopEnvironment (make-Const (sub1 count)) (make-Const 0))))]))))
(: compile-box-environment-value (BoxEnv CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-box-environment-value exp cenv target linkage)
(append-instruction-sequences
(make-AssignPrimOpStatement (make-EnvLexicalReference (BoxEnv-depth exp) #f)
(make-MakeBoxedEnvironmentValue (BoxEnv-depth exp)))
(compile (BoxEnv-body exp) cenv target linkage)))
(: compile-with-cont-mark (WithContMark CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-with-cont-mark exp cenv target linkage)
(: in-return-context (-> InstructionSequence))
(define (in-return-context)
(append-instruction-sequences
(compile (WithContMark-key exp) cenv 'val next-linkage/expects-single)
(make-AssignImmediateStatement
(make-ControlFrameTemporary 'pendingContinuationMarkKey)
(make-Reg 'val))
(compile (WithContMark-value exp) cenv 'val next-linkage/expects-single)
(make-PerformStatement (make-InstallContinuationMarkEntry!))
(compile (WithContMark-body exp) cenv target linkage)))
(: in-other-context ((U NextLinkage LabelLinkage) -> InstructionSequence))
(define (in-other-context linkage)
(let ([body-next-linkage (cond [(NextLinkage? linkage)
linkage]
[(LabelLinkage? linkage)
(make-NextLinkage (LabelLinkage-context linkage))])])
(end-with-linkage
linkage cenv
(append-instruction-sequences
(make-PushControlFrame/Generic)
(compile (WithContMark-key exp) cenv 'val next-linkage/expects-single)
(make-AssignImmediateStatement (make-ControlFrameTemporary 'pendingContinuationMarkKey)
(make-Reg 'val))
(compile (WithContMark-value exp) cenv 'val next-linkage/expects-single)
(make-PerformStatement (make-InstallContinuationMarkEntry!))
(compile (WithContMark-body exp) cenv target body-next-linkage)
(make-PopControlFrame)))))
(cond
[(ReturnLinkage? linkage)
(in-return-context)]
[(NextLinkage? linkage)
(in-other-context linkage)]
[(LabelLinkage? linkage)
(in-other-context linkage)]))
(: compile-apply-values (ApplyValues CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-apply-values exp cenv target linkage)
(log-debug (format "apply values ~a" exp))
(let ([on-zero (make-label 'onZero)]
[after-args-evaluated (make-label 'afterArgsEvaluated)]
[consumer-info
(extract-static-knowledge (ApplyValues-proc exp) cenv)])
(append-instruction-sequences
(make-PushControlFrame/Generic)
(compile (ApplyValues-proc exp)
cenv
(make-ControlFrameTemporary 'pendingApplyValuesProc)
next-linkage/expects-single)
(compile (ApplyValues-args-expr exp)
cenv
'val
next-linkage/keep-multiple-on-stack)
(make-TestAndJumpStatement (make-TestZero (make-Reg 'argcount)) after-args-evaluated)
(make-PushImmediateOntoEnvironment (make-Reg 'val) #f)
after-args-evaluated
(make-AssignImmediateStatement
'proc
(make-ControlFrameTemporary 'pendingApplyValuesProc))
(make-PopControlFrame)
(compile-general-procedure-call cenv (make-Reg 'argcount) target linkage))))
(: compile-def-values (DefValues CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-def-values exp cenv target linkage)
(let* ([ids (DefValues-ids exp)]
[rhs (DefValues-rhs exp)]
[n (length ids)])
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(compile rhs cenv 'val (make-NextLinkage (length ids)))
(if (> n 0)
(apply append-instruction-sequences
(map (lambda: ([id : ToplevelRef]
[from : OpArg])
(make-AssignImmediateStatement
(make-EnvPrefixReference (+ (ensure-natural (sub1 n))
(ToplevelRef-depth id))
(ToplevelRef-pos id))
from))
ids
(if (> n 0)
(cons (make-Reg 'val)
(build-list (sub1 n)
(lambda: ([i : Natural])
(make-EnvLexicalReference i #f))))
empty)))
empty-instruction-sequence)
(if (> (length ids) 1)
(make-PopEnvironment (make-Const (sub1 (length ids)))
(make-Const 0))
empty-instruction-sequence)))))
(: compile-primitive-kernel-value (PrimitiveKernelValue CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-primitive-kernel-value exp cenv target linkage)
(let ([id (PrimitiveKernelValue-id exp)])
(cond
[(KernelPrimitiveName? id)
(let ([singular-context-check (emit-singular-context linkage)])
(end-with-linkage linkage
cenv
(append-instruction-sequences
(make-AssignImmediateStatement target exp)
singular-context-check)))]
[else
(unless (set-contains? (current-seen-unimplemented-kernel-primitives)
id)
(set-insert! (current-seen-unimplemented-kernel-primitives)
id)
((current-warn-unimplemented-kernel-primitive) id))
(make-PerformStatement (make-RaiseUnimplementedPrimitiveError! id))])))
(: append-instruction-sequences (InstructionSequence * -> InstructionSequence))
(define (append-instruction-sequences . seqs)
(append-seq-list seqs))
(: append-2-sequences (InstructionSequence InstructionSequence -> InstructionSequence))
(define (append-2-sequences seq1 seq2)
(make-instruction-sequence
(append (statements seq1) (statements seq2))))
(: append-seq-list ((Listof InstructionSequence) -> InstructionSequence))
(define (append-seq-list seqs)
(if (null? seqs)
empty-instruction-sequence
(append-2-sequences (car seqs)
(append-seq-list (cdr seqs)))))
(: ensure-natural (Integer -> Natural))
(define (ensure-natural n)
(if (>= n 0)
n
(error 'ensure-natural "Not a natural: ~s\n" n)))
(: ensure-prefix (CompileTimeEnvironmentEntry -> Prefix))
(define (ensure-prefix x)
(if (Prefix? x)
x
(error 'ensure-prefix "Not a prefix: ~s" x)))
(: ensure-lam (Any -> Lam))
(define (ensure-lam x)
(if (Lam? x)
x
(error 'ensure-lam "Not a Lam: ~s" x)))
(: ensure-toplevelref (Any -> ToplevelRef))
(define (ensure-toplevelref x)
(if (ToplevelRef? x)
x
(error 'ensure-toplevelref "Not a ToplevelRef: ~s" x)))
(: adjust-target-depth (Target Natural -> Target))
(define (adjust-target-depth target n)
(cond
[(eq? target 'val)
target]
[(eq? target 'proc)
target]
[(eq? target 'argcount)
target]
[(EnvLexicalReference? target)
(make-EnvLexicalReference (+ n (EnvLexicalReference-depth target))
(EnvLexicalReference-unbox? target))]
[(EnvPrefixReference? target)
(make-EnvPrefixReference (+ n (EnvPrefixReference-depth target))
(EnvPrefixReference-pos target))]
[(PrimitivesReference? target)
target]
[(ControlFrameTemporary? target)
target]
[(ModulePrefixTarget? target)
target]))
(: adjust-expression-depth (Expression Natural Natural -> Expression))
(define (adjust-expression-depth exp n skip)
(cond
[(Top? exp)
(make-Top (Top-prefix exp)
(adjust-expression-depth (Top-code exp) n (add1 skip)))]
[(Module? exp)
(make-Module (Module-name exp)
(Module-path exp)
(Module-prefix exp)
(Module-requires exp)
(Module-provides exp)
(adjust-expression-depth (Module-code exp) n (add1 skip)))]
[(Constant? exp)
exp]
[(ToplevelRef? exp)
(if (< (ToplevelRef-depth exp) skip)
exp
(make-ToplevelRef (ensure-natural (- (ToplevelRef-depth exp) n))
(ToplevelRef-pos exp)
(ToplevelRef-constant? exp)
(ToplevelRef-check-defined? exp)))]
[(LocalRef? exp)
(if (< (LocalRef-depth exp) skip)
exp
(make-LocalRef (ensure-natural (- (LocalRef-depth exp) n))
(LocalRef-unbox? exp)))]
[(ToplevelSet? exp)
(if (< (ToplevelSet-depth exp) skip)
(make-ToplevelSet (ToplevelSet-depth exp)
(ToplevelSet-pos exp)
(adjust-expression-depth (ToplevelSet-value exp) n skip))
(make-ToplevelSet (ensure-natural (- (ToplevelSet-depth exp) n))
(ToplevelSet-pos exp)
(adjust-expression-depth (ToplevelSet-value exp) n skip)))]
[(Branch? exp)
(make-Branch (adjust-expression-depth (Branch-predicate exp) n skip)
(adjust-expression-depth (Branch-consequent exp) n skip)
(adjust-expression-depth (Branch-alternative exp) n skip))]
[(Lam? exp)
(make-Lam (Lam-name exp)
(Lam-num-parameters exp)
(Lam-rest? exp)
(Lam-body exp)
(map (lambda: ([d : Natural])
(if (< d skip)
d
(ensure-natural (- d n))))
(Lam-closure-map exp))
(Lam-entry-label exp))]
[(CaseLam? exp)
(make-CaseLam (CaseLam-name exp)
(map (lambda: ([lam : (U Lam EmptyClosureReference)])
(cond
[(Lam? lam)
(ensure-lam (adjust-expression-depth lam n skip))]
[(EmptyClosureReference? lam)
lam]))
(CaseLam-clauses exp))
(CaseLam-entry-label exp))]
[(EmptyClosureReference? exp)
exp]
[(Seq? exp)
(make-Seq (map (lambda: ([action : Expression])
(adjust-expression-depth action n skip))
(Seq-actions exp)))]
[(Splice? exp)
(make-Splice (map (lambda: ([action : Expression])
(adjust-expression-depth action n skip))
(Splice-actions exp)))]
[(Begin0? exp)
(make-Begin0 (map (lambda: ([action : Expression])
(adjust-expression-depth action n skip))
(Begin0-actions exp)))]
[(App? exp)
(make-App (adjust-expression-depth (App-operator exp) n
(+ skip (length (App-operands exp))))
(map (lambda: ([operand : Expression])
(adjust-expression-depth
operand n (+ skip (length (App-operands exp)))))
(App-operands exp)))]
[(Let1? exp)
(make-Let1 (adjust-expression-depth (Let1-rhs exp) n (add1 skip))
(adjust-expression-depth (Let1-body exp) n (add1 skip)))]
[(LetVoid? exp)
(make-LetVoid (LetVoid-count exp)
(adjust-expression-depth (LetVoid-body exp)
n
(+ skip (LetVoid-count exp)))
(LetVoid-boxes? exp))]
[(LetRec? exp)
(make-LetRec (let: loop : (Listof Lam) ([procs : (Listof Lam) (LetRec-procs exp)])
(cond
[(empty? procs)
'()]
[else
(cons (ensure-lam (adjust-expression-depth
(first procs)
n
skip))
(loop (rest procs)))]))
(adjust-expression-depth (LetRec-body exp) n
skip))]
[(InstallValue? exp)
(if (< (InstallValue-depth exp) skip)
(make-InstallValue (InstallValue-count exp)
(InstallValue-depth exp)
(adjust-expression-depth (InstallValue-body exp)
n
skip)
(InstallValue-box? exp))
(make-InstallValue (InstallValue-count exp)
(ensure-natural (- (InstallValue-depth exp) n))
(adjust-expression-depth (InstallValue-body exp)
n
skip)
(InstallValue-box? exp)))]
[(BoxEnv? exp)
(if (< (BoxEnv-depth exp) skip)
(make-BoxEnv (BoxEnv-depth exp)
(adjust-expression-depth (BoxEnv-body exp) n skip))
(make-BoxEnv (ensure-natural (- (BoxEnv-depth exp) n))
(adjust-expression-depth (BoxEnv-body exp) n skip)))]
[(WithContMark? exp)
(make-WithContMark (adjust-expression-depth (WithContMark-key exp) n skip)
(adjust-expression-depth (WithContMark-value exp) n skip)
(adjust-expression-depth (WithContMark-body exp) n skip))]
[(ApplyValues? exp)
(make-ApplyValues (adjust-expression-depth (ApplyValues-proc exp) n skip)
(adjust-expression-depth (ApplyValues-args-expr exp) n skip))]
[(DefValues? exp)
(make-DefValues (map (lambda: ([id : ToplevelRef])
(ensure-toplevelref
(adjust-expression-depth id n skip)))
(DefValues-ids exp))
(adjust-expression-depth (DefValues-rhs exp) n skip))]
[(PrimitiveKernelValue? exp)
exp]
[(VariableReference? exp)
(make-VariableReference
(ensure-toplevelref
(adjust-expression-depth (VariableReference-toplevel exp) n skip)))]
[(Require? exp)
exp]))