#lang typed/racket/base
(require "arity-structs.rkt"
"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"
"analyzer.rkt"
racket/list
racket/match)
(require/typed "../logger.rkt"
[log-debug (String -> Void)])
(require/typed "compiler-helper.rkt"
[ensure-const-value (Any -> const-value)])
(require/typed "../parser/modprovide.rkt"
[get-provided-names (Expression -> (Listof ModuleProvide))])
(provide (rename-out [-compile compile])
compile-general-procedure-call)
(: current-lambda-being-compiled (Parameterof (U #f Lam)))
(define current-lambda-being-compiled (make-parameter #f))
(: -compile (Expression Target Linkage -> (Listof Statement)))
(define (-compile exp target linkage)
(define lambda-bodies (collect-all-lambdas-with-bodies exp))
(define after-lam-bodies (make-label 'afterLamBodies))
(define-values (before-pop-prompt-multiple before-pop-prompt)
(new-linked-labels 'beforePopPrompt))
(optimize-il
(statements
(append-instruction-sequences
(make-Goto (make-Label after-lam-bodies))
(compile-lambda-bodies lambda-bodies)
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-SubtractArg (make-Reg 'argcount) (make-Const 1))
(make-Const 0))
before-pop-prompt
(if (eq? target 'val)
empty-instruction-sequence
(make-AssignImmediate target (make-Reg 'val)))))))
(: 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-AssignImmediate 'proc (make-ControlStackLabel))
(make-PopControlFrame)
(make-Goto (make-Reg 'proc)))]
[else
(append-instruction-sequences
(make-AssignImmediate 'proc (make-ControlStackLabel))
(make-PopControlFrame)
(make-Goto (make-Reg 'proc)))])]
[(NextLinkage? linkage)
empty-instruction-sequence]
[(LabelLinkage? linkage)
(make-Goto (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-Perform (make-ExtendEnvironment/Prefix! names))
(compile (Top-code top)
(cons (Top-prefix top) cenv)
'val
next-linkage/drop-multiple)
(make-AssignImmediate 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-Perform (make-InstallModuleEntry! name path module-entry))
(make-Goto (make-Label after-module-body))
module-entry
(make-Perform (make-MarkModuleInvoked! path))
(apply append-instruction-sequences
(map compile-module-invoke (Module-requires mod)))
(make-Perform (make-ExtendEnvironment/Prefix! names))
(make-AssignImmediate (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-AssignImmediate 'proc (make-ControlStackLabel))
(make-PopControlFrame)
(make-Perform (make-FinalizeModuleInvokation! path))
(make-Goto (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-AssignImmediate 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
(define linked (make-label 'linked))
(define-values (on-return-multiple on-return) (new-linked-labels 'onReturn))
(append-instruction-sequences
(make-TestAndJump (make-TestTrue (make-ModulePredicate a-module-name 'linked?))
linked)
(make-DebugPrint (make-Const
(format "DEBUG: the module ~a hasn't been linked in!!!"
(ModuleLocator-name a-module-name))))
(make-Goto (make-Label (LinkedLabel-label on-return)))
linked
(make-TestAndJump (make-TestTrue
(make-ModulePredicate a-module-name 'invoked?))
(LinkedLabel-label on-return))
(make-PushControlFrame/Call on-return)
(make-Goto (ModuleEntry a-module-name))
on-return-multiple
(make-PopEnvironment (new-SubtractArg (make-Reg 'argcount)
(make-Const 1))
(make-Const 0))
on-return)]))
(: 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-AssignImmediate 'argcount (make-Const 1))]
[(natural? context)
(if (= context 1)
empty-instruction-sequence
(append-instruction-sequences
(make-AssignImmediate 'argcount (make-Const 1))
(make-Perform (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-AssignImmediate target (make-Const
(ensure-const-value (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-AssignImmediate 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-AssignImmediate 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)
(define prefix (ensure-prefix (list-ref cenv (ToplevelRef-depth exp))))
(define prefix-element (list-ref (Prefix-names prefix) (ToplevelRef-pos exp)))
(let ([singular-context-check (emit-singular-context linkage)])
(end-with-linkage linkage
cenv
(append-instruction-sequences
(cond
[(ModuleVariable? prefix-element)
(cond [(kernel-module-name? (ModuleVariable-module-name prefix-element))
(make-AssignPrimOp target
(make-PrimitivesReference
(kernel-module-variable->primitive-name
prefix-element)
))]
[else
(make-AssignImmediate
target
(make-EnvPrefixReference (ToplevelRef-depth exp)
(ToplevelRef-pos exp)
#t))])]
[else
(append-instruction-sequences
(if (ToplevelRef-check-defined? exp)
(make-Perform (make-CheckToplevelBound!
(ToplevelRef-depth exp)
(ToplevelRef-pos exp)))
empty-instruction-sequence)
(if (ToplevelRef-constant? exp)
(make-Comment (format "Constant toplevel ref: ~s"
(extract-static-knowledge exp cenv)))
empty-instruction-sequence)
(make-AssignImmediate
target
(make-EnvPrefixReference (ToplevelRef-depth exp)
(ToplevelRef-pos exp)
#f)))])
singular-context-check))))
(: compile-toplevel-set (ToplevelSet CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-toplevel-set exp cenv target linkage)
(define prefix (ensure-prefix (list-ref cenv (ToplevelSet-depth exp))))
(define prefix-element (list-ref (Prefix-names prefix) (ToplevelSet-pos exp)))
(let ([get-value-code
(cond
[(ModuleVariable? prefix-element)
(compile (ToplevelSet-value exp)
cenv
(make-EnvPrefixReference (ToplevelSet-depth exp)
(ToplevelSet-pos exp)
#t)
next-linkage/expects-single)]
[else
(compile (ToplevelSet-value exp)
cenv
(make-EnvPrefixReference (ToplevelSet-depth exp)
(ToplevelSet-pos exp)
#f)
next-linkage/expects-single)])]
[singular-context-check (emit-singular-context linkage)])
(end-with-linkage
linkage
cenv
(append-instruction-sequences
get-value-code
(make-AssignImmediate 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-TestAndJump (make-TestFalse (make-Reg 'val))
f-branch:)
c-code
f-branch: a-code
(if (NextLinkage? linkage)
after-if:
empty-instruction-sequence))))))
(: 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))
(define-values (on-return/multiple on-return)
(new-linked-labels 'beforePromptPop))
(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-AssignImmediate target (make-Reg 'val))))]
[else
(define-values (on-return/multiple on-return)
(new-linked-labels 'beforePromptPop))
(append-instruction-sequences
(make-PushControlFrame/Prompt (make-DefaultContinuationPromptTag)
on-return)
(compile (first seq) cenv 'val return-linkage/nontail)
on-return/multiple
(make-PopEnvironment (new-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
(compile (first seq) cenv 'val next-linkage/keep-multiple-on-stack)
(make-TestAndJump (make-TestZero (make-Reg 'argcount)) after-first-seq)
(make-PushImmediateOntoEnvironment (make-Reg 'val) #f)
after-first-seq
(make-PushControlFrame/Generic)
(make-AssignImmediate (make-ControlFrameTemporary 'pendingBegin0Count)
(make-Reg 'argcount))
(make-Perform (make-UnspliceRestFromStack! (make-Const 0) (make-Reg 'argcount)))
(make-AssignImmediate (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-Perform (make-SpliceListIntoStack! (make-Const 0)))
(make-AssignImmediate 'argcount (make-ControlFrameTemporary 'pendingBegin0Count))
(make-PopControlFrame)
(make-TestAndJump (make-TestZero (make-Reg 'argcount)) after-values-reinstated)
(make-AssignImmediate '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-AssignImmediate target (make-Reg 'val))
(cond
[(ReturnLinkage? linkage)
(cond
[(ReturnLinkage-tail? linkage)
(append-instruction-sequences
(make-PopEnvironment (make-Const (length cenv))
(new-SubtractArg (make-Reg 'argcount)
(make-Const 1)))
(make-AssignImmediate 'proc (make-ControlStackLabel/MultipleValueReturn))
(make-PopControlFrame)
(make-Goto (make-Reg 'proc)))]
[else
(append-instruction-sequences
(make-AssignImmediate 'proc (make-ControlStackLabel/MultipleValueReturn))
(make-PopControlFrame)
(make-Goto (make-Reg 'proc)))])]
[(NextLinkage? linkage)
empty-instruction-sequence]
[(LabelLinkage? linkage)
(make-Goto (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-AssignPrimOp
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-AssignPrimOp
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-PushEnvironment n #f)
(apply append-instruction-sequences
(map (lambda: ([lam : (U Lam EmptyClosureReference)]
[target : Target])
(make-AssignPrimOp
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-AssignPrimOp
(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-AssignPrimOp
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)
(parameterize ([current-lambda-being-compiled exp])
(let: ([maybe-unsplice-rest-argument : InstructionSequence
(if (Lam-rest? exp)
(make-Perform
(make-UnspliceRestFromStack!
(make-Const (Lam-num-parameters exp))
(new-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-Perform (make-InstallClosureValues!
(length (Lam-closure-map exp)))))
empty-instruction-sequence)]
[lam-body-code : InstructionSequence
(compile (Lam-body exp)
cenv
'val
return-linkage)])
(append-instruction-sequences
(Lam-entry-label exp)
(Comment (format "lambda body for ~a" (Lam-name 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-TestAndJump (make-TestClosureArityMismatch
(make-CompiledProcedureClosureReference
(make-Reg 'proc)
i)
(make-Reg 'argcount))
not-match)
(make-AssignImmediate
'proc
(make-CompiledProcedureClosureReference (make-Reg 'proc) i))
(make-Goto (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)]
[(operator-is-statically-known-identifier? op-knowledge)
=>
(lambda (id)
(cond
[(KernelPrimitiveName/Inline? id)
(compile-open-codeable-application id exp cenv target linkage)]
[((current-primitive-identifier?) id)
=> (lambda (expected-arity)
(compile-primitive-application exp cenv target linkage id expected-arity))]
[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-AssignImmediate 'proc op-knowledge)
(make-Perform
(make-RaiseOperatorApplicationError! (make-Reg 'proc))))]
[else
(default)]))))
(: operator-is-statically-known-identifier? (CompileTimeEnvironmentEntry -> (U False Symbol)))
(define (operator-is-statically-known-identifier? op-knowledge)
(cond [(PrimitiveKernelValue? op-knowledge)
(let ([id (PrimitiveKernelValue-id op-knowledge)])
id)]
[(ModuleVariable? op-knowledge)
(cond
[(kernel-module-name? (ModuleVariable-module-name op-knowledge))
(kernel-module-variable->primitive-name op-knowledge)]
[else
#f])]
[else
#f]))
(: compile-general-application (App CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-general-application exp cenv target linkage)
(define n (length (App-operands exp)))
(define extended-cenv (extend-compile-time-environment/scratch-space
cenv
(length (App-operands exp))))
(define proc+operands-code
(cond
[(andmap side-effect-free-expression? (cons (App-operator exp) (App-operands exp)))
(define proc-code (compile (App-operator exp) extended-cenv 'proc next-linkage/expects-single))
(define 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])
(make-EnvLexicalReference i #f)))))
(apply append-instruction-sequences proc-code operand-codes)]
[else
(define 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))
(define 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
proc-code
(juggle-operands operand-codes))]))
(append-instruction-sequences
(make-PushEnvironment (length (App-operands exp)) #f)
proc+operands-code
(make-AssignImmediate 'argcount (make-Const (length (App-operands exp))))
(compile-general-procedure-call cenv
(make-Const (length (App-operands exp)))
target
linkage)))
(: compile-primitive-application (App CompileTimeEnvironment Target Linkage Symbol Arity -> InstructionSequence))
(define (compile-primitive-application exp cenv target linkage primitive-name expected-arity)
(let* ([extended-cenv
(extend-compile-time-environment/scratch-space
cenv
(length (App-operands exp)))]
[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])
(make-EnvLexicalReference i #f))))])
(append-instruction-sequences
(make-PushEnvironment (length (App-operands exp)) #f)
(apply append-instruction-sequences operand-codes)
(if (number? expected-arity)
empty-instruction-sequence
(make-AssignImmediate 'argcount (make-Const (length (App-operands exp)))))
(if (arity-matches? expected-arity (length (App-operands exp)))
(compile-primitive-procedure-call primitive-name
cenv
(make-Const (length (App-operands exp)))
target
linkage)
(append-instruction-sequences
(compile (App-operator exp) extended-cenv 'proc next-linkage/expects-single)
(make-Perform (make-RaiseArityMismatchError!
(make-Reg 'proc)
expected-arity
(make-Const (length (App-operands exp))))))))))
(: compile-primitive-procedure-call (Symbol CompileTimeEnvironment OpArg Target Linkage -> InstructionSequence))
(define (compile-primitive-procedure-call primitive-name cenv number-of-arguments target linkage)
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(make-AssignPrimOp 'val (make-ApplyPrimitiveProcedure primitive-name))
(make-PopEnvironment number-of-arguments (make-Const 0))
(if (eq? target 'val)
empty-instruction-sequence
(make-AssignImmediate target (make-Reg 'val)))
(emit-singular-context linkage))))
(: compile-open-codeable-application
(KernelPrimitiveName/Inline App CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-open-codeable-application kernel-op exp cenv target linkage)
(let ([singular-context-check (emit-singular-context linkage)]
[n (length (App-operands exp))])
(define expected-operand-types
(kernel-primitive-expected-operand-types kernel-op n))
(: make-runtime-arity-mismatch-code (Arity -> InstructionSequence))
(define (make-runtime-arity-mismatch-code expected-arity)
(end-with-linkage
linkage cenv
(append-instruction-sequences
(make-PushEnvironment n #f)
(apply append-instruction-sequences
(map (lambda: ([operand : Expression]
[target : Target])
(compile operand
(extend-compile-time-environment/scratch-space
cenv
(length (App-operands exp)))
target
next-linkage/expects-single))
(App-operands exp)
(build-list (length (App-operands exp))
(lambda: ([i : Natural])
(make-EnvLexicalReference i #f)))))
(make-AssignImmediate 'proc (make-PrimitiveKernelValue kernel-op))
(make-AssignImmediate 'argcount
(make-Const (length (App-operands exp))))
(make-Perform (make-RaiseArityMismatchError!
(make-Reg 'proc)
expected-arity
(make-Const n))))))
(cond
[(IncorrectArity? expected-operand-types)
(make-runtime-arity-mismatch-code (IncorrectArity-expected expected-operand-types))]
[(not (= n (length expected-operand-types)))
(make-runtime-arity-mismatch-code (length expected-operand-types))]
[else
(cond
[(andmap side-effect-free-expression? (App-operands exp))
(let* ([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)))
expected-operand-types
operand-knowledge)]
[operand-poss
(side-effect-free-operands->opargs (map (lambda: ([op : Expression])
(ensure-side-effect-free-expression
(adjust-expression-depth op n n)))
(App-operands exp))
operand-knowledge)])
(end-with-linkage
linkage cenv
(append-instruction-sequences
(make-AssignPrimOp target
(make-CallKernelPrimitiveProcedure
kernel-op
operand-poss
expected-operand-types
typechecks?))
singular-context-check)))]
[else
(let*-values ([(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-side-effect-free-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))]
[(constant-operand-knowledge)
(map (lambda: ([arg : Expression])
(extract-static-knowledge arg extended-cenv))
constant-operands)]
[(operand-knowledge)
(append constant-operand-knowledge
(map (lambda: ([arg : Expression])
(extract-static-knowledge arg extended-cenv))
rest-operands))]
[(typechecks?)
(map (lambda: ([dom : OperandDomain]
[known : CompileTimeEnvironmentEntry])
(not (redundant-check? dom known)))
expected-operand-types
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)
(side-effect-free-operands->opargs constant-operands constant-operand-knowledge)]
[(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-AssignPrimOp (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-side-effect-free-expression (Expression -> (U Constant ToplevelRef LocalRef PrimitiveKernelValue)))
(define (ensure-side-effect-free-expression e)
(if (or (Constant? e)
(LocalRef? e)
(ToplevelRef? e)
(PrimitiveKernelValue? e))
e
(error 'ensure-side-effect-free-expression)))
(: side-effect-free-expression? (Expression -> Boolean))
(define (side-effect-free-expression? e)
(or (Constant? e)
(LocalRef? e)
(ToplevelRef? e)
(PrimitiveKernelValue? e)))
(: side-effect-free-operands->opargs ((Listof (U Constant LocalRef ToplevelRef PrimitiveKernelValue))
(Listof CompileTimeEnvironmentEntry)
-> (Listof OpArg)))
(define (side-effect-free-operands->opargs rands knowledge)
(map (lambda: ([e : (U Constant LocalRef ToplevelRef PrimitiveKernelValue)]
[k : CompileTimeEnvironmentEntry])
(cond
[(Constant? e)
(make-Const (ensure-const-value (Constant-v e)))]
[(LocalRef? e)
(make-EnvLexicalReference (LocalRef-depth e)
(LocalRef-unbox? e))]
[(ToplevelRef? e)
(cond
[(ModuleVariable? k)
(make-EnvPrefixReference (ToplevelRef-depth e) (ToplevelRef-pos e) #t)]
[else
(make-EnvPrefixReference (ToplevelRef-depth e) (ToplevelRef-pos e) #f)])]
[(PrimitiveKernelValue? e)
e]))
rands
knowledge))
(: 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))]
[(vector)
(vector? (Const-const knowledge))]
[(pair)
(pair? (Const-const knowledge))]
[(caarpair)
(let ([x (Const-const knowledge)])
(and (pair? x)
(pair? (car x))))])]
[else
#f])]))
(: split-operands-by-constants
((Listof Expression) ->
(values (Listof (U Constant))
(Listof Expression))))
(define (split-operands-by-constants rands)
(let: loop : (values (Listof (U Constant)) (Listof Expression))
([rands : (Listof Expression) rands]
[constants : (Listof (U Constant))
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-operator-knowledge exp cenv target linkage)
(let ([arity-check
(cond [(arity-matches? (StaticallyKnownLam-arity static-operator-knowledge)
(length (App-operands exp)))
empty-instruction-sequence]
[else
(make-Perform
(make-RaiseArityMismatchError!
(make-Reg 'proc)
(StaticallyKnownLam-arity static-operator-knowledge)
(make-Const (length (App-operands exp)))))])])
(let* ([extended-cenv
(extend-compile-time-environment/scratch-space
cenv
(length (App-operands exp)))]
[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])
(make-EnvLexicalReference i #f))))]
[proc-code (compile (App-operator exp)
extended-cenv
'proc
next-linkage/expects-single)])
(append-instruction-sequences
(make-PushEnvironment (length (App-operands exp)) #f)
(apply append-instruction-sequences operand-codes)
proc-code
arity-check
(compile-procedure-call/statically-known-lam static-operator-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-AssignImmediate 'proc
(make-EnvLexicalReference n #f))
(make-AssignImmediate (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
'keep-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)
(end-with-linkage
linkage
cenv
(append-instruction-sequences
(make-Perform (make-CheckClosureAndArity!))
(compile-compiled-procedure-application cenv
number-of-arguments
'dynamic
target
linkage))))
(: compile-procedure-call/statically-known-lam
(StaticallyKnownLam CompileTimeEnvironment CompileTimeEnvironment Natural Target Linkage -> InstructionSequence))
(define (compile-procedure-call/statically-known-lam static-operator-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-AssignImmediate 'argcount
(make-Const n))
(compile-compiled-procedure-application cenv
(make-Const n)
(make-Label
(StaticallyKnownLam-entry-point static-operator-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)
(define entry-point-target
(cond [(Label? entry-point)
entry-point]
[(eq? entry-point 'dynamic)
(make-CompiledProcedureEntry (make-Reg 'proc))]))
(define maybe-migrate-val-to-target
(cond
[(eq? target 'val)
empty-instruction-sequence]
[else
(make-AssignImmediate target (make-Reg 'val))]))
(define-values (on-return/multiple on-return) (new-linked-labels 'procReturn))
(define nontail-jump-into-procedure
(append-instruction-sequences
(make-PushControlFrame/Call on-return)
(make-Goto 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-Perform (make-SetFrameCallee! (make-Reg 'proc)))
(make-Goto entry-point-target)))]
[else
(make-Goto entry-point-target)])]
[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-Goto (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 (new-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-Goto (make-Label after-return))
on-return
(make-AssignImmediate 'argcount (make-Const 1))
after-return))]
[(natural? context)
(cond
[(= context 1)
(append-instruction-sequences
on-return/multiple
(make-Perform
(make-RaiseContextExpectedValuesError! 1))
on-return)]
[else
(let ([after-value-check (make-label 'afterValueCheck)])
(append-instruction-sequences
on-return/multiple
(make-TestAndJump (make-TestZero (new-SubtractArg (make-Reg 'argcount)
(make-Const context)))
after-value-check)
on-return
(make-Perform
(make-RaiseContextExpectedValuesError! context))
after-value-check))])]))
(: 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)]
[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 (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-PushEnvironment 1 #f)
rhs-code
body-code
after-body-code
(cond
[(eq? context 'tail)
empty-instruction-sequence]
[(eq? context 'drop-multiple)
(make-PopEnvironment (make-Const 1)
(make-Const 0))]
[(eq? context 'keep-multiple)
(make-PopEnvironment (make-Const 1)
(new-SubtractArg
(make-Reg 'argcount)
(make-Const 1)))]
[else
(cond [(= context 0)
(make-PopEnvironment (make-Const 1)
(make-Const 0))]
[(= context 1)
(make-PopEnvironment (make-Const 1)
(make-Const 0))]
[else
(make-PopEnvironment (make-Const 1)
(new-SubtractArg
(make-Const context)
(make-Const 1)))])])))))
(: 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-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)
(new-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)
(new-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-Perform (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
(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
(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
(compile (InstallValue-body exp)
cenv
'val
(make-NextLinkage count))
(apply append-instruction-sequences
(map (lambda: ([to : EnvLexicalReference]
[from : OpArg])
(append-instruction-sequences
(make-AssignImmediate 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-AssignPrimOp (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-AssignImmediate
(make-ControlFrameTemporary 'pendingContinuationMarkKey)
(make-Reg 'val))
(compile (WithContMark-value exp) cenv 'val next-linkage/expects-single)
(make-Perform (make-InstallContinuationMarkEntry!))
(compile (WithContMark-body exp) cenv target linkage)))
(: in-other-context ((U NextLinkage LabelLinkage) -> InstructionSequence))
(define (in-other-context linkage)
(define-values (on-return/multiple: on-return:)
(new-linked-labels 'procReturn))
(define context (linkage-context linkage))
(define check-values-context-on-procedure-return
(emit-values-context-check-on-procedure-return
context on-return/multiple: on-return:))
(define maybe-migrate-val-to-target
(cond
[(eq? target 'val)
empty-instruction-sequence]
[else
(make-AssignImmediate target (make-Reg 'val))]))
(append-instruction-sequences
(make-PushControlFrame/Call on-return:)
(compile (WithContMark-key exp) cenv 'val next-linkage/expects-single)
(make-AssignImmediate (make-ControlFrameTemporary 'pendingContinuationMarkKey)
(make-Reg 'val))
(compile (WithContMark-value exp) cenv 'val next-linkage/expects-single)
(make-Perform (make-InstallContinuationMarkEntry!))
(compile (WithContMark-body exp) cenv 'val return-linkage/nontail)
check-values-context-on-procedure-return
maybe-migrate-val-to-target))
(cond
[(ReturnLinkage? linkage)
(in-return-context)]
[(NextLinkage? linkage)
(in-other-context linkage)]
[(LabelLinkage? linkage)
(append-instruction-sequences
(in-other-context linkage)
(make-Goto (make-Label (LabelLinkage-label linkage))))]))
(: compile-apply-values (ApplyValues CompileTimeEnvironment Target Linkage -> InstructionSequence))
(define (compile-apply-values exp cenv target linkage)
(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-TestAndJump (make-TestZero (make-Reg 'argcount)) after-args-evaluated)
(make-PushImmediateOntoEnvironment (make-Reg 'val) #f)
after-args-evaluated
(make-AssignImmediate
'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-AssignImmediate
(make-EnvPrefixReference (+ (ensure-natural (sub1 n))
(ToplevelRef-depth id))
(ToplevelRef-pos id)
#f)
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-AssignImmediate 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-Perform (make-RaiseUnimplementedPrimitiveError! id))])))
(: ensure-natural (Integer -> Natural))
(define (ensure-natural n)
(if (>= n 0)
n
(error 'ensure-natural "Not a natural: ~s\n" n)))
(: 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)
(EnvPrefixReference-modvar? target))]
[(PrimitivesReference? target)
target]
[(ControlFrameTemporary? target)
target]
[(ModulePrefixTarget? target)
target]
[(ModuleVariable? 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]))