on develop help sign in
Make fast-weak optional
commitf0b5e75f0f7539915071447b4e5e0c4c6ec633a6 authorRyan Trinkle <ryan.trinkle@gmail.com> dateWed 4 Oct 2017, 23:38 (9 years ago) parentfe21a50
3 files changed+28−20
reflex.cabal+8 src/Data/FastWeakBag.hs+10−10 src/Reflex/FastWeak.hs+10−10
reflex.cabal+8
@@ -43,6 +43,11 @@ flag experimental-dependent-sum-instances
4343 default: False
4444 manual: True
4545
46+flag fast-weak
47+ description: Use the primitive implementation of FastWeak in GHCJS; note that this requires GHCJS to be built with FastWeak and FastWeakBag present in the RTS, which is not the default
48+ default: False
49+ manual: True
50+
4651library
4752 hs-source-dirs: src
4853 build-depends:
@@ -142,6 +147,9 @@ library
142147 if flag(experimental-dependent-sum-instances)
143148 ghc-options: -DEXPERIMENTAL_DEPENDENT_SUM_INSTANCES
144149
150+ if flag(fast-weak) && impl(ghcjs)
151+ ghc-options: -DGHCJS_FAST_WEAK
152+
145153 if impl(ghcjs)
146154 build-depends: ghcjs-base
147155
src/Data/FastWeakBag.hs+10−10
@@ -3,7 +3,7 @@
33#ifdef USE_REFLEX_OPTIMIZER
44{-# OPTIONS_GHC -fplugin=Reflex.Optimizer #-}
55#endif
6−#ifdef ghcjs_HOST_OS
6+#ifdef GHCJS_FAST_WEAK
77{-# LANGUAGE ForeignFunctionInterface #-}
88{-# LANGUAGE JavaScriptFFI #-}
99#endif
@@ -21,7 +21,7 @@ module Data.FastWeakBag
2121 , remove
2222 -- * Internal functions
2323 -- These will not always be available.
24−#ifndef ghcjs_HOST_OS
24+#ifndef GHCJS_FAST_WEAK
2525 , _weakBag_children --TODO: Don't export this
2626#endif
2727 ) where
@@ -29,7 +29,7 @@ module Data.FastWeakBag
2929import Control.Monad hiding (forM_, mapM_)
3030import Control.Monad.IO.Class
3131
32−#ifdef ghcjs_HOST_OS
32+#ifdef GHCJS_FAST_WEAK
3333import GHCJS.Types
3434import Reflex.FastWeak (unsafeFromRawJSVal, unsafeToRawJSVal, js_isNull)
3535#else
@@ -46,7 +46,7 @@ import Prelude hiding (mapM_, traverse)
4646-- | A @FastWeakBag a@ holds a set of values of type @a@, but does not retain them -
4747-- that is, they can still be garbage-collected. As long as the @a@s remain
4848-- alive, the 'FastWeakBag' will continue to refer to them.
49−#ifdef ghcjs_HOST_OS
49+#ifdef GHCJS_FAST_WEAK
5050newtype FastWeakBag a = FastWeakBag JSVal
5151#else
5252data FastWeakBag a = FastWeakBag
@@ -59,7 +59,7 @@ data FastWeakBag a = FastWeakBag
5959-- the caller retains the ticket, the item is guranteed to stay in memory (and
6060-- thus in the 'FastWeakBag'). The ticket can also be used to remove the item from
6161-- the 'FastWeakBag' prematurely (i.e. while it is still alive), using 'remove'.
62−#ifdef ghcjs_HOST_OS
62+#ifdef GHCJS_FAST_WEAK
6363newtype FastWeakBagTicket a = FastWeakBagTicket JSVal
6464#else
6565data FastWeakBagTicket a = FastWeakBagTicket
@@ -74,7 +74,7 @@ insert :: a -- ^ The item
7474 -> FastWeakBag a -- ^ The 'FastWeakBag' to insert into
7575 -> IO (FastWeakBagTicket a) -- ^ Returns a 'FastWeakBagTicket' that ensures the item
7676 -- is retained and allows the item to be removed.
77−#ifdef ghcjs_HOST_OS
77+#ifdef GHCJS_FAST_WEAK
7878insert a wb = js_insert (unsafeToRawJSVal a) wb
7979foreign import javascript unsafe "$r = new h$FastWeakBagTicket($2, $1);" js_insert :: JSVal -> FastWeakBag a -> IO (FastWeakBagTicket a)
8080#else
@@ -93,7 +93,7 @@ insert a (FastWeakBag nextId children) = {-# SCC "insert" #-} do
9393-- | Create an empty 'FastWeakBag'.
9494{-# INLINE empty #-}
9595empty :: IO (FastWeakBag a)
96−#ifdef ghcjs_HOST_OS
96+#ifdef GHCJS_FAST_WEAK
9797empty = js_empty
9898foreign import javascript unsafe "$r = new h$FastWeakBag();" js_empty :: IO (FastWeakBag a)
9999#else
@@ -110,7 +110,7 @@ empty = {-# SCC "empty" #-} do
110110-- | Check whether a 'FastWeakBag' is empty.
111111{-# INLINE isEmpty #-}
112112isEmpty :: FastWeakBag a -> IO Bool
113−#ifdef ghcjs_HOST_OS
113+#ifdef GHCJS_FAST_WEAK
114114isEmpty = js_isEmpty
115115foreign import javascript unsafe "(function(){ for(var i = 0; i < $1.tickets.length; i++) { if($1.tickets[i] !== null) { return false; } }; return true; })()" js_isEmpty :: FastWeakBag a -> IO Bool --TODO: Clean up as we go along so this isn't O(n) every time
116116#else
@@ -123,7 +123,7 @@ isEmpty bag = {-# SCC "isEmpty" #-} IntMap.null <$> readIORef (_weakBag_children
123123-- when the traversal began will be visited exactly once; however, no guarantee
124124-- is made about the order of the traversal.
125125traverse :: forall a m. MonadIO m => FastWeakBag a -> (a -> m ()) -> m ()
126−#ifdef ghcjs_HOST_OS
126+#ifdef GHCJS_FAST_WEAK
127127traverse wb f = do
128128 let go cursor = when (not $ js_isNull cursor) $ do
129129 val <- liftIO $ js_getTicketValue cursor
@@ -146,7 +146,7 @@ traverse (FastWeakBag _ children) f = {-# SCC "traverse" #-} do
146146-- on the same 'FastWeakBagTicket'.
147147{-# INLINE remove #-}
148148remove :: FastWeakBagTicket a -> IO ()
149−#ifdef ghcjs_HOST_OS
149+#ifdef GHCJS_FAST_WEAK
150150remove = js_remove
151151foreign import javascript unsafe "$1.bag.tickets[$1.pos] = null; $1.bag = new h$FastWeakBag(); $1.bag.tickets.push($1); $1.pos = 0;" js_remove :: FastWeakBagTicket a -> IO () --TODO: Don't bother with the new surrogate FastWeakBag; instead, make the GC check for bag === null, and then null it out here
152152#else
src/Reflex/FastWeak.hs+10−10
@@ -1,7 +1,7 @@
11{-# LANGUAGE CPP #-}
22{-# LANGUAGE LambdaCase #-}
33{-# LANGUAGE ScopedTypeVariables #-}
4−#ifdef ghcjs_HOST_OS
4+#if GHCJS_FAST_WEAK
55{-# LANGUAGE ForeignFunctionInterface #-}
66{-# LANGUAGE JavaScriptFFI #-}
77#endif
@@ -14,7 +14,7 @@ module Reflex.FastWeak
1414 , getFastWeakValue
1515 , getFastWeakTicket
1616 , emptyFastWeak
17−#ifdef ghcjs_HOST_OS
17+#ifdef GHCJS_FAST_WEAK
1818 --TODO: Move these elsewhere
1919 , unsafeFromRawJSVal
2020 , unsafeToRawJSVal
@@ -25,7 +25,7 @@ module Reflex.FastWeak
2525import GHC.Exts (Any)
2626import Unsafe.Coerce
2727
28−#ifdef ghcjs_HOST_OS
28+#ifdef GHCJS_FAST_WEAK
2929import GHCJS.Types
3030#else
3131import Control.Exception (evaluate)
@@ -34,7 +34,7 @@ import System.Mem.Weak
3434#endif
3535
3636
37−#ifdef ghcjs_HOST_OS
37+#ifdef GHCJS_FAST_WEAK
3838newtype FastWeakTicket a = FastWeakTicket JSVal
3939
4040newtype FastWeak a = FastWeak JSVal
@@ -59,7 +59,7 @@ type FastWeak a = Weak a
5959
6060-- This needs to be in IO so we know that we've relinquished the ticket
6161getFastWeakTicketValue :: FastWeakTicket a -> IO a
62−#ifdef ghcjs_HOST_OS
62+#ifdef GHCJS_FAST_WEAK
6363getFastWeakTicketValue t = do
6464 v <- js_ticketVal t
6565 return $ unsafeFromRawJSVal v
@@ -70,7 +70,7 @@ getFastWeakTicketValue = return . _fastWeakTicket_val
7070#endif
7171
7272getFastWeakValue :: FastWeak a -> IO (Maybe a)
73−#ifdef ghcjs_HOST_OS
73+#ifdef GHCJS_FAST_WEAK
7474getFastWeakValue w = do
7575 r <- js_weakVal w
7676 case js_isNull r of
@@ -85,7 +85,7 @@ getFastWeakValue = deRefWeak
8585#endif
8686
8787getFastWeakTicket :: forall a. FastWeak a -> IO (Maybe (FastWeakTicket a))
88−#ifdef ghcjs_HOST_OS
88+#ifdef GHCJS_FAST_WEAK
8989getFastWeakTicket w = do
9090 r <- js_weakTicket w
9191 case js_isNull r of
@@ -105,7 +105,7 @@ getFastWeakTicket w = do
105105
106106-- I think it's fine if this is lazy - it'll retain the 'a', but so would the output; we just need to make sure it's forced before we start relying on the associated FastWeak to actually be weak
107107mkFastWeakTicket :: a -> IO (FastWeakTicket a)
108−#ifdef ghcjs_HOST_OS
108+#ifdef GHCJS_FAST_WEAK
109109mkFastWeakTicket v = js_fastWeakTicket (unsafeToRawJSVal v)
110110
111111foreign import javascript unsafe "$r = new h$FastWeakTicket($1);" js_fastWeakTicket :: JSVal -> IO (FastWeakTicket a)
@@ -120,7 +120,7 @@ mkFastWeakTicket v = do
120120#endif
121121
122122-- Needs IO so that it can force the value - otherwise, could end up with a reference to the Ticket, which would retain the value
123−#ifdef ghcjs_HOST_OS
123+#ifdef GHCJS_FAST_WEAK
124124foreign import javascript unsafe "$r = $1.weak;" getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
125125#else
126126getFastWeakTicketWeak :: FastWeakTicket a -> IO (FastWeak a)
@@ -131,7 +131,7 @@ getFastWeakTicketWeak = return . _fastWeakTicket_weak
131131emptyFastWeak :: FastWeak a
132132emptyFastWeak = unsafeCoerce w
133133 where w :: FastWeak Any
134−#ifdef ghcjs_HOST_OS
134+#ifdef GHCJS_FAST_WEAK
135135 w = js_emptyWeak
136136foreign import javascript unsafe "$r = new h$FastWeak(null);" js_emptyWeak :: FastWeak Any
137137#else