{-# LINE 1 "libraries/ghci/GHCi/InfoTable.hsc" #-}
{-# LANGUAGE CPP, MagicHash, ScopedTypeVariables #-}
module GHCi.InfoTable
  (
{-# LINE 14 "libraries/ghci/GHCi/InfoTable.hsc" #-}
    mkConInfoTable
{-# LINE 16 "libraries/ghci/GHCi/InfoTable.hsc" #-}
  ) where
import Prelude 
{-# LINE 20 "libraries/ghci/GHCi/InfoTable.hsc" #-}
import Foreign
import Foreign.C
import GHC.Ptr
import GHC.Exts
import GHC.Exts.Heap
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
{-# LINE 28 "libraries/ghci/GHCi/InfoTable.hsc" #-}
ghciTablesNextToCode :: Bool
{-# LINE 31 "libraries/ghci/GHCi/InfoTable.hsc" #-}
ghciTablesNextToCode = True
{-# LINE 35 "libraries/ghci/GHCi/InfoTable.hsc" #-}
{-# LINE 37 "libraries/ghci/GHCi/InfoTable.hsc" #-}
mkConInfoTable
   :: Int     
   -> Int     
   -> Int     
   -> Int     
   -> ByteString  
   -> IO (Ptr StgInfoTable)
      
      
mkConInfoTable ptr_words nonptr_words tag ptrtag con_desc =
  castFunPtrToPtr <$> newExecConItbl itbl con_desc
  where
     entry_addr = interpConstrEntry !! ptrtag
     code' = mkJumpToAddr entry_addr
     itbl  = StgInfoTable {
                 entry = if ghciTablesNextToCode
                         then Nothing
                         else Just entry_addr,
                 ptrs  = fromIntegral ptr_words,
                 nptrs = fromIntegral nonptr_words,
                 tipe  = CONSTR,
                 srtlen = fromIntegral tag,
                 code  = if ghciTablesNextToCode
                         then Just code'
                         else Nothing
              }
funPtrToInt :: FunPtr a -> Int
funPtrToInt (FunPtr a) = I# (addr2Int# a)
data Arch = ArchSPARC
          | ArchPPC
          | ArchX86
          | ArchX86_64
          | ArchAlpha
          | ArchARM
          | ArchARM64
          | ArchPPC64
          | ArchPPC64LE
          | ArchUnknown
 deriving Show
platform :: Arch
platform =
{-# LINE 96 "libraries/ghci/GHCi/InfoTable.hsc" #-}
       ArchX86_64
{-# LINE 114 "libraries/ghci/GHCi/InfoTable.hsc" #-}
mkJumpToAddr :: EntryFunPtr -> ItblCodes
mkJumpToAddr a = case platform of
    ArchSPARC ->
        
        
        
        
        
        
        
        
        
        let w32 = fromIntegral (funPtrToInt a)
            hi22, lo10 :: Word32 -> Word32
            lo10 x = x .&. 0x3FF
            hi22 x = (x `shiftR` 10) .&. 0x3FFFF
        in Right [ 0x07000000 .|. (hi22 w32),
                   0x8610E000 .|. (lo10 w32),
                   0x81C0C000,
                   0x01000000 ]
    ArchPPC ->
        
        
        
        
        
        
        let w32 = fromIntegral (funPtrToInt a)
            hi16 x = (x `shiftR` 16) .&. 0xFFFF
            lo16 x = x .&. 0xFFFF
        in Right [ 0x3D800000 .|. hi16 w32,
                   0x618C0000 .|. lo16 w32,
                   0x7D8903A6, 0x4E800420 ]
    ArchX86 ->
        
        
        
        
        let w32 = fromIntegral (funPtrToInt a) :: Word32
            insnBytes :: [Word8]
            insnBytes
               = [0xB8, byte0 w32, byte1 w32,
                        byte2 w32, byte3 w32,
                  0xFF, 0xE0]
        in
            Left insnBytes
    ArchX86_64 ->
        
        
        
        
        
        
        
        
        
        
        
        
        
        let w64 = fromIntegral (funPtrToInt a) :: Word64
            insnBytes :: [Word8]
            insnBytes
               = [0xff, 0x25, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
                  byte0 w64, byte1 w64, byte2 w64, byte3 w64,
                  byte4 w64, byte5 w64, byte6 w64, byte7 w64]
        in
            Left insnBytes
    ArchAlpha ->
        let w64 = fromIntegral (funPtrToInt a) :: Word64
        in Right [ 0xc3800000      
                 , 0xa79c000c      
                 , 0x6bfc0000      
                 , 0x47ff041f      
                 , fromIntegral (w64 .&. 0x0000FFFF)
                 , fromIntegral ((w64 `shiftR` 32) .&. 0x0000FFFF) ]
    ArchARM { } ->
        
        
        
        
        
        
        
        
        let w32 = fromIntegral (funPtrToInt a) :: Word32
        in Left [ 0x00, 0x10, 0x9f, 0xe5
                , 0x11, 0xff, 0x2f, 0xe1
                , byte0 w32, byte1 w32, byte2 w32, byte3 w32]
    ArchARM64 { } ->
        
        
        
        
        
        
        
        
        
        
       let w64 = fromIntegral (funPtrToInt a) :: Word64
       in Right [ 0x58000041
                , 0xd61f0020
                , fromIntegral w64
                , fromIntegral (w64 `shiftR` 32) ]
    ArchPPC64 ->
        
        
        
        
        
        
        
        
        
        
        
        
        
        
       let  w32 = fromIntegral (funPtrToInt a)
            hi16 x = (x `shiftR` 16) .&. 0xFFFF
            lo16 x = x .&. 0xFFFF
       in Right [ 0x3D800000 .|. hi16 w32,
                  0x618C0000 .|. lo16 w32,
                  0xE96C0000,
                  0xE84C0008,
                  0x7D6903A6,
                  0xE96C0010,
                  0x4E800420]
    ArchPPC64LE ->
        
        
        
        
        
        
        
        
        
        let w32 = fromIntegral (funPtrToInt a)
            hi16 x = (x `shiftR` 16) .&. 0xFFFF
            lo16 x = x .&. 0xFFFF
        in Right [ 0x3D800000 .|. hi16 w32,
                   0x618C0000 .|. lo16 w32,
                   0x7D8903A6, 0x4E800420 ]
    
    
    
    ArchUnknown -> error "mkJumpToAddr: ArchUnknown is unsupported"
byte0 :: (Integral w) => w -> Word8
byte0 w = fromIntegral w
byte1, byte2, byte3, byte4, byte5, byte6, byte7
       :: (Integral w, Bits w) => w -> Word8
byte1 w = fromIntegral (w `shiftR` 8)
byte2 w = fromIntegral (w `shiftR` 16)
byte3 w = fromIntegral (w `shiftR` 24)
byte4 w = fromIntegral (w `shiftR` 32)
byte5 w = fromIntegral (w `shiftR` 40)
byte6 w = fromIntegral (w `shiftR` 48)
byte7 w = fromIntegral (w `shiftR` 56)
foreign import ccall "&stg_interp_constr1_entry" stg_interp_constr1_entry :: EntryFunPtr
foreign import ccall "&stg_interp_constr2_entry" stg_interp_constr2_entry :: EntryFunPtr
foreign import ccall "&stg_interp_constr3_entry" stg_interp_constr3_entry :: EntryFunPtr
foreign import ccall "&stg_interp_constr4_entry" stg_interp_constr4_entry :: EntryFunPtr
foreign import ccall "&stg_interp_constr5_entry" stg_interp_constr5_entry :: EntryFunPtr
foreign import ccall "&stg_interp_constr6_entry" stg_interp_constr6_entry :: EntryFunPtr
foreign import ccall "&stg_interp_constr7_entry" stg_interp_constr7_entry :: EntryFunPtr
interpConstrEntry :: [EntryFunPtr]
interpConstrEntry = [ error "pointer tag 0"
                    , stg_interp_constr1_entry
                    , stg_interp_constr2_entry
                    , stg_interp_constr3_entry
                    , stg_interp_constr4_entry
                    , stg_interp_constr5_entry
                    , stg_interp_constr6_entry
                    , stg_interp_constr7_entry ]
data StgConInfoTable = StgConInfoTable {
   conDesc   :: Ptr Word8,
   infoTable :: StgInfoTable
}
pokeConItbl
  :: Ptr StgConInfoTable -> Ptr StgConInfoTable -> StgConInfoTable
  -> IO ()
pokeConItbl wr_ptr _ex_ptr itbl = do
{-# LINE 328 "libraries/ghci/GHCi/InfoTable.hsc" #-}
  
  
  let con_desc_offset = conDesc itbl `minusPtr` (_ex_ptr `plusPtr` conInfoTableSizeB)
  ((\hsc_ptr -> pokeByteOff hsc_ptr 0)) wr_ptr con_desc_offset
{-# LINE 332 "libraries/ghci/GHCi/InfoTable.hsc" #-}
{-# LINE 338 "libraries/ghci/GHCi/InfoTable.hsc" #-}
  pokeItbl (wr_ptr `plusPtr` ((8))) (infoTable itbl)
{-# LINE 339 "libraries/ghci/GHCi/InfoTable.hsc" #-}
sizeOfEntryCode :: Int
sizeOfEntryCode
  | not ghciTablesNextToCode = 0
  | otherwise =
     case mkJumpToAddr undefined of
       Left  xs -> sizeOf (head xs) * length xs
       Right xs -> sizeOf (head xs) * length xs
newExecConItbl :: StgInfoTable -> ByteString -> IO (FunPtr ())
newExecConItbl obj con_desc
   = alloca $ \pcode -> do
        let lcon_desc = BS.length con_desc + 1
            
            
            sz = fromIntegral (conInfoTableSizeB + sizeOfEntryCode)
               
               
               
               
        wr_ptr <- _allocateExec (sz + fromIntegral lcon_desc) pcode
        ex_ptr <- peek pcode
        let cinfo = StgConInfoTable { conDesc = ex_ptr `plusPtr` fromIntegral sz
                                    , infoTable = obj }
        pokeConItbl wr_ptr ex_ptr cinfo
        BS.useAsCStringLen con_desc $ \(src, len) ->
            copyBytes (castPtr wr_ptr `plusPtr` fromIntegral sz) src len
        let null_off = fromIntegral sz + fromIntegral (BS.length con_desc)
        poke (castPtr wr_ptr `plusPtr` null_off) (0 :: Word8)
        _flushExec sz ex_ptr 
{-# LINE 371 "libraries/ghci/GHCi/InfoTable.hsc" #-}
        return (castPtrToFunPtr (ex_ptr `plusPtr` conInfoTableSizeB))
{-# LINE 375 "libraries/ghci/GHCi/InfoTable.hsc" #-}
foreign import ccall unsafe "allocateExec"
  _allocateExec :: CUInt -> Ptr (Ptr a) -> IO (Ptr a)
foreign import ccall unsafe "flushExec"
  _flushExec :: CUInt -> Ptr a -> IO ()
wORD_SIZE :: Int
wORD_SIZE = (8)
{-# LINE 387 "libraries/ghci/GHCi/InfoTable.hsc" #-}
conInfoTableSizeB :: Int
conInfoTableSizeB = wORD_SIZE + itblSize
{-# LINE 391 "libraries/ghci/GHCi/InfoTable.hsc" #-}