{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StaticPointers #-}
{-# LANGUAGE TemplateHaskell #-}
module Clr.Inline.Utils.Embed where
import Clr.Marshal.Host
import Control.Monad
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Foreign
import GHC.StaticPtr
import Language.Haskell.TH as TH
import Language.Haskell.TH.Syntax as TH
import System.IO.Unsafe
newtype ClrBytecode = ClrBytecode
{ bytecode :: ByteString
}
instance TH.Lift ClrBytecode where
lift ClrBytecode{..} =
[| ClrBytecode
(BS.pack $(TH.lift (BS.unpack bytecode)))
|]
embedBytecode :: String -> ClrBytecode -> Q ()
embedBytecode name bs = do
ptr <- TH.newName $ name ++ "_inlineclr__bytecode"
TH.addTopDecls =<<
sequence
[ TH.sigD ptr [t| StaticPtr ClrBytecode |]
, TH.valD (TH.varP ptr) (TH.normalB [| static $(TH.lift bs) |]) []
]
unembedBytecode :: IO ()
{-# NOINLINE unembedBytecode #-}
unembedBytecode = doit `seq` return ()
where
{-# NOINLINE doit #-}
doit = unsafePerformIO $ do
keys <- staticPtrKeys
forM_ keys $
unsafeLookupStaticPtr >=> \case
Just (sptr :: StaticPtr ClrBytecode) -> do
let ClrBytecode bytes = deRefStaticPtr sptr
loadBytecode bytes
_ -> return ()
foreign import ccall "dynamic" assemblyLoad :: FunPtr (Ptr Int -> Int -> IO()) -> (Ptr Int -> Int -> IO ())
loadBytecode :: ByteString -> IO ()
loadBytecode bs =
unsafeGetPointerToMethod "LoadAssemblyFromBytes" >>= \f ->
BS.useAsCStringLen bs $ \(ptr,len) -> assemblyLoad f (castPtr ptr) len