module ByteCode.Type(
-- * Data Types
-- ** Top-level bytecode declarations
BCModule(..)
, BCDecl(..)
-- ** Constant tables
, ConstTable
, ConstItem(..)
, GType(..)
, CRef
-- ** Code representations
, Code(..)
, GraphNode(..)
, Graph
, Jumpers
, GLabel(..)
, Write(..)
, Ins(..)
, PrimOp(..)
, Tag
, Label
-- ** Use sets
, UseSet(..)
, emptyUS
, UseIns
-- * Constants
, xFlNone
, xFlVoid
, fNone, fInvisible, fLambda, intFlags
, frameSize
, calcHeapExtra
, splitQualified
) where
import Prim(PrimOp(..))
import qualified Data.Map as Map
import qualified Data.Set as Set
import Util.Extra(Pos)
import Syntax(CallConv)
import NT
import PosCode(LambdaFlags(..))
import Flags(Flags, sHat)
-- | A bytecode program
data BCModule = BCModule {
bcmModule :: String,
bcmDecls :: [BCDecl]
}
-- | A Declaration is a top level bcode entry
data BCDecl = Fun { fName :: String, fPos :: Pos, fArity :: Int, fArgs :: [String],
fCode :: Code, fConsts :: ConstTable, fIsPrim :: Bool, fStack :: Int, fNumDictArgs :: Int,
fFlags :: [LambdaFlags] }
| Con { cName :: String, cPos :: Pos, cSize :: Int, cTag :: Int }
| Prim { pName :: String, pPos :: Pos }
| External { xName :: String, xPos :: Pos, xArity :: Int,
xCName :: String, xCallConv :: String, xArgsTypes :: [String] }
fNone, fInvisible, fLambda :: Int
fNone = 0x00
fInvisible = 0x01
fLambda = 0x02
intFlags :: [LambdaFlags] -> Int
intFlags lfs = sum (map f lfs)
where
f LamFLNone = fNone
f LamFLIntro = fInvisible
f LamFLLambda = fLambda
xFlNone, xFlVoid :: Int
xFlNone = 0x00
xFlVoid = 0x01
-- | A constant table maps constant references to constant items
type ConstTable = Map.Map CRef ConstItem
type CRef = Int
-- | A constant in the constant table
data ConstItem = CGlobal String GType {- CAF, FUN, FUN0, CON, ZCON -}
| CInt Int
| CInteger Integer
| CFloat Float
| CDouble Double
| CString String
| CPos Pos
| CVarDesc String Pos
deriving (Eq, Ord, Show)
-- | Common applicative form, function info, node for non-CAF, constructor info,
-- node for zero arity constructor, primitive function info
data GType = GCAF | GFUN | GFUN0 | GCON | GZCON | GPRIM | GEXT
deriving (Eq, Ord, Show)
-- | Code can be several things;
-- either a simple list of instructions or a code flow graph
data Code = CLinear [(Ins,UseSet)]
| CGraph GLabel Graph Jumpers
| CWrites [Write]
-- | A graph associates labels with graph nodes
type Graph = Map.Map GLabel GraphNode
-- | Jumpers lists for each label all the graph nodes that might jump to it
type Jumpers = Map.Map GLabel (Set.Set GLabel)
-- | a graph node is either:
--
-- * @ GLinear is eval next
-- is = the linear sequence of instructions
-- eval = whether this block has an EVAL at the end
-- next = the label of the next block
-- @
--
-- * @ GCase int alts default
-- int = true if this is a case over integers
-- alts = the alternatives of the case
-- default = the default branch of the case, if any
-- @
--
-- * @ GIf true false
-- true = the true label of the if
-- false = the false label of the if
-- @
--
-- * @ GReturn
-- terminal node in the graph
-- @
data GraphNode = GLinear [UseIns] Bool GLabel
| GCase Bool [(Tag,GLabel)] (Maybe GLabel)
| GIf GLabel GLabel
| GReturn
| GDead
-- | A graph label, just wraps a label, helps with typechecking and we can sort the other way round
data GLabel = GLabel Label deriving Eq
-- | It's most useful to have these sorted in increasing order, so labels
-- are compared in the reverse order as labels
instance Ord GLabel where
compare (GLabel x) (GLabel y) = case compare x y of
LT -> GT
EQ -> EQ
GT -> LT
instance Show GLabel where
show (GLabel l) = "L_" ++ show l
-- | A write is a data section that should be written to the final bytecode file, Label is used as a placeholder
data Write = WUByte Int
| WUShort Int
| WLabel Int Label
| WByte Int
| WShort Int
-- | The use set for an instruction lists the variables that the instructions 'gives'
-- as well as those that it needs, from this we can calculate what should be zapped.
data UseSet = UseSet { useDepth :: Int, useGive :: [String], useNeed :: Set.Set String }
-- | Create an empty use set
emptyUS :: UseSet
emptyUS = UseSet 0 [] Set.empty
-- | A bytecode instruction paired with its use set
type UseIns = (Ins,UseSet)
-- a block is a unflattened section of BCode
-- BLinear is - linear block of instructions, this originally corresponds to an
-- uninterruptable linear sequence of instructions. Later it's flattened.
-- BCase int tags - a case statement block, 'int' is true if the case is over integers
-- tags is the list of (tag,code) pairs.
-- BIf true false - if block with true and false code
-- BFatBar esc code fail - a 'fat bar' is used as an internal way to collect together defaults for cases
-- 'esc' is true if the failure can escape.
-- BWrite writes - a code block that has been converted into a series of bytes and shorts
-- (i.e. assembled). This makes it easier to fix labels to jump addresses
-- BFail - go to the 'nearest' fatbar handler.
{-
data Block = BLinear [(Ins, UseSet)]
| BCase Bool [(Tag,Code)]
| BIf Code Code
| BFatBar Bool Code Code
| BWrite [Write]
| BFail
-}
{-
data Block = BLinear Label [(Ins,UseSet)] (Maybe Label)
| BCase Label Bool [(Tag,Label)] (Maybe Label)
| BIf Label Label Label
-}
type Tag = Int
-- | The instructions
data Ins = END_CODE
| START_FUN -- ^ never appears just used in zap analysis
| NEED_STACK Int
| NEED_HEAP Int
| PUSH Int
| PUSH_ZAP Int
| ZAP_STACK Int
| PUSH_ARG Int -- ^ is this supposed to be an 'Int' or an 'Id'? [SamB]
-- ^ Int, first argument = 0, second = 1, etc [TomS]
| PUSH_ZAP_ARG Int
| ZAP_ARG Int
| PUSH_INT Int
| PUSH_CHAR Int
| PUSH_CONST CRef
| MK_AP CRef Int
| MK_PAP CRef Int
| MK_CON CRef Int
| APPLY Int
| UNPACK Int
| SLIDE Int
| POP Int
| ALLOC Int
| UPDATE Int
| RETURN
| EVAL
| RETURN_EVAL
| NOP
| P_ADD PrimOp
| P_SUB PrimOp
| P_MUL PrimOp
| P_DIV PrimOp
| P_MOD PrimOp
| P_CMP_EQ PrimOp
| P_CMP_NE PrimOp
| P_CMP_LE PrimOp
| P_CMP_LT PrimOp
| P_CMP_GE PrimOp
| P_CMP_GT PrimOp
| P_NEG PrimOp
| P_STRING
| P_FROM_ENUM
| CASE Bool [(Tag,Label)] (Maybe Label)
| STOP
| TABLE_SWITCH [Label]
| LOOKUP_SWITCH [(Tag,Label)] Label
| INT_SWITCH [(Tag,Label)] Label
| JUMP_FALSE Label
| JUMP Label
| LABEL Label
| PRIMITIVE
| EXTERNAL
| SELECTOR_EVAL
| SELECT Int
| TAP CRef
| TCON CRef
| TPRIMCON CRef
| TAPPLY CRef Int
| TIF CRef
| TGUARD CRef
| TCASE CRef
| TRETURN
| TPRIMAP CRef Int
| TPRIMRESULT CRef
| TPUSH
| TPUSHVAR CRef
| TPROJECT CRef
| COMMENT String
deriving (Eq,Ord,Show)
type Label = Int
frameSize :: Int
frameSize = 3
calcHeapExtra :: Flags -> Int
calcHeapExtra flags = if sHat flags then 2 else 0
-- | split a qualified name into (module,item)
splitQualified :: String -> (String,String)
splitQualified s = case break (==';') s of
(mod,[]) -> (mod,[])
(mod,i:is) -> (mod,is)
|