{-# LANGUAGE Unsafe #-} {-# LANGUAGE NoImplicitPrelude , MagicHash , UnboxedTuples #-} {-# OPTIONS_HADDOCK not-home #-} ----------------------------------------------------------------------------- -- | -- Module : GHC.Stable -- Copyright : (c) The University of Glasgow, 1992-2004 -- License : see libraries/base/LICENSE -- -- Maintainer : ffi@haskell.org -- Stability : internal -- Portability : non-portable (GHC Extensions) -- -- Stable pointers. -- ----------------------------------------------------------------------------- module GHC.Stable ( StablePtr(..), newStablePtr, deRefStablePtr, freeStablePtr, castStablePtrToPtr, castPtrToStablePtr ) where import GHC.Ptr import GHC.Base import Unsafe.Coerce ( unsafeCoerceAddr ) ----------------------------------------------------------------------------- -- Stable Pointers {- | A /stable pointer/ is a reference to a Haskell expression that is guaranteed not to be affected by garbage collection, i.e., it will neither be deallocated nor will the value of the stable pointer itself change during garbage collection (ordinary references may be relocated during garbage collection). Consequently, stable pointers can be passed to foreign code, which can treat it as an opaque reference to a Haskell value. A value of type @StablePtr a@ is a stable pointer to a Haskell expression of type @a@. -} data {-# CTYPE "HsStablePtr" #-} StablePtr a = StablePtr (StablePtr# a) -- | -- Create a stable pointer referring to the given Haskell value. -- newStablePtr :: a -> IO (StablePtr a) newStablePtr :: forall a. a -> IO (StablePtr a) newStablePtr a a = forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a IO forall a b. (a -> b) -> a -> b $ \ State# RealWorld s -> case forall a. a -> State# RealWorld -> (# State# RealWorld, StablePtr# a #) makeStablePtr# a a State# RealWorld s of (# State# RealWorld s', StablePtr# a sp #) -> (# State# RealWorld s', forall a. StablePtr# a -> StablePtr a StablePtr StablePtr# a sp #) -- | -- Obtain the Haskell value referenced by a stable pointer, i.e., the -- same value that was passed to the corresponding call to -- 'newStablePtr'. If the argument to 'deRefStablePtr' has -- already been freed using 'freeStablePtr', the behaviour of -- 'deRefStablePtr' is undefined. -- deRefStablePtr :: StablePtr a -> IO a deRefStablePtr :: forall a. StablePtr a -> IO a deRefStablePtr (StablePtr StablePtr# a sp) = forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a IO forall a b. (a -> b) -> a -> b $ \State# RealWorld s -> forall a. StablePtr# a -> State# RealWorld -> (# State# RealWorld, a #) deRefStablePtr# StablePtr# a sp State# RealWorld s -- | -- Dissolve the association between the stable pointer and the Haskell -- value. Afterwards, if the stable pointer is passed to -- 'deRefStablePtr' or 'freeStablePtr', the behaviour is -- undefined. However, the stable pointer may still be passed to -- 'castStablePtrToPtr', but the @'Foreign.Ptr.Ptr' ()@ value returned -- by 'castStablePtrToPtr', in this case, is undefined (in particular, -- it may be 'Foreign.Ptr.nullPtr'). Nevertheless, the call -- to 'castStablePtrToPtr' is guaranteed not to diverge. -- foreign import ccall unsafe "hs_free_stable_ptr" freeStablePtr :: StablePtr a -> IO () -- | -- Coerce a stable pointer to an address. No guarantees are made about -- the resulting value, except that the original stable pointer can be -- recovered by 'castPtrToStablePtr'. In particular, the address may not -- refer to an accessible memory location and any attempt to pass it to -- the member functions of the class 'Foreign.Storable.Storable' leads to -- undefined behaviour. -- castStablePtrToPtr :: StablePtr a -> Ptr () castStablePtrToPtr :: forall a. StablePtr a -> Ptr () castStablePtrToPtr (StablePtr StablePtr# a s) = forall a. Addr# -> Ptr a Ptr (forall (a :: TYPE 'AddrRep) (b :: TYPE 'AddrRep). a -> b unsafeCoerceAddr StablePtr# a s) -- | -- The inverse of 'castStablePtrToPtr', i.e., we have the identity -- -- > sp == castPtrToStablePtr (castStablePtrToPtr sp) -- -- for any stable pointer @sp@ on which 'freeStablePtr' has -- not been executed yet. Moreover, 'castPtrToStablePtr' may -- only be applied to pointers that have been produced by -- 'castStablePtrToPtr'. -- castPtrToStablePtr :: Ptr () -> StablePtr a castPtrToStablePtr :: forall a. Ptr () -> StablePtr a castPtrToStablePtr (Ptr Addr# a) = forall a. StablePtr# a -> StablePtr a StablePtr (forall (a :: TYPE 'AddrRep) (b :: TYPE 'AddrRep). a -> b unsafeCoerceAddr Addr# a) -- | @since 2.01 instance Eq (StablePtr a) where (StablePtr StablePtr# a sp1) == :: StablePtr a -> StablePtr a -> Bool == (StablePtr StablePtr# a sp2) = case forall a. StablePtr# a -> StablePtr# a -> Int# eqStablePtr# StablePtr# a sp1 StablePtr# a sp2 of Int# 0# -> Bool False Int# _ -> Bool True