    {-# LANGUAGE RecordWildCards, DeriveGeneric, GeneralizedNewtypeDeriving,
        BangPatterns #-}
    module GHCi.ResolvedBCO
      ( ResolvedBCO(..)
      , ResolvedBCOPtr(..)
      ) where

    import SizedSeq
    import GHCi.RemoteTypes
    import GHCi.BreakArray

    import Control.Monad.ST
    import Data.Array.Unboxed
    import Data.Array.Base
    import Data.Binary
    import GHC.Generics

    -- -----------------------------------------------------------------------------
    -- ResolvedBCO

    -- A A ResolvedBCO is one in which all the Name references have been
    -- resolved to actual addresses or RemoteHValues.
    --
    -- Note, all arrays are zero-indexed (we assume this when
    -- serializing/deserializing)
    data ResolvedBCO
       = ResolvedBCO {
            resolvedBCOArity  :: {-# UNPACK #-} !Int,
            resolvedBCOInstrs :: UArray Int Word,           -- insns
            resolvedBCOBitmap :: UArray Int Word,           -- bitmap
            resolvedBCOLits   :: UArray Int Word,           -- non-ptrs
            resolvedBCOPtrs   :: (SizedSeq ResolvedBCOPtr)  -- ptrs
       }
       deriving (Generic, Show)

    instance Binary ResolvedBCO where
      put ResolvedBCO{..} = do
        put resolvedBCOArity
        putArray resolvedBCOInstrs
        putArray resolvedBCOBitmap
        putArray resolvedBCOLits
        put resolvedBCOPtrs
      get = ResolvedBCO <$> get <*> getArray <*> getArray <*> getArray <*> get

    -- Specialized versions of the binary get/put for UArray Int Word.
    -- This saves a bit of time and allocation over using the default
    -- get/put, because we get specialisd code and also avoid serializing
    -- the bounds.
    putArray :: UArray Int Word -> Put
    putArray a@(UArray _ _ n _) = do
      put n
      mapM_ put (elems a)

    getArray :: Get (UArray Int Word)
    getArray = do
      n  <- get
      xs <- gets n []
      return $! mkArray n xs
     where
      gets 0 xs = return xs
      gets n xs = do
        x <- get
        gets (n-1) (x:xs)

      mkArray :: Int -> [Word] -> UArray Int Word
      mkArray n0 xs0 = runST $ do
        !marr <- newArray (0,n0-1) 0
        let go 0 _ = return ()
            go _ [] = error "mkArray"
            go n (x:xs) = do
              let n' = n-1
              unsafeWrite marr n' x
              go n' xs
        go n0 xs0
        unsafeFreezeSTUArray marr

    data ResolvedBCOPtr
      = ResolvedBCORef {-# UNPACK #-} !Int
          -- ^ reference to the Nth BCO in the current set
      | ResolvedBCOPtr {-# UNPACK #-} !(RemoteRef HValue)
          -- ^ reference to a previously created BCO
      | ResolvedBCOStaticPtr {-# UNPACK #-} !(RemotePtr ())
          -- ^ reference to a static ptr
      | ResolvedBCOPtrBCO ResolvedBCO
          -- ^ a nested BCO
      | ResolvedBCOPtrBreakArray {-# UNPACK #-} !(RemoteRef BreakArray)
          -- ^ Resolves to the MutableArray# inside the BreakArray
      deriving (Generic, Show)

    instance Binary ResolvedBCOPtr