implementation module Sjit.Compile import StdEnv import StdGeneric import StdMaybe import StdOverloadedList import Control.Applicative import Control.Monad import Data.Either from Data.Func import mapSt, $ from Data.Map import :: Map(..), get, put, newMap, fromList import Sjit.Syntax import code from "sjit_c." appendProgram :: !Bool !Program !JITState -> JITState appendProgram is_main prog jitst # new_code_ptr = append jitst.code_start jitst.code_len jitst.code_ptr jitst.mapping jitst.n_instr (encode prog) is_main = { jitst & code_ptr = new_code_ptr , n_instr = jitst.n_instr + size prog } where append :: !Int !Int !Int !Int !Int !{#Int} !Bool -> Int append _ _ _ _ _ _ _ = code { ccall jit_append "pIppIAI:p" } bootstrap :: (!Program, !CompileState) bootstrap # (len_bs, bs_funs) = bootstrap_funs # is = {i \\ i <- flatten [is \\ (_,is) <- header]} = ( is, { vars = newMap , funs = fromList bs_funs , sp = 0 , pc = len_bs , blocks = [!is!] , jitst = appendProgram False is (initJITState 1000) }) where bootstrap_funs :: (!Int, ![(String, Int)]) bootstrap_funs = iter 0 header where iter :: !Int ![(String, [Instr])] -> (!Int, ![(String, Int)]) iter pc [] = (pc, []) iter pc [(name,is):rest] # fun = (name,pc) # (pc,funs) = iter (pc+length is) rest = (pc,[fun:funs]) header :: [(!String, ![Instr])] header = [ ("_", [PushI 0,Call 0 /* main address */,Halt]) , ("+", [IAddRet]) , ("*", [IMulRet]) , ("-", [ISubRet]) , ("/", [IDivRet]) ] initJITState :: !Int -> JITState initJITState maxlen # (code_start,mapping) = init maxlen (maxlen*10) = { n_instr = 0 , code_start = code_start , code_len = maxlen*10 , code_ptr = code_start , mapping = mapping } where init :: !Int !Int -> (!Int, !Int) init _ _ = code { ccall init_jit "II:Vpp" } compile :: !Function !CompileState -> Either String CompileState compile f cs # cs & funs = put f.fun_name cs.pc cs.funs # vars = cs.vars # cs & vars = foldr (uncurry put) cs.vars [(v,sp) \\ v <- f.fun_args & sp <- [cs.sp+1..]] = case expr f.fun_expr cs of Left e -> Left e Right (is,cs) # is = {i \\ i <- reverse [Ret:Put (max 1 (length f.fun_args)+1):is]} -> Right { cs & vars = vars , pc = cs.pc+2 , blocks = cs.blocks ++| [!is!] , jitst = appendProgram (f.fun_name == "main") is cs.jitst } where expr :: !Expr !CompileState -> Either String (![Instr], !CompileState) expr (Int i) cs = Right ([PushI i], {cs & sp=cs.sp+1, pc=cs.pc+1}) expr (Bool b) cs = Right ([PushI (if b 1 0)], {cs & sp=cs.sp+1, pc=cs.pc+1}) expr (Var v) cs = case get v cs.vars of Just i -> Right ([PushRef (i-cs.sp)], {cs & sp=cs.sp+1, pc=cs.pc+1}) Nothing -> Left ("undefined variable '" +++ v +++ "'") expr (App f args) cs # args = if (args=:[]) [Int 0] args = case mapStM expr args {cs & sp=cs.sp+1} of Left e -> Left e Right (iss,cs) -> case get f cs.funs of Just f -> Right ( [Pop (length args-1):Call f:flatten iss] , {cs & sp=cs.sp+2-length args, pc=cs.pc+2} ) Nothing -> Left ("undefined function '" +++ toString f +++ "'") mapStM :: !(a st -> m (b, st)) ![a] !st -> m ([b], st) | Monad m mapStM _ [] st = pure ([], st) mapStM f [x:xs] st = f x st >>= \(y,st) -> mapStM f xs st >>= \(ys,st) -> pure ([y:ys],st) generic gEncodedSize a :: !a -> Int gEncodedSize{|Int|} _ = 1 gEncodedSize{|{!}|} fx xs = 1 + sum [fx x \\ x <-: xs] gEncodedSize{|UNIT|} _ = 0 gEncodedSize{|PAIR|} fx fy (PAIR x y) = fx x + fy y gEncodedSize{|EITHER|} fl _ (LEFT l) = fl l gEncodedSize{|EITHER|} _ fr (RIGHT r) = fr r gEncodedSize{|CONS|} fx (CONS x) = fx x + 1 gEncodedSize{|OBJECT|} fx (OBJECT x) = fx x generic gEncode a :: !a !Int !*{#Int} -> (!Int, !*{#Int}) gEncode{|Int|} n i arr = (i+1, {arr & [i]=n}) gEncode{|{!}|} fx xs i arr = walk 0 (i+1) {arr & [i]=sz} where sz = size xs walk ai i arr | ai >= sz = (i,arr) # (i,arr) = fx xs.[ai] i arr = walk (ai+1) i arr gEncode{|UNIT|} _ i arr = (i,arr) gEncode{|PAIR|} fx fy (PAIR x y) i arr # (i,arr) = fx x i arr = fy y i arr gEncode{|EITHER|} fl _ (LEFT l) i arr = fl l i arr gEncode{|EITHER|} _ fr (RIGHT r) i arr = fr r i arr gEncode{|CONS of {gcd_index}|} fx (CONS x) i arr = fx x (i+1) {arr & [i]=gcd_index} gEncode{|OBJECT|} fx (OBJECT x) i arr = fx x i arr derive gEncodedSize Instr derive gEncode Instr encode :: !a -> *{#Int} | gEncodedSize{|*|}, gEncode{|*|} a encode x # (_,arr) = gEncode{|*|} x 0 (createArray (gEncodedSize{|*|} x) -1) = arr