├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── package.yaml ├── src ├── Assembler.hs ├── JIT.hs └── Main.hs ├── stack.yaml └── tinyjit.cabal /.gitignore: -------------------------------------------------------------------------------- 1 | *.sw[po] 2 | dist/ 3 | .cabal-sandbox 4 | cabal.sandbox.config 5 | *.c 6 | *.s 7 | *.o 8 | .stack-work 9 | *.hi 10 | dist-newstyle 11 | stack.yaml.lock 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Use new container infrastructure to enable caching 2 | sudo: false 3 | 4 | # Choose a lightweight base image; we provide our own build tools. 5 | language: c 6 | 7 | # GHC depends on GMP. You can add other dependencies here as well. 8 | addons: 9 | apt: 10 | packages: 11 | - libgmp-dev 12 | 13 | # The different configurations we want to test. You could also do things like 14 | # change flags or use --stack-yaml to point to a different file. 15 | env: 16 | - ARGS="" 17 | - ARGS="--resolver lts-13" 18 | - ARGS="--resolver lts-14" 19 | - ARGS="--resolver lts" 20 | - ARGS="--resolver nightly" 21 | 22 | before_install: 23 | # Download and unpack the stack executable 24 | - mkdir -p ~/.local/bin 25 | - export PATH=$HOME/.local/bin:$PATH 26 | - travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack' 27 | 28 | # This line does all of the work: installs GHC if necessary, build the library, 29 | # executables, and test suites, and runs the test suites. --no-terminal works 30 | # around some quirks in Travis's terminal implementation. 31 | script: stack $ARGS --no-terminal --install-ghc test --haddock 32 | 33 | # Caching so the next build will be fast too. 34 | cache: 35 | directories: 36 | - $HOME/.stack 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2020, Stephen Diehl 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to 5 | deal in the Software without restriction, including without limitation the 6 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 | sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Haskell JIT Example 2 | ------------------- 3 | 4 | [![Build Status](https://travis-ci.org/sdiehl/tinyjit.svg)](https://travis-ci.org/sdiehl/tinyjit) 5 | [![MIT License](http://img.shields.io/badge/license-mit-blue.svg)](https://github.com/sdiehl/tinyjit/blob/master/LICENSE) 6 | 7 | Tiny example of building a intermediate language that JIT compiles Haskell DSL 8 | into x86-64 machine code. 9 | 10 | Usage 11 | ----- 12 | 13 | The factorial function can be written in assembly, taking the input value in 14 | ``%rcx`` and computing the resulting value in ``%rax``. 15 | 16 | ```perl 17 | .global main 18 | 19 | main: 20 | mov rcx, 5 21 | mov rax, 1 22 | .factor: 23 | mul rcx 24 | loop .factor 25 | ret 26 | ``` 27 | 28 | In our Haskell logic we compose these operations inside of the ``X86`` monad. 29 | 30 | ```haskell 31 | factorial :: Int64 -> X86 () 32 | factorial n = do 33 | mov rcx (I n) 34 | mov rax (I 1) 35 | l1 <- label 36 | mul rcx 37 | loop l1 38 | ret 39 | ``` 40 | 41 | The resulting logic can be JIT compiled inside of Haskell and invoked from 42 | inside the Haskell runtime by calling out to the JIT'd memory. 43 | 44 | ```haskell 45 | main :: IO () 46 | main = do 47 | let jitsize = 256*1024 48 | mem <- allocateMemory jitsize 49 | let jitm = assemble mem (factorial 5) 50 | 51 | case jitm of 52 | Left err -> putStrLn err 53 | Right jitst -> do 54 | let machCode = _mach jitst 55 | fn <- jit mem machCode 56 | res <- fn 57 | putStrLn $ "Result: " <> show res 58 | ``` 59 | 60 | The machine code is generated. 61 | 62 | ``` 63 | 48 c7 c1 05 00 00 00 48 c7 c0 01 00 00 00 48 f7 e1 e2 fc c3 64 | ``` 65 | 66 | And executed to yield the result: 67 | 68 | ``` 69 | Result: 120 70 | ``` 71 | 72 | License 73 | ------- 74 | 75 | Released under the MIT License. 76 | Copyright (c) 2016-2020, Stephen Diehl 77 | -------------------------------------------------------------------------------- /package.yaml: -------------------------------------------------------------------------------- 1 | name : tinyjit 2 | version : '0.1.0' 3 | synopsis : Tiny Haskell JIT 4 | description : Tiny Haskell JIT Example 5 | category : Compilers 6 | author : Stephen Diehl 7 | maintainer : stephen.m.diehl@gmail.com 8 | copyright : 2016-2020 Stephen Diehl 9 | license : MIT 10 | homepage : https://github.com/sdiehl/tinyjit 11 | github : sdiehl/tinyjit 12 | 13 | dependencies: 14 | - base >= 4.6 && < 5.0 15 | - unix >= 2.6 && < 2.8 16 | - transformers >= 0.4 && < 0.6 17 | - binary >= 0.7 && < 0.9 18 | - bytestring >= 0.10 && < 0.11 19 | - vector >= 0.10 && < 0.13 20 | 21 | executables: 22 | example: 23 | main: Main.hs 24 | source-dirs: src 25 | -------------------------------------------------------------------------------- /src/Assembler.hs: -------------------------------------------------------------------------------- 1 | module Assembler ( 2 | Reg, 3 | Instr, 4 | X86, 5 | Val(..), 6 | JITMem(..), 7 | 8 | assemble, 9 | 10 | ret, 11 | add, 12 | sub, 13 | push, 14 | pop, 15 | call, 16 | mul, 17 | imul, 18 | mov, 19 | nop, 20 | inc, 21 | dec, 22 | loop, 23 | 24 | rax, 25 | rbp, 26 | rsp, 27 | rdi, 28 | rdx, 29 | rsi, 30 | rcx, 31 | 32 | label, 33 | 34 | prologue, 35 | epilogue, 36 | 37 | hex, 38 | bytes, 39 | ) where 40 | 41 | import Data.Int 42 | import Data.Word 43 | import Data.Bits 44 | import Data.Monoid 45 | import Data.Typeable 46 | import Data.Binary.Put 47 | import Data.ByteString.Lazy.Char8 (ByteString, unpack) 48 | import qualified Data.ByteString.Internal as BS (c2w, w2c) 49 | 50 | import Numeric (showHex, showIntAtBase) 51 | 52 | import Control.Monad.Trans.Class 53 | import Control.Monad.Trans.State 54 | import Control.Monad.Trans.Except 55 | 56 | import Foreign.Ptr 57 | import Foreign.C.Types 58 | import Foreign.C.String 59 | 60 | import JIT 61 | 62 | ------------------------------------------------------------------------------- 63 | -- X86 Monad 64 | ------------------------------------------------------------------------------- 65 | 66 | data Reg 67 | = RAX -- Accumulator 68 | | RCX -- Counter (Loop counters) 69 | | RDX -- Data 70 | | RBX -- Base / General Purpose 71 | | RSP -- Current stack pointer 72 | | RBP -- Previous Stack Frame Link 73 | | RSI -- Source Index Pointer 74 | | RDI -- Destination Index Pointer 75 | deriving (Eq, Show) 76 | 77 | data Val 78 | = I Int64 -- int 79 | | R Reg -- register 80 | | A Word32 -- Addr 81 | deriving (Eq, Show) 82 | 83 | data Instr 84 | = Ret 85 | | Mov Val Val 86 | | Add Val Val 87 | | Sub Val Val 88 | | Mul Val 89 | | IMul Val Val 90 | | Xor Val Val 91 | | Inc Val 92 | | Dec Val 93 | | Push Val 94 | | Pop Val 95 | | Call Val 96 | | Loop Val 97 | | Nop 98 | | Syscall 99 | deriving (Eq, Show) 100 | 101 | ------------------------------------------------------------------------------- 102 | -- Monad 103 | ------------------------------------------------------------------------------- 104 | 105 | data JITMem = JITMem 106 | { _instrs :: [Instr] 107 | , _mach :: [Word8] 108 | , _icount :: Word32 109 | , _memptr :: Word32 110 | , _memoff :: Word32 111 | } deriving (Eq, Show) 112 | 113 | type X86 a = StateT JITMem (Except String) a 114 | 115 | istate :: Word32 -> JITMem 116 | istate start = JITMem 117 | { _instrs = [] 118 | , _icount = 0 119 | , _mach = [] 120 | , _memptr = start 121 | , _memoff = start 122 | } 123 | 124 | emit :: [Word8] -> X86 () 125 | emit i = modify $ \s -> s 126 | { _mach = _mach s ++ i 127 | , _memoff = _memoff s + fromIntegral (length i) 128 | } 129 | 130 | imm :: Integral a => a -> X86 () 131 | imm = emit . bytes 132 | 133 | -- Instructions 134 | 135 | ret :: X86 () 136 | ret = do 137 | emit [0xc3] 138 | 139 | add :: Val -> Val -> X86 () 140 | add (R l) (I r) = do 141 | emit [0x48] -- REX prefix 142 | emit [0x05] -- ADD 143 | imm r 144 | add (R l) (R r) = do 145 | emit [0x48] -- REX prefix 146 | emit [0x01] -- ADD 147 | emit [0xc0 .|. index r `shiftL` 3 .|. index l] 148 | add _ _ = nodef 149 | 150 | sub :: Val -> Val -> X86 () 151 | sub (R l) (I r) = do 152 | emit [0x48] -- REX prefix 153 | emit [0x2D] -- SUB 154 | imm r 155 | sub (R l) (R r) = do 156 | emit [0x48] -- REX prefix 157 | emit [0x29] -- SUB 158 | emit [0xc0 .|. index r `shiftL` 3 .|. index l] 159 | 160 | push :: Val -> X86 () 161 | push (R l) = do 162 | emit [0x50 + index l] 163 | push _ = nodef 164 | 165 | pop :: Val -> X86 () 166 | pop (R l) = do 167 | emit [0x58 + index l] 168 | pop _ = nodef 169 | 170 | call :: Val -> X86 () 171 | call (A dst) = do 172 | emit [0xE8] 173 | src <- gets _memoff 174 | imm (dst - (src + 5)) 175 | call _ = nodef 176 | 177 | mul :: Val -> X86 () 178 | mul (R l) = do 179 | emit [0x48] 180 | emit [0xF7] 181 | emit [0xE0 .|. index l] 182 | mul _ = nodef 183 | 184 | imul :: Val -> Val -> X86 () 185 | imul (R l) (I r) = do 186 | emit [0x48] 187 | emit [0x69] 188 | emit [0xc0 .|. index l] 189 | imm r 190 | imul (R l) (R r) = do 191 | emit [0x48] 192 | emit [0x0F] 193 | emit [0xAF] 194 | emit [0xC0 .|. index r `shiftL` 3 .|. index l] 195 | imul _ _ = nodef 196 | 197 | mov :: Val -> Val -> X86 () 198 | mov (R dst) (I src) = do 199 | emit [0x48] 200 | emit [0xC7] 201 | emit [0xC0 .|. (index dst .&. 7)] 202 | imm src 203 | mov (R dst) (A src) = do 204 | emit [0x48] 205 | emit [0xC7] 206 | emit [0xC7] 207 | imm src 208 | mov (R dst) (R src) = do 209 | emit [0x48] -- REX.W prefix 210 | emit [0x89] -- MOV 211 | emit [0xC0 .|. index src `shiftL` 3 .|. index dst] 212 | mov _ _ = nodef 213 | 214 | nop :: X86 () 215 | nop = do 216 | emit [0x90] 217 | 218 | inc :: Val -> X86() 219 | inc (R dst) = do 220 | emit [0x48] -- REX prefix 221 | emit [0xFF] -- INC 222 | emit [0xc0 + index dst] 223 | inc _ = nodef 224 | 225 | dec :: Val -> X86() 226 | dec (R dst) = do 227 | emit [0x48] -- REX prefix 228 | emit [0xFF] -- DEC 229 | emit [0xc0 + (index dst + 8)] 230 | dec _ = nodef 231 | 232 | loop :: Val -> X86() 233 | loop (A dst) = do 234 | emit [0xE2] 235 | src <- gets _memoff 236 | ptr <- gets _memptr 237 | emit [fromIntegral $ dst - src] 238 | loop _ = nodef 239 | 240 | syscall :: X86 () 241 | syscall = do 242 | emit [0x0f] 243 | emit [0x05] 244 | 245 | -- Functions 246 | 247 | prologue :: X86 () 248 | prologue = do 249 | push rbp 250 | mov rbp rsp 251 | 252 | epilogue :: X86 () 253 | epilogue = do 254 | pop rax 255 | mov rsp rbp 256 | pop rbp 257 | ret 258 | 259 | -- Registers 260 | 261 | rax :: Val 262 | rax = R RAX 263 | 264 | rbp :: Val 265 | rbp = R RBP 266 | 267 | rsp :: Val 268 | rsp = R RSP 269 | 270 | rdi :: Val 271 | rdi = R RDI 272 | 273 | rsi :: Val 274 | rsi = R RSI 275 | 276 | rdx :: Val 277 | rdx = R RDX 278 | 279 | rcx :: Val 280 | rcx = R RCX 281 | 282 | label :: X86 Val 283 | label = do 284 | addr <- gets _memoff 285 | return (A addr) 286 | 287 | nodef :: X86 () 288 | nodef = lift $ throwE "Invalid operation" 289 | 290 | index :: Reg -> Word8 291 | index x = case x of 292 | RAX -> 0 293 | RCX -> 1 294 | RDX -> 2 295 | RBX -> 3 296 | RSP -> 4 297 | RBP -> 5 298 | RSI -> 6 299 | RDI -> 7 300 | 301 | assemble :: Ptr a -> X86 b -> Either String JITMem 302 | assemble start = runExcept . flip execStateT (istate ptr) 303 | where 304 | ptr = heapPtr start 305 | 306 | hex :: (Integral a, Show a) => a -> String 307 | hex x = showHex x "" 308 | 309 | bytes :: Integral a => a -> [Word8] 310 | bytes x = fmap BS.c2w bs 311 | where 312 | bs = unpack $ runPut $ putWord32le (fromIntegral x) 313 | -------------------------------------------------------------------------------- /src/JIT.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DeriveDataTypeable #-} 2 | {-# LANGUAGE ForeignFunctionInterface #-} 3 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 4 | 5 | module JIT 6 | ( allocateMemory, 7 | codePtr, 8 | vecPtr, 9 | asciz, 10 | extern, 11 | heapPtr, 12 | getFunction, 13 | jit, 14 | ) 15 | where 16 | 17 | import Control.Exception 18 | import Control.Monad (when) 19 | import Control.Monad.Trans.State 20 | import Control.Monad.Trans.Writer 21 | import Data.Binary.Put 22 | import Data.Bits 23 | import qualified Data.ByteString.Internal as BS (c2w, w2c) 24 | import Data.ByteString.Lazy.Char8 25 | import Data.Int 26 | import Data.Monoid 27 | import Data.Typeable 28 | import qualified Data.Vector.Storable as V 29 | import qualified Data.Vector.Storable.Mutable as VM 30 | import Data.Word 31 | import Foreign.C.String 32 | import Foreign.C.Types 33 | import Foreign.ForeignPtr 34 | import Foreign.Marshal.Utils (copyBytes) 35 | import Foreign.Ptr 36 | import Foreign.Storable 37 | import System.Posix.DynamicLinker 38 | import System.Posix.Types 39 | import Unsafe.Coerce 40 | 41 | ------------------------------------------------------------------------------- 42 | -- Prot Option 43 | ------------------------------------------------------------------------------- 44 | 45 | newtype ProtOption = ProtOption CInt 46 | deriving (Eq, Show, Ord, Num, Bits) 47 | 48 | newtype MmapOption = MmapOption CInt 49 | deriving (Eq, Show, Ord, Num, Bits) 50 | 51 | protExec :: ProtOption 52 | protExec = ProtOption 0x01 53 | 54 | protRead :: ProtOption 55 | protRead = ProtOption 0x04 56 | 57 | protWrite :: ProtOption 58 | protWrite = ProtOption 0x02 59 | 60 | protNone :: ProtOption 61 | protNone = ProtOption 0x0 62 | 63 | mmapNone :: MmapOption 64 | mmapNone = MmapOption 0x0 65 | 66 | mmapAnon :: MmapOption 67 | mmapAnon = MmapOption 0x20 68 | 69 | mmapPrivate :: MmapOption 70 | mmapPrivate = MmapOption 0x02 71 | 72 | instance Semigroup ProtOption where 73 | (ProtOption a) <> (ProtOption b) = ProtOption (a .|. b) 74 | 75 | instance Monoid ProtOption where 76 | mempty = protNone 77 | 78 | instance Semigroup MmapOption where 79 | (MmapOption a) <> (MmapOption b) = MmapOption (a .|. b) 80 | 81 | instance Monoid MmapOption where 82 | mempty = mmapNone 83 | 84 | ------------------------------------------------------------------------------- 85 | -- JIT Memory 86 | ------------------------------------------------------------------------------- 87 | 88 | mapAnon, mapPrivate :: MmapFlags 89 | mapAnon = 0x20 90 | mapPrivate = 0x02 91 | 92 | newtype MmapFlags = MmapFlags {unMmapFlags :: CInt} 93 | deriving (Eq, Show, Ord, Num, Bits) 94 | 95 | foreign import ccall "dynamic" 96 | mkFun :: FunPtr (IO Int) -> IO Int 97 | 98 | getFunction :: Ptr Word8 -> IO Int 99 | getFunction mem = do 100 | let fptr = unsafeCoerce mem :: FunPtr (IO Int) 101 | mkFun fptr 102 | 103 | jit :: Ptr Word8 -> [Word8] -> IO (IO Int) 104 | jit mem machCode = do 105 | code <- codePtr machCode 106 | withForeignPtr (vecPtr code) $ \ptr -> do 107 | {-print ptr -- Pointer to Haskell array-} 108 | {-print mem -- Pointer to JIT memory-} 109 | copyBytes mem ptr (8 * 6) 110 | return (getFunction mem) 111 | 112 | data MmapException = MmapException 113 | deriving (Eq, Ord, Show, Typeable) 114 | 115 | instance Exception MmapException 116 | 117 | foreign import ccall unsafe "sys/mman.h mmap" 118 | c_mmap :: Ptr () -> CSize -> ProtOption -> MmapFlags -> Fd -> COff -> IO (Ptr a) 119 | 120 | mmap :: 121 | Ptr () -> 122 | CSize -> 123 | ProtOption -> 124 | MmapFlags -> 125 | Fd -> 126 | COff -> 127 | IO (Ptr Word8) 128 | mmap addr len prot flags fd offset = do 129 | ptr <- c_mmap addr len prot flags fd offset 130 | when (ptr == intPtrToPtr (-1)) $ throwIO MmapException 131 | return ptr 132 | 133 | codePtr :: [Word8] -> IO (VM.IOVector Word8) 134 | codePtr = V.thaw . V.fromList 135 | 136 | vecPtr :: Storable a => VM.MVector s a -> ForeignPtr a 137 | vecPtr = fst . VM.unsafeToForeignPtr0 138 | 139 | allocateMemory :: CSize -> IO (Ptr Word8) 140 | allocateMemory size = mmap nullPtr size pflags mflags (-1) 0 141 | where 142 | pflags = protRead <> protWrite 143 | mflags = mapAnon .|. mapPrivate 144 | 145 | asciz :: [Char] -> IO Word32 146 | asciz str = do 147 | ptr <- newCString (str ++ ['\n']) 148 | return $ heapPtr ptr 149 | 150 | extern :: String -> IO Word32 151 | extern name = do 152 | dl <- dlopen "" [RTLD_LAZY, RTLD_GLOBAL] 153 | fn <- dlsym dl name 154 | return $ heapPtr $ castFunPtrToPtr fn 155 | 156 | heapPtr :: Ptr a -> Word32 157 | heapPtr = fromIntegral . ptrToIntPtr 158 | -------------------------------------------------------------------------------- /src/Main.hs: -------------------------------------------------------------------------------- 1 | module Main ( 2 | main 3 | ) where 4 | 5 | import Data.Int 6 | import Data.Word 7 | import Data.Monoid 8 | 9 | import Foreign.C.Types 10 | 11 | import JIT 12 | import Assembler 13 | 14 | -- Example 1 15 | arith :: X86 () 16 | arith = do 17 | mov rax (I 18) 18 | add rax (I 4) 19 | sub rax (I 2) 20 | inc rax 21 | dec rax 22 | inc rax 23 | imul rax (I 2) 24 | mul rax 25 | ret 26 | 27 | -- Example 2 28 | factorial :: Int64 -> X86 () 29 | factorial n = do 30 | mov rcx (I n) 31 | mov rax (I 1) 32 | l1 <- label 33 | mul rcx 34 | loop l1 35 | ret 36 | 37 | -- Example 3 38 | printf :: Word32 -> Word32 -> X86 () 39 | printf fnptr msg = do 40 | push rbp 41 | mov rbp rsp 42 | mov rdi (A msg) 43 | call (A fnptr) 44 | pop rbp 45 | mov rax (I 0) 46 | ret 47 | 48 | dump :: [Word8] -> IO () 49 | dump = mapM_ (Prelude.putStrLn . hex) 50 | 51 | main :: IO () 52 | main = do 53 | let jitsize = 256*1024 54 | 55 | fn <- extern "printf" 56 | msg <- asciz "Hello Haskell" 57 | mem <- allocateMemory jitsize 58 | 59 | {-let jitm = assemble mem arith-} 60 | let jitm = assemble mem (factorial 5) 61 | {-let jitm = assemble mem (printf fn msg)-} 62 | 63 | case jitm of 64 | Left err -> putStrLn err 65 | Right jitst -> do 66 | let machCode = _mach jitst 67 | dump machCode 68 | 69 | fn <- jit mem machCode 70 | res <- fn 71 | putStrLn $ "Result: " <> show res 72 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-14.0 2 | packages: 3 | - '.' 4 | extra-deps: [] 5 | flags: {} 6 | extra-package-dbs: [] 7 | -------------------------------------------------------------------------------- /tinyjit.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.31.2. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | -- 7 | -- hash: ebd447e6dae9c79432e7c174a932fe7e8b48fa0a4bcb8b658f2ed8e1af6307b0 8 | 9 | name: tinyjit 10 | version: 0.1.0 11 | description: Tiny Haskell JIT Example 12 | category: Compilers 13 | synopsis: Tiny Haskell JIT 14 | homepage: https://github.com/sdiehl/tinyjit 15 | bug-reports: https://github.com/sdiehl/tinyjit/issues 16 | license: MIT 17 | license-file: LICENSE 18 | author: Stephen Diehl 19 | maintainer: stephen.m.diehl@gmail.com 20 | copyright: 2016-2020 Stephen Diehl 21 | build-type: Simple 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/sdiehl/tinyjit 26 | 27 | executable example 28 | main-is: Main.hs 29 | default-language: Haskell2010 30 | hs-source-dirs: 31 | src 32 | other-modules: 33 | Assembler 34 | JIT 35 | Paths_tinyjit 36 | build-depends: 37 | base >=4.6 && <5.0, 38 | binary >=0.7 && <0.9, 39 | bytestring >=0.10 && <0.11, 40 | transformers >=0.4 && <0.6, 41 | unix >=2.6 && <2.8, 42 | vector >=0.10 && <0.13 43 | --------------------------------------------------------------------------------