X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=Mate%2FBasicBlocks.hs;h=7fd2e4830eca4c7699fafde8030da559f11b4fb5;hb=2ac2a68eb5b709caa636d1a9a56a40268d378550;hp=3fa4a6c699b73931ec8045d50db8a458e07af622;hpb=022b945b3f13f7f855fa304fcf0ece0967fa508d;p=mate.git diff --git a/Mate/BasicBlocks.hs b/Mate/BasicBlocks.hs index 3fa4a6c..7fd2e48 100644 --- a/Mate/BasicBlocks.hs +++ b/Mate/BasicBlocks.hs @@ -17,6 +17,7 @@ import qualified Data.ByteString.Lazy as B import Data.Maybe import Control.Monad.State import Control.Applicative +import Control.Arrow import JVM.ClassFile import JVM.Converter @@ -34,6 +35,15 @@ type BBState = Targets type AnalyseState = State BBState [OffIns] +noException :: B.ByteString +noException = B.empty + +emptyBasicBlock :: BasicBlock +emptyBasicBlock = BasicBlock + { code = [] + , exception = noException + , successor = Return } + printMapBB :: MapBB -> IO () printMapBB hmap = do printfBb "BlockIDs: " @@ -118,26 +128,7 @@ buildCFG :: [Instruction] -> MapBB buildCFG xs = buildCFG' M.empty xs' xs' where xs' :: [OffIns] - xs' = evalState (calculateInstructionOffset xs >>= markBackwardTargets) [] - --- get already calculated jmp-targets and mark the predecessor of the --- target-instruction as "FallThrough". we just care about backwards --- jumps here (forward jumps are handled in buildCFG') -markBackwardTargets :: [OffIns] -> AnalyseState -markBackwardTargets [] = return [] -markBackwardTargets (x:[]) = return [x] -markBackwardTargets (x@(x_off,x_bbend,x_ins):y@(y_off,_,_):xs) = do - rest <- markBackwardTargets (y:xs) - targets <- get - let isTarget = y_off `elem` targets - x_new = case x_bbend of - Just _ -> x -- already marked, don't change - Nothing -> if isTarget then checkX y_off else x - checkX w16 = case x_bbend of - Nothing -> (x_off, Just $ FallThrough w16, x_ins) -- mark previous insn - _ -> error "basicblock: something is wrong" - return $ x_new:rest - + xs' = evalState (calculateInstructionOffset xs) [] buildCFG' :: MapBB -> [OffIns] -> [OffIns] -> MapBB @@ -162,7 +153,7 @@ buildCFG' hmap ((off, entry, _):xs) insns = buildCFG' (insertlist entryi hmap) x parseBasicBlock :: Int -> [OffIns] -> BasicBlock -parseBasicBlock i insns = BasicBlock insonly endblock +parseBasicBlock i insns = emptyBasicBlock { code = insonly, successor = endblock } where (lastblock, is) = takeWhilePlusOne validins omitins insns (_, _, insonly) = unzip3 is @@ -173,7 +164,7 @@ parseBasicBlock i insns = BasicBlock insonly endblock takeWhilePlusOne _ _ [] = (Nothing, []) takeWhilePlusOne p omit (x:xs) | omit x = next - | p x = (\(ys, xs') -> (ys, x:xs')) next + | p x = second (x:) next | otherwise = (Just x, [x]) where next = takeWhilePlusOne p omit xs @@ -204,8 +195,15 @@ calculateInstructionOffset = cio' (0, Nothing, NOP) IRETURN -> notarget ARETURN -> notarget RETURN -> notarget - _ -> ((off, Nothing, x):) <$> next + _ -> normalins where + normalins = do + tailinsns <- next -- eval remaining instructions + isNextInsATarget <- (elem newoffset) <$> get + let bbtyp = if isNextInsATarget + then Just $ FallThrough newoffset + else Nothing + return $ (off, bbtyp, x):tailinsns notarget = ((off, Just Return, x):) <$> next onetarget w16 = do let jump = off `addW16Signed` w16 @@ -217,8 +215,9 @@ calculateInstructionOffset = cio' (0, Nothing, NOP) let jump = off `addW16Signed` w16 modify (jump:) ((off, Just $ TwoTarget nojump jump, x):) <$> next - next = cio' newoffset xs - newoffset = (off + insnLength x, Nothing, NOP) + next = cio' nextins xs + nextins = (newoffset, Nothing, NOP) + newoffset = off + insnLength x -- TODO(bernhard): does GHC memomize results? i.e. does it calculate the size -- of `NOP' only once?