-- | Convert absolute labeled jumps to relative offset jumps, also -- converts bytecode into \"write\" format module ByteCode.Relative (bcRelative) where import ByteCode.Type import qualified Data.Map as Map import Maybe(fromJust) import Util.Extra --------------------------------------------------------------------------------------------------- type Labels = Map.Map Label Int type Writes = [Write] -> [Write] --------------------------------------------------------------------------------------------------- type CodePosn = Int -- | Convert to relative jumps and convert to \"write\" format bcRelative :: BCModule -> BCModule bcRelative m = m { bcmDecls = map relative $ bcmDecls m } relative :: BCDecl -> BCDecl relative (Fun n p z as (CLinear is) cn pr st nd fl) = Fun n p z as (CWrites ws') cn pr st nd fl where (ws,ls) = lCode (map fst is) 0 Map.empty ws' = patch (ws []) ls relative x = x lCode :: [Ins] -> CodePosn -> Labels -> (Writes, Labels) lCode [] n ls = (id, ls) lCode (LABEL j:is) n ls = lCode is n (Map.insert j n ls) lCode (i:is) n ls = ((ws++) . wss, ls') where ws = lIns i n (wss,ls') = lCode is (n+wSize ws) ls wSize :: [Write] -> Int wSize ws = sum $ map wSizeOf ws wSizeOf :: Write -> Int wSizeOf (WUByte _) = 1 wSizeOf (WUShort _) = 2 wSizeOf (WLabel _ _ ) = 2 wSizeOf (WByte _) = 1 wSizeOf (WShort _) = 2 divUp :: Int -> Int -> Int divUp x y | m == 0 = d | otherwise = d + 1 where (d,m) = x `divMod` y lIns :: Ins -> CodePosn -> [Write] lIns (START_FUN) p = [] lIns (END_CODE) p = lOp tEndCode lIns (NEED_HEAP n) p = lOpLt tNeedHeap 32 n lIns (NEED_STACK n) p = lOpLt tNeedStack 16 n lIns (PUSH n) p = lOp12i tPush iPush n lIns (PUSH_ZAP n) p = lOp12i tPushZap iPushZap n lIns (ZAP_STACK n) p = lOp12i tZapStack 0 n lIns (PUSH_ARG n) p = lOp1i tPushArg iPushArg n lIns (PUSH_ZAP_ARG n) p = lOp1i tPushZapArg iPushZapArg n lIns (ZAP_ARG n) p = lOp1i tZapArg 0 n lIns (PUSH_INT n) p = lOp12iS tPushInt iPushInt n lIns (PUSH_CHAR n) p = lOp1i tPushChar 0 n lIns (PUSH_CONST n) p = lOp12i tPushConst iPushConst n lIns (MK_AP n _) p = lOp12i tMkAp iMkAp n lIns (MK_PAP f n) p = lOp12i_1 tMkPap 0 f n lIns (APPLY n) p = lOp1i' 1 tApply iApply n lIns (MK_CON n _) p = lOp12i tMkCon iMkCon n lIns (UNPACK _) p = lOp tUnpack lIns (SLIDE n) p = lOp12i' 1 tSlide iSlide n lIns (POP n) p = lOp12i tPop 0 n lIns (ALLOC n) p = lOp12i tAlloc 0 n lIns (UPDATE n) p = lOp12i tUpdate 0 n lIns (SELECT n) p = lOp12i tSelect iSelect n lIns (RETURN) p = lOp tReturn lIns (EVAL) p = lOp tEval lIns (RETURN_EVAL) p = lOp tReturnEval lIns (TABLE_SWITCH as) p = lOpTable tTableSwitch p as lIns (LOOKUP_SWITCH as md) p = lOpLookup tLookupSwitch p WUShort as md lIns (INT_SWITCH as md) p = lOpLookup tIntSwitch p WShort as md lIns (JUMP_FALSE j) p = lOpJ tJumpFalse p j lIns (JUMP j) p = lOpJ tJump p j lIns (P_ADD op) p = lOpPrim tAdd op lIns (P_SUB op) p = lOpPrim tSub op lIns (P_MUL op) p = lOpPrim tMul op lIns (P_DIV op) p = lOpPrim tDiv op lIns (P_MOD op) p = lOpPrim tMod op lIns (P_CMP_EQ op) p = lOpPrim tEq op lIns (P_CMP_NE op) p = lOpPrim tNe op lIns (P_CMP_LE op) p = lOpPrim tLe op lIns (P_CMP_LT op) p = lOpPrim tLt op lIns (P_CMP_GE op) p = lOpPrim tGe op lIns (P_CMP_GT op) p = lOpPrim tGt op lIns (P_NEG op) p = lOpPrim tNeg op lIns (P_STRING) p = lOp tString lIns (P_FROM_ENUM) p = lOp tFromEnum lIns (PRIMITIVE) p = lOp tPrimitive lIns (EXTERNAL) p = lOp tExternal lIns (SELECTOR_EVAL) p = lOp tSelectorEval lIns (TAP i) p = lOp12i tTAp 0 i lIns (TCON i) p = lOp12i tTCon 0 i lIns (TPRIMCON i) p = lOp12i tTPrimCon 0 i lIns (TAPPLY i n) p = lOp12i_1 tTApply 0 i n lIns (TIF i) p = lOp12i tTIf 0 i lIns (TGUARD i) p = lOp12i tTGuard 0 i lIns (TCASE i) p = lOp12i tTCase 0 i lIns (TRETURN) p = lOp tTReturn lIns (TPRIMAP i n) p = lOp12i tTPrimAp 0 i lIns (TPRIMRESULT i) p = lOp12i tTPrimResult 0 i lIns (TPUSH) p = lOp tTPush lIns (TPUSHVAR i) p = lOp12i tTPushVar 0 i lIns (TPROJECT i) p = lOp12i tTProject 0 i lIns x p = error $ "lIns no code for "++show x lOp :: Int -> [Write] lOp t | isUByte t = [ WUByte t ] | otherwise = error $ "lOp: tag is too big!" ++ show t lOpLt :: Int -> Int -> Int -> [Write] lOpLt t i n | n <= i = lOp t | otherwise = lOp (t+1) ++ [ WUByte (n `divUp` i) ] lOp1i' :: Int -> Int -> Int -> Int -> [Write] lOp1i' x t i n | n < i && n >= x = lOp (t+1+(n-x)) | otherwise = lOp t ++ [ WUByte n ] lOp1i :: Int -> Int -> Int -> [Write] lOp1i = lOp1i' 0 lOp12i' :: Int -> Int -> Int -> Int -> [Write] lOp12i' x t i n | n < i && n >= x = lOp (t+2+(n-x)) | isUByte n = lOp t ++ [ WUByte n ] | otherwise = lOp (t+1) ++ [ WUShort n ] lOp12i :: Int -> Int -> Int -> [Write] lOp12i = lOp12i' 0 lOp12iS :: Int -> Int -> Int -> [Write] lOp12iS t i n | n < i && n >= 0 = lOp (t+2+n) | isByte n = lOp t ++ [ WByte n ] | otherwise = lOp (t+1)++ [ WShort n ] lOp12i_1 :: Int -> Int -> Int -> Int -> [Write] lOp12i_1 t i n m = lOp12i t i n ++ [ WUByte m ] lOpJ :: Int -> CodePosn -> Label -> [Write] lOpJ t p j = lOp t ++ [ WLabel (p+1) j ] lOpPrim :: Int -> PrimOp -> [Write] lOpPrim t OpWord = lOp t lOpPrim t OpFloat = lOp (t+1) lOpPrim t OpDouble = lOp (t+2) lOpTable :: Int -> CodePosn -> [Label] -> [Write] lOpTable t p as = lOp t ++ [WUShort (length as)] ++ map (WLabel (p+1)) as lOpLookup :: Int -> CodePosn -> (Int->Write) -> [(Tag,Label)] -> Label -> [Write] lOpLookup t p tag as j = lOp t ++ [WUShort (length as)] ++ [WLabel (p+1) j] ++ concatMap (\(t,j) -> [ tag t, WLabel (p+1) j ]) as lPad :: Int -> [Write] lPad n = replicate ((4 - (n `mod` 4)) `mod` 4) (WUByte 0) --------------------------------------------------------------------------------------------------- patch :: [Write] -> Labels -> [Write] patch ws ls = pWrites ls 0 ws pWrites :: Labels -> Int -> [Write] -> [Write] pWrites ls n [] = [] pWrites ls n ((WLabel p j):ws) = pWrites ls n (WUShort r : ws) where r = (fromJust $ Map.lookup j ls) - p pWrites ls n (w:ws) = w : pWrites ls n' ws where n' = n + wSizeOf w --------------------------------------------------------------------------------------------------- iPush, iPushZap, iPushArg, iPushZapArg , iZapArg, iPushInt, iPushConst, iMkAp, iApply, iMkCon, iSlide, iSelect :: Int iPush = 2 :: Int iPushZap = 4 :: Int iPushArg = 4 :: Int iPushZapArg = 4 :: Int iZapArg = 2 :: Int iPushInt = 2 :: Int iPushConst = 8 :: Int iMkAp = 16 :: Int iApply = 2 :: Int iMkCon = 4 :: Int iSlide = 2 :: Int iSelect = 2 :: Int tEndCode :: Int tEndCode = 0 tNeedHeap, tNeedStack, tPush, tPushZap, tZapStack, tPushArg, tPushZapArg , tZapArg, tPushInt, tPushChar, tPushConst, tMkAp, tMkPap, tApply, tMkCon, tUnpack , tSlide, tPop, tAlloc, tUpdate, tSelect, tReturn, tEval, tReturnEval, tTableSwitch, tLookupSwitch , tIntSwitch, tJumpFalse, tJump, tAdd, tSub, tMul, tDiv, tMod, tEq, tNe, tLe, tLt, tGe, tGt, tNeg , tString, tFromEnum, tPrimitive, tSelectorEval, tExternal, tTAp, tTCon, tTPrimCon, tTApply, tTIf , tTGuard, tTCase, tTPrimAp, tTPrimResult, tTReturn, tTPush, tTPushVar, tTProject, tLast :: Int tNeedHeap = tEndCode + 1 tNeedStack = tNeedHeap + 2 tPush = tNeedStack + 2 tPushZap = tPush + 2 + iPush tZapStack = tPushZap + 2 + iPushZap tPushArg = tZapStack + 2 tPushZapArg = tPushArg + 1 + iPushArg tZapArg = tPushZapArg + 1 + iPushZapArg tPushInt = tZapArg + 1 + iZapArg tPushChar = tPushInt + 2 + iPushInt tPushConst = tPushChar + 1 tMkAp = tPushConst + 2 + iPushConst tMkPap = tMkAp + 2 + iMkAp tApply = tMkPap + 2 tMkCon = tApply + 1 + iApply tUnpack = tMkCon + 2 + iMkCon tSlide = tUnpack + 1 tPop = tSlide + 2 + iSlide tAlloc = tPop + 2 tUpdate = tAlloc + 2 tSelect = tUpdate + 2 tReturn = tSelect + 2 + iSelect tEval = tReturn + 1 tReturnEval = tEval + 1 tTableSwitch = tReturnEval + 1 tLookupSwitch = tTableSwitch + 1 tIntSwitch = tLookupSwitch + 1 tJumpFalse = tIntSwitch + 1 tJump = tJumpFalse + 1 tAdd = tJump + 1 tSub = tAdd + 3 tMul = tSub + 3 tDiv = tMul + 3 tMod = tDiv + 3 tEq = tMod + 3 tNe = tEq + 3 tLe = tNe + 3 tLt = tLe + 3 tGe = tLt + 3 tGt = tGe + 3 tNeg = tGt + 3 tString = tNeg + 3 tFromEnum = tString + 1 tPrimitive = tFromEnum + 1 tSelectorEval = tPrimitive + 1 tExternal = tSelectorEval + 1 tTAp = tExternal + 1 tTCon = tTAp + 2 tTPrimCon = tTCon + 2 tTApply = tTPrimCon + 2 tTIf = tTApply + 2 tTGuard = tTIf + 2 tTCase = tTGuard + 2 tTPrimAp = tTCase + 2 tTPrimResult = tTPrimAp + 2 tTReturn = tTPrimResult + 2 tTPush = tTReturn + 1 tTPushVar = tTPush + 1 tTProject = tTPushVar + 2 tLast = tTProject + 2