@@ -13,7 +13,9 @@ import Data.Traversable
13import Control.Monad hiding (mapM, mapM_, forM_, forM, sequence)
13import Control.Monad hiding (mapM, mapM_, forM_, forM, sequence)
14import Control.Monad.Reader hiding (mapM, mapM_, forM_, forM, sequence)
14import Control.Monad.Reader hiding (mapM, mapM_, forM_, forM, sequence)
15import GHC.Exts
15import GHC.Exts
16+#if !MIN_VERSION_base(4,8,0)
16import Control.Applicative
17import Control.Applicative
17import Data.Dependent.Map (DMap, DSum (..))
19import Data.Dependent.Map (DMap, DSum (..))
18import qualified Data.Dependent.Map as DMap
20import qualified Data.Dependent.Map as DMap
19import Data.GADT.Compare
21import Data.GADT.Compare
@@ -164,7 +166,7 @@ hold v0 e = do
164 , holdNodeId = unsafeNodeId (v0, e)
166 , holdNodeId = unsafeNodeId (v0, e)
167− !s = SubscriberHold h
169+ s <- newSubscriberHold h
168 writeIORef subscriberRef $ unsafeCoerce s
170 writeIORef subscriberRef $ unsafeCoerce s
169 modifyIORef' holdInitRef (SomeHoldInit e h :)
171 modifyIORef' holdInitRef (SomeHoldInit e h :)
170 return $ BehaviorHold h
172 return $ BehaviorHold h
@@ -277,7 +279,7 @@ instance GCompare k => GCompare (FanSubscriberKey k) where
277data FanSubscribed k
279data FanSubscribed k
278 = FanSubscribed { fanSubscribedSubscribers :: !(IORef (DMap (FanSubscriberKey k)))
280 = FanSubscribed { fanSubscribedSubscribers :: !(IORef (DMap (FanSubscriberKey k)))
279 , fanSubscribedParent :: !(EventSubscribed (DMap k))
281 , fanSubscribedParent :: !(EventSubscribed (DMap k))
280− , fanSubscribedSelf :: !(Subscriber (DMap k))
282+ , fanSubscribedSelf :: {-# NOUNPACK #-} (Subscriber (DMap k))
281#ifdef DEBUG_NODEIDS
283#ifdef DEBUG_NODEIDS
282 , fanSubscribedNodeId :: Int
284 , fanSubscribedNodeId :: Int
@@ -292,9 +294,9 @@ data SwitchSubscribed a
292 = SwitchSubscribed { switchSubscribedOccurrence :: !(IORef (Maybe a))
294 = SwitchSubscribed { switchSubscribedOccurrence :: !(IORef (Maybe a))
293 , switchSubscribedHeight :: !(IORef Int)
295 , switchSubscribedHeight :: !(IORef Int)
294 , switchSubscribedSubscribers :: !(IORef [WeakSubscriber a])
296 , switchSubscribedSubscribers :: !(IORef [WeakSubscriber a])
295− , switchSubscribedSelf :: !(Subscriber a)
297+ , switchSubscribedSelf :: {-# NOUNPACK #-} (Subscriber a)
296 , switchSubscribedSelfWeak :: !(IORef (Weak (Subscriber a)))
298 , switchSubscribedSelfWeak :: !(IORef (Weak (Subscriber a)))
297− , switchSubscribedOwnInvalidator :: !Invalidator
299+ , switchSubscribedOwnInvalidator :: {-# NOUNPACK #-} Invalidator
298 , switchSubscribedOwnWeakInvalidator :: !(IORef (Weak Invalidator))
300 , switchSubscribedOwnWeakInvalidator :: !(IORef (Weak Invalidator))
299 , switchSubscribedBehaviorParents :: !(IORef [SomeBehaviorSubscribed])
301 , switchSubscribedBehaviorParents :: !(IORef [SomeBehaviorSubscribed])
300 , switchSubscribedParent :: !(Behavior (Event a))
302 , switchSubscribedParent :: !(Behavior (Event a))
@@ -313,7 +315,7 @@ data CoincidenceSubscribed a
313 = CoincidenceSubscribed { coincidenceSubscribedOccurrence :: !(IORef (Maybe a))
315 = CoincidenceSubscribed { coincidenceSubscribedOccurrence :: !(IORef (Maybe a))
314 , coincidenceSubscribedSubscribers :: !(IORef [WeakSubscriber a])
316 , coincidenceSubscribedSubscribers :: !(IORef [WeakSubscriber a])
315 , coincidenceSubscribedHeight :: !(IORef Int)
317 , coincidenceSubscribedHeight :: !(IORef Int)
316− , coincidenceSubscribedOuter :: !(Subscriber (Event a))
318+ , coincidenceSubscribedOuter :: {-# NOUNPACK #-} (Subscriber (Event a))
317 , coincidenceSubscribedOuterParent :: !(EventSubscribed (Event a))
319 , coincidenceSubscribedOuterParent :: !(EventSubscribed (Event a))
318 , coincidenceSubscribedInnerParent :: !(IORef (Maybe (EventSubscribed a)))
320 , coincidenceSubscribedInnerParent :: !(IORef (Maybe (EventSubscribed a)))
319#ifdef DEBUG_NODEIDS
321#ifdef DEBUG_NODEIDS
@@ -390,6 +392,59 @@ data EventSubscribed a
390 | EventSubscribedSwitch !(SwitchSubscribed a)
392 | EventSubscribedSwitch !(SwitchSubscribed a)
391 | EventSubscribedCoincidence !(CoincidenceSubscribed a)
393 | EventSubscribedCoincidence !(CoincidenceSubscribed a)
395+-- These function are constructor functions that are marked NOINLINE so they are
396+-- opaque to GHC. If we do not do this, then GHC will sometimes fuse the constructor away
397+-- so any weak references that are attached to the constructors will have their
398+-- finalizer run. Using the opaque constructor, does not see the
399+-- constructor application, so it behaves like an IORef and cannot be fused away.
401+-- The result is also evaluated to WHNF, since forcing a thunk invalidates
402+-- the weak pointer to it in some cases.
404+{-# NOINLINE newRootSubscribed #-}
405+newRootSubscribed :: IORef (Maybe a) -> IORef [WeakSubscriber a] -> IO (RootSubscribed a)
406+newRootSubscribed occ subs =
407+ return $! RootSubscribed
408+ { rootSubscribedOccurrence = occ
409+ , rootSubscribedSubscribers = subs
412+{-# NOINLINE newSubscriberPush #-}
413+newSubscriberPush :: (a -> EventM (Maybe b)) -> PushSubscribed a b -> IO (Subscriber a)
414+newSubscriberPush compute subd = return $! SubscriberPush compute subd
416+{-# NOINLINE newSubscriberHold #-}
417+newSubscriberHold :: Hold a -> IO (Subscriber a)
418+newSubscriberHold h = return $! SubscriberHold h
420+{-# NOINLINE newSubscriberFan #-}
421+newSubscriberFan :: GCompare k => FanSubscribed k -> IO (Subscriber (DMap k))
422+newSubscriberFan subd = return $! SubscriberFan subd
424+{-# NOINLINE newSubscriberSwitch #-}
425+newSubscriberSwitch :: SwitchSubscribed a -> IO (Subscriber a)
426+newSubscriberSwitch subd = return $! SubscriberSwitch subd
428+{-# NOINLINE newSubscriberCoincidenceOuter #-}
429+newSubscriberCoincidenceOuter :: CoincidenceSubscribed b -> IO (Subscriber (Event b))
430+newSubscriberCoincidenceOuter subd = return $! SubscriberCoincidenceOuter subd
432+{-# NOINLINE newSubscriberCoincidenceInner #-}
433+newSubscriberCoincidenceInner :: CoincidenceSubscribed a -> IO (Subscriber a)
434+newSubscriberCoincidenceInner subd = return $! SubscriberCoincidenceInner subd
436+{-# NOINLINE newInvalidatorSwitch #-}
437+newInvalidatorSwitch :: SwitchSubscribed a -> IO Invalidator
438+newInvalidatorSwitch subd = return $! InvalidatorSwitch subd
440+{-# NOINLINE newInvalidatorPull #-}
441+newInvalidatorPull :: Pull a -> IO Invalidator
442+newInvalidatorPull p = return $! InvalidatorPull p
444+{-# NOINLINE newBox #-}
445+newBox :: a -> IO (Box a)
446+newBox a = return $! Box a
393--type role Behavior representational
448--type role Behavior representational
394data Behavior a
449data Behavior a
395 = BehaviorHold !(Hold a)
450 = BehaviorHold !(Hold a)
@@ -605,7 +660,7 @@ data SomeCoincidenceInfo = forall a. SomeCoincidenceInfo (Weak (Subscriber a)) (
606subscribeCoincidenceInner :: Event a -> Int -> CoincidenceSubscribed a -> EventM (Maybe a, Int, EventSubscribed a)
661subscribeCoincidenceInner :: Event a -> Int -> CoincidenceSubscribed a -> EventM (Maybe a, Int, EventSubscribed a)
607subscribeCoincidenceInner o outerHeight subscribedUnsafe = do
662subscribeCoincidenceInner o outerHeight subscribedUnsafe = do
608− let !subInner = SubscriberCoincidenceInner subscribedUnsafe
663+ subInner <- liftIO $ newSubscriberCoincidenceInner subscribedUnsafe
609 wsubInner <- liftIO $ mkWeakPtrWithDebug subInner "SubscriberCoincidenceInner"
664 wsubInner <- liftIO $ mkWeakPtrWithDebug subInner "SubscriberCoincidenceInner"
610 innerSubd <- {-# SCC "innerSubd" #-} (subscribe o $ WeakSubscriberSimple wsubInner)
665 innerSubd <- {-# SCC "innerSubd" #-} (subscribe o $ WeakSubscriberSimple wsubInner)
611 innerOcc <- liftIO $ getEventSubscribedOcc innerSubd
666 innerOcc <- liftIO $ getEventSubscribedOcc innerSubd
@@ -644,7 +699,7 @@ readBehaviorTracked b = case b of
644 liftIO $ touch $ pullSubscribedOwnInvalidator subscribed
699 liftIO $ touch $ pullSubscribedOwnInvalidator subscribed
645 return $ pullSubscribedValue subscribed
700 return $ pullSubscribedValue subscribed
646 Nothing -> do
701 Nothing -> do
647− let !i = InvalidatorPull p
702+ i <- liftIO $ newInvalidatorPull p
648 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorPull"
703 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorPull"
649 parentsRef <- liftIO $ newIORef []
704 parentsRef <- liftIO $ newIORef []
650 a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) $ Just (wi, parentsRef)
705 a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) $ Just (wi, parentsRef)
@@ -776,10 +831,7 @@ getRootSubscribed r = do
776 Just subscribed -> return subscribed
831 Just subscribed -> return subscribed
777 Nothing -> liftIO $ do
832 Nothing -> liftIO $ do
778 subscribersRef <- newIORef []
833 subscribersRef <- newIORef []
779− let !subscribed = RootSubscribed
834+ subscribed <- newRootSubscribed (rootOccurrence r) subscribersRef
780− { rootSubscribedOccurrence = rootOccurrence r
781− , rootSubscribedSubscribers = subscribersRef
783 -- Strangely, init needs the same stuff as a RootSubscribed has, but it must not be the same as the one that everyone's subscribing to, or it'll leak memory
835 -- Strangely, init needs the same stuff as a RootSubscribed has, but it must not be the same as the one that everyone's subscribing to, or it'll leak memory
784 uninit <- rootInit r $ RootTrigger (subscribersRef, rootOccurrence r)
836 uninit <- rootInit r $ RootTrigger (subscribersRef, rootOccurrence r)
785 addFinalizer subscribed $ do
837 addFinalizer subscribed $ do
@@ -797,7 +849,7 @@ getPushSubscribed p = do
797 Just subscribed -> return subscribed
849 Just subscribed -> return subscribed
798 Nothing -> do -- Not yet subscribed
850 Nothing -> do -- Not yet subscribed
799 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ liftM fromJust $ readIORef $ pushSubscribed p
851 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ liftM fromJust $ readIORef $ pushSubscribed p
800− let !s = SubscriberPush (pushCompute p) subscribedUnsafe
852+ s <- liftIO $ newSubscriberPush (pushCompute p) subscribedUnsafe
801 ws <- liftIO $ mkWeakPtrWithDebug s "SubscriberPush"
853 ws <- liftIO $ mkWeakPtrWithDebug s "SubscriberPush"
802 subd <- subscribe (pushParent p) $ WeakSubscriberSimple ws
854 subd <- subscribe (pushParent p) $ WeakSubscriberSimple ws
803 parentOcc <- liftIO $ getEventSubscribedOcc subd
855 parentOcc <- liftIO $ getEventSubscribedOcc subd
@@ -826,7 +878,7 @@ getMergeSubscribed m = {-# SCC "getMergeSubscribed.entire" #-} do
826 Nothing -> if DMap.null $ mergeParents m then emptyMergeSubscribed else do
878 Nothing -> if DMap.null $ mergeParents m then emptyMergeSubscribed else do
827 subscribedRef <- liftIO $ newIORef $ error "getMergeSubscribed: subscribedRef not yet initialized"
879 subscribedRef <- liftIO $ newIORef $ error "getMergeSubscribed: subscribedRef not yet initialized"
828 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
880 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
829− let !s = Box subscribedUnsafe
881+ s <- liftIO $ newBox subscribedUnsafe
830 ws <- liftIO $ mkWeakPtrWithDebug s "SubscriberMerge"
882 ws <- liftIO $ mkWeakPtrWithDebug s "SubscriberMerge"
831 subscribers :: [(Any, Maybe (DSum k), Int, DSum (WrapArg EventSubscribed k))] <- forM (DMap.toList $ mergeParents m) $ {-# SCC "getMergeSubscribed.a" #-} \(WrapArg k :=> e) -> {-# SCC "getMergeSubscribed.a1" #-} do
883 subscribers :: [(Any, Maybe (DSum k), Int, DSum (WrapArg EventSubscribed k))] <- forM (DMap.toList $ mergeParents m) $ {-# SCC "getMergeSubscribed.a" #-} \(WrapArg k :=> e) -> {-# SCC "getMergeSubscribed.a1" #-} do
832 parentSubd <- {-# SCC "getMergeSubscribed.a.parentSubd" #-} subscribe e $ WeakSubscriberMerge k ws
884 parentSubd <- {-# SCC "getMergeSubscribed.a.parentSubd" #-} subscribe e $ WeakSubscriberMerge k ws
@@ -886,7 +938,7 @@ getFanSubscribed f = do
886 Just subscribed -> return subscribed
938 Just subscribed -> return subscribed
887 Nothing -> do
939 Nothing -> do
888 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ liftM fromJust $ readIORef $ fanSubscribed f
940 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ liftM fromJust $ readIORef $ fanSubscribed f
889− let !sub = SubscriberFan subscribedUnsafe
941+ sub <- liftIO $ newSubscriberFan subscribedUnsafe
890 wsub <- liftIO $ mkWeakPtrWithDebug sub "SubscriberFan"
942 wsub <- liftIO $ mkWeakPtrWithDebug sub "SubscriberFan"
891 subd <- subscribe (fanParent f) $ WeakSubscriberSimple wsub
943 subd <- subscribe (fanParent f) $ WeakSubscriberSimple wsub
892 subscribersRef <- liftIO $ newIORef DMap.empty
944 subscribersRef <- liftIO $ newIORef DMap.empty
@@ -909,8 +961,8 @@ getSwitchSubscribed s = do
909 Nothing -> do
961 Nothing -> do
910 subscribedRef <- liftIO $ newIORef $ error "getSwitchSubscribed: subscribed has not yet been created"
962 subscribedRef <- liftIO $ newIORef $ error "getSwitchSubscribed: subscribed has not yet been created"
911 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
963 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
912− let !i = InvalidatorSwitch subscribedUnsafe
964+ i <- liftIO $ newInvalidatorSwitch subscribedUnsafe
913− !sub = SubscriberSwitch subscribedUnsafe
965+ sub <- liftIO $ newSubscriberSwitch subscribedUnsafe
914 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorSwitch"
966 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorSwitch"
915 wiRef <- liftIO $ newIORef wi
967 wiRef <- liftIO $ newIORef wi
916 wsub <- liftIO $ mkWeakPtrWithDebug sub "SubscriberSwitch"
968 wsub <- liftIO $ mkWeakPtrWithDebug sub "SubscriberSwitch"
@@ -951,7 +1003,7 @@ getCoincidenceSubscribed c = do
951 Nothing -> do
1003 Nothing -> do
952 subscribedRef <- liftIO $ newIORef $ error "getCoincidenceSubscribed: subscribed has not yet been created"
1004 subscribedRef <- liftIO $ newIORef $ error "getCoincidenceSubscribed: subscribed has not yet been created"
953 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
1005 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
954− let !subOuter = SubscriberCoincidenceOuter subscribedUnsafe
1006+ subOuter <- liftIO $ newSubscriberCoincidenceOuter subscribedUnsafe
955 wsubOuter <- liftIO $ mkWeakPtrWithDebug subOuter "subOuter"
1007 wsubOuter <- liftIO $ mkWeakPtrWithDebug subOuter "subOuter"
956 outerSubd <- subscribe (coincidenceParent c) $ WeakSubscriberSimple wsubOuter
1008 outerSubd <- subscribe (coincidenceParent c) $ WeakSubscriberSimple wsubOuter
957 outerOcc <- liftIO $ getEventSubscribedOcc outerSubd
1009 outerOcc <- liftIO $ getEventSubscribedOcc outerSubd
@@ -1287,10 +1339,12 @@ instance MonadRef EventM where
1287 {-# INLINE newRef #-}
1339 {-# INLINE newRef #-}
1288 {-# INLINE readRef #-}
1340 {-# INLINE readRef #-}
1289 {-# INLINE writeRef #-}
1341 {-# INLINE writeRef #-}
1290− {-# INLINE atomicModifyRef #-}
1291 newRef = liftIO . newRef
1342 newRef = liftIO . newRef
1292 readRef = liftIO . readRef
1343 readRef = liftIO . readRef
1293 writeRef r a = liftIO $ writeRef r a
1344 writeRef r a = liftIO $ writeRef r a
1346+instance MonadAtomicRef EventM where
1347+ {-# INLINE atomicModifyRef #-}
1294 atomicModifyRef r f = liftIO $ atomicModifyRef r f
1348 atomicModifyRef r f = liftIO $ atomicModifyRef r f
1296newtype SpiderHost a = SpiderHost { runSpiderHost :: IO a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO)
1350newtype SpiderHost a = SpiderHost { runSpiderHost :: IO a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO)
@@ -1334,6 +1388,8 @@ instance MonadRef SpiderHost where
1334 newRef = SpiderHost . newRef
1388 newRef = SpiderHost . newRef
1335 readRef = SpiderHost . readRef
1389 readRef = SpiderHost . readRef
1336 writeRef r = SpiderHost . writeRef r
1390 writeRef r = SpiderHost . writeRef r
1392+instance MonadAtomicRef SpiderHost where
1337 atomicModifyRef r = SpiderHost . atomicModifyRef r
1393 atomicModifyRef r = SpiderHost . atomicModifyRef r
1339instance MonadRef SpiderHostFrame where
1395instance MonadRef SpiderHostFrame where
@@ -1341,4 +1397,6 @@ instance MonadRef SpiderHostFrame where
1341 newRef = SpiderHostFrame . newRef
1397 newRef = SpiderHostFrame . newRef
1342 readRef = SpiderHostFrame . readRef
1398 readRef = SpiderHostFrame . readRef
1343 writeRef r = SpiderHostFrame . writeRef r
1399 writeRef r = SpiderHostFrame . writeRef r
1401+instance MonadAtomicRef SpiderHostFrame where
1344 atomicModifyRef r = SpiderHostFrame . atomicModifyRef r
1402 atomicModifyRef r = SpiderHostFrame . atomicModifyRef r