diff --git a/compiler/compiler.rkt b/compiler/compiler.rkt index 27dd3aa..98400d5 100644 --- a/compiler/compiler.rkt +++ b/compiler/compiler.rkt @@ -7,12 +7,11 @@ "kernel-primitives.rkt" "optimize-il.rkt" "analyzer-structs.rkt" - #;"analyzer.rkt" "../parameters.rkt" "../sets.rkt" - racket/match racket/bool - racket/list) + racket/list + racket/match) (require/typed "../logger.rkt" [log-debug (String -> Void)]) @@ -22,9 +21,6 @@ -#;(: current-analysis (Parameterof Analysis)) -#;(define current-analysis (make-parameter (empty-analysis))) - (: -compile (Expression Target Linkage -> (Listof Statement))) @@ -543,8 +539,7 @@ (: compile-branch (Branch CompileTimeEnvironment Target Linkage -> InstructionSequence)) ;; Compiles a conditional branch. (define (compile-branch exp cenv target linkage) - (let: ([t-branch : Symbol (make-label 'trueBranch)] - [f-branch : Symbol (make-label 'falseBranch)] + (let: ([f-branch : Symbol (make-label 'falseBranch)] [after-if : Symbol (make-label 'afterIf)]) (let ([consequent-linkage (cond @@ -564,7 +559,6 @@ (make-instruction-sequence `(,(make-TestAndJumpStatement (make-TestFalse (make-Reg 'val)) f-branch))) - t-branch c-code f-branch a-code diff --git a/js-assembler/assemble-expression.rkt b/js-assembler/assemble-expression.rkt index 2fc3391..64cc655 100644 --- a/js-assembler/assemble-expression.rkt +++ b/js-assembler/assemble-expression.rkt @@ -4,9 +4,7 @@ "assemble-helpers.rkt" "assemble-open-coded.rkt" "../compiler/il-structs.rkt" - "../compiler/lexical-structs.rkt" - racket/string - racket/list) + racket/string) (provide assemble-op-expression) diff --git a/js-assembler/assemble.rkt b/js-assembler/assemble.rkt index 918a1b3..33a3832 100644 --- a/js-assembler/assemble.rkt +++ b/js-assembler/assemble.rkt @@ -1,23 +1,21 @@ #lang typed/racket/base (require "assemble-structs.rkt" "assemble-helpers.rkt" - "assemble-open-coded.rkt" "assemble-expression.rkt" "assemble-perform-statement.rkt" - "collect-jump-targets.rkt" "../compiler/il-structs.rkt" - "../compiler/lexical-structs.rkt" - "../compiler/expression-structs.rkt" - "../helpers.rkt" "optimize-basic-blocks.rkt" "fracture.rkt" racket/string racket/list) +(require/typed "../logger.rkt" + [log-debug (String -> Void)]) (provide assemble/write-invoke assemble-statement) + ;; Parameter that controls the generation of a trace. (define current-emit-debug-trace? (make-parameter #f)) @@ -32,27 +30,36 @@ (fprintf op "(function(MACHINE, success, fail, params) {\n") (fprintf op "var param;\n") (fprintf op "var RUNTIME = plt.runtime;\n") - (let: ([basic-blocks : (Listof BasicBlock) - (optimize-basic-blocks (fracture stmts))]) - (for-each - (lambda: ([basic-block : BasicBlock]) - (displayln (assemble-basic-block basic-block) op) - (newline op)) - basic-blocks) - (write-linked-label-attributes stmts op) - - (fprintf op "MACHINE.params.currentErrorHandler = fail;\n") - (fprintf op "MACHINE.params.currentSuccessHandler = success;\n") - (fprintf op #< Void)) +;; Write out all the basic blocks. +(define (write-blocks blocks op) + (for ([b blocks]) + (log-debug (format "Emitting code for basic block ~s" (BasicBlock-name b))) + (displayln (assemble-basic-block b) op) + (newline op))) @@ -152,7 +159,7 @@ EOF [(TestAndJumpStatement? stmt) (let*: ([test : PrimitiveTest (TestAndJumpStatement-op stmt)] [jump : String (assemble-jump - (make-Label (TestAndJumpStatement-label stmt)))]) + (make-Label (TestAndJumpStatement-label stmt)))]) ;; to help localize type checks, we add a type annotation here. (ann (cond [(TestFalse? test) diff --git a/js-assembler/collect-jump-targets.rkt b/js-assembler/collect-jump-targets.rkt index 14b7fde..812bfc9 100644 --- a/js-assembler/collect-jump-targets.rkt +++ b/js-assembler/collect-jump-targets.rkt @@ -1,177 +1,344 @@ #lang typed/racket/base (require "../compiler/expression-structs.rkt" "../compiler/il-structs.rkt" - "../compiler/lexical-structs.rkt" - "../helpers.rkt" - racket/list) + "../compiler/lexical-structs.rkt" + "../helpers.rkt" + racket/list) -(provide collect-general-jump-targets) +(provide collect-general-jump-targets + collect-entry-points) (: collect-general-jump-targets ((Listof Statement) -> (Listof Symbol))) ;; collects all the labels that are potential targets for GOTOs or branches. (define (collect-general-jump-targets stmts) + + (: collect-statement (Statement -> (Listof Symbol))) + (define (collect-statement stmt) + (cond + [(symbol? stmt) + empty] + [(LinkedLabel? stmt) + (list (LinkedLabel-label stmt) + (LinkedLabel-linked-to stmt))] + [(DebugPrint? stmt) + empty] + [(AssignImmediateStatement? stmt) + (let: ([v : OpArg (AssignImmediateStatement-value stmt)]) + (collect-input v))] + [(AssignPrimOpStatement? stmt) + (collect-primitive-operator (AssignPrimOpStatement-op stmt))] + [(PerformStatement? stmt) + (collect-primitive-command (PerformStatement-op stmt))] + [(TestAndJumpStatement? stmt) + (list (TestAndJumpStatement-label stmt))] + [(GotoStatement? stmt) + (collect-input (GotoStatement-target stmt))] + [(PushEnvironment? stmt) + empty] + [(PopEnvironment? stmt) + empty] + [(PushImmediateOntoEnvironment? stmt) + (collect-input (PushImmediateOntoEnvironment-value stmt))] + [(PushControlFrame/Generic? stmt) + empty] + [(PushControlFrame/Call? stmt) + (label->labels (PushControlFrame/Call-label stmt))] + [(PushControlFrame/Prompt? stmt) + (label->labels (PushControlFrame/Prompt-label stmt))] + [(PopControlFrame? stmt) + empty] + [(Comment? stmt) + empty])) + + + + (: collect-input (OpArg -> (Listof Symbol))) + (define (collect-input an-input) + (cond + [(Reg? an-input) + empty] + [(Const? an-input) + empty] + [(Label? an-input) + (list (Label-name an-input))] + [(EnvLexicalReference? an-input) + empty] + [(EnvPrefixReference? an-input) + empty] + [(EnvWholePrefixReference? an-input) + empty] + [(SubtractArg? an-input) + (append (collect-input (SubtractArg-lhs an-input)) + (collect-input (SubtractArg-rhs an-input)))] + [(ControlStackLabel? an-input) + empty] + [(ControlStackLabel/MultipleValueReturn? an-input) + empty] + [(ControlFrameTemporary? an-input) + empty] + [(CompiledProcedureEntry? an-input) + (collect-input (CompiledProcedureEntry-proc an-input))] + [(CompiledProcedureClosureReference? an-input) + (collect-input (CompiledProcedureClosureReference-proc an-input))] + [(PrimitiveKernelValue? an-input) + empty] + [(ModuleEntry? an-input) + empty] + [(IsModuleInvoked? an-input) + empty] + [(IsModuleLinked? an-input) + empty] + [(VariableReference? an-input) + empty])) + + + (: collect-location ((U Reg Label) -> (Listof Symbol))) + (define (collect-location a-location) + (cond + [(Reg? a-location) + empty] + [(Label? a-location) + (list (Label-name a-location))])) + + (: collect-primitive-operator (PrimitiveOperator -> (Listof Symbol))) + (define (collect-primitive-operator op) + (cond + [(GetCompiledProcedureEntry? op) + empty] + [(MakeCompiledProcedure? op) + (list (MakeCompiledProcedure-label op))] + [(MakeCompiledProcedureShell? op) + (list (MakeCompiledProcedureShell-label op))] + [(ApplyPrimitiveProcedure? op) + empty] + [(CaptureEnvironment? op) + empty] + [(CaptureControl? op) + empty] + [(MakeBoxedEnvironmentValue? op) + empty] + [(CallKernelPrimitiveProcedure? op) + empty])) + + (: collect-primitive-command (PrimitiveCommand -> (Listof Symbol))) + (define (collect-primitive-command op) + (cond + [(InstallModuleEntry!? op) + (list (InstallModuleEntry!-entry-point op))] + [else + empty] + ;; currently written this way because I'm hitting some bad type-checking behavior. + #;([(CheckToplevelBound!? op) + empty] + [(CheckClosureArity!? op) + empty] + [(CheckPrimitiveArity!? op) + empty] + [(ExtendEnvironment/Prefix!? op) + empty] + [(InstallClosureValues!? op) + empty] + [(RestoreEnvironment!? op) + empty] + [(RestoreControl!? op) + empty] + [(SetFrameCallee!? op) + empty] + [(SpliceListIntoStack!? op) + empty] + [(UnspliceRestFromStack!? op) + empty] + [(FixClosureShellMap!? op) + empty] + [(InstallContinuationMarkEntry!? op) + empty] + [(RaiseContextExpectedValuesError!? op) + empty] + [(RaiseArityMismatchError!? op) + empty] + [(RaiseOperatorApplicationError!? op) + empty]))) + + (unique/eq? (let: loop : (Listof Symbol) ([stmts : (Listof Statement) stmts]) - (cond [(empty? stmts) - empty] - [else - (let: ([stmt : Statement (first stmts)]) - (append (collect-statement stmt) - (loop (rest stmts))))])))) + (cond [(empty? stmts) + empty] + [else + (let: ([stmt : Statement (first stmts)]) + (append (collect-statement stmt) + (loop (rest stmts))))])))) -(: collect-statement (Statement -> (Listof Symbol))) -(define (collect-statement stmt) - (cond - [(symbol? stmt) - empty] - [(LinkedLabel? stmt) - (list (LinkedLabel-label stmt) - (LinkedLabel-linked-to stmt))] - [(DebugPrint? stmt) - empty] - [(AssignImmediateStatement? stmt) - (let: ([v : OpArg (AssignImmediateStatement-value stmt)]) - (collect-input v))] - [(AssignPrimOpStatement? stmt) - (collect-primitive-operator (AssignPrimOpStatement-op stmt))] - [(PerformStatement? stmt) - (collect-primitive-command (PerformStatement-op stmt))] - [(TestAndJumpStatement? stmt) - (list (TestAndJumpStatement-label stmt))] - [(GotoStatement? stmt) - (collect-input (GotoStatement-target stmt))] - [(PushEnvironment? stmt) - empty] - [(PopEnvironment? stmt) - empty] - [(PushImmediateOntoEnvironment? stmt) - (collect-input (PushImmediateOntoEnvironment-value stmt))] - [(PushControlFrame/Generic? stmt) - empty] - [(PushControlFrame/Call? stmt) - (label->labels (PushControlFrame/Call-label stmt))] - [(PushControlFrame/Prompt? stmt) - (label->labels (PushControlFrame/Prompt-label stmt))] - [(PopControlFrame? stmt) - empty] - [(Comment? stmt) - empty])) +(: collect-entry-points ((Listof Statement) -> (Listof Symbol))) +;; collects all the labels that are general entry points. The entry points are +;; from the starting basic block, from functions headers, and finally return points. +(define (collect-entry-points stmts) + + (: collect-statement (Statement -> (Listof Symbol))) + (define (collect-statement stmt) + (cond + [(symbol? stmt) + empty] + [(LinkedLabel? stmt) + (list (LinkedLabel-label stmt) + (LinkedLabel-linked-to stmt))] + [(DebugPrint? stmt) + empty] + [(AssignImmediateStatement? stmt) + (let: ([v : OpArg (AssignImmediateStatement-value stmt)]) + (collect-input v))] + [(AssignPrimOpStatement? stmt) + (collect-primitive-operator (AssignPrimOpStatement-op stmt))] + [(PerformStatement? stmt) + (collect-primitive-command (PerformStatement-op stmt))] + [(TestAndJumpStatement? stmt) + empty] + [(GotoStatement? stmt) + empty] + [(PushEnvironment? stmt) + empty] + [(PopEnvironment? stmt) + empty] + [(PushImmediateOntoEnvironment? stmt) + (collect-input (PushImmediateOntoEnvironment-value stmt))] + [(PushControlFrame/Generic? stmt) + empty] + [(PushControlFrame/Call? stmt) + (label->labels (PushControlFrame/Call-label stmt))] + [(PushControlFrame/Prompt? stmt) + (label->labels (PushControlFrame/Prompt-label stmt))] + [(PopControlFrame? stmt) + empty] + [(Comment? stmt) + empty])) + + + + (: collect-input (OpArg -> (Listof Symbol))) + (define (collect-input an-input) + (cond + [(Reg? an-input) + empty] + [(Const? an-input) + empty] + [(Label? an-input) + (list (Label-name an-input))] + [(EnvLexicalReference? an-input) + empty] + [(EnvPrefixReference? an-input) + empty] + [(EnvWholePrefixReference? an-input) + empty] + [(SubtractArg? an-input) + (append (collect-input (SubtractArg-lhs an-input)) + (collect-input (SubtractArg-rhs an-input)))] + [(ControlStackLabel? an-input) + empty] + [(ControlStackLabel/MultipleValueReturn? an-input) + empty] + [(ControlFrameTemporary? an-input) + empty] + [(CompiledProcedureEntry? an-input) + (collect-input (CompiledProcedureEntry-proc an-input))] + [(CompiledProcedureClosureReference? an-input) + (collect-input (CompiledProcedureClosureReference-proc an-input))] + [(PrimitiveKernelValue? an-input) + empty] + [(ModuleEntry? an-input) + empty] + [(IsModuleInvoked? an-input) + empty] + [(IsModuleLinked? an-input) + empty] + [(VariableReference? an-input) + empty])) + + + (: collect-location ((U Reg Label) -> (Listof Symbol))) + (define (collect-location a-location) + (cond + [(Reg? a-location) + empty] + [(Label? a-location) + (list (Label-name a-location))])) + + (: collect-primitive-operator (PrimitiveOperator -> (Listof Symbol))) + (define (collect-primitive-operator op) + (cond + [(GetCompiledProcedureEntry? op) + empty] + [(MakeCompiledProcedure? op) + (list (MakeCompiledProcedure-label op))] + [(MakeCompiledProcedureShell? op) + (list (MakeCompiledProcedureShell-label op))] + [(ApplyPrimitiveProcedure? op) + empty] + [(CaptureEnvironment? op) + empty] + [(CaptureControl? op) + empty] + [(MakeBoxedEnvironmentValue? op) + empty] + [(CallKernelPrimitiveProcedure? op) + empty])) + + (: collect-primitive-command (PrimitiveCommand -> (Listof Symbol))) + (define (collect-primitive-command op) + (cond + [(InstallModuleEntry!? op) + (list (InstallModuleEntry!-entry-point op))] + [else + empty] + ;; currently written this way because I'm hitting some bad type-checking behavior. + #;([(CheckToplevelBound!? op) + empty] + [(CheckClosureArity!? op) + empty] + [(CheckPrimitiveArity!? op) + empty] + [(ExtendEnvironment/Prefix!? op) + empty] + [(InstallClosureValues!? op) + empty] + [(RestoreEnvironment!? op) + empty] + [(RestoreControl!? op) + empty] + [(SetFrameCallee!? op) + empty] + [(SpliceListIntoStack!? op) + empty] + [(UnspliceRestFromStack!? op) + empty] + [(FixClosureShellMap!? op) + empty] + [(InstallContinuationMarkEntry!? op) + empty] + [(RaiseContextExpectedValuesError!? op) + empty] + [(RaiseArityMismatchError!? op) + empty] + [(RaiseOperatorApplicationError!? op) + empty]))) + + + (unique/eq? + (let: loop : (Listof Symbol) ([stmts : (Listof Statement) stmts]) + (cond [(empty? stmts) + empty] + [else + (let: ([stmt : Statement (first stmts)]) + (append (collect-statement stmt) + (loop (rest stmts))))])))) -(: collect-input (OpArg -> (Listof Symbol))) -(define (collect-input an-input) - (cond - [(Reg? an-input) - empty] - [(Const? an-input) - empty] - [(Label? an-input) - (list (Label-name an-input))] - [(EnvLexicalReference? an-input) - empty] - [(EnvPrefixReference? an-input) - empty] - [(EnvWholePrefixReference? an-input) - empty] - [(SubtractArg? an-input) - (append (collect-input (SubtractArg-lhs an-input)) - (collect-input (SubtractArg-rhs an-input)))] - [(ControlStackLabel? an-input) - empty] - [(ControlStackLabel/MultipleValueReturn? an-input) - empty] - [(ControlFrameTemporary? an-input) - empty] - [(CompiledProcedureEntry? an-input) - (collect-input (CompiledProcedureEntry-proc an-input))] - [(CompiledProcedureClosureReference? an-input) - (collect-input (CompiledProcedureClosureReference-proc an-input))] - [(PrimitiveKernelValue? an-input) - empty] - [(ModuleEntry? an-input) - empty] - [(IsModuleInvoked? an-input) - empty] - [(IsModuleLinked? an-input) - empty] - [(VariableReference? an-input) - empty])) - - -(: collect-location ((U Reg Label) -> (Listof Symbol))) -(define (collect-location a-location) - (cond - [(Reg? a-location) - empty] - [(Label? a-location) - (list (Label-name a-location))])) - -(: collect-primitive-operator (PrimitiveOperator -> (Listof Symbol))) -(define (collect-primitive-operator op) - (cond - [(GetCompiledProcedureEntry? op) - empty] - [(MakeCompiledProcedure? op) - (list (MakeCompiledProcedure-label op))] - [(MakeCompiledProcedureShell? op) - (list (MakeCompiledProcedureShell-label op))] - [(ApplyPrimitiveProcedure? op) - empty] - [(CaptureEnvironment? op) - empty] - [(CaptureControl? op) - empty] - [(MakeBoxedEnvironmentValue? op) - empty] - [(CallKernelPrimitiveProcedure? op) - empty])) - -(: collect-primitive-command (PrimitiveCommand -> (Listof Symbol))) -(define (collect-primitive-command op) - (cond - [(InstallModuleEntry!? op) - (list (InstallModuleEntry!-entry-point op))] - [else - empty] - ;; currently written this way because I'm hitting some bad type-checking behavior. - #;([(CheckToplevelBound!? op) - empty] - [(CheckClosureArity!? op) - empty] - [(CheckPrimitiveArity!? op) - empty] - [(ExtendEnvironment/Prefix!? op) - empty] - [(InstallClosureValues!? op) - empty] - [(RestoreEnvironment!? op) - empty] - [(RestoreControl!? op) - empty] - [(SetFrameCallee!? op) - empty] - [(SpliceListIntoStack!? op) - empty] - [(UnspliceRestFromStack!? op) - empty] - [(FixClosureShellMap!? op) - empty] - [(InstallContinuationMarkEntry!? op) - empty] - [(RaiseContextExpectedValuesError!? op) - empty] - [(RaiseArityMismatchError!? op) - empty] - [(RaiseOperatorApplicationError!? op) - empty]))) - @@ -180,9 +347,9 @@ (: label->labels ((U Symbol LinkedLabel) -> (Listof Symbol))) (define (label->labels label) (cond - [(symbol? label) - (list label)] - [(LinkedLabel? label) - (list (LinkedLabel-label label) - (LinkedLabel-linked-to label))])) + [(symbol? label) + (list label)] + [(LinkedLabel? label) + (list (LinkedLabel-label label) + (LinkedLabel-linked-to label))])) diff --git a/js-assembler/fracture.rkt b/js-assembler/fracture.rkt index 7de7173..acaf6da 100644 --- a/js-assembler/fracture.rkt +++ b/js-assembler/fracture.rkt @@ -1,26 +1,30 @@ #lang typed/racket/base (require "assemble-structs.rkt" - "assemble-helpers.rkt" - "assemble-open-coded.rkt" - "assemble-expression.rkt" - "assemble-perform-statement.rkt" "collect-jump-targets.rkt" "../compiler/il-structs.rkt" - "../compiler/lexical-structs.rkt" "../compiler/expression-structs.rkt" - "../helpers.rkt" - racket/string racket/list) +;; Breaks up a sequence of statements into a list of basic blocks. +;; +;; The first basic block is special, and represents the start of execution. +;; +;; A basic block consists of a sequence of straight line statements, followed by one of +;; the following: +;; +;; * A conditional jump. +;; * An unconditional jump. +;; * Termination. + (provide fracture) - ;; fracture: (listof stmt) -> (listof basic-block) -(: fracture ((Listof Statement) -> (Listof BasicBlock))) +(: fracture ((Listof Statement) -> (values (Listof BasicBlock) + (Listof Symbol)))) (define (fracture stmts) (let*: ([first-block-label : Symbol (if (and (not (empty? stmts)) (symbol? (first stmts))) @@ -31,48 +35,52 @@ (rest stmts) stmts)] [jump-targets : (Listof Symbol) - (cons first-block-label (collect-general-jump-targets stmts))]) - (let: loop : (Listof BasicBlock) - ([name : Symbol first-block-label] - [acc : (Listof UnlabeledStatement) '()] - [basic-blocks : (Listof BasicBlock) '()] - [stmts : (Listof Statement) stmts] - [last-stmt-goto? : Boolean #f]) - (cond - [(null? stmts) - (reverse (cons (make-BasicBlock name (reverse acc)) - basic-blocks))] - [else - (let: ([first-stmt : Statement (car stmts)]) - (: do-on-label (Symbol -> (Listof BasicBlock))) - (define (do-on-label label-name) - (cond - [(member label-name jump-targets) - (loop label-name - '() - (cons (make-BasicBlock - name - (if last-stmt-goto? - (reverse acc) - (reverse (append `(,(make-GotoStatement (make-Label label-name))) - acc)))) - basic-blocks) - (cdr stmts) - last-stmt-goto?)] - [else - (loop name - acc - basic-blocks - (cdr stmts) - last-stmt-goto?)])) - (cond - [(symbol? first-stmt) - (do-on-label first-stmt)] - [(LinkedLabel? first-stmt) - (do-on-label (LinkedLabel-label first-stmt))] - [else - (loop name - (cons first-stmt acc) - basic-blocks - (cdr stmts) - (GotoStatement? (car stmts)))]))])))) + (cons first-block-label (collect-general-jump-targets stmts))] + [entry-points : (Listof Symbol) + (cons first-block-label (collect-entry-points stmts))]) + + (let: loop : (values (Listof BasicBlock) (Listof Symbol)) + ([name : Symbol first-block-label] + [acc : (Listof UnlabeledStatement) '()] + [basic-blocks : (Listof BasicBlock) '()] + [stmts : (Listof Statement) stmts] + [last-stmt-goto? : Boolean #f]) + (cond + [(null? stmts) + (values (reverse (cons (make-BasicBlock name (reverse acc)) + basic-blocks)) + entry-points)] + [else + (let: ([first-stmt : Statement (car stmts)]) + (: do-on-label (Symbol -> (values (Listof BasicBlock) (Listof Symbol)))) + (define (do-on-label label-name) + (cond + [(member label-name jump-targets) + (loop label-name + '() + (cons (make-BasicBlock + name + (if last-stmt-goto? + (reverse acc) + (reverse (append `(,(make-GotoStatement (make-Label label-name))) + acc)))) + basic-blocks) + (cdr stmts) + last-stmt-goto?)] + [else + (loop name + acc + basic-blocks + (cdr stmts) + last-stmt-goto?)])) + (cond + [(symbol? first-stmt) + (do-on-label first-stmt)] + [(LinkedLabel? first-stmt) + (do-on-label (LinkedLabel-label first-stmt))] + [else + (loop name + (cons first-stmt acc) + basic-blocks + (cdr stmts) + (GotoStatement? (car stmts)))]))]))))