1 {-# LANGUAGE FlexibleContexts, TypeFamilies, OverloadedStrings #-}
2 module JVM.Generator where
4 import Control.Monad.State as St
8 import qualified Data.Map as M
9 import qualified Data.Set as S
10 import qualified Data.ByteString.Lazy as B
16 data GState = GState {
17 generated :: [Instruction],
18 currentPool :: Pool Resolved,
19 doneMethods :: [Method Resolved],
20 currentMethod :: Maybe (Method Resolved)}
23 emptyGState = GState {
25 currentPool = M.empty,
27 currentMethod = Nothing }
29 type Generate a = State GState a
31 appendPool :: Constant Resolved -> Pool Resolved -> (Pool Resolved, Word16)
33 let size = fromIntegral (M.size pool)
34 pool' = M.insert size c pool
37 addItem :: Constant Resolved -> Generate Word16
39 pool <- St.gets currentPool
40 case lookupPool c pool of
41 Just i -> return (i+1)
43 let (pool', i) = appendPool c pool
45 St.put $ st {currentPool = pool'}
48 lookupPool :: Constant Resolved -> Pool Resolved -> Maybe Word16
50 fromIntegral `fmap` findIndex (== c) (M.elems pool)
52 addNT :: Binary (Signature a) => NameType a -> Generate Word16
53 addNT (NameType name sig) = do
55 x <- addItem (CNameType name bsig)
60 addSig :: MethodSignature -> Generate Word16
61 addSig c@(MethodSignature args ret) = do
65 addToPool :: Constant Resolved -> Generate Word16
66 addToPool c@(CClass str) = do
69 addToPool c@(CField cls name) = do
70 addToPool (CClass cls)
73 addToPool c@(CMethod cls name) = do
74 addToPool (CClass cls)
77 addToPool c@(CIfaceMethod cls name) = do
78 addToPool (CClass cls)
81 addToPool c@(CString str) = do
84 addToPool c@(CNameType name sig) = do
88 addToPool c = addItem c
90 putInstruction :: Instruction -> Generate ()
91 putInstruction instr = do
93 let code = generated st
94 St.put $ st {generated = code ++ [instr]}
96 i0 :: Instruction -> Generate ()
99 i1 :: (Word16 -> Instruction) -> Constant Resolved -> Generate ()
104 i8 :: (Word8 -> Instruction) -> Constant Resolved -> Generate ()
107 i0 (fn $ fromIntegral ix)
109 startMethod :: [AccessFlag] -> B.ByteString -> MethodSignature -> Generate ()
110 startMethod flags name sig = do
111 addToPool (CString name)
114 let method = Method {
115 methodAccessFlags = S.fromList flags,
117 methodSignature = sig,
118 methodAttributesCount = 0,
119 methodAttributes = AR M.empty }
120 St.put $ st {generated = [],
121 currentMethod = Just method }
123 endMethod :: Generate ()
125 m <- St.gets currentMethod
126 code <- St.gets genCode
128 Nothing -> fail "endMethod without startMethod!"
130 let method' = method {methodAttributes = AR $ M.fromList [("Code", encodeMethod code)],
131 methodAttributesCount = 1}
133 St.put $ st {generated = [],
134 currentMethod = Nothing,
135 doneMethods = doneMethods st ++ [method']}
137 newMethod :: [AccessFlag] -> B.ByteString -> [ArgumentSignature] -> ReturnSignature -> Generate () -> Generate (NameType Method)
138 newMethod flags name args ret gen = do
139 let sig = MethodSignature args ret
140 startMethod flags name sig
143 return (NameType name sig)
145 genCode :: GState -> Code
147 codeStackSize = 4096,
150 codeInstructions = generated st,
154 codeAttributes = AP [] }
156 len = fromIntegral $ B.length $ encodeInstructions (generated st)
158 initClass :: B.ByteString -> Generate Word16
160 addToPool (CClass "java/lang/Object")
161 addToPool (CClass name)
162 addToPool (CString "Code")
164 generate :: B.ByteString -> Generate () -> Class Resolved
169 res = execState generator emptyGState
175 constsPoolSize = fromIntegral $ M.size (currentPool res),
176 constsPool = currentPool res,
177 accessFlags = S.fromList [ACC_PUBLIC, ACC_STATIC],
179 superClass = "java/lang/Object",
182 classFieldsCount = 0,
184 classMethodsCount = fromIntegral $ length (doneMethods res),
185 classMethods = doneMethods res,
186 classAttributesCount = 0,
187 classAttributes = AR M.empty }