@@ -73,6 +73,7 @@ import Language.Javascript.JSaddle.Types
7373import Language.Javascript.JSaddle.Exception (JSException(..))
7474import Control.DeepSeq (deepseq)
7575import GHC.Stats (getGCStatsEnabled, getGCStats, GCStats(..))
76+import Data.Foldable (forM_)
7677#endif
7778
7879-- | Enable (or disable) JSaddle logging
@@ -162,25 +163,26 @@ runJavaScript sendBatch entryPoint = do
162163 callbacks <- newTVarIO M.empty
163164 nextRef' <- newTVarIO 0
164165 finalizerThreads' <- newMVar S.empty
166+ animationFrameHandlers' <- newMVar []
165167 loggingEnabled <- newIORef False
166168 let ctx = JSContextRef {
167− contextId = contextId'
168− , startTime = startTime'
169− , doSendCommand = \cmd -> cmd `deepseq` do
170− result <- newEmptyMVar
171− atomically $ writeTChan commandChan (Right (cmd, result))
172− unsafeInterleaveIO $
173− takeMVar result >>= \case
174− (ThrowJSValue (JSValueReceived v)) -> throwIO $ JSException (JSVal v)
175− r -> return r
176− , doSendAsyncCommand = \cmd -> cmd `deepseq` atomically (writeTChan commandChan $ Left cmd)
177− , addCallback = \(Object (JSVal val)) cb -> atomically $ modifyTVar' callbacks (M.insert val cb)
178− , freeCallback = \(Object (JSVal val)) -> atomically $ modifyTVar' callbacks (M.delete val)
179− , nextRef = nextRef'
180− , doEnableLogging = atomicWriteIORef loggingEnabled
181− , finalizerThreads = finalizerThreads'
182− }
183− let processResults :: Bool -> Results -> IO ()
169+ contextId = contextId'
170+ , startTime = startTime'
171+ , doSendCommand = \cmd -> cmd `deepseq` do
172+ result <- newEmptyMVar
173+ atomically $ writeTChan commandChan (Right (cmd, result))
174+ unsafeInterleaveIO $
175+ takeMVar result >>= \case
176+ (ThrowJSValue (JSValueReceived v)) -> throwIO $ JSException (JSVal v)
177+ r -> return r
178+ , doSendAsyncCommand = \cmd -> cmd `deepseq` atomically (writeTChan commandChan $ Left cmd)
179+ , addCallback = \(Object (JSVal val)) cb -> atomically $ modifyTVar' callbacks (M.insert val cb)
180+ , nextRef = nextRef'
181+ , doEnableLogging = atomicWriteIORef loggingEnabled
182+ , finalizerThreads = finalizerThreads'
183+ , animationFrameHandlers = animationFrameHandlers'
184+ }
185+ processResults :: Bool -> Results -> IO ()
184186 processResults syncCallbacks = \case
185187 (ProtocolError err) -> error $ "Protocol error : " <> T.unpack err
186188 (Callback n br (JSValueReceived fNumber) f this a) -> do
@@ -224,14 +226,20 @@ runJavaScript sendBatch entryPoint = do
224226 putMVar lastAsyncBatch batch
225227 sendBatch batch
226228 takeResult recvMVar nBatch >>= \case
227− (n, _) | n /= nBatch -> error $ "Unexpected jsaddle results (expected batch " <> show nBatch <> ", got batch " <> show n <> ")"
228− (_, Success results) | length results /= length resultMVars -> error "Unexpected number of jsaddle results"
229− | otherwise -> zipWithM_ putMVar resultMVars results
230− (_, Failure results exception) -> do
231− -- The exception will only be rethrown in Haskell if/when one of the
232− -- missing results (if any) is evaluated.
233− putStrLn "A JavaScript exception was thrown! (may not reach Haskell code)"
234− zipWithM_ putMVar resultMVars $ results <> repeat (ThrowJSValue exception)
229+ (n, _) | n /= nBatch -> error $ "Unexpected jsaddle results (expected batch " <> show nBatch <> ", got batch " <> show n <> ")"
230+ (_, Success callbacksToFree results)
231+ | length results /= length resultMVars -> error "Unexpected number of jsaddle results"
232+ | otherwise -> do
233+ zipWithM_ putMVar resultMVars results
234+ forM_ callbacksToFree $ \(JSValueReceived val) ->
235+ atomically (modifyTVar' callbacks (M.delete val))
236+ (_, Failure callbacksToFree results exception) -> do
237+ -- The exception will only be rethrown in Haskell if/when one of the
238+ -- missing results (if any) is evaluated.
239+ putStrLn "A JavaScript exception was thrown! (may not reach Haskell code)"
240+ zipWithM_ putMVar resultMVars $ results <> repeat (ThrowJSValue exception)
241+ forM_ callbacksToFree $ \(JSValueReceived val) ->
242+ atomically (modifyTVar' callbacks (M.delete val))
235243 return (asyncResults, syncResults, runReaderT (unJSM entryPoint) ctx)
236244 where
237245 numberForeverFromM_ :: (Monad m, Enum n) => n -> (n -> m a) -> m ()