ddc-core-tetra-0.4.3.1: DDC/Core/Tetra/Convert/Layout.hs
-- | Layout of algebraic data.
module DDC.Core.Tetra.Convert.Layout
( -- * Heap Objects
HeapObject(..)
, heapObjectOfDataCtor
-- * Fields
, payloadSizeOfDataCtor
, fieldOffsetsOfDataCtor)
where
import DDC.Core.Tetra.Convert.Boxing
import DDC.Core.Tetra.Prim
import DDC.Core.Salt.Platform
import DDC.Type.Exp.Simple
import DDC.Type.DataDef
import Control.Monad
import Data.Maybe
import qualified DDC.Core.Salt.Name as A
-- HeapObject -----------------------------------------------------------------
-- | Enumerates the heap object formats that can be used to store
-- algebraic data.
--
-- The layout of these is defined in the @ObjectNN.dce@ file of the runtime
-- system, where @NN@ is the word size of the machine.
data HeapObject
= HeapObjectBoxed
| HeapObjectMixed
| HeapObjectRaw
| HeapObjectRawSmall
deriving (Eq, Show)
-- | Decide which heap object to use to represent a data constructor.
heapObjectOfDataCtor :: Platform -> DataCtor Name -> Maybe HeapObject
heapObjectOfDataCtor pp ctor
-- If all the fields are boxed objects then used a Boxed heap object,
-- as these just contain pointer fields.
| tsFields <- dataCtorFieldTypes ctor
, all isBoxedRepType tsFields
= Just HeapObjectBoxed
-- All of the primitive numeric types will fit in a RawSmall object.
-- Each field needs to be non-abstract, and have a real width.
| [t1] <- dataCtorFieldTypes ctor
, Just (NameTyConTetra TyConTetraU, [tp]) <- takePrimTyConApps t1
, Just (NamePrimTyCon ptc, []) <- takePrimTyConApps tp
, isJust $ A.primTyConWidth pp ptc
= Just HeapObjectRawSmall
-- Unboxed strings are represented as pointers to static memory.
-- The pointer will fit in a RawSmall object.
| [t1] <- dataCtorFieldTypes ctor
, Just (NameTyConTetra TyConTetraU, [tp]) <- takePrimTyConApps t1
, Just (NamePrimTyCon PrimTyConTextLit, []) <- takePrimTyConApps tp
= Just HeapObjectRawSmall
| otherwise
= Nothing
-- Field Layout ---------------------------------------------------------------
-- | Get the size of the payload for this data constructor.
-- The payload holds all the fields, but does not include
-- header information such as the constructor tag.
--
-- This doesn't add any padding for misaligned fields.
payloadSizeOfDataCtor :: Platform -> DataCtor Name -> Maybe Integer
payloadSizeOfDataCtor platform ctor
= liftM sum
$ sequence
$ map (fieldSizeOfType platform)
$ dataCtorFieldTypes ctor
-- | Given a constructor definition,
-- get the offset of each field in the payload of a heap object.
--
-- We don't know the absolute offset from the beginning of the heap
-- object, because the size of the header is only known by the runtime
-- system.
--
-- This doesn't add any padding for misaligned fields.
fieldOffsetsOfDataCtor :: Platform -> DataCtor Name -> Maybe [Integer]
fieldOffsetsOfDataCtor platform ctor
= liftM (init . scanl (+) 0)
$ sequence
$ map (fieldSizeOfType platform)
$ dataCtorFieldTypes ctor
-- | Get the raw size of a field of this type, without padding.
fieldSizeOfType :: Platform -> Type Name -> Maybe Integer
fieldSizeOfType platform tt
= case tt of
-- Polymorphic objects are represented boxed.
TVar{} -> Just $ platformAddrBytes platform
-- Type constructor might be a primitive or boxed value type.
TCon tc
-> case tc of
TyConBound (UPrim n _) _ -> fieldSizeOfPrim platform n
TyConBound _ _ -> Just $ platformAddrBytes platform
_ -> Nothing
--- Higher kinded types are not value types.
TAbs{} -> Nothing
-- Assume anything that isn't a primitive constructor is
-- represented by a pointer.
TApp{} -> Just $ platformAddrBytes platform
-- We're not supporting polymorphic fields yet.
TForall{} -> Nothing
-- We shouldn't find any TSums, because field types always have
-- kind data.
TSum{} -> Nothing
-- | Get the raw size of a value with this type name.
fieldSizeOfPrim :: Platform -> Name -> Maybe Integer
fieldSizeOfPrim platform nn
= case nn of
NameDaConTetra{} -> Just $ platformAddrBytes platform
NamePrimTyCon tc -> fieldSizeOfPrimTyCon platform tc
_ -> Nothing
-- | Get the raw size of a value with this primitive type constructor.
fieldSizeOfPrimTyCon :: Platform -> PrimTyCon -> Maybe Integer
fieldSizeOfPrimTyCon platform tc
= case tc of
-- It might make sense to represent these as zero bytes,
-- but I can't think of reason to have them in data type definitions.
PrimTyConVoid -> Nothing
PrimTyConBool -> Just $ 1
PrimTyConNat -> Just $ platformNatBytes platform
PrimTyConInt -> Just $ platformNatBytes platform
PrimTyConSize -> Just $ platformNatBytes platform
PrimTyConWord bits
| bits `rem` 8 == 0 -> Just $ fromIntegral $ bits `div` 8
| otherwise -> Nothing
PrimTyConFloat bits
| bits `rem` 8 == 0 -> Just $ fromIntegral $ bits `div` 8
| otherwise -> Nothing
-- Vectors don't appear as raw fields.
PrimTyConVec{} -> Nothing
-- Address value.
PrimTyConAddr -> Just $ platformAddrBytes platform
-- Pointer tycon shouldn't appear by itself.
PrimTyConPtr -> Nothing
-- Address of static memory where the string data is stored.
PrimTyConTextLit -> Just $ platformAddrBytes platform
PrimTyConTag -> Just $ platformTagBytes platform