diff --git a/.github/workflows/bundle-ucm.yaml b/.github/workflows/bundle-ucm.yaml index bd05781b39..e97da0292a 100644 --- a/.github/workflows/bundle-ucm.yaml +++ b/.github/workflows/bundle-ucm.yaml @@ -59,6 +59,7 @@ jobs: --ghc-options='-O2' \ --local-bin-path ucm-bin \ --copy-bins \ + --flag unison-runtime:optchecks \ && break; done diff --git a/unison-runtime/package.yaml b/unison-runtime/package.yaml index 850a83046c..4cf83f10c9 100644 --- a/unison-runtime/package.yaml +++ b/unison-runtime/package.yaml @@ -2,7 +2,7 @@ name: unison-runtime github: unisonweb/unison copyright: Copyright (C) 2013-2024 Unison Computing, PBC and contributors -ghc-options: -Wall -funbox-strict-fields -O2 +ghc-options: -fmax-worker-args=100 -Wall -funbox-strict-fields -O2 flags: arraychecks: @@ -11,6 +11,13 @@ flags: stackchecks: manual: true default: false + + # Run optimization assertion tests, make sure this runs with O2 + optchecks: + manual: true + default: false + + # Dumps core for debugging to unison-runtime/.stack-work/dist//ghc-x.y.z/build/ dumpcore: manual: true default: false @@ -20,8 +27,13 @@ when: cpp-options: -DARRAY_CHECK - condition: flag(stackchecks) cpp-options: -DSTACK_CHECK + - condition: flag(optchecks) + ghc-options: -O2 + cpp-options: -DOPT_CHECK + dependencies: + - inspection-testing - condition: flag(dumpcore) - ghc-options: -ddump-simpl -ddump-stg-final -ddump-to-file -dsuppress-coercions -dsuppress-idinfo -dsuppress-module-prefixes # -dsuppress-type-applications -dsuppress-type-signatures + ghc-options: -ddump-simpl -ddump-stg-final -ddump-to-file -dsuppress-coercions -dsuppress-idinfo -dsuppress-module-prefixes -ddump-str-signatures -ddump-simpl-stats # -dsuppress-type-applications -dsuppress-type-signatures library: source-dirs: src @@ -65,6 +77,8 @@ library: - tagged - temporary - text + - template-haskell + - inspection-testing - time - tls - unison-codebase-sqlite diff --git a/unison-runtime/src/Unison/Runtime/Exception.hs b/unison-runtime/src/Unison/Runtime/Exception.hs index 7d0d7bd5ea..2e79c163bd 100644 --- a/unison-runtime/src/Unison/Runtime/Exception.hs +++ b/unison-runtime/src/Unison/Runtime/Exception.hs @@ -1,4 +1,10 @@ -module Unison.Runtime.Exception where +module Unison.Runtime.Exception + ( RuntimeExn (..), + die, + dieP, + exn, + ) +where import Control.Exception import Data.String (fromString) @@ -17,9 +23,12 @@ instance Exception RuntimeExn die :: (HasCallStack) => String -> IO a die = throwIO . PE callStack . P.lit . fromString +{-# INLINE die #-} dieP :: (HasCallStack) => P.Pretty P.ColorText -> IO a dieP = throwIO . PE callStack +{-# INLINE dieP #-} exn :: (HasCallStack) => String -> a exn = throw . PE callStack . P.lit . fromString +{-# INLINE exn #-} diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 60808351e1..71808e9ab3 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -1,7 +1,9 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} +{-# LANGUAGE MagicHash #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeOperators #-} +{-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} @@ -22,6 +24,7 @@ import Data.IORef (IORef) import Data.Sequence qualified as Sq import Data.Time.Clock.POSIX (POSIXTime) import Data.Word (Word16, Word32, Word64, Word8) +import GHC.Base (IO (..)) import GHC.IO.Exception (IOErrorType (..), IOException (..)) import Network.Socket (Socket) import Network.UDP (UDPSocket) @@ -53,8 +56,8 @@ import Unison.Util.Text (Text, pack, unpack) -- Foreign functions operating on stacks data ForeignFunc where FF :: - (Stack -> Args -> IO a) -> - (Stack -> r -> IO Stack) -> + (XStack -> Args -> IO a) -> + (XStack -> r -> IOStack) -> (a -> IO r) -> ForeignFunc @@ -74,12 +77,17 @@ class ForeignConvention a where Stack -> a -> IO Stack mkForeign :: + forall a r. (ForeignConvention a, ForeignConvention r) => (a -> IO r) -> ForeignFunc -mkForeign ev = FF readArgs writeForeign ev +mkForeign ev = FF readArgs doWrite ev where - readArgs stk (argsToLists -> args) = + doWrite :: XStack -> r -> IOStack + doWrite stk a = case writeForeign (packXStack stk) a of + (IO f) -> \state -> case f state of + (# state', stk #) -> (# state', unpackXStack stk #) + readArgs (packXStack -> stk) (argsToLists -> args) = readForeign args stk >>= \case ([], a) -> pure a _ -> diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index a9103e1ec4..33619b22b0 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -6,6 +6,7 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE UnboxedTuples #-} module Unison.Runtime.Interface ( startRuntime, @@ -858,8 +859,8 @@ prepareEvaluation ppe tm ctx = do Just r -> r Nothing -> error "prepareEvaluation: could not remap main ref" -watchHook :: IORef Val -> Stack -> IO () -watchHook r stk = peek stk >>= writeIORef r +watchHook :: IORef Val -> XStack -> IO () +watchHook r xstk = peek (packXStack xstk) >>= writeIORef r backReferenceTm :: EnumMap Word64 Reference -> diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 596f355353..fa73ea66e6 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -1,8 +1,30 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} - -module Unison.Runtime.Machine where +{-# LANGUAGE MagicHash #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE UnboxedTuples #-} + +module Unison.Runtime.Machine + ( ActiveThreads, + CCache (..), + Combs, + Tracer (..), + apply0, + baseCCache, + cacheAdd, + cacheAdd0, + eval0, + expandSandbox, + preEvalTopLevelConstants, + refLookup, + refNumTm, + refNumsTm, + refNumsTy, + reifyValue, + resolveSection, + ) +where import Control.Concurrent (ThreadId) import Control.Concurrent.STM as STM @@ -21,7 +43,9 @@ import Data.Set qualified as Set import Data.Text qualified as DTx import Data.Text.IO qualified as Tx import Data.Traversable +import GHC.Base (IO (..)) import GHC.Conc as STM (unsafeIOToSTM) +import GHC.Stack import Unison.Builtin.Decls (exceptionRef, ioFailureRef) import Unison.Builtin.Decls qualified as Rf import Unison.ConstructorReference qualified as CR @@ -49,7 +73,7 @@ import Unison.Runtime.ANF as ANF import Unison.Runtime.ANF qualified as ANF import Unison.Runtime.Array as PA import Unison.Runtime.Builtin -import Unison.Runtime.Exception +import Unison.Runtime.Exception (RuntimeExn (..)) import Unison.Runtime.Foreign import Unison.Runtime.Foreign.Function import Unison.Runtime.MCode @@ -62,6 +86,7 @@ import Unison.Util.Bytes qualified as By import Unison.Util.EnumContainers as EC import Unison.Util.Monoid qualified as Monoid import Unison.Util.Pretty (toPlainUnbroken) +import Unison.Util.Pretty qualified as P import Unison.Util.Text qualified as Util.Text import UnliftIO qualified import UnliftIO.Concurrent qualified as UnliftIO @@ -71,6 +96,10 @@ import UnliftIO.Concurrent qualified as UnliftIO import Unison.Debug qualified as Debug import System.IO.Unsafe (unsafePerformIO) #endif + +#ifdef OPT_CHECK +import Test.Inspection qualified as TI +#endif {- ORMOLU_ENABLE -} -- | A ref storing every currently active thread. @@ -138,15 +167,6 @@ refNumTm cc r = (M.lookup r -> Just w) -> pure w _ -> die $ "refNumTm: unknown reference: " ++ show r -refNumTy :: CCache -> Reference -> IO Word64 -refNumTy cc r = - refNumsTy cc >>= \case - (M.lookup r -> Just w) -> pure w - _ -> die $ "refNumTy: unknown reference: " ++ show r - -refNumTy' :: CCache -> Reference -> IO (Maybe Word64) -refNumTy' cc r = M.lookup r <$> refNumsTy cc - baseCCache :: Bool -> IO CCache baseCCache sandboxed = do CCache ffuncs sandboxed noTrace @@ -187,13 +207,6 @@ info ctx x = infos ctx (show x) infos :: String -> String -> IO () infos ctx s = putStrLn $ ctx ++ ": " ++ s -stk'info :: Stack -> IO () -stk'info s@(Stack _ _ sp _ _) = do - let prn i - | i < 0 = return () - | otherwise = bpeekOff s i >>= print >> prn (i - 1) - prn sp - -- Entry point for evaluating a section eval0 :: CCache -> ActiveThreads -> MSection -> IO () eval0 !env !activeThreads !co = do @@ -230,7 +243,7 @@ topDEnv _ _ _ = (mempty, id) -- This is the entry point actually used in the interactive -- environment currently. apply0 :: - Maybe (Stack -> IO ()) -> + Maybe (XStack -> IO ()) -> CCache -> ActiveThreads -> Word64 -> @@ -252,7 +265,7 @@ apply0 !callback !env !threadTracker !i = do -- if it's cached, we can just finish CachedVal _ val -> bump stk >>= \stk -> poke stk val where - k0 = maybe KE (CB . Hook) callback + k0 = fromMaybe KE (callback <&> \cb -> CB . Hook $ \stk -> cb stk) -- Apply helper currently used for forking. Creates the new stacks -- necessary to evaluate a closure with the provided information. @@ -266,35 +279,11 @@ apply1 callback env threadTracker clo = do stk <- alloc apply env mempty threadTracker stk k0 True ZArgs $ clo where - k0 = CB $ Hook callback - --- Entry point for evaluating a saved continuation. --- --- The continuation must be from an evaluation context expecting a --- unit value. -jump0 :: - (Stack -> IO ()) -> - CCache -> - ActiveThreads -> - Closure -> - IO () -jump0 !callback !env !activeThreads !clo = do - stk <- alloc - cmbs <- readTVarIO $ combs env - (denv, kf) <- - topDEnv cmbs <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) - stk <- bump stk - bpoke stk (Enum Rf.unitRef TT.unitTag) - jump env denv activeThreads stk (kf k0) (VArg1 0) clo - where - k0 = CB (Hook callback) + k0 = CB $ Hook (\stk -> callback $ packXStack stk) unitValue :: Closure unitValue = Enum Rf.unitRef TT.unitTag -lookupDenv :: Word64 -> DEnv -> Val -lookupDenv p denv = fromMaybe (BoxedVal BlackHole) $ EC.lookup p denv - litToVal :: MLit -> Val litToVal = \case MT t -> BoxedVal $ Foreign (Wrap Rf.textRef t) @@ -538,7 +527,8 @@ exec !_ !denv !_activeThreads !stk !k _ (BPrim2 CMPU i j) = do exec !_ !_ !_activeThreads !stk !k r (BPrim2 THRO i j) = do name <- peekOffBi @Util.Text.Text stk i x <- peekOff stk j - throwIO (BU (traceK r k) (Util.Text.toText name) x) + () <- throwIO (BU (traceK r k) (Util.Text.toText name) x) + error "throwIO should never return" exec !env !denv !_activeThreads !stk !k _ (BPrim2 TRCE i j) | sandboxed env = die "attempted to use sandboxed operation: trace" | otherwise = do @@ -596,9 +586,11 @@ exec !_ !denv !_activeThreads !stk !k _ (Seq as) = do pokeS stk $ Sq.fromList l pure (denv, stk, k) exec !env !denv !_activeThreads !stk !k _ (ForeignCall _ w args) - | Just (FF arg res ev) <- EC.lookup w (foreignFuncs env) = - (denv,,k) - <$> (arg stk args >>= ev >>= res stk) + | Just (FF arg res ev) <- EC.lookup w (foreignFuncs env) = do + let xStack = unpackXStack stk + r <- arg (unpackXStack stk) args >>= ev + IO $ \s -> case res xStack r s of + (# s, xstk #) -> (# s, (denv, packXStack xstk, k) #) | otherwise = die $ "reference to unknown foreign function: " ++ show w exec !env !denv !activeThreads !stk !k _ (Fork i) @@ -665,14 +657,6 @@ encodeExn stk exc = do (Rf.threadKilledFailureRef, disp ie, boxedVal unitValue) | otherwise = (Rf.miscFailureRef, disp exn, boxedVal unitValue) -numValue :: Maybe Reference -> Val -> IO Word64 -numValue _ (UnboxedVal v _) = pure (fromIntegral @Int @Word64 v) -numValue mr clo = - die $ - "numValue: bad closure: " - ++ show clo - ++ maybe "" (\r -> "\nexpected type: " ++ show r) mr - -- | Evaluate a section eval :: CCache -> @@ -710,7 +694,7 @@ eval !env !denv !activeThreads !stk !k r (RMatch i pu br) = do (ANF.rawTag -> e, ANF.rawTag -> t) | Just ebs <- EC.lookup e br -> eval env denv activeThreads stk k r $ selectBranch t ebs - | otherwise -> unhandledErr "eval" env e + | otherwise -> unhandledAbilityRequest eval !env !denv !activeThreads !stk !k _ (Yield args) | asize stk > 0, VArg1 i <- args = @@ -743,6 +727,9 @@ eval !_ !_ !_ !_activeThreads !_ _ Exit = pure () eval !_ !_ !_ !_activeThreads !_ _ (Die s) = die s {-# NOINLINE eval #-} +unhandledAbilityRequest :: (HasCallStack) => IO a +unhandledAbilityRequest = error . show . PE callStack . P.lit . fromString $ "eval: unhandled ability request" + forkEval :: CCache -> ActiveThreads -> Val -> IO ThreadId forkEval env activeThreads clo = do @@ -1059,13 +1046,6 @@ closeArgs mode !stk !seg args = augSeg mode stk seg as | otherwise = Nothing l = fsize stk - i -peekForeign :: Stack -> Int -> IO a -peekForeign stk i = - bpeekOff stk i >>= \case - Foreign x -> pure $ unwrapForeign x - _ -> die "bad foreign argument" -{-# INLINE peekForeign #-} - uprim1 :: Stack -> UPrim1 -> Int -> IO Stack uprim1 !stk DECI !i = do m <- peekOffI stk i @@ -1970,7 +1950,7 @@ yield !env !denv !activeThreads !stk !k = leap denv k stk <- restoreFrame stk fsz asz stk <- ensure stk f eval env denv activeThreads stk k ref nx - leap _ (CB (Hook f)) = f stk + leap _ (CB (Hook f)) = f (unpackXStack stk) leap _ KE = pure () {-# INLINE yield #-} @@ -2038,17 +2018,6 @@ splitCont !denv !stk !k !p = return (BoxedVal $ Captured ck asz seg, denv, stk, k) {-# INLINE splitCont #-} -discardCont :: - DEnv -> - Stack -> - K -> - Word64 -> - IO (DEnv, Stack, K) -discardCont denv stk k p = - splitCont denv stk k p - <&> \(_, denv, stk, k) -> (denv, stk, k) -{-# INLINE discardCont #-} - resolve :: CCache -> DEnv -> Stack -> MRef -> IO Val resolve _ _ _ (Env cix mcomb) = pure $ mCombVal cix mcomb resolve _ _ stk (Stk i) = peekOff stk i @@ -2080,9 +2049,6 @@ resolveSection cc section = do dummyRef :: Reference dummyRef = Builtin (DTx.pack "dummy") -reserveIds :: Word64 -> TVar Word64 -> IO Word64 -reserveIds n free = atomically . stateTVar free $ \i -> (i, i + n) - updateMap :: (Semigroup s) => s -> TVar s -> STM s updateMap new0 r = do new <- evaluateSTM new0 @@ -2282,8 +2248,8 @@ preEvalTopLevelConstants cacheableCombs newCombs cc = do activeThreads <- Just <$> UnliftIO.newIORef mempty evaluatedCacheableCombsVar <- newTVarIO mempty for_ (EC.mapToList cacheableCombs) \(w, _) -> do - let hook stk = do - val <- peek stk + let hook xstk = do + val <- peek (packXStack xstk) atomically $ do modifyTVar evaluatedCacheableCombsVar $ EC.mapInsert w (EC.mapSingleton 0 $ CachedVal w val) apply0 (Just hook) cc activeThreads w @@ -2714,3 +2680,45 @@ arrayCmp cmpVal l r = go i | i < 0 = EQ | otherwise = cmpVal (PA.indexArray l i) (PA.indexArray r i) <> go (i - 1) + +die :: (HasCallStack) => String -> IO a +die s = do + void . throwIO . PE callStack . P.lit . fromString $ s + -- This is unreachable, but we need it to fix some quirks in GHC's + -- worker/wrapper optimization, specifically, it seems that when throwIO's polymorphic return + -- value is specialized to a type like 'Stack' which we want GHC to unbox, it will sometimes + -- fail to unbox it, possibly because it can't unbox it when it's strictly a type application. + -- For whatever reason, this seems to fix it while still allowing us to throw exceptions in IO + -- like we prefer. + error "unreachable" +{-# INLINE die #-} + +{- ORMOLU_DISABLE -} +#ifdef OPT_CHECK +-- Assert that we don't allocate any 'Stack' objects in 'eval', since we expect GHC to always +-- trigger the worker/wrapper optimization and unbox it fully, and if it fails to do so, we want to +-- know about it. +-- +-- Note: this must remain in this module, it can't be moved to a testing module, this is a requirement of the inspection +-- testing library. +-- +-- Note: We _must_ check 'eval0' instead of 'eval' here because if you simply check 'eval', you'll be +-- testing the 'wrapper' part of the worker/wrapper, which will always mention the 'Stack' object as part of its +-- unwrapping, and since there's no way to refer to the generated wrapper directly, we instead refer to 'eval0' +-- which allocates its own stack to pass in, meaning it's one level above the wrapper, and GHC should always detect that +-- it can call the worker directly without using the wrapper. +-- See: https://github.com/nomeata/inspection-testing/issues/50 for more information. +-- +-- If this test starts failing, here are some things you can check. +-- +-- 1. Are 'Stack's being passed to dynamic functions? If so, try changing those functions to take an 'XStack' instead, +-- and manually unpack/pack the 'Stack' where necessary. +-- 2. Are there calls to 'die' or 'throwIO' or something similar in which a fully polymorphic type variable is being +-- specialized to 'Stack'? Sometimes this trips up the optimization, you can try using an 'error' instead, or even +-- following the 'throwIO' with a useless call to @error "unreachable"@, this seems to help for some reason. +-- See this page for more info on precise exceptions: https://gitlab.haskell.org/ghc/ghc/-/wikis/exceptions/precise-exceptions +-- +-- Best of luck! +TI.inspect $ 'eval0 `TI.hasNoType` ''Stack +#endif +{- ORMOLU_ENABLE -} diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 4e0375c957..3747114de6 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -1,5 +1,8 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE MagicHash #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE UnboxedTuples #-} module Unison.Runtime.Stack ( K (..), @@ -27,6 +30,16 @@ module Unison.Runtime.Stack Augment (..), Dump (..), Stack (..), + XStack, + pattern XStack, + packXStack, + unpackXStack, + IOStack, + apX, + fpX, + spX, + ustkX, + bstkX, Off, SZ, FP, @@ -127,18 +140,21 @@ module Unison.Runtime.Stack intTypeTag, charTypeTag, floatTypeTag, + hasNoAllocations, ) where import Control.Monad.Primitive import Data.Char qualified as Char import Data.IORef (IORef) -import Data.Kind (Constraint) import Data.Primitive (sizeOf) import Data.Primitive.ByteArray qualified as BA import Data.Tagged (Tagged (..)) import Data.Word +import GHC.Base import GHC.Exts as L (IsList (..)) +import Language.Haskell.TH qualified as TH +import Test.Inspection qualified as TI import Unison.Prelude import Unison.Reference (Reference) import Unison.Runtime.ANF (PackedTag) @@ -189,7 +205,7 @@ type DebugCallStack = (() :: Constraint) #endif {- ORMOLU_ENABLE -} -newtype Callback = Hook (Stack -> IO ()) +newtype Callback = Hook (XStack -> IO ()) instance Eq Callback where _ == _ = True @@ -620,6 +636,26 @@ data Stack = Stack bstk :: {-# UNPACK #-} !(MutableArray (PrimState IO) Closure) } +-- Unboxed representation of the Stack, used to force GHC optimizations in a few spots. +type XStack = (# Int#, Int#, Int#, MutableByteArray# (PrimState IO), MutableArray# (PrimState IO) Closure #) + +type IOStack = State# RealWorld -> (# State# RealWorld, XStack #) + +pattern XStack :: Int# -> Int# -> Int# -> MutableByteArray# RealWorld -> MutableArray# RealWorld Closure -> Stack +pattern XStack {apX, fpX, spX, ustkX, bstkX} = Stack (I# apX) (I# fpX) (I# spX) (MutableByteArray ustkX) (MutableArray bstkX) + +{-# COMPLETE XStack #-} + +{-# INLINE XStack #-} + +packXStack :: XStack -> Stack +packXStack (# ap, fp, sp, ustk, bstk #) = Stack {ap = I# ap, fp = I# fp, sp = I# sp, ustk = MutableByteArray ustk, bstk = MutableArray bstk} +{-# INLINE packXStack #-} + +unpackXStack :: Stack -> XStack +unpackXStack (Stack (I# ap) (I# fp) (I# sp) (MutableByteArray ustk) (MutableArray bstk)) = (# ap, fp, sp, ustk, bstk #) +{-# INLINE unpackXStack #-} + instance Show Stack where show (Stack ap fp sp _ _) = "Stack " ++ show ap ++ " " ++ show fp ++ " " ++ show sp @@ -1212,3 +1248,6 @@ contTermRefs f (Mark _ _ m k) = contTermRefs f (Push _ _ (CIx r _ _) _ _ k) = f r <> contTermRefs f k contTermRefs _ _ = mempty + +hasNoAllocations :: TH.Name -> TI.Obligation +hasNoAllocations n = TI.mkObligation n TI.NoAllocation diff --git a/unison-runtime/unison-runtime.cabal b/unison-runtime/unison-runtime.cabal index a23132a3f9..0477ee1bf5 100644 --- a/unison-runtime/unison-runtime.cabal +++ b/unison-runtime/unison-runtime.cabal @@ -25,6 +25,10 @@ flag dumpcore manual: True default: False +flag optchecks + manual: True + default: False + flag stackchecks manual: True default: False @@ -87,7 +91,7 @@ library TypeApplications TypeFamilies ViewPatterns - ghc-options: -Wall -funbox-strict-fields -O2 + ghc-options: -fmax-worker-args=100 -Wall -funbox-strict-fields -O2 build-depends: asn1-encoding , asn1-types @@ -109,6 +113,7 @@ library , directory , exceptions , filepath + , inspection-testing , iproute , lens , memory @@ -125,6 +130,7 @@ library , safe-exceptions , stm , tagged + , template-haskell , temporary , text , time @@ -146,8 +152,13 @@ library cpp-options: -DARRAY_CHECK if flag(stackchecks) cpp-options: -DSTACK_CHECK + if flag(optchecks) + ghc-options: -O2 + cpp-options: -DOPT_CHECK + build-depends: + inspection-testing if flag(dumpcore) - ghc-options: -ddump-simpl -ddump-stg-final -ddump-to-file -dsuppress-coercions -dsuppress-idinfo -dsuppress-module-prefixes + ghc-options: -ddump-simpl -ddump-stg-final -ddump-to-file -dsuppress-coercions -dsuppress-idinfo -dsuppress-module-prefixes -ddump-str-signatures -ddump-simpl-stats test-suite runtime-tests type: exitcode-stdio-1.0 @@ -194,7 +205,7 @@ test-suite runtime-tests TypeApplications TypeFamilies ViewPatterns - ghc-options: -Wall -funbox-strict-fields -O2 -W -threaded -rtsopts "-with-rtsopts=-N -T" -v0 + ghc-options: -fmax-worker-args=100 -Wall -funbox-strict-fields -O2 -W -threaded -rtsopts "-with-rtsopts=-N -T" -v0 build-depends: base , bytes @@ -227,5 +238,10 @@ test-suite runtime-tests cpp-options: -DARRAY_CHECK if flag(stackchecks) cpp-options: -DSTACK_CHECK + if flag(optchecks) + ghc-options: -O2 + cpp-options: -DOPT_CHECK + build-depends: + inspection-testing if flag(dumpcore) - ghc-options: -ddump-simpl -ddump-stg-final -ddump-to-file -dsuppress-coercions -dsuppress-idinfo -dsuppress-module-prefixes + ghc-options: -ddump-simpl -ddump-stg-final -ddump-to-file -dsuppress-coercions -dsuppress-idinfo -dsuppress-module-prefixes -ddump-str-signatures -ddump-simpl-stats