@@ -13,7 +13,9 @@ import Data.Traversable
1313import Control.Monad hiding (mapM, mapM_, forM_, forM, sequence)
1414import Control.Monad.Reader hiding (mapM, mapM_, forM_, forM, sequence)
1515import GHC.Exts
16+#if !MIN_VERSION_base(4,8,0)
1617import Control.Applicative
18+#endif
1719import Data.Dependent.Map (DMap, DSum (..))
1820import qualified Data.Dependent.Map as DMap
1921import Data.GADT.Compare
@@ -164,7 +166,7 @@ hold v0 e = do
164166 , holdNodeId = unsafeNodeId (v0, e)
165167#endif
166168 }
167− !s = SubscriberHold h
169+ s <- newSubscriberHold h
168170 writeIORef subscriberRef $ unsafeCoerce s
169171 modifyIORef' holdInitRef (SomeHoldInit e h :)
170172 return $ BehaviorHold h
@@ -277,7 +279,7 @@ instance GCompare k => GCompare (FanSubscriberKey k) where
277279data FanSubscribed k
278280 = FanSubscribed { fanSubscribedSubscribers :: !(IORef (DMap (FanSubscriberKey k)))
279281 , fanSubscribedParent :: !(EventSubscribed (DMap k))
280− , fanSubscribedSelf :: !(Subscriber (DMap k))
282+ , fanSubscribedSelf :: {-# NOUNPACK #-} (Subscriber (DMap k))
281283#ifdef DEBUG_NODEIDS
282284 , fanSubscribedNodeId :: Int
283285#endif
@@ -292,9 +294,9 @@ data SwitchSubscribed a
292294 = SwitchSubscribed { switchSubscribedOccurrence :: !(IORef (Maybe a))
293295 , switchSubscribedHeight :: !(IORef Int)
294296 , switchSubscribedSubscribers :: !(IORef [WeakSubscriber a])
295− , switchSubscribedSelf :: !(Subscriber a)
297+ , switchSubscribedSelf :: {-# NOUNPACK #-} (Subscriber a)
296298 , switchSubscribedSelfWeak :: !(IORef (Weak (Subscriber a)))
297− , switchSubscribedOwnInvalidator :: !Invalidator
299+ , switchSubscribedOwnInvalidator :: {-# NOUNPACK #-} Invalidator
298300 , switchSubscribedOwnWeakInvalidator :: !(IORef (Weak Invalidator))
299301 , switchSubscribedBehaviorParents :: !(IORef [SomeBehaviorSubscribed])
300302 , switchSubscribedParent :: !(Behavior (Event a))
@@ -313,7 +315,7 @@ data CoincidenceSubscribed a
313315 = CoincidenceSubscribed { coincidenceSubscribedOccurrence :: !(IORef (Maybe a))
314316 , coincidenceSubscribedSubscribers :: !(IORef [WeakSubscriber a])
315317 , coincidenceSubscribedHeight :: !(IORef Int)
316− , coincidenceSubscribedOuter :: !(Subscriber (Event a))
318+ , coincidenceSubscribedOuter :: {-# NOUNPACK #-} (Subscriber (Event a))
317319 , coincidenceSubscribedOuterParent :: !(EventSubscribed (Event a))
318320 , coincidenceSubscribedInnerParent :: !(IORef (Maybe (EventSubscribed a)))
319321#ifdef DEBUG_NODEIDS
@@ -390,6 +392,59 @@ data EventSubscribed a
390392 | EventSubscribedSwitch !(SwitchSubscribed a)
391393 | EventSubscribedCoincidence !(CoincidenceSubscribed a)
392394
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.
400+--
401+-- The result is also evaluated to WHNF, since forcing a thunk invalidates
402+-- the weak pointer to it in some cases.
403+
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
410+ }
411+
412+{-# NOINLINE newSubscriberPush #-}
413+newSubscriberPush :: (a -> EventM (Maybe b)) -> PushSubscribed a b -> IO (Subscriber a)
414+newSubscriberPush compute subd = return $! SubscriberPush compute subd
415+
416+{-# NOINLINE newSubscriberHold #-}
417+newSubscriberHold :: Hold a -> IO (Subscriber a)
418+newSubscriberHold h = return $! SubscriberHold h
419+
420+{-# NOINLINE newSubscriberFan #-}
421+newSubscriberFan :: GCompare k => FanSubscribed k -> IO (Subscriber (DMap k))
422+newSubscriberFan subd = return $! SubscriberFan subd
423+
424+{-# NOINLINE newSubscriberSwitch #-}
425+newSubscriberSwitch :: SwitchSubscribed a -> IO (Subscriber a)
426+newSubscriberSwitch subd = return $! SubscriberSwitch subd
427+
428+{-# NOINLINE newSubscriberCoincidenceOuter #-}
429+newSubscriberCoincidenceOuter :: CoincidenceSubscribed b -> IO (Subscriber (Event b))
430+newSubscriberCoincidenceOuter subd = return $! SubscriberCoincidenceOuter subd
431+
432+{-# NOINLINE newSubscriberCoincidenceInner #-}
433+newSubscriberCoincidenceInner :: CoincidenceSubscribed a -> IO (Subscriber a)
434+newSubscriberCoincidenceInner subd = return $! SubscriberCoincidenceInner subd
435+
436+{-# NOINLINE newInvalidatorSwitch #-}
437+newInvalidatorSwitch :: SwitchSubscribed a -> IO Invalidator
438+newInvalidatorSwitch subd = return $! InvalidatorSwitch subd
439+
440+{-# NOINLINE newInvalidatorPull #-}
441+newInvalidatorPull :: Pull a -> IO Invalidator
442+newInvalidatorPull p = return $! InvalidatorPull p
443+
444+{-# NOINLINE newBox #-}
445+newBox :: a -> IO (Box a)
446+newBox a = return $! Box a
447+
393448--type role Behavior representational
394449data Behavior a
395450 = BehaviorHold !(Hold a)
@@ -605,7 +660,7 @@ data SomeCoincidenceInfo = forall a. SomeCoincidenceInfo (Weak (Subscriber a)) (
605660
606661subscribeCoincidenceInner :: Event a -> Int -> CoincidenceSubscribed a -> EventM (Maybe a, Int, EventSubscribed a)
607662subscribeCoincidenceInner o outerHeight subscribedUnsafe = do
608− let !subInner = SubscriberCoincidenceInner subscribedUnsafe
663+ subInner <- liftIO $ newSubscriberCoincidenceInner subscribedUnsafe
609664 wsubInner <- liftIO $ mkWeakPtrWithDebug subInner "SubscriberCoincidenceInner"
610665 innerSubd <- {-# SCC "innerSubd" #-} (subscribe o $ WeakSubscriberSimple wsubInner)
611666 innerOcc <- liftIO $ getEventSubscribedOcc innerSubd
@@ -644,7 +699,7 @@ readBehaviorTracked b = case b of
644699 liftIO $ touch $ pullSubscribedOwnInvalidator subscribed
645700 return $ pullSubscribedValue subscribed
646701 Nothing -> do
647− let !i = InvalidatorPull p
702+ i <- liftIO $ newInvalidatorPull p
648703 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorPull"
649704 parentsRef <- liftIO $ newIORef []
650705 a <- liftIO $ runReaderT (unBehaviorM $ pullCompute p) $ Just (wi, parentsRef)
@@ -776,10 +831,7 @@ getRootSubscribed r = do
776831 Just subscribed -> return subscribed
777832 Nothing -> liftIO $ do
778833 subscribersRef <- newIORef []
779− let !subscribed = RootSubscribed
780− { rootSubscribedOccurrence = rootOccurrence r
781− , rootSubscribedSubscribers = subscribersRef
782− }
834+ subscribed <- newRootSubscribed (rootOccurrence r) subscribersRef
783835 -- 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
784836 uninit <- rootInit r $ RootTrigger (subscribersRef, rootOccurrence r)
785837 addFinalizer subscribed $ do
@@ -797,7 +849,7 @@ getPushSubscribed p = do
797849 Just subscribed -> return subscribed
798850 Nothing -> do -- Not yet subscribed
799851 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ liftM fromJust $ readIORef $ pushSubscribed p
800− let !s = SubscriberPush (pushCompute p) subscribedUnsafe
852+ s <- liftIO $ newSubscriberPush (pushCompute p) subscribedUnsafe
801853 ws <- liftIO $ mkWeakPtrWithDebug s "SubscriberPush"
802854 subd <- subscribe (pushParent p) $ WeakSubscriberSimple ws
803855 parentOcc <- liftIO $ getEventSubscribedOcc subd
@@ -826,7 +878,7 @@ getMergeSubscribed m = {-# SCC "getMergeSubscribed.entire" #-} do
826878 Nothing -> if DMap.null $ mergeParents m then emptyMergeSubscribed else do
827879 subscribedRef <- liftIO $ newIORef $ error "getMergeSubscribed: subscribedRef not yet initialized"
828880 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
829− let !s = Box subscribedUnsafe
881+ s <- liftIO $ newBox subscribedUnsafe
830882 ws <- liftIO $ mkWeakPtrWithDebug s "SubscriberMerge"
831883 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
832884 parentSubd <- {-# SCC "getMergeSubscribed.a.parentSubd" #-} subscribe e $ WeakSubscriberMerge k ws
@@ -886,7 +938,7 @@ getFanSubscribed f = do
886938 Just subscribed -> return subscribed
887939 Nothing -> do
888940 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ liftM fromJust $ readIORef $ fanSubscribed f
889− let !sub = SubscriberFan subscribedUnsafe
941+ sub <- liftIO $ newSubscriberFan subscribedUnsafe
890942 wsub <- liftIO $ mkWeakPtrWithDebug sub "SubscriberFan"
891943 subd <- subscribe (fanParent f) $ WeakSubscriberSimple wsub
892944 subscribersRef <- liftIO $ newIORef DMap.empty
@@ -909,8 +961,8 @@ getSwitchSubscribed s = do
909961 Nothing -> do
910962 subscribedRef <- liftIO $ newIORef $ error "getSwitchSubscribed: subscribed has not yet been created"
911963 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
912− let !i = InvalidatorSwitch subscribedUnsafe
913− !sub = SubscriberSwitch subscribedUnsafe
964+ i <- liftIO $ newInvalidatorSwitch subscribedUnsafe
965+ sub <- liftIO $ newSubscriberSwitch subscribedUnsafe
914966 wi <- liftIO $ mkWeakPtrWithDebug i "InvalidatorSwitch"
915967 wiRef <- liftIO $ newIORef wi
916968 wsub <- liftIO $ mkWeakPtrWithDebug sub "SubscriberSwitch"
@@ -951,7 +1003,7 @@ getCoincidenceSubscribed c = do
9511003 Nothing -> do
9521004 subscribedRef <- liftIO $ newIORef $ error "getCoincidenceSubscribed: subscribed has not yet been created"
9531005 subscribedUnsafe <- liftIO $ unsafeInterleaveIO $ readIORef subscribedRef
954− let !subOuter = SubscriberCoincidenceOuter subscribedUnsafe
1006+ subOuter <- liftIO $ newSubscriberCoincidenceOuter subscribedUnsafe
9551007 wsubOuter <- liftIO $ mkWeakPtrWithDebug subOuter "subOuter"
9561008 outerSubd <- subscribe (coincidenceParent c) $ WeakSubscriberSimple wsubOuter
9571009 outerOcc <- liftIO $ getEventSubscribedOcc outerSubd
@@ -1287,10 +1339,12 @@ instance MonadRef EventM where
12871339 {-# INLINE newRef #-}
12881340 {-# INLINE readRef #-}
12891341 {-# INLINE writeRef #-}
1290− {-# INLINE atomicModifyRef #-}
12911342 newRef = liftIO . newRef
12921343 readRef = liftIO . readRef
12931344 writeRef r a = liftIO $ writeRef r a
1345+
1346+instance MonadAtomicRef EventM where
1347+ {-# INLINE atomicModifyRef #-}
12941348 atomicModifyRef r f = liftIO $ atomicModifyRef r f
12951349
12961350newtype SpiderHost a = SpiderHost { runSpiderHost :: IO a } deriving (Functor, Applicative, Monad, MonadFix, MonadIO)
@@ -1334,6 +1388,8 @@ instance MonadRef SpiderHost where
13341388 newRef = SpiderHost . newRef
13351389 readRef = SpiderHost . readRef
13361390 writeRef r = SpiderHost . writeRef r
1391+
1392+instance MonadAtomicRef SpiderHost where
13371393 atomicModifyRef r = SpiderHost . atomicModifyRef r
13381394
13391395instance MonadRef SpiderHostFrame where
@@ -1341,4 +1397,6 @@ instance MonadRef SpiderHostFrame where
13411397 newRef = SpiderHostFrame . newRef
13421398 readRef = SpiderHostFrame . readRef
13431399 writeRef r = SpiderHostFrame . writeRef r
1400+
1401+instance MonadAtomicRef SpiderHostFrame where
13441402 atomicModifyRef r = SpiderHostFrame . atomicModifyRef r