diff --git a/.github/workflows/ci-test-jit.yaml b/.github/workflows/ci-test-jit.yaml index 1d062a5ca2..0ab3c291d6 100644 --- a/.github/workflows/ci-test-jit.yaml +++ b/.github/workflows/ci-test-jit.yaml @@ -4,7 +4,7 @@ on: workflow_call: env: - runtime_tests_version: "@unison/runtime-tests/releases/0.0.1" + runtime_tests_version: "@unison/runtime-tests/releases/0.0.2" # for best results, this should match the path in ci.yaml too; but GH doesn't make it easy to share them. runtime_tests_codebase: "~/.cache/unisonlanguage/runtime-tests.unison" diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 26e214abdc..23e9b8aeaa 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,8 +14,8 @@ on: env: ## Some version numbers that are used during CI ormolu_version: 0.7.2.0 - jit_version: "@unison/internal/releases/0.0.20" - runtime_tests_version: "@unison/runtime-tests/releases/0.0.1" + jit_version: "@unison/internal/releases/0.0.21" + runtime_tests_version: "@unison/runtime-tests/releases/0.0.2" ## Some cached directories # a temp path for caching a built `ucm` diff --git a/parser-typechecker/src/Unison/Builtin.hs b/parser-typechecker/src/Unison/Builtin.hs index 1a9477fa63..15934d4895 100644 --- a/parser-typechecker/src/Unison/Builtin.hs +++ b/parser-typechecker/src/Unison/Builtin.hs @@ -103,7 +103,7 @@ builtinEffectDecls :: [(Symbol, (R.Id, EffectDeclaration))] builtinEffectDecls = [(v, (r, Intrinsic <$ d)) | (v, r, d) <- DD.builtinEffectDecls] codeLookup :: (Applicative m) => CodeLookup Symbol m Ann -codeLookup = CodeLookup (const $ pure Nothing) $ \r -> +codeLookup = CodeLookup (const $ pure Nothing) (const $ pure Nothing) $ \r -> pure $ lookup r [(r, Right x) | (r, x) <- snd <$> builtinDataDecls] <|> lookup r [(r, Left x) | (r, x) <- snd <$> builtinEffectDecls] diff --git a/parser-typechecker/src/Unison/Codebase/CodeLookup.hs b/parser-typechecker/src/Unison/Codebase/CodeLookup.hs index aad2794519..b27a2e7948 100644 --- a/parser-typechecker/src/Unison/Codebase/CodeLookup.hs +++ b/parser-typechecker/src/Unison/Codebase/CodeLookup.hs @@ -8,38 +8,44 @@ import Unison.Prelude import Unison.Reference qualified as Reference import Unison.Term (Term) import Unison.Term qualified as Term +import Unison.Type (Type) import Unison.Util.Defns (Defns (..)) import Unison.Util.Set qualified as Set import Unison.Var (Var) data CodeLookup v m a = CodeLookup { getTerm :: Reference.Id -> m (Maybe (Term v a)), + getTypeOfTerm :: Reference.Id -> m (Maybe (Type v a)), getTypeDeclaration :: Reference.Id -> m (Maybe (Decl v a)) } instance MFunctor (CodeLookup v) where - hoist f (CodeLookup tm tp) = CodeLookup (f . tm) (f . tp) + hoist f (CodeLookup tm tmTyp tp) = CodeLookup (f . tm) (f . tmTyp) (f . tp) instance (Ord v, Functor m) => Functor (CodeLookup v m) where - fmap f cl = CodeLookup tm ty + fmap f cl = CodeLookup tm tmTyp ty where tm id = fmap (Term.amap f) <$> getTerm cl id ty id = fmap md <$> getTypeDeclaration cl id + tmTyp id = (fmap . fmap) f <$> getTypeOfTerm cl id md (Left e) = Left (f <$> e) md (Right d) = Right (f <$> d) instance (Monad m) => Semigroup (CodeLookup v m a) where - c1 <> c2 = CodeLookup tm ty + c1 <> c2 = CodeLookup tm tmTyp ty where tm id = do o <- getTerm c1 id case o of Nothing -> getTerm c2 id; Just _ -> pure o + tmTyp id = do + o <- getTypeOfTerm c1 id + case o of Nothing -> getTypeOfTerm c2 id; Just _ -> pure o ty id = do o <- getTypeDeclaration c1 id case o of Nothing -> getTypeDeclaration c2 id; Just _ -> pure o instance (Monad m) => Monoid (CodeLookup v m a) where - mempty = CodeLookup (const $ pure Nothing) (const $ pure Nothing) + mempty = CodeLookup (const $ pure Nothing) (const $ pure Nothing) (const $ pure Nothing) -- todo: can this be implemented in terms of TransitiveClosure.transitiveClosure? -- todo: add some tests on this guy? diff --git a/parser-typechecker/src/Unison/Codebase/CodeLookup/Util.hs b/parser-typechecker/src/Unison/Codebase/CodeLookup/Util.hs index 82c323fe78..708891159e 100644 --- a/parser-typechecker/src/Unison/Codebase/CodeLookup/Util.hs +++ b/parser-typechecker/src/Unison/Codebase/CodeLookup/Util.hs @@ -8,15 +8,18 @@ import Unison.DataDeclaration qualified as DataDeclaration import Unison.Prelude import Unison.Reference qualified as Reference import Unison.Term qualified as Term +import Unison.Type qualified as Type import Unison.UnisonFile qualified as UF import Unison.UnisonFile.Type (TypecheckedUnisonFile) import Unison.Var (Var) fromTypecheckedUnisonFile :: forall m v a. (Var v, Monad m) => TypecheckedUnisonFile v a -> CodeLookup v m a -fromTypecheckedUnisonFile tuf = CodeLookup tm ty +fromTypecheckedUnisonFile tuf = CodeLookup tm tmTyp ty where tm :: Reference.Id -> m (Maybe (Term.Term v a)) - tm id = pure $ Map.lookup id termMap + tm id = pure . fmap fst $ Map.lookup id termMap + tmTyp :: Reference.Id -> m (Maybe (Type.Type v a)) + tmTyp id = pure . fmap snd $ Map.lookup id termMap ty :: Reference.Id -> m (Maybe (DataDeclaration.Decl v a)) ty id = pure $ Map.lookup id dataDeclMap <|> Map.lookup id effectDeclMap dataDeclMap = @@ -31,5 +34,5 @@ fromTypecheckedUnisonFile tuf = CodeLookup tm ty | (_, (Reference.DerivedId id, ad)) <- Map.toList (UF.effectDeclarations' tuf) ] - termMap :: Map Reference.Id (Term.Term v a) - termMap = Map.fromList [(id, tm) | (_a, id, _wk, tm, _tp) <- toList $ UF.hashTermsId tuf] + termMap :: Map Reference.Id (Term.Term v a, Type.Type v a) + termMap = Map.fromList [(id, (tm, typ)) | (_a, id, _wk, tm, typ) <- toList $ UF.hashTermsId tuf] diff --git a/parser-typechecker/src/Unison/Util/EnumContainers.hs b/parser-typechecker/src/Unison/Util/EnumContainers.hs index ec61f3f8cc..0a84aa4dd2 100644 --- a/parser-typechecker/src/Unison/Util/EnumContainers.hs +++ b/parser-typechecker/src/Unison/Util/EnumContainers.hs @@ -15,6 +15,7 @@ module Unison.Util.EnumContainers keysSet, restrictKeys, withoutKeys, + mapDifference, member, lookup, lookupWithDefault, @@ -118,6 +119,9 @@ restrictKeys (EM m) (ES s) = EM $ IM.restrictKeys m s withoutKeys :: (EnumKey k) => EnumMap k a -> EnumSet k -> EnumMap k a withoutKeys (EM m) (ES s) = EM $ IM.withoutKeys m s +mapDifference :: (EnumKey k) => EnumMap k a -> EnumMap k b -> EnumMap k a +mapDifference (EM l) (EM r) = EM $ IM.difference l r + member :: (EnumKey k) => k -> EnumSet k -> Bool member e (ES s) = IS.member (keyToInt e) s diff --git a/scheme-libs/racket/unison-runtime.rkt b/scheme-libs/racket/unison-runtime.rkt index da1ddb5ed0..ad8afbe06a 100644 --- a/scheme-libs/racket/unison-runtime.rkt +++ b/scheme-libs/racket/unison-runtime.rkt @@ -68,12 +68,12 @@ (let ([bs (grab-bytes port)]) (match (builtin-Value.deserialize (bytes->chunked-bytes bs)) [(unison-data _ t (list q)) - (= t ref-either-right:tag) + #:when (= t ref-either-right:tag) (apply values (unison-tuple->list (reify-value (unison-quote-val q))))] - [else - (raise "unexpected input")]))) + [val + (raise (format "unexpected input: ~a " (describe-value val)))]))) (define (natural->bytes/variable n) (let rec ([i n] [acc '()]) diff --git a/unison-core/src/Unison/Type.hs b/unison-core/src/Unison/Type.hs index a1fd4fec52..7f26318001 100644 --- a/unison-core/src/Unison/Type.hs +++ b/unison-core/src/Unison/Type.hs @@ -57,6 +57,9 @@ _Ref = _Ctor @"Ref" -- | Types are represented as ABTs over the base functor F, with variables in `v` type Type v a = ABT.Term F v a +-- | For use with recursion schemes. +type TypeF v a r = ABT.Term' F v a r + wrapV :: (Ord v) => Type v a -> Type (ABT.V v) a wrapV = ABT.vmap ABT.Bound diff --git a/unison-runtime/package.yaml b/unison-runtime/package.yaml index 6b76ed9274..a7526e5b07 100644 --- a/unison-runtime/package.yaml +++ b/unison-runtime/package.yaml @@ -72,6 +72,7 @@ library: - unison-pretty-printer - unison-syntax - unison-util-bytes + - unison-util-recursion - unliftio - vector - crypton-x509 diff --git a/unison-runtime/src/Unison/Codebase/Execute.hs b/unison-runtime/src/Unison/Codebase/Execute.hs index 71f345220c..22b54c6f7d 100644 --- a/unison-runtime/src/Unison/Codebase/Execute.hs +++ b/unison-runtime/src/Unison/Codebase/Execute.hs @@ -68,6 +68,10 @@ execute codebase runtime mainPath = codebaseToCodeLookup :: (MonadIO m) => Codebase m Symbol Parser.Ann -> CL.CodeLookup Symbol m Parser.Ann codebaseToCodeLookup c = - CL.CodeLookup (Codebase.runTransaction c . getTerm c) (Codebase.runTransaction c . getTypeDeclaration c) + CL.CodeLookup goGetTerm goGetTypeOfTerm goGetTypeDecl <> Builtin.codeLookup <> IOSource.codeLookupM + where + goGetTerm = (Codebase.runTransaction c . getTerm c) + goGetTypeOfTerm = (Codebase.runTransaction c . getTypeOfTermImpl c) + goGetTypeDecl = (Codebase.runTransaction c . getTypeDeclaration c) diff --git a/unison-runtime/src/Unison/Runtime/ANF.hs b/unison-runtime/src/Unison/Runtime/ANF.hs index 0c2fa20ff8..c4e1ef15e6 100644 --- a/unison-runtime/src/Unison/Runtime/ANF.hs +++ b/unison-runtime/src/Unison/Runtime/ANF.hs @@ -33,6 +33,7 @@ module Unison.Runtime.ANF internalBug, Mem (..), Lit (..), + Cacheability (..), Direction (..), SuperNormal (..), SuperGroup (..), @@ -53,6 +54,7 @@ module Unison.Runtime.ANF CTag, Tag (..), GroupRef (..), + Code (..), Value (..), Cont (..), BLit (..), @@ -66,11 +68,15 @@ module Unison.Runtime.ANF equivocate, superNormalize, anfTerm, + codeGroup, valueTermLinks, valueLinks, groupTermLinks, + foldGroup, foldGroupLinks, + overGroup, overGroupLinks, + traverseGroup, traverseGroupLinks, normalLinks, prettyGroup, @@ -1476,6 +1482,11 @@ data SuperGroup v = Rec } deriving (Show) +-- | Whether the evaluation of a given definition is cacheable or not. +-- i.e. it's a top-level pure value. +data Cacheability = Cacheable | Uncacheable + deriving stock (Eq, Show) + instance (Var v) => Eq (SuperGroup v) where g0 == g1 | Left _ <- equivocate g0 g1 = False | otherwise = True @@ -1529,6 +1540,31 @@ data Value | BLit BLit deriving (Show) +-- Since we can now track cacheability of supergroups, this type +-- pairs the two together. This is the type that should be used +-- as the representation of unison Code values rather than the +-- previous `SuperGroup Symbol`. +data Code = CodeRep (SuperGroup Symbol) Cacheability + deriving (Show) + +codeGroup :: Code -> SuperGroup Symbol +codeGroup (CodeRep sg _) = sg + +instance Eq Code where + CodeRep sg1 _ == CodeRep sg2 _ = sg1 == sg2 + +overGroup :: (SuperGroup Symbol -> SuperGroup Symbol) -> Code -> Code +overGroup f (CodeRep sg ch) = CodeRep (f sg) ch + +foldGroup :: Monoid m => (SuperGroup Symbol -> m) -> Code -> m +foldGroup f (CodeRep sg _) = f sg + +traverseGroup :: + Applicative f => + (SuperGroup Symbol -> f (SuperGroup Symbol)) -> + Code -> f Code +traverseGroup f (CodeRep sg ch) = flip CodeRep ch <$> f sg + data Cont = KE | Mark Word64 Word64 [Reference] (Map Reference Value) Cont @@ -1542,7 +1578,7 @@ data BLit | TyLink Reference | Bytes Bytes | Quote Value - | Code (SuperGroup Symbol) + | Code Code | BArr PA.ByteArray | Pos Word64 | Neg Word64 diff --git a/unison-runtime/src/Unison/Runtime/ANF/Rehash.hs b/unison-runtime/src/Unison/Runtime/ANF/Rehash.hs index 4bd3c2434f..a6a50722d8 100644 --- a/unison-runtime/src/Unison/Runtime/ANF/Rehash.hs +++ b/unison-runtime/src/Unison/Runtime/ANF/Rehash.hs @@ -1,7 +1,7 @@ module Unison.Runtime.ANF.Rehash where import Crypto.Hash -import Data.Bifunctor (bimap, first, second) +import Data.Bifunctor (bimap, second) import Data.ByteArray (convert) import Data.ByteString (cons) import Data.ByteString.Lazy (toChunks) @@ -16,25 +16,23 @@ import Unison.Reference as Reference import Unison.Referent as Referent import Unison.Runtime.ANF as ANF import Unison.Runtime.ANF.Serialize as ANF -import Unison.Var (Var) +import Unison.Symbol (Symbol) checkGroupHashes :: - (Var v) => - [(Referent, SuperGroup v)] -> + [(Referent, Code)] -> Either (Text, [Referent]) (Either [Referent] [Referent]) checkGroupHashes rgs = case checkMissing rgs of Left err -> Left err Right [] -> - case rehashGroups . Map.fromList $ first toReference <$> rgs of + case rehashGroups . Map.fromList $ bimap toReference codeGroup <$> rgs of Left err -> Left err Right (rrs, _) -> Right . Right . fmap (Ref . fst) . filter (uncurry (/=)) $ Map.toList rrs Right ms -> Right (Left $ Ref <$> ms) rehashGroups :: - (Var v) => - Map.Map Reference (SuperGroup v) -> - Either (Text, [Referent]) (Map.Map Reference Reference, Map.Map Reference (SuperGroup v)) + Map.Map Reference (SuperGroup Symbol) -> + Either (Text, [Referent]) (Map.Map Reference Reference, Map.Map Reference (SuperGroup Symbol)) rehashGroups m | badsccs <- filter (not . checkSCC) sccs, not $ null badsccs = @@ -56,12 +54,11 @@ rehashGroups m (rm, sgs) = rehashSCC scc checkMissing :: - (Var v) => - [(Referent, SuperGroup v)] -> + [(Referent, Code)] -> Either (Text, [Referent]) [Reference] -checkMissing (unzip -> (rs, gs)) = do +checkMissing (unzip -> (rs, cs)) = do is <- fmap Set.fromList . traverse f $ rs - pure . nub . foldMap (filter (p is) . groupTermLinks) $ gs + pure . nub . foldMap (filter (p is) . groupTermLinks . codeGroup) $ cs where f (Ref (DerivedId i)) = pure i f r@Ref {} = @@ -74,9 +71,8 @@ checkMissing (unzip -> (rs, gs)) = do p _ _ = False rehashSCC :: - (Var v) => - SCC (Reference, SuperGroup v) -> - (Map.Map Reference Reference, Map.Map Reference (SuperGroup v)) + SCC (Reference, SuperGroup Symbol) -> + (Map.Map Reference Reference, Map.Map Reference (SuperGroup Symbol)) rehashSCC scc | checkSCC scc = (refreps, newSGs) where @@ -103,7 +99,7 @@ rehashSCC scc refreps = Map.fromList $ fmap (\(r, _) -> (r, replace r)) ps rehashSCC scc = error $ "unexpected SCC:\n" ++ show scc -checkSCC :: SCC (Reference, SuperGroup v) -> Bool +checkSCC :: SCC (Reference, a) -> Bool checkSCC AcyclicSCC {} = True checkSCC (CyclicSCC []) = True checkSCC (CyclicSCC (p : ps)) = all (same p) ps diff --git a/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs b/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs index 995856e1b4..ba97dfa080 100644 --- a/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/ANF/Serialize.hs @@ -330,6 +330,25 @@ getGroup = do cs <- replicateM l (getComb ctx n) Rec (zip vs cs) <$> getComb ctx n +putCode :: MonadPut m => EC.EnumMap FOp Text -> Code -> m () +putCode fops (CodeRep g c) = putGroup mempty fops g *> putCacheability c + +getCode :: MonadGet m => Word32 -> m Code +getCode v = CodeRep <$> getGroup <*> getCache + where + getCache | v == 3 = getCacheability + | otherwise = pure Uncacheable + +putCacheability :: MonadPut m => Cacheability -> m () +putCacheability Uncacheable = putWord8 0 +putCacheability Cacheable = putWord8 1 + +getCacheability :: MonadGet m => m Cacheability +getCacheability = getWord8 >>= \case + 0 -> pure Uncacheable + 1 -> pure Cacheable + n -> exn $ "getBLit: unrecognized cacheability byte: " ++ show n + putComb :: (MonadPut m) => (Var v) => @@ -659,7 +678,7 @@ putBLit (TmLink r) = putTag TmLinkT *> putReferent r putBLit (TyLink r) = putTag TyLinkT *> putReference r putBLit (Bytes b) = putTag BytesT *> putBytes b putBLit (Quote v) = putTag QuoteT *> putValue v -putBLit (Code g) = putTag CodeT *> putGroup mempty mempty g +putBLit (Code co) = putTag CodeT *> putCode mempty co putBLit (BArr a) = putTag BArrT *> putByteArray a putBLit (Pos n) = putTag PosT *> putPositive n putBLit (Neg n) = putTag NegT *> putPositive n @@ -676,7 +695,9 @@ getBLit v = TyLinkT -> TyLink <$> getReference BytesT -> Bytes <$> getBytes QuoteT -> Quote <$> getValue v - CodeT -> Code <$> getGroup + CodeT -> Code <$> getCode cv + where + cv | v == 5 = 3 | otherwise = 2 BArrT -> BArr <$> getByteArray PosT -> Pos <$> getPositive NegT -> Neg <$> getPositive @@ -913,18 +934,16 @@ getCont v = <*> getGroupRef <*> getCont v -deserializeGroup :: (Var v) => ByteString -> Either String (SuperGroup v) -deserializeGroup bs = runGetS (getVersion *> getGroup) bs +deserializeCode :: ByteString -> Either String Code +deserializeCode bs = runGetS (getVersion >>= getCode) bs where getVersion = getWord32be >>= \case - 1 -> pure () - 2 -> pure () + n | 1 <= n && n <= 3 -> pure n n -> fail $ "deserializeGroup: unknown version: " ++ show n -serializeGroup :: - (Var v) => EC.EnumMap FOp Text -> SuperGroup v -> ByteString -serializeGroup fops sg = runPutS (putVersion *> putGroup mempty fops sg) +serializeCode :: EC.EnumMap FOp Text -> Code -> ByteString +serializeCode fops co = runPutS (putVersion *> putCode fops co) where putVersion = putWord32be codeVersion @@ -970,7 +989,7 @@ getVersionedValue = getVersion >>= getValue n | n < 1 -> fail $ "deserializeValue: unknown version: " ++ show n | n < 3 -> fail $ "deserializeValue: unsupported version: " ++ show n - | n <= 4 -> pure n + | n <= 5 -> pure n | otherwise -> fail $ "deserializeValue: unknown version: " ++ show n deserializeValue :: ByteString -> Either String Value @@ -981,13 +1000,21 @@ serializeValue v = runPutS (putVersion *> putValue v) where putVersion = putWord32be valueVersion -serializeValueLazy :: Value -> L.ByteString -serializeValueLazy v = runPutLazy (putVersion *> putValue v) +-- This serializer is used exclusively for hashing unison values. +-- For this reason, it doesn't prefix the string with the current +-- version, so that only genuine changes in the way things are +-- serialized will change hashes. +-- +-- The 4 prefix is used because we were previously including the +-- version in the hash, so to maintain the same hashes, we need to +-- include the extra bytes that were previously there. +serializeValueForHash :: Value -> L.ByteString +serializeValueForHash v = runPutLazy (putPrefix *> putValue v) where - putVersion = putWord32be valueVersion + putPrefix = putWord32be 4 valueVersion :: Word32 -valueVersion = 4 +valueVersion = 5 codeVersion :: Word32 -codeVersion = 2 +codeVersion = 3 diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index 070bdd8118..0a31bdce41 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -2304,7 +2304,7 @@ unitValue :: Closure unitValue = Closure.Enum Ty.unitRef 0 natValue :: Word64 -> Closure -natValue w = Closure.DataU1 Ty.natRef 0 (fromIntegral w) +natValue w = Closure.DataU1 Ty.natRef 0 (fromIntegral w) mkForeignTls :: forall a r. @@ -2860,23 +2860,24 @@ declareForeigns = do declareForeign Untracked "Code.validateLinks" boxToExnEBoxBox . mkForeign - $ \(lsgs0 :: [(Referent, SuperGroup Symbol)]) -> do + $ \(lsgs0 :: [(Referent, Code)]) -> do let f (msg, rs) = Failure Ty.miscFailureRef (Util.Text.fromText msg) rs pure . first f $ checkGroupHashes lsgs0 declareForeign Untracked "Code.dependencies" boxDirect . mkForeign - $ \(sg :: SuperGroup Symbol) -> + $ \(CodeRep sg _) -> pure $ Wrap Ty.termLinkRef . Ref <$> groupTermLinks sg declareForeign Untracked "Code.serialize" boxDirect . mkForeign - $ \(sg :: SuperGroup Symbol) -> - pure . Bytes.fromArray $ serializeGroup builtinForeignNames sg + $ \(co :: Code) -> + pure . Bytes.fromArray $ serializeCode builtinForeignNames co declareForeign Untracked "Code.deserialize" boxToEBoxBox . mkForeign - $ pure . deserializeGroup @Symbol . Bytes.toArray + $ pure . deserializeCode . Bytes.toArray declareForeign Untracked "Code.display" boxBoxDirect . mkForeign $ - \(nm, sg) -> pure $ prettyGroup @Symbol (Util.Text.unpack nm) sg "" + \(nm, (CodeRep sg _)) -> + pure $ prettyGroup @Symbol (Util.Text.unpack nm) sg "" declareForeign Untracked "Value.dependencies" boxDirect . mkForeign $ pure . fmap (Wrap Ty.termLinkRef . Ref) . valueTermLinks @@ -2924,7 +2925,7 @@ declareForeigns = do L.ByteString -> Hash.Digest a hashlazy _ l = Hash.hashlazy l - in pure . Bytes.fromArray . hashlazy alg $ serializeValueLazy x + in pure . Bytes.fromArray . hashlazy alg $ serializeValueForHash x declareForeign Untracked "crypto.hmac" crypto'hmac . mkForeign $ \(HashAlgorithm _ alg, key, x) -> @@ -2935,7 +2936,7 @@ declareForeigns = do . HMAC.updates (HMAC.initialize $ Bytes.toArray @BA.Bytes key) $ L.toChunks s - in pure . Bytes.fromArray . hmac alg $ serializeValueLazy x + in pure . Bytes.fromArray . hmac alg $ serializeValueForHash x declareForeign Untracked "crypto.Ed25519.sign.impl" boxBoxBoxToEFBox . mkForeign @@ -2961,7 +2962,7 @@ declareForeigns = do Right a -> Right a declareForeign Untracked "Universal.murmurHash" murmur'hash . mkForeign $ - pure . asWord64 . hash64 . serializeValueLazy + pure . asWord64 . hash64 . serializeValueForHash declareForeign Tracked "IO.randomBytes" natToBox . mkForeign $ \n -> Bytes.fromArray <$> getRandomBytes @IO @ByteString n @@ -3156,9 +3157,9 @@ declareForeigns = do $ Right <$> PA.freezeByteArray src (fromIntegral off) (fromIntegral len) declareForeign Untracked "MutableArray.freeze" boxNatNatToExnBox . mkForeign $ - \(src :: PA.MutableArray PA.RealWorld Closure.RClosure, off, len) -> + \(src :: PA.MutableArray PA.RealWorld Closure, off, len) -> if len == 0 - then fmap Right . PA.unsafeFreezeArray =<< PA.newArray 0 Closure.BlackHole + then fmap Right . PA.unsafeFreezeArray =<< PA.newArray 0 ( Closure.BlackHole) else checkBounds "MutableArray.freeze" @@ -3173,7 +3174,7 @@ declareForeigns = do pure . PA.sizeofByteArray declareForeign Tracked "IO.array" natToBox . mkForeign $ - \n -> PA.newArray n (Closure.BlackHole :: Closure.RClosure) + \n -> PA.newArray n (Closure.BlackHole :: Closure) declareForeign Tracked "IO.arrayOf" boxNatToBox . mkForeign $ \(v :: Closure, n) -> PA.newArray n v declareForeign Tracked "IO.bytearray" natToBox . mkForeign $ PA.newByteArray @@ -3185,7 +3186,7 @@ declareForeigns = do pure arr declareForeign Untracked "Scope.array" natToBox . mkForeign $ - \n -> PA.newArray n (Closure.BlackHole :: Closure.RClosure) + \n -> PA.newArray n (Closure.BlackHole :: Closure) declareForeign Untracked "Scope.arrayOf" boxNatToBox . mkForeign $ \(v :: Closure, n) -> PA.newArray n v declareForeign Untracked "Scope.bytearray" natToBox . mkForeign $ PA.newByteArray diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index 13084ea1dc..ce27068199 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -32,10 +32,9 @@ import Unison.Runtime.Foreign maybeUnwrapForeign, ) import Unison.Runtime.IOSource (iarrayFromListRef, ibarrayFromBytesRef) -import Unison.Runtime.MCode (CombIx (..), pattern RCombIx, pattern RCombRef) +import Unison.Runtime.MCode (CombIx (..)) import Unison.Runtime.Stack - ( Closure, - GClosure (..), + ( Closure (..), pattern DataC, pattern PApV, ) @@ -153,33 +152,34 @@ decompile :: (Word64 -> Word64 -> Maybe (Term v ())) -> Closure -> DecompResult v -decompile _ _ (DataC rf (maskTags -> ct) [] []) - | rf == booleanRef = tag2bool ct -decompile _ _ (DataC rf (maskTags -> ct) [i] []) = - decompileUnboxed rf ct i -decompile backref topTerms (DataC rf _ [] [b]) - | rf == anyRef = - app () (builtin () "Any.Any") <$> decompile backref topTerms b -decompile backref topTerms (DataC rf (maskTags -> ct) [] bs) = - apps' (con rf ct) <$> traverse (decompile backref topTerms) bs -decompile backref topTerms (PApV (RCombIx (CIx rf rt k)) [] bs) - | rf == Builtin "jumpCont" = err Cont $ bug "" - | Builtin nm <- rf = - apps' (builtin () nm) <$> traverse (decompile backref topTerms) bs - | Just t <- topTerms rt k = - Term.etaReduceEtaVars . substitute t - <$> traverse (decompile backref topTerms) bs - | k > 0, - Just _ <- topTerms rt 0 = - err (UnkLocal rf k) $ bug "" - | otherwise = err (UnkComb rf) $ ref () rf -decompile _ _ (PAp (RCombRef rf) _ _) = - err (BadPAp rf) $ bug "" -decompile _ _ (DataC rf _ _ _) = err (BadData rf) $ bug "" -decompile _ _ BlackHole = err Exn $ bug "" -decompile _ _ (Captured {}) = err Cont $ bug "" -decompile backref topTerms (Foreign f) = - decompileForeign backref topTerms f +decompile backref topTerms = \case + DataC rf (maskTags -> ct) [] [] + | rf == booleanRef -> tag2bool ct + DataC rf (maskTags -> ct) [i] [] -> + decompileUnboxed rf ct i + (DataC rf _ [] [b]) + | rf == anyRef -> + app () (builtin () "Any.Any") <$> decompile backref topTerms b + (DataC rf (maskTags -> ct) [] bs) -> + apps' (con rf ct) <$> traverse (decompile backref topTerms) bs + (PApV (CIx rf rt k) _ [] bs) + | rf == Builtin "jumpCont" -> err Cont $ bug "" + | Builtin nm <- rf -> + apps' (builtin () nm) <$> traverse (decompile backref topTerms) bs + | Just t <- topTerms rt k -> + Term.etaReduceEtaVars . substitute t + <$> traverse (decompile backref topTerms) bs + | k > 0, + Just _ <- topTerms rt 0 -> + err (UnkLocal rf k) $ bug "" + | otherwise -> err (UnkComb rf) $ ref () rf + (PAp (CIx rf _ _) _ _ _) -> + err (BadPAp rf) $ bug "" + (DataC rf _ _ _) -> err (BadData rf) $ bug "" + BlackHole -> err Exn $ bug "" + (Captured {}) -> err Cont $ bug "" + (Foreign f) -> + decompileForeign backref topTerms f tag2bool :: (Var v) => Word64 -> DecompResult v tag2bool 0 = pure (boolean () False) diff --git a/unison-runtime/src/Unison/Runtime/Foreign.hs b/unison-runtime/src/Unison/Runtime/Foreign.hs index c9cd12fafb..5559ce9b6c 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign.hs @@ -34,8 +34,7 @@ import System.IO (Handle) import System.Process (ProcessHandle) import Unison.Reference (Reference) import Unison.Referent (Referent) -import Unison.Runtime.ANF (SuperGroup, Value) -import Unison.Symbol (Symbol) +import Unison.Runtime.ANF (Code, Value) import Unison.Type qualified as Ty import Unison.Util.Bytes (Bytes) import Unison.Util.Text (Text) @@ -130,8 +129,8 @@ charClassCmp :: CharPattern -> CharPattern -> Ordering charClassCmp = compare {-# NOINLINE charClassCmp #-} -codeEq :: SuperGroup Symbol -> SuperGroup Symbol -> Bool -codeEq sg1 sg2 = sg1 == sg2 +codeEq :: Code -> Code -> Bool +codeEq co1 co2 = co1 == co2 {-# NOINLINE codeEq #-} tylEq :: Reference -> Reference -> Bool @@ -256,9 +255,7 @@ instance BuiltinForeign FilePath where foreignRef = Tagged Ty.filePathRef instance BuiltinForeign TLS.Context where foreignRef = Tagged Ty.tlsRef -instance BuiltinForeign (SuperGroup Symbol) where - foreignRef = Tagged Ty.codeRef - +instance BuiltinForeign Code where foreignRef = Tagged Ty.codeRef instance BuiltinForeign Value where foreignRef = Tagged Ty.valueRef instance BuiltinForeign TimeSpec where foreignRef = Tagged Ty.timeSpecRef diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index de73cc7331..e793d93508 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -31,12 +31,11 @@ import Network.UDP (UDPSocket) import System.IO (BufferMode (..), Handle, IOMode, SeekMode) import Unison.Builtin.Decls qualified as Ty import Unison.Reference (Reference) -import Unison.Runtime.ANF (Mem (..), SuperGroup, Value, internalBug) +import Unison.Runtime.ANF (Mem (..), Code, Value, internalBug) import Unison.Runtime.Exception import Unison.Runtime.Foreign import Unison.Runtime.MCode import Unison.Runtime.Stack -import Unison.Symbol (Symbol) import Unison.Type ( iarrayRef, ibytearrayRef, @@ -124,7 +123,7 @@ instance ForeignConvention Char where -- In reality this fixes the type to be 'RClosure', but allows us to defer -- the typechecker a bit and avoid a bunch of annoying type annotations. -instance (GClosure comb ~ Elem 'BX) => ForeignConvention (GClosure comb) where +instance ForeignConvention Closure where readForeign us (i : bs) _ bstk = (us,bs,) <$> peekOff bstk i readForeign _ [] _ _ = foreignCCError "Closure" writeForeign ustk bstk c = do @@ -441,7 +440,7 @@ instance ForeignConvention BufferMode where -- In reality this fixes the type to be 'RClosure', but allows us to defer -- the typechecker a bit and avoid a bunch of annoying type annotations. -instance (GClosure comb ~ Elem 'BX) => ForeignConvention [GClosure comb] where +instance ForeignConvention [Closure] where readForeign us (i : bs) _ bstk = (us,bs,) . toList <$> peekOffS bstk i readForeign _ _ _ _ = foreignCCError "[Closure]" @@ -453,27 +452,27 @@ instance ForeignConvention [Foreign] where readForeign = readForeignAs (fmap marshalToForeign) writeForeign = writeForeignAs (fmap Foreign) -instance ForeignConvention (MVar RClosure) where +instance ForeignConvention (MVar Closure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap mvarRef) -instance ForeignConvention (TVar RClosure) where +instance ForeignConvention (TVar Closure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap tvarRef) -instance ForeignConvention (IORef RClosure) where +instance ForeignConvention (IORef Closure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap refRef) -instance ForeignConvention (Ticket RClosure) where +instance ForeignConvention (Ticket Closure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap ticketRef) -instance ForeignConvention (Promise RClosure) where +instance ForeignConvention (Promise Closure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap promiseRef) -instance ForeignConvention (SuperGroup Symbol) where +instance ForeignConvention Code where readForeign = readForeignBuiltin writeForeign = writeForeignBuiltin @@ -485,7 +484,7 @@ instance ForeignConvention Foreign where readForeign = readForeignAs marshalToForeign writeForeign = writeForeignAs Foreign -instance ForeignConvention (PA.MutableArray s RClosure) where +instance ForeignConvention (PA.MutableArray s Closure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap marrayRef) @@ -493,7 +492,7 @@ instance ForeignConvention (PA.MutableByteArray s) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap mbytearrayRef) -instance ForeignConvention (PA.Array RClosure) where +instance ForeignConvention (PA.Array Closure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap iarrayRef) @@ -505,13 +504,13 @@ instance {-# OVERLAPPABLE #-} (BuiltinForeign b) => ForeignConvention b where readForeign = readForeignBuiltin writeForeign = writeForeignBuiltin -fromUnisonPair :: RClosure -> (a, b) +fromUnisonPair :: Closure -> (a, b) fromUnisonPair (DataC _ _ [] [x, DataC _ _ [] [y, _]]) = (unwrapForeignClosure x, unwrapForeignClosure y) fromUnisonPair _ = error "fromUnisonPair: invalid closure" toUnisonPair :: - (BuiltinForeign a, BuiltinForeign b) => (a, b) -> RClosure + (BuiltinForeign a, BuiltinForeign b) => (a, b) -> Closure toUnisonPair (x, y) = DataC Ty.pairRef @@ -522,7 +521,7 @@ toUnisonPair (x, y) = un = DataC Ty.unitRef 0 [] [] wr z = Foreign $ wrapBuiltin z -unwrapForeignClosure :: RClosure -> a +unwrapForeignClosure :: Closure -> a unwrapForeignClosure = unwrapForeign . marshalToForeign instance {-# OVERLAPPABLE #-} (BuiltinForeign a, BuiltinForeign b) => ForeignConvention [(a, b)] where diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 103242c8d4..78a9665a00 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -23,8 +23,6 @@ where import Control.Concurrent.STM as STM import Control.Exception (throwIO) import Control.Monad --- import Data.Bits (shiftL) - import Control.Monad.State import Data.Binary.Get (runGetOrFail) import Data.ByteString qualified as BS @@ -48,6 +46,7 @@ import Data.Set as Set ) import Data.Set qualified as Set import Data.Text as Text (isPrefixOf, pack, unpack) +import Data.Void (absurd) import GHC.IO.Exception (IOErrorType (NoSuchThing, OtherError, PermissionDenied), IOException (ioe_description, ioe_type)) import GHC.Stack (callStack) import Network.Simple.TCP (Socket, acceptFork, listen, recv, send) @@ -71,6 +70,7 @@ import System.Process waitForProcess, withCreateProcess, ) +import Unison.ABT qualified as ABT import Unison.Builtin.Decls qualified as RF import Unison.Codebase.CodeLookup (CodeLookup (..)) import Unison.Codebase.MainTerm (builtinIOTestTypes, builtinMain) @@ -101,22 +101,23 @@ import Unison.Runtime.Exception import Unison.Runtime.MCode ( Args (..), CombIx (..), - Combs, + GCombs, GInstr (..), GSection (..), RCombs, RefNums (..), + absurdCombs, combDeps, combTypes, emitComb, emptyRNs, - rCombIx, resolveCombs, ) import Unison.Runtime.MCode.Serialize import Unison.Runtime.Machine ( ActiveThreads, CCache (..), + Combs, Tracer (..), apply0, baseCCache, @@ -124,6 +125,7 @@ import Unison.Runtime.Machine cacheAdd0, eval0, expandSandbox, + preEvalTopLevelConstants, refLookup, refNumTm, refNumsTm, @@ -139,29 +141,45 @@ import Unison.Syntax.HashQualified qualified as HQ (toText) import Unison.Syntax.NamePrinter (prettyHashQualified) import Unison.Syntax.TermPrinter import Unison.Term qualified as Tm +import Unison.Type qualified as Type import Unison.Util.EnumContainers as EC import Unison.Util.Monoid (foldMapM) import Unison.Util.Pretty as P +import Unison.Util.Recursion qualified as Rec import UnliftIO qualified import UnliftIO.Concurrent qualified as UnliftIO type Term v = Tm.Term v () -data Remapping = Remap - { remap :: Map.Map Reference Reference, - backmap :: Map.Map Reference Reference +type Type v = Type.Type v () + +-- Note that these annotations are suggestions at best, since in many places codebase refs, intermediate refs, and +-- floated refs are all intermingled. +type CodebaseReference = Reference + +-- Note that these annotations are suggestions at best, since in many places codebase refs, intermediate refs, and +-- floated refs are all intermingled. +type IntermediateReference = Reference + +-- Note that these annotations are suggestions at best, since in many places codebase refs, intermediate refs, and +-- floated refs are all intermingled. +type FloatedReference = Reference + +data Remapping from to = Remap + { remap :: Map.Map from to, + backmap :: Map.Map to from } -instance Semigroup Remapping where +instance (Ord from, Ord to) => Semigroup (Remapping from to) where Remap r1 b1 <> Remap r2 b2 = Remap (r1 <> r2) (b1 <> b2) -instance Monoid Remapping where +instance (Ord from, Ord to) => Monoid (Remapping from to) where mempty = Remap mempty mempty data EvalCtx = ECtx { dspec :: DataSpec, - floatRemap :: Remapping, - intermedRemap :: Remapping, + floatRemap :: Remapping CodebaseReference FloatedReference, + intermedRemap :: Remapping FloatedReference IntermediateReference, decompTm :: Map.Map Reference (Map.Map Word64 (Term Symbol)), ccache :: CCache } @@ -326,7 +344,7 @@ backrefAdd :: backrefAdd m ctx@ECtx {decompTm} = ctx {decompTm = m <> decompTm} -remapAdd :: Map.Map Reference Reference -> Remapping -> Remapping +remapAdd :: (Ord from, Ord to) => Map.Map from to -> Remapping from to -> Remapping from to remapAdd m Remap {remap, backmap} = Remap {remap = m <> remap, backmap = tm <> backmap} where @@ -340,31 +358,31 @@ intermedRemapAdd :: Map.Map Reference Reference -> EvalCtx -> EvalCtx intermedRemapAdd m ctx@ECtx {intermedRemap} = ctx {intermedRemap = remapAdd m intermedRemap} -baseToIntermed :: EvalCtx -> Reference -> Maybe Reference +baseToIntermed :: EvalCtx -> CodebaseReference -> Maybe IntermediateReference baseToIntermed ctx r = do r <- Map.lookup r . remap $ floatRemap ctx Map.lookup r . remap $ intermedRemap ctx -- Runs references through the forward maps to get intermediate -- references. Works on both base and floated references. -toIntermed :: EvalCtx -> Reference -> Reference +toIntermed :: EvalCtx -> Reference -> IntermediateReference toIntermed ctx r | r <- Map.findWithDefault r r . remap $ floatRemap ctx, Just r <- Map.lookup r . remap $ intermedRemap ctx = r toIntermed _ r = r -floatToIntermed :: EvalCtx -> Reference -> Maybe Reference +floatToIntermed :: EvalCtx -> FloatedReference -> Maybe IntermediateReference floatToIntermed ctx r = Map.lookup r . remap $ intermedRemap ctx -intermedToBase :: EvalCtx -> Reference -> Maybe Reference +intermedToBase :: EvalCtx -> IntermediateReference -> Maybe CodebaseReference intermedToBase ctx r = do r <- Map.lookup r . backmap $ intermedRemap ctx Map.lookup r . backmap $ floatRemap ctx -- Runs references through the backmaps with defaults at all steps. -backmapRef :: EvalCtx -> Reference -> Reference +backmapRef :: EvalCtx -> Reference -> CodebaseReference backmapRef ctx r0 = r2 where r1 = Map.findWithDefault r0 r0 . backmap $ intermedRemap ctx @@ -430,7 +448,7 @@ loadDeps :: EvalCtx -> [(Reference, Either [Int] [Int])] -> [Reference] -> - IO (EvalCtx, [(Reference, SuperGroup Symbol)]) + IO (EvalCtx, [(Reference, Code)]) loadDeps cl ppe ctx tyrs tmrs = do let cc = ccache ctx sand <- readTVarIO (sandbox cc) @@ -442,10 +460,40 @@ loadDeps cl ppe ctx tyrs tmrs = do _ -> False ctx <- foldM (uncurry . allocType) ctx $ Prelude.filter p tyrs let tyAdd = Set.fromList $ fst <$> tyrs - out@(_, rgrp) <- loadCode cl ppe ctx tmrs - out <$ cacheAdd0 tyAdd rgrp (expandSandbox sand rgrp) cc + (ctx', rgrp) <- loadCode cl ppe ctx tmrs + crgrp <- traverse (checkCacheability cl ctx') rgrp + (ctx', crgrp) <$ cacheAdd0 tyAdd crgrp (expandSandbox sand rgrp) cc -compileValue :: Reference -> [(Reference, SuperGroup Symbol)] -> Value +checkCacheability :: + CodeLookup Symbol IO () -> + EvalCtx -> + (IntermediateReference, SuperGroup Symbol) -> + IO (IntermediateReference, Code) +checkCacheability cl ctx (r, sg) = + getTermType codebaseRef >>= \case + -- A term's result is cacheable iff it has no arrows in its type, + -- this is sufficient since top-level definitions can't have effects without a delay. + Just typ | not (Rec.cata hasArrows typ) -> + pure (r, CodeRep sg Cacheable) + _ -> pure (r, CodeRep sg Uncacheable) + where + codebaseRef = backmapRef ctx r + getTermType :: CodebaseReference -> IO (Maybe (Type Symbol)) + getTermType = \case + (RF.DerivedId i) -> + getTypeOfTerm cl i >>= \case + Just t -> pure $ Just t + Nothing -> pure Nothing + RF.Builtin {} -> pure $ Nothing + hasArrows :: Type.TypeF v a Bool -> Bool + hasArrows abt = case ABT.out' abt of + (ABT.Tm f) -> case f of + Type.Arrow _ _ -> True + other -> or other + t -> or t + + +compileValue :: Reference -> [(Reference, Code)] -> Value compileValue base = flip pair (rf base) . ANF.BLit . List . Seq.fromList . fmap cpair where @@ -781,22 +829,24 @@ prepareEvaluation :: PrettyPrintEnv -> Term Symbol -> EvalCtx -> - IO (EvalCtx, [(Reference, SuperGroup Symbol)], Reference) + IO (EvalCtx, [(Reference, Code)], Reference) prepareEvaluation ppe tm ctx = do - missing <- cacheAdd rgrp (ccache ctx') + missing <- cacheAdd rcode (ccache ctx') when (not . null $ missing) . fail $ reportBug "E029347" $ "Error in prepareEvaluation, cache is missing: " <> show missing - pure (backrefAdd rbkr ctx', rgrp, rmn) + pure (backrefAdd rbkr ctx', rcode, rmn) where + uncacheable g = CodeRep g Uncacheable (rmn0, frem, rgrp0, rbkr) = intermediateTerm ppe ctx tm int b r | b || Map.member r rgrp0 = r | otherwise = toIntermed ctx r (ctx', rrefs, rgrp) = performRehash - ((fmap . overGroupLinks) int rgrp0) + ((fmap . overGroupLinks) int $ rgrp0) (floatRemapAdd frem ctx) + rcode = second uncacheable <$> rgrp rmn = case Map.lookup rmn0 rrefs of Just r -> r Nothing -> error "prepareEvaluation: could not remap main ref" @@ -806,9 +856,9 @@ watchHook r _ bstk = peek bstk >>= writeIORef r backReferenceTm :: EnumMap Word64 Reference -> - Remapping -> - Remapping -> - Map.Map Reference (Map.Map Word64 (Term Symbol)) -> + Remapping IntermediateReference CodebaseReference -> + Remapping FloatedReference IntermediateReference -> + Map.Map CodebaseReference (Map.Map Word64 (Term Symbol)) -> Word64 -> Word64 -> Maybe (Term Symbol) @@ -879,7 +929,7 @@ nativeEvalInContext :: EvalCtx -> Socket -> PortNumber -> - [(Reference, SuperGroup Symbol)] -> + [(Reference, Code)] -> Reference -> IO (Either Error ([Error], Term Symbol)) nativeEvalInContext executable ppe ctx serv port codes base = do @@ -931,7 +981,7 @@ nativeEvalInContext executable ppe ctx serv port codes base = do nativeCompileCodes :: CompileOpts -> FilePath -> - [(Reference, SuperGroup Symbol)] -> + [(Reference, Code)] -> Reference -> FilePath -> IO () @@ -1006,7 +1056,7 @@ executeMainComb :: CCache -> IO (Either (Pretty ColorText) ()) executeMainComb init cc = do - rSection <- resolveSection cc $ Ins (Pack RF.unitRef 0 ZArgs) $ Call True init (BArg1 0) + rSection <- resolveSection cc $ Ins (Pack RF.unitRef 0 ZArgs) $ Call True init init (BArg1 0) result <- UnliftIO.try . eval0 cc Nothing $ rSection case result of @@ -1207,6 +1257,7 @@ data StoredCache = SCache (EnumMap Word64 Combs) (EnumMap Word64 Reference) + (EnumSet Word64) (EnumMap Word64 Reference) Word64 Word64 @@ -1217,9 +1268,10 @@ data StoredCache deriving (Show) putStoredCache :: (MonadPut m) => StoredCache -> m () -putStoredCache (SCache cs crs trs ftm fty int rtm rty sbs) = do - putEnumMap putNat (putEnumMap putNat (putComb putCombIx)) cs +putStoredCache (SCache cs crs cacheableCombs trs ftm fty int rtm rty sbs) = do + putEnumMap putNat (putEnumMap putNat (putComb absurd)) cs putEnumMap putNat putReference crs + putEnumSet putNat cacheableCombs putEnumMap putNat putReference trs putNat ftm putNat fty @@ -1231,8 +1283,9 @@ putStoredCache (SCache cs crs trs ftm fty int rtm rty sbs) = do getStoredCache :: (MonadGet m) => m StoredCache getStoredCache = SCache - <$> getEnumMap getNat (getEnumMap getNat (getComb getCombIx)) + <$> getEnumMap getNat (getEnumMap getNat getComb) <*> getEnumMap getNat getReference + <*> getEnumSet getNat <*> getEnumMap getNat getReference <*> getNat <*> getNat @@ -1259,17 +1312,32 @@ tabulateErrors errs = : (listErrors errs) restoreCache :: StoredCache -> IO CCache -restoreCache (SCache cs crs trs ftm fty int rtm rty sbs) = - CCache builtinForeigns False debugText - <$> newTVarIO combs - <*> newTVarIO (crs <> builtinTermBackref) - <*> newTVarIO (trs <> builtinTypeBackref) - <*> newTVarIO ftm - <*> newTVarIO fty - <*> newTVarIO int - <*> newTVarIO (rtm <> builtinTermNumbering) - <*> newTVarIO (rty <> builtinTypeNumbering) - <*> newTVarIO (sbs <> baseSandboxInfo) +restoreCache (SCache cs crs cacheableCombs trs ftm fty int rtm rty sbs) = do + cc <- + CCache builtinForeigns False debugText + <$> newTVarIO srcCombs + <*> newTVarIO combs + <*> newTVarIO (crs <> builtinTermBackref) + <*> newTVarIO cacheableCombs + <*> newTVarIO (trs <> builtinTypeBackref) + <*> newTVarIO ftm + <*> newTVarIO fty + <*> newTVarIO int + <*> newTVarIO (rtm <> builtinTermNumbering) + <*> newTVarIO (rty <> builtinTypeNumbering) + <*> newTVarIO (sbs <> baseSandboxInfo) + let (unresolvedCacheableCombs, unresolvedNonCacheableCombs) = + srcCombs + & absurdCombs + & EC.mapToList + & foldMap + ( \(k, v) -> + if k `member` cacheableCombs + then (EC.mapSingleton k v, mempty) + else (mempty, EC.mapSingleton k v) + ) + preEvalTopLevelConstants unresolvedCacheableCombs unresolvedNonCacheableCombs cc + pure cc where decom = decompile @@ -1286,28 +1354,33 @@ restoreCache (SCache cs crs trs ftm fty int rtm rty sbs) = (debugTextFormat fancy $ pretty PPE.empty dv) rns = emptyRNs {dnum = refLookup "ty" builtinTypeNumbering} rf k = builtinTermBackref ! k - combs :: EnumMap Word64 RCombs - combs = + srcCombs :: EnumMap Word64 Combs + srcCombs = let builtinCombs = mapWithKey (\k v -> emitComb @Symbol rns (rf k) k mempty (0, v)) numberedTermLookup in builtinCombs <> cs - & resolveCombs Nothing + combs :: EnumMap Word64 (RCombs Closure) + combs = + srcCombs + & absurdCombs + & resolveCombs Nothing traceNeeded :: Word64 -> - EnumMap Word64 RCombs -> - IO (EnumMap Word64 RCombs) + EnumMap Word64 (GCombs clos comb) -> + IO (EnumMap Word64 (GCombs clos comb)) traceNeeded init src = fmap (`withoutKeys` ks) $ go mempty init where ks = keysSet numberedTermLookup go acc w | hasKey w acc = pure acc | Just co <- EC.lookup w src = - foldlM go (mapInsert w co acc) (foldMap (combDeps . fmap rCombIx) co) + foldlM go (mapInsert w co acc) (foldMap combDeps co) | otherwise = die $ "traceNeeded: unknown combinator: " ++ show w buildSCache :: EnumMap Word64 Combs -> EnumMap Word64 Reference -> + EnumSet Word64 -> EnumMap Word64 Reference -> Word64 -> Word64 -> @@ -1316,10 +1389,11 @@ buildSCache :: Map Reference Word64 -> Map Reference (Set Reference) -> StoredCache -buildSCache cs crsrc trsrc ftm fty intsrc rtmsrc rtysrc sndbx = +buildSCache cs crsrc cacheableCombs trsrc ftm fty intsrc rtmsrc rtysrc sndbx = SCache cs crs + cacheableCombs trs ftm fty @@ -1346,8 +1420,9 @@ buildSCache cs crsrc trsrc ftm fty intsrc rtmsrc rtysrc sndbx = standalone :: CCache -> Word64 -> IO StoredCache standalone cc init = buildSCache - <$> (readTVarIO (combs cc) >>= traceNeeded init >>= pure . unTieRCombs) + <$> (readTVarIO (srcCombs cc) >>= traceNeeded init) <*> readTVarIO (combRefs cc) + <*> readTVarIO (cacheableCombs cc) <*> readTVarIO (tagRefs cc) <*> readTVarIO (freshTm cc) <*> readTVarIO (freshTy cc) @@ -1355,6 +1430,3 @@ standalone cc init = <*> readTVarIO (refTm cc) <*> readTVarIO (refTy cc) <*> readTVarIO (sandbox cc) - where - unTieRCombs :: EnumMap Word64 RCombs -> EnumMap Word64 Combs - unTieRCombs = fmap . fmap . fmap $ rCombIx diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 8f2f5a3d2d..ee018e0f96 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -17,14 +17,12 @@ module Unison.Runtime.MCode GSection (.., MatchT, MatchW), RSection, Section, - GComb (..), + GComb (.., Lam), + GCombInfo (..), Comb, RComb (..), - pattern RCombIx, - pattern RCombRef, - rCombToComb, + RCombInfo, GCombs, - Combs, RCombs, CombIx (..), GRef (..), @@ -42,10 +40,10 @@ module Unison.Runtime.MCode emitCombs, emitComb, resolveCombs, + absurdCombs, emptyRNs, argsToLists, combRef, - rCombRef, combDeps, combTypes, prettyCombs, @@ -53,7 +51,9 @@ module Unison.Runtime.MCode ) where -import Data.Bifunctor (bimap, first) +import Data.Bifoldable (Bifoldable (..)) +import Data.Bifunctor (Bifunctor, bimap, first) +import Data.Bitraversable (Bitraversable (..), bifoldMapDefault, bimapDefault) import Data.Bits (shiftL, shiftR, (.|.)) import Data.Coerce import Data.Functor ((<&>)) @@ -61,6 +61,7 @@ import Data.List (partition) import Data.Map.Strict qualified as M import Data.Primitive.ByteArray import Data.Primitive.PrimArray +import Data.Void (Void, absurd) import Data.Word (Word16, Word64) import GHC.Stack (HasCallStack) import Unison.ABT.Normalized (pattern TAbss) @@ -456,7 +457,7 @@ data MLit type Instr = GInstr CombIx -type RInstr = GInstr RComb +type RInstr clos = GInstr (RComb clos) -- Instructions for manipulating the data stack in the main portion of -- a block @@ -525,7 +526,7 @@ data GInstr comb type Section = GSection CombIx -type RSection = GSection RComb +type RSection clos = GSection (RComb clos) data GSection comb = -- Apply a function to arguments. This is the 'slow path', and @@ -543,7 +544,8 @@ data GSection comb -- sufficient for where we're jumping to. Call !Bool -- skip stack check - !comb -- global function reference + !CombIx + {- Lazy! Might be cyclic -} comb !Args -- arguments | -- Jump to a captured continuation value. Jump @@ -560,7 +562,18 @@ data GSection comb | -- Sequence two sections. The second is pushed as a return -- point for the results of the first. Stack modifications in -- the first are lost on return to the second. - Let !(GSection comb) !comb + -- + -- The stored CombIx is a combinator that contains the second + -- section, which can be used to reconstruct structures that + -- throw away the section, like serializable continuation values. + -- Code generation will emit the section as its own combinator, + -- but also include it directly here. + Let + !(GSection comb) -- binding + !CombIx -- body section refrence + !Int -- unboxed stack safety + !Int -- boxed stack safety + !(GSection comb) -- body code | -- Throw an exception with the given message Die String | -- Immediately stop a thread of interpretation. This is more of @@ -595,9 +608,6 @@ data CombIx combRef :: CombIx -> Reference combRef (CIx r _ _) = r -rCombRef :: RComb -> Reference -rCombRef (RComb cix _) = combRef cix - data RefNums = RN { dnum :: Reference -> Word64, cnum :: Reference -> Word64 @@ -608,10 +618,12 @@ emptyRNs = RN mt mt where mt _ = internalBug "RefNums: empty" -type Comb = GComb CombIx +type Comb = GComb Void CombIx -data GComb comb - = Lam +-- Actual information for a proper combinator. The GComb type is no +-- longer strictly a 'combinator.' +data GCombInfo comb + = LamI !Int -- Number of unboxed arguments !Int -- Number of boxed arguments !Int -- Maximum needed unboxed frame size @@ -619,61 +631,55 @@ data GComb comb !(GSection comb) -- Entry deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) -type Combs = GCombs CombIx +data GComb clos comb + = Comb {-# unpack #-} !(GCombInfo comb) + | -- A pre-evaluated comb, typically a pure top-level const + CachedClosure !Word64 {- top level comb ix -} !clos + deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) -type RCombs = GCombs RComb +pattern Lam + :: Int -> Int -> Int -> Int -> GSection comb -> GComb clos comb +pattern Lam ua ba uf bf sect = Comb (LamI ua ba uf bf sect) +-- it seems GHC can't figure this out itself +{-# complete CachedClosure, Lam #-} --- | Extract the CombIx from an RComb. -pattern RCombIx :: CombIx -> RComb -pattern RCombIx r <- (rCombIx -> r) +instance Bifunctor GComb where + bimap = bimapDefault -{-# COMPLETE RCombIx #-} +instance Bifoldable GComb where + bifoldMap = bifoldMapDefault --- | Extract the Reference from an RComb. -pattern RCombRef :: Reference -> RComb -pattern RCombRef r <- (combRef . rCombIx -> r) +instance Bitraversable GComb where + bitraverse f _ (CachedClosure cix c) = CachedClosure cix <$> f c + bitraverse _ f (Lam u b uf bf s) = Lam u b uf bf <$> traverse f s -{-# COMPLETE RCombRef #-} +type RCombs clos = GCombs clos (RComb clos) -- | The fixed point of a GComb where all references to a Comb are themselves Combs. -data RComb = RComb - { rCombIx :: !CombIx, - unRComb :: (GComb RComb {- Possibly recursive comb, keep it lazy or risk blowing up -}) - } +newtype RComb clos = RComb { unRComb :: GComb clos (RComb clos) } --- Eq and Ord instances on the CombIx to avoid infinite recursion when --- comparing self-recursive functions. -instance Eq RComb where - RComb r1 _ == RComb r2 _ = r1 == r2 +type RCombInfo clos = GCombInfo (RComb clos) -instance Ord RComb where - compare (RComb r1 _) (RComb r2 _) = compare r1 r2 - --- | Convert an RComb to a Comb by forgetting the sections and keeping only the CombIx. -rCombToComb :: RComb -> Comb -rCombToComb (RComb _ix c) = rCombIx <$> c - --- | RCombs can be infinitely recursive so we show the CombIx instead. -instance Show RComb where - show (RComb ix _) = show ix +instance Show (RComb clos) where + show _ = "" -- | Map of combinators, parameterized by comb reference type -type GCombs comb = EnumMap Word64 (GComb comb) +type GCombs clos comb = EnumMap Word64 (GComb clos comb) -- | A reference to a combinator, parameterized by comb type Ref = GRef CombIx -type RRef = GRef RComb +type RRef clos = GRef (RComb clos) data GRef comb = Stk !Int -- stack reference to a closure - | Env !comb -- direct reference to comb, usually embedded as an RComb + | Env !CombIx {- Lazy! Might be cyclic -} comb | Dyn !Word64 -- dynamic scope reference to a closure deriving (Show, Eq, Ord, Functor, Foldable, Traversable) type Branch = GBranch CombIx -type RBranch = GBranch RComb +type RBranch clos = GBranch (RComb clos) data GBranch comb = -- if tag == n then t else f @@ -800,17 +806,16 @@ emitCombs rns grpr grpn (Rec grp ent) = -- tying the knot recursively when necessary. resolveCombs :: -- Existing in-scope combs that might be referenced - -- TODO: Do we ever actually need to pass this? - Maybe (EnumMap Word64 RCombs) -> + Maybe (EnumMap Word64 (RCombs clos)) -> -- Combinators which need their knots tied. - EnumMap Word64 Combs -> - EnumMap Word64 RCombs + EnumMap Word64 (GCombs clos CombIx) -> + EnumMap Word64 (RCombs clos) resolveCombs mayExisting combs = -- Fixed point lookup; -- We make sure not to force resolved Combs or we'll loop forever. let ~resolved = combs - <&> (fmap . fmap) \(cix@(CIx _ n i)) -> + <&> (fmap . fmap) \(CIx _ n i) -> let cmbs = case mayExisting >>= EC.lookup n of Just cmbs -> cmbs Nothing -> @@ -818,7 +823,7 @@ resolveCombs mayExisting combs = Just cmbs -> cmbs Nothing -> error $ "unknown combinator `" ++ show n ++ "`." in case EC.lookup i cmbs of - Just cmb -> RComb cix cmb + Just cmb -> RComb cmb Nothing -> error $ "unknown section `" @@ -828,6 +833,9 @@ resolveCombs mayExisting combs = ++ "`." in resolved +absurdCombs :: EnumMap Word64 (EnumMap Word64 (GComb Void cix)) -> EnumMap Word64 (GCombs any cix) +absurdCombs = fmap . fmap . first $ absurd + -- Type for aggregating the necessary stack frame size. First field is -- unboxed size, second is boxed. The Applicative instance takes the -- point-wise maximum, so that combining values from different branches @@ -859,12 +867,13 @@ onCount f (EM e) = EM $ fmap f <$> e letIndex :: Word16 -> Word64 -> Word64 letIndex l c = c .|. fromIntegral l -record :: Ctx v -> Word16 -> Emit Section -> Emit Word64 +record :: Ctx v -> Word16 -> Emit Section -> Emit (Word64, Comb) record ctx l (EM es) = EM $ \c -> let (m, C u b s) = es c (au, ab) = countCtx0 0 0 ctx n = letIndex l c - in (EC.mapInsert n (Lam au ab u b s) m, C u b n) + comb = Lam au ab u b s + in (EC.mapInsert n comb m, C u b (n, comb)) recordTop :: [v] -> Word16 -> Emit Section -> Emit () recordTop vs l (EM e) = EM $ \c -> @@ -918,8 +927,9 @@ emitSection rns grpr grpn rec ctx (TLets d us ms bu bo) = ectx = pushCtx (zip us ms) ctx emitSection rns grpr grpn rec ctx (TName u (Left f) args bo) = emitClosures grpr grpn rec ctx args $ \ctx as -> - Ins (Name (Env (CIx f (cnum rns f) 0)) as) - <$> emitSection rns grpr grpn rec (Var u BX ctx) bo + let cix = (CIx f (cnum rns f) 0) + in Ins (Name (Env cix cix) as) + <$> emitSection rns grpr grpn rec (Var u BX ctx) bo emitSection rns grpr grpn rec ctx (TName u (Right v) args bo) | Just (i, BX) <- ctxResolve ctx v = emitClosures grpr grpn rec ctx args $ \ctx as -> @@ -927,14 +937,16 @@ emitSection rns grpr grpn rec ctx (TName u (Right v) args bo) <$> emitSection rns grpr grpn rec (Var u BX ctx) bo | Just n <- rctxResolve rec v = emitClosures grpr grpn rec ctx args $ \ctx as -> - Ins (Name (Env (CIx grpr grpn n)) as) - <$> emitSection rns grpr grpn rec (Var u BX ctx) bo + let cix = (CIx grpr grpn n) + in Ins (Name (Env cix cix) as) + <$> emitSection rns grpr grpn rec (Var u BX ctx) bo | otherwise = emitSectionVErr v emitSection _ grpr grpn rec ctx (TVar v) | Just (i, BX) <- ctxResolve ctx v = countCtx ctx . Yield $ BArg1 i | Just (i, UN) <- ctxResolve ctx v = countCtx ctx . Yield $ UArg1 i | Just j <- rctxResolve rec v = - countCtx ctx $ App False (Env (CIx grpr grpn j)) ZArgs + let cix = (CIx grpr grpn j) + in countCtx ctx $ App False (Env cix cix) ZArgs | otherwise = emitSectionVErr v emitSection _ _ grpn _ ctx (TPrm p args) = -- 3 is a conservative estimate of how many extra stack slots @@ -1062,12 +1074,14 @@ emitFunction _ grpr grpn rec ctx (FVar v) as | Just (i, BX) <- ctxResolve ctx v = App False (Stk i) as | Just j <- rctxResolve rec v = - App False (Env (CIx grpr grpn j)) as + let cix = CIx grpr grpn j + in App False (Env cix cix) as | otherwise = emitSectionVErr v emitFunction rns _grpr _ _ _ (FComb r) as | otherwise -- slow path = - App False (Env (CIx r n 0)) as + let cix = CIx r n 0 + in App False (Env cix cix) as where n = cnum rns r emitFunction rns _grpr _ _ _ (FCon r t) as = @@ -1170,7 +1184,9 @@ emitLet rns grpr grpn rec d vcs ctx bnd <$> emitSection rns grpr grpn rec (Block ctx) bnd <*> record (pushCtx vcs ctx) w esect where - f s w = Let s (CIx grpr grpn w) + f s (w, Lam _ _ un bx bd) = + let cix = (CIx grpr grpn w) + in Let s cix un bx bd -- Translate from ANF prim ops to machine code operations. The -- machine code operations are divided with respect to more detailed @@ -1520,7 +1536,8 @@ emitClosures grpr grpn rec ctx args k = allocate ctx (a : as) k | Just _ <- ctxResolve ctx a = allocate ctx as k | Just n <- rctxResolve rec a = - Ins (Name (Env (CIx grpr grpn n)) ZArgs) <$> allocate (Var a BX ctx) as k + let cix = (CIx grpr grpn n) + in Ins (Name (Env cix cix) ZArgs) <$> allocate (Var a BX ctx) as k | otherwise = internalBug $ "emitClosures: unknown reference: " ++ show a @@ -1551,29 +1568,32 @@ demuxArgs as0 = -- TODO: handle ranges (us, bs) -> DArgN (primArrayFromList us) (primArrayFromList bs) -combDeps :: Comb -> [Word64] +combDeps :: GComb clos comb -> [Word64] combDeps (Lam _ _ _ _ s) = sectionDeps s +combDeps (CachedClosure {}) = [] -combTypes :: Comb -> [Word64] +combTypes :: GComb any comb -> [Word64] combTypes (Lam _ _ _ _ s) = sectionTypes s +combTypes (CachedClosure {}) = [] -sectionDeps :: Section -> [Word64] -sectionDeps (App _ (Env (CIx _ w _)) _) = [w] -sectionDeps (Call _ (CIx _ w _) _) = [w] +sectionDeps :: GSection comb -> [Word64] +sectionDeps (App _ (Env (CIx _ w _) _) _) = [w] +sectionDeps (Call _ (CIx _ w _) _ _) = [w] sectionDeps (Match _ br) = branchDeps br sectionDeps (DMatch _ _ br) = branchDeps br sectionDeps (RMatch _ pu br) = sectionDeps pu ++ foldMap branchDeps br sectionDeps (NMatch _ _ br) = branchDeps br sectionDeps (Ins i s) - | Name (Env (CIx _ w _)) _ <- i = w : sectionDeps s + | Name (Env (CIx _ w _) _) _ <- i = w : sectionDeps s | otherwise = sectionDeps s -sectionDeps (Let s (CIx _ w _)) = w : sectionDeps s +sectionDeps (Let s (CIx _ w _) _ _ b) = + w : sectionDeps s ++ sectionDeps b sectionDeps _ = [] -sectionTypes :: Section -> [Word64] +sectionTypes :: GSection comb -> [Word64] sectionTypes (Ins i s) = instrTypes i ++ sectionTypes s -sectionTypes (Let s _) = sectionTypes s +sectionTypes (Let s _ _ _ b) = sectionTypes s ++ sectionTypes b sectionTypes (Match _ br) = branchTypes br sectionTypes (DMatch _ _ br) = branchTypes br sectionTypes (NMatch _ _ br) = branchTypes br @@ -1581,14 +1601,14 @@ sectionTypes (RMatch _ pu br) = sectionTypes pu ++ foldMap branchTypes br sectionTypes _ = [] -instrTypes :: Instr -> [Word64] +instrTypes :: GInstr comb -> [Word64] instrTypes (Pack _ w _) = [w `shiftR` 16] instrTypes (Reset ws) = setToList ws instrTypes (Capture w) = [w] instrTypes (SetDyn w _) = [w] instrTypes _ = [] -branchDeps :: Branch -> [Word64] +branchDeps :: GBranch comb -> [Word64] branchDeps (Test1 _ s1 d) = sectionDeps s1 ++ sectionDeps d branchDeps (Test2 _ s1 _ s2 d) = sectionDeps s1 ++ sectionDeps s2 ++ sectionDeps d @@ -1597,7 +1617,7 @@ branchDeps (TestW d m) = branchDeps (TestT d m) = sectionDeps d ++ foldMap sectionDeps m -branchTypes :: Branch -> [Word64] +branchTypes :: GBranch comb -> [Word64] branchTypes (Test1 _ s1 d) = sectionTypes s1 ++ sectionTypes d branchTypes (Test2 _ s1 _ s2 d) = sectionTypes s1 ++ sectionTypes s2 ++ sectionTypes d @@ -1620,15 +1640,16 @@ prettyCombs w es = (mapToList es) prettyComb :: Word64 -> Word64 -> Comb -> ShowS -prettyComb w i (Lam ua ba _ _ s) = - shows w - . showString ":" - . shows i - . shows [ua, ba] - . showString ":\n" - . prettySection 2 s - -prettySection :: Int -> Section -> ShowS +prettyComb w i = \case + (Lam ua ba _ _ s) -> + shows w + . showString ":" + . shows i + . shows [ua, ba] + . showString ":\n" + . prettySection 2 s + +prettySection :: (Show comb) => Int -> GSection comb -> ShowS prettySection ind sec = indent ind . case sec of App _ r as -> @@ -1636,7 +1657,7 @@ prettySection ind sec = . showsPrec 12 r . showString " " . prettyArgs as - Call _ i as -> + Call _ i _ as -> showString "Call " . shows i . showString " " . prettyArgs as Jump i as -> showString "Jump " . shows i . showString " " . prettyArgs as @@ -1648,12 +1669,12 @@ prettySection ind sec = Yield as -> showString "Yield " . prettyArgs as Ins i nx -> prettyIns i . showString "\n" . prettySection ind nx - Let s n -> + Let s _ _ _ b -> showString "Let\n" . prettySection (ind + 2) s . showString "\n" . indent ind - . prettyIx n + . prettySection ind b Die s -> showString $ "Die " ++ s Exit -> showString "Exit" DMatch _ i bs -> @@ -1679,15 +1700,7 @@ prettySection ind sec = . showString " ->\n" . prettyBranches (ind + 1) e -prettyIx :: CombIx -> ShowS -prettyIx (CIx _ c s) = - showString "Resume[" - . shows c - . showString "," - . shows s - . showString "]" - -prettyBranches :: Int -> Branch -> ShowS +prettyBranches :: (Show comb) => Int -> GBranch comb -> ShowS prettyBranches ind bs = case bs of Test1 i e df -> pdf df . picase i e @@ -1717,7 +1730,7 @@ un = ('U' :) bx :: ShowS bx = ('B' :) -prettyIns :: Instr -> ShowS +prettyIns :: (Show comb) => GInstr comb -> ShowS prettyIns (Pack r i as) = showString "Pack " . showsPrec 10 r diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index 039e2670db..3546b17ce2 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -15,18 +15,36 @@ import Data.Bytes.Put import Data.Bytes.Serial import Data.Bytes.VarInt import Data.Primitive.PrimArray +import Data.Void (Void) import Data.Word (Word64) import GHC.Exts (IsList (..)) import Unison.Runtime.MCode hiding (MatchT) import Unison.Runtime.Serialize import Unison.Util.Text qualified as Util.Text -putComb :: (MonadPut m) => (cix -> m ()) -> GComb cix -> m () -putComb putCix (Lam ua ba uf bf body) = - pInt ua *> pInt ba *> pInt uf *> pInt bf *> putSection putCix body +data CombT = LamT | CachedClosureT -getComb :: (MonadGet m) => m cix -> m (GComb cix) -getComb gCix = Lam <$> gInt <*> gInt <*> gInt <*> gInt <*> (getSection gCix) +instance Tag CombT where + tag2word LamT = 0 + tag2word CachedClosureT = 1 + + word2tag 0 = pure LamT + word2tag 1 = pure CachedClosureT + word2tag n = unknownTag "CombT" n + +putComb :: (MonadPut m) => (clos -> m ()) -> GComb clos comb -> m () +putComb pClos = \case + (Lam ua ba uf bf body) -> + putTag LamT *> pInt ua *> pInt ba *> pInt uf *> pInt bf *> putSection body + (CachedClosure w c) -> + putTag CachedClosureT *> putNat w *> pClos c + +getComb :: (MonadGet m) => m (GComb Void CombIx) +getComb = + getTag >>= \case + LamT -> + Lam <$> gInt <*> gInt <*> gInt <*> gInt <*> getSection + CachedClosureT -> error "getComb: Unexpected serialized Cached Closure" data SectionT = AppT @@ -70,41 +88,52 @@ instance Tag SectionT where word2tag 11 = pure RMatchT word2tag i = unknownTag "SectionT" i -putSection :: (MonadPut m) => (cix -> m ()) -> GSection cix -> m () -putSection pCix = \case - App b r a -> putTag AppT *> serialize b *> putRef pCix r *> putArgs a - Call b cix a -> putTag CallT *> serialize b *> pCix cix *> putArgs a +putSection :: (MonadPut m) => GSection cix -> m () +putSection = \case + App b r a -> putTag AppT *> serialize b *> putRef r *> putArgs a + Call b cix _comb a -> putTag CallT *> serialize b *> putCombIx cix *> putArgs a Jump i a -> putTag JumpT *> pInt i *> putArgs a - Match i b -> putTag MatchT *> pInt i *> putBranch pCix b + Match i b -> putTag MatchT *> pInt i *> putBranch b Yield a -> putTag YieldT *> putArgs a - Ins i s -> putTag InsT *> putInstr pCix i *> putSection pCix s - Let s ci -> putTag LetT *> putSection pCix s *> pCix ci + Ins i s -> putTag InsT *> putInstr i *> putSection s + Let s ci uf bf bd -> + putTag LetT + *> putSection s + *> putCombIx ci + *> pInt uf + *> pInt bf + *> putSection bd Die s -> putTag DieT *> serialize s Exit -> putTag ExitT - DMatch mr i b -> putTag DMatchT *> putMaybe mr putReference *> pInt i *> putBranch pCix b - NMatch mr i b -> putTag NMatchT *> putMaybe mr putReference *> pInt i *> putBranch pCix b + DMatch mr i b -> putTag DMatchT *> putMaybe mr putReference *> pInt i *> putBranch b + NMatch mr i b -> putTag NMatchT *> putMaybe mr putReference *> pInt i *> putBranch b RMatch i pu bs -> putTag RMatchT *> pInt i - *> putSection pCix pu - *> putEnumMap pWord (putBranch pCix) bs + *> putSection pu + *> putEnumMap pWord putBranch bs -getSection :: (MonadGet m) => m cix -> m (GSection cix) -getSection gCix = +getSection :: (MonadGet m) => m Section +getSection = getTag >>= \case - AppT -> App <$> deserialize <*> getRef gCix <*> getArgs - CallT -> Call <$> deserialize <*> gCix <*> getArgs + AppT -> App <$> deserialize <*> getRef <*> getArgs + CallT -> do + skipCheck <- deserialize + cix <- getCombIx + args <- getArgs + pure $ Call skipCheck cix cix args JumpT -> Jump <$> gInt <*> getArgs - MatchT -> Match <$> gInt <*> getBranch gCix + MatchT -> Match <$> gInt <*> getBranch YieldT -> Yield <$> getArgs - InsT -> Ins <$> getInstr gCix <*> getSection gCix - LetT -> Let <$> getSection gCix <*> gCix + InsT -> Ins <$> getInstr <*> getSection + LetT -> + Let <$> getSection <*> getCombIx <*> gInt <*> gInt <*> getSection DieT -> Die <$> deserialize ExitT -> pure Exit - DMatchT -> DMatch <$> getMaybe getReference <*> gInt <*> getBranch gCix - NMatchT -> NMatch <$> getMaybe getReference <*> gInt <*> getBranch gCix + DMatchT -> DMatch <$> getMaybe getReference <*> gInt <*> getBranch + NMatchT -> NMatch <$> getMaybe getReference <*> gInt <*> getBranch RMatchT -> - RMatch <$> gInt <*> getSection gCix <*> getEnumMap gWord (getBranch gCix) + RMatch <$> gInt <*> getSection <*> getEnumMap gWord getBranch data InstrT = UPrim1T @@ -166,8 +195,8 @@ instance Tag InstrT where word2tag 17 = pure BLitT word2tag n = unknownTag "InstrT" n -putInstr :: (MonadPut m) => (cix -> m ()) -> GInstr cix -> m () -putInstr pCix = \case +putInstr :: (MonadPut m) => GInstr cix -> m () +putInstr = \case (UPrim1 up i) -> putTag UPrim1T *> putTag up *> pInt i (UPrim2 up i j) -> putTag UPrim2T *> putTag up *> pInt i *> pInt j (BPrim1 bp i) -> putTag BPrim1T *> putTag bp *> pInt i @@ -175,7 +204,7 @@ putInstr pCix = \case (ForeignCall b w a) -> putTag ForeignCallT *> serialize b *> pWord w *> putArgs a (SetDyn w i) -> putTag SetDynT *> pWord w *> pInt i (Capture w) -> putTag CaptureT *> pWord w - (Name r a) -> putTag NameT *> putRef pCix r *> putArgs a + (Name r a) -> putTag NameT *> putRef r *> putArgs a (Info s) -> putTag InfoT *> serialize s (Pack r w a) -> putTag PackT *> putReference r *> pWord w *> putArgs a (Lit l) -> putTag LitT *> putLit l @@ -187,8 +216,8 @@ putInstr pCix = \case (Seq a) -> putTag SeqT *> putArgs a (TryForce i) -> putTag TryForceT *> pInt i -getInstr :: (MonadGet m) => m cix -> m (GInstr cix) -getInstr gCix = +getInstr :: (MonadGet m) => m Instr +getInstr = getTag >>= \case UPrim1T -> UPrim1 <$> getTag <*> gInt UPrim2T -> UPrim2 <$> getTag <*> gInt <*> gInt @@ -197,7 +226,7 @@ getInstr gCix = ForeignCallT -> ForeignCall <$> deserialize <*> gWord <*> getArgs SetDynT -> SetDyn <$> gWord <*> gInt CaptureT -> Capture <$> gWord - NameT -> Name <$> getRef gCix <*> getArgs + NameT -> Name <$> getRef <*> getArgs InfoT -> Info <$> deserialize PackT -> Pack <$> getReference <*> gWord <*> getArgs LitT -> Lit <$> getLit @@ -300,16 +329,18 @@ instance Tag RefT where word2tag 2 = pure DynT word2tag n = unknownTag "RefT" n -putRef :: (MonadPut m) => (cix -> m ()) -> GRef cix -> m () -putRef _pCix (Stk i) = putTag StkT *> pInt i -putRef pCix (Env cix) = putTag EnvT *> pCix cix -putRef _pCix (Dyn i) = putTag DynT *> pWord i +putRef :: (MonadPut m) => GRef cix -> m () +putRef (Stk i) = putTag StkT *> pInt i +putRef (Env cix _) = putTag EnvT *> putCombIx cix +putRef (Dyn i) = putTag DynT *> pWord i -getRef :: (MonadGet m) => m cix -> m (GRef cix) -getRef gCix = +getRef :: (MonadGet m) => m Ref +getRef = getTag >>= \case StkT -> Stk <$> gInt - EnvT -> Env <$> gCix + EnvT -> do + cix <- getCombIx + pure $ Env cix cix DynT -> Dyn <$> gWord putCombIx :: (MonadPut m) => CombIx -> m () @@ -364,34 +395,34 @@ instance Tag BranchT where word2tag 3 = pure TestTT word2tag n = unknownTag "BranchT" n -putBranch :: (MonadPut m) => (cix -> m ()) -> GBranch cix -> m () -putBranch pCix (Test1 w s d) = - putTag Test1T *> pWord w *> putSection pCix s *> putSection pCix d -putBranch pCix (Test2 a sa b sb d) = +putBranch :: (MonadPut m) => GBranch cix -> m () +putBranch (Test1 w s d) = + putTag Test1T *> pWord w *> putSection s *> putSection d +putBranch (Test2 a sa b sb d) = putTag Test2T *> pWord a - *> putSection pCix sa + *> putSection sa *> pWord b - *> putSection pCix sb - *> putSection pCix d -putBranch pCix (TestW d m) = - putTag TestWT *> putSection pCix d *> putEnumMap pWord (putSection pCix) m -putBranch pCix (TestT d m) = - putTag TestTT *> putSection pCix d *> putMap (putText . Util.Text.toText) (putSection pCix) m - -getBranch :: (MonadGet m) => m cix -> m (GBranch cix) -getBranch gCix = + *> putSection sb + *> putSection d +putBranch (TestW d m) = + putTag TestWT *> putSection d *> putEnumMap pWord putSection m +putBranch (TestT d m) = + putTag TestTT *> putSection d *> putMap (putText . Util.Text.toText) putSection m + +getBranch :: (MonadGet m) => m Branch +getBranch = getTag >>= \case - Test1T -> Test1 <$> gWord <*> getSection gCix <*> getSection gCix + Test1T -> Test1 <$> gWord <*> getSection <*> getSection Test2T -> Test2 <$> gWord - <*> getSection gCix + <*> getSection <*> gWord - <*> getSection gCix - <*> getSection gCix - TestWT -> TestW <$> getSection gCix <*> getEnumMap gWord (getSection gCix) - TestTT -> TestT <$> getSection gCix <*> getMap (Util.Text.fromText <$> getText) (getSection gCix) + <*> getSection + <*> getSection + TestWT -> TestW <$> getSection <*> getEnumMap gWord getSection + TestTT -> TestT <$> getSection <*> getMap (Util.Text.fromText <$> getText) getSection gInt :: (MonadGet m) => m Int gInt = unVarInt <$> deserialize diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 14744462fc..a6589aa016 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -4,14 +4,13 @@ {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ViewPatterns #-} --- TODO: Fix up all the uni-patterns -{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} module Unison.Runtime.Machine where import Control.Concurrent (ThreadId) import Control.Concurrent.STM as STM import Control.Exception +import Control.Lens import Data.Bits import Data.Map.Strict qualified as M import Data.Ord (comparing) @@ -26,6 +25,7 @@ import GHC.Conc as STM (unsafeIOToSTM) import Unison.Builtin.Decls (exceptionRef, ioFailureRef) import Unison.Builtin.Decls qualified as Rf import Unison.ConstructorReference qualified as CR +import Unison.Debug qualified as Debug import Unison.Prelude hiding (Text) import Unison.Reference ( Reference, @@ -35,9 +35,13 @@ import Unison.Reference ) import Unison.Referent (Referent, pattern Con, pattern Ref) import Unison.Runtime.ANF as ANF - ( CompileExn (..), + ( Cacheability (..), + Code (..), + CompileExn (..), Mem (..), SuperGroup, + codeGroup, + foldGroup, foldGroupLinks, maskTags, packTags, @@ -64,9 +68,11 @@ import UnliftIO.Concurrent qualified as UnliftIO -- | A ref storing every currently active thread. -- This is helpful for cleaning up orphaned threads when the main process --- completes. We track threads when running in a host process like UCM, --- otherwise we don't bother since forked threads are cleaned up automatically on --- termination. +-- completes. +-- +-- We track threads when running in a host process like UCM, +-- otherwise, in one-off environments 'Nothing' is used and we don't bother tracking forked threads since they'll be +-- cleaned up automatically on process termination. type ActiveThreads = Maybe (IORef (Set ThreadId)) type Tag = Word64 @@ -74,6 +80,20 @@ type Tag = Word64 -- dynamic environment type DEnv = EnumMap Word64 Closure +type MCombs = RCombs Closure + +type Combs = GCombs Void CombIx + +type MSection = RSection Closure + +type MBranch = RBranch Closure + +type MInstr = RInstr Closure + +type MComb = RComb Closure + +type MRef = RRef Closure + data Tracer = NoTrace | MsgTrace String String String @@ -84,8 +104,12 @@ data CCache = CCache { foreignFuncs :: EnumMap Word64 ForeignFunc, sandboxed :: Bool, tracer :: Bool -> Closure -> Tracer, - combs :: TVar (EnumMap Word64 RCombs), + -- Combinators in their original form, where they're easier to serialize into SCache + srcCombs :: TVar (EnumMap Word64 Combs), + combs :: TVar (EnumMap Word64 MCombs), combRefs :: TVar (EnumMap Word64 Reference), + -- Combs which we're allowed to cache after evaluating + cacheableCombs :: TVar (EnumSet Word64), tagRefs :: TVar (EnumMap Word64 Reference), freshTm :: TVar Word64, freshTy :: TVar Word64, @@ -119,8 +143,10 @@ refNumTy' cc r = M.lookup r <$> refNumsTy cc baseCCache :: Bool -> IO CCache baseCCache sandboxed = do CCache ffuncs sandboxed noTrace - <$> newTVarIO combs + <$> newTVarIO srcCombs + <*> newTVarIO combs <*> newTVarIO builtinTermBackref + <*> newTVarIO cacheableCombs <*> newTVarIO builtinTypeBackref <*> newTVarIO ftm <*> newTVarIO fty @@ -129,6 +155,7 @@ baseCCache sandboxed = do <*> newTVarIO builtinTypeNumbering <*> newTVarIO baseSandboxInfo where + cacheableCombs = mempty ffuncs | sandboxed = sandboxedForeigns | otherwise = builtinForeigns noTrace _ _ = NoTrace ftm = 1 + maximum builtinTermNumbering @@ -136,12 +163,15 @@ baseCCache sandboxed = do rns = emptyRNs {dnum = refLookup "ty" builtinTypeNumbering} - combs :: EnumMap Word64 RCombs - combs = - ( mapWithKey + srcCombs :: EnumMap Word64 Combs + srcCombs = + numberedTermLookup + & mapWithKey (\k v -> let r = builtinTermBackref ! k in emitComb @Symbol rns r k mempty (0, v)) - numberedTermLookup - ) + combs :: EnumMap Word64 MCombs + combs = + srcCombs + & absurdCombs & resolveCombs Nothing info :: (Show a) => String -> a -> IO () @@ -158,7 +188,7 @@ stk'info s@(BS _ _ sp _) = do prn sp -- Entry point for evaluating a section -eval0 :: CCache -> ActiveThreads -> RSection -> IO () +eval0 :: CCache -> ActiveThreads -> MSection -> IO () eval0 !env !activeThreads !co = do ustk <- alloc bstk <- alloc @@ -167,21 +197,25 @@ eval0 !env !activeThreads !co = do topDEnv cmbs <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) eval env denv activeThreads ustk bstk (k KE) dummyRef co +mCombClosure :: CombIx -> MComb -> Closure +mCombClosure cix (RComb (Comb comb)) = + PAp cix comb unull bnull +mCombClosure _ (RComb (CachedClosure _ clo)) = clo + topDEnv :: - EnumMap Word64 RCombs -> + EnumMap Word64 MCombs -> M.Map Reference Word64 -> M.Map Reference Word64 -> (DEnv, K -> K) topDEnv combs rfTy rfTm | Just n <- M.lookup exceptionRef rfTy, - -- TODO: Should I special-case this raise ref and pass it down from the top rather than always looking it up? rcrf <- Builtin (DTx.pack "raise"), - Just j <- M.lookup rcrf rfTm = - let cix = (CIx rcrf j 0) - comb = rCombSection combs cix - in ( EC.mapSingleton n (PAp comb unull bnull), - Mark 0 0 (EC.setSingleton n) mempty - ) + Just j <- M.lookup rcrf rfTm, + cix <- CIx rcrf j 0, + clo <- mCombClosure cix $ rCombSection combs cix = + ( EC.mapSingleton n clo, + Mark 0 0 (EC.setSingleton n) mempty + ) topDEnv _ _ _ = (mempty, id) -- Entry point for evaluating a numbered combinator. @@ -205,9 +239,13 @@ apply0 !callback !env !threadTracker !i = do r <- case EC.lookup i cmbrs of Just r -> pure r Nothing -> die "apply0: missing reference to entry point" - let entryComb = rCombSection cmbs (CIx r i 0) - apply env denv threadTracker ustk bstk (kf k0) True ZArgs $ - PAp entryComb unull bnull + let entryCix = (CIx r i 0) + case unRComb $ rCombSection cmbs entryCix of + Comb entryComb -> + apply env denv threadTracker ustk bstk (kf k0) True ZArgs $ + PAp entryCix entryComb unull bnull + -- if it's cached, we can just finish + CachedClosure _ clo -> bump bstk >>= \bstk -> poke bstk clo where k0 = maybe KE (CB . Hook) callback @@ -270,7 +308,7 @@ exec :: Stack 'BX -> K -> Reference -> - RInstr -> + MInstr -> IO (DEnv, Stack 'UN, Stack 'BX, K) exec !_ !denv !_activeThreads !ustk !bstk !k _ (Info tx) = do info tx ustk @@ -298,7 +336,9 @@ exec !env !denv !_activeThreads !ustk !bstk !k _ (BPrim1 MISS i) | sandboxed env = die "attempted to use sandboxed operation: isMissing" | otherwise = do clink <- peekOff bstk i - let Ref link = unwrapForeign $ marshalToForeign clink + let link = case unwrapForeign $ marshalToForeign clink of + Ref r -> r + _ -> error "exec:BPrim1:MISS: Expected Ref" m <- readTVarIO (intermed env) ustk <- bump ustk if (link `M.member` m) then poke ustk 1 else poke ustk 0 @@ -319,7 +359,7 @@ exec !env !denv !_activeThreads !ustk !bstk !k _ (BPrim1 CVLD i) | otherwise = do arg <- peekOffS bstk i news <- decodeCacheArgument arg - codeValidate news env >>= \case + codeValidate (second codeGroup <$> news) env >>= \case Nothing -> do ustk <- bump ustk poke ustk 0 @@ -336,8 +376,12 @@ exec !env !denv !_activeThreads !ustk !bstk !k _ (BPrim1 LKUP i) | sandboxed env = die "attempted to use sandboxed operation: lookup" | otherwise = do clink <- peekOff bstk i - let Ref link = unwrapForeign $ marshalToForeign clink + let link = case unwrapForeign $ marshalToForeign clink of + Ref r -> r + _ -> error "exec:BPrim1:LKUP: Expected Ref" m <- readTVarIO (intermed env) + rfn <- readTVarIO (refTm env) + cach <- readTVarIO (cacheableCombs env) ustk <- bump ustk bstk <- case M.lookup link m of Nothing @@ -345,12 +389,17 @@ exec !env !denv !_activeThreads !ustk !bstk !k _ (BPrim1 LKUP i) Just sn <- EC.lookup w numberedTermLookup -> do poke ustk 1 bstk <- bump bstk - bstk <$ pokeBi bstk (ANF.Rec [] sn) + bstk <$ pokeBi bstk (CodeRep (ANF.Rec [] sn) Uncacheable) | otherwise -> bstk <$ poke ustk 0 Just sg -> do poke ustk 1 bstk <- bump bstk - bstk <$ pokeBi bstk sg + let ch + | Just n <- M.lookup link rfn, + EC.member n cach = + Cacheable + | otherwise = Uncacheable + bstk <$ pokeBi bstk (CodeRep sg ch) pure (denv, ustk, bstk, k) exec !_ !denv !_activeThreads !ustk !bstk !k _ (BPrim1 TLTT i) = do clink <- peekOff bstk i @@ -593,7 +642,7 @@ eval :: Stack 'BX -> K -> Reference -> - RSection -> + MSection -> IO () eval !env !denv !activeThreads !ustk !bstk !k r (Match i (TestT df cs)) = do t <- peekOffBi bstk i @@ -629,14 +678,22 @@ eval !env !denv !activeThreads !ustk !bstk !k _ (Yield args) eval !env !denv !activeThreads !ustk !bstk !k _ (App ck r args) = resolve env denv bstk r >>= apply env denv activeThreads ustk bstk k ck args -eval !env !denv !activeThreads !ustk !bstk !k _ (Call ck rcomb args) = +eval !env !denv !activeThreads !ustk !bstk !k _ (Call ck _combIx rcomb args) = enter env denv activeThreads ustk bstk k ck args rcomb eval !env !denv !activeThreads !ustk !bstk !k _ (Jump i args) = peekOff bstk i >>= jump env denv activeThreads ustk bstk k args -eval !env !denv !activeThreads !ustk !bstk !k r (Let nw cix) = do +eval !env !denv !activeThreads !ustk !bstk !k r (Let nw cix uf bf sect) = do (ustk, ufsz, uasz) <- saveFrame ustk (bstk, bfsz, basz) <- saveFrame bstk - eval env denv activeThreads ustk bstk (Push ufsz bfsz uasz basz cix k) r nw + eval + env + denv + activeThreads + ustk + bstk + (Push ufsz bfsz uasz basz cix uf bf sect k) + r + nw eval !env !denv !activeThreads !ustk !bstk !k r (Ins i nx) = do (denv, ustk, bstk, k) <- exec env denv activeThreads ustk bstk k r i eval env denv activeThreads ustk bstk k r nx @@ -691,28 +748,33 @@ enter :: K -> Bool -> Args -> - RComb -> + MComb -> IO () -enter !env !denv !activeThreads !ustk !bstk !k !ck !args !rcomb = do - ustk <- if ck then ensure ustk uf else pure ustk - bstk <- if ck then ensure bstk bf else pure bstk - (ustk, bstk) <- moveArgs ustk bstk args - ustk <- acceptArgs ustk ua - bstk <- acceptArgs bstk ba - -- TODO: start putting references in `Call` if we ever start - -- detecting saturated calls. - eval env denv activeThreads ustk bstk k dummyRef entry - where - (RComb _ (Lam ua ba uf bf entry)) = rcomb +enter !env !denv !activeThreads !ustk !bstk !k !ck !args = \case + (RComb (Lam ua ba uf bf entry)) -> do + ustk <- if ck then ensure ustk uf else pure ustk + bstk <- if ck then ensure bstk bf else pure bstk + (ustk, bstk) <- moveArgs ustk bstk args + ustk <- acceptArgs ustk ua + bstk <- acceptArgs bstk ba + -- TODO: start putting references in `Call` if we ever start + -- detecting saturated calls. + eval env denv activeThreads ustk bstk k dummyRef entry + (RComb (CachedClosure _cix clos)) -> do + ustk <- discardFrame ustk + bstk <- discardFrame bstk + bstk <- bump bstk + poke bstk clos + yield env denv activeThreads ustk bstk k {-# INLINE enter #-} -- fast path by-name delaying name :: Stack 'UN -> Stack 'BX -> Args -> Closure -> IO (Stack 'BX) name !ustk !bstk !args clo = case clo of - PAp comb useg bseg -> do + PAp cix comb useg bseg -> do (useg, bseg) <- closeArgs I ustk bstk useg bseg args bstk <- bump bstk - poke bstk $ PAp comb useg bseg + poke bstk $ PAp cix comb useg bseg pure bstk _ -> die $ "naming non-function: " ++ show clo {-# INLINE name #-} @@ -729,38 +791,41 @@ apply :: Args -> Closure -> IO () -apply !env !denv !activeThreads !ustk !bstk !k !ck !args (PAp comb useg bseg) = - case unRComb comb of - Lam ua ba uf bf entry - | ck || ua <= uac && ba <= bac -> do - ustk <- ensure ustk uf - bstk <- ensure bstk bf - (ustk, bstk) <- moveArgs ustk bstk args - ustk <- dumpSeg ustk useg A - bstk <- dumpSeg bstk bseg A - ustk <- acceptArgs ustk ua - bstk <- acceptArgs bstk ba - eval env denv activeThreads ustk bstk k (rCombRef comb) entry - | otherwise -> do - (useg, bseg) <- closeArgs C ustk bstk useg bseg args - ustk <- discardFrame =<< frameArgs ustk - bstk <- discardFrame =<< frameArgs bstk +apply !env !denv !activeThreads !ustk !bstk !k !ck !args = \case + (PAp cix@(CIx combRef _ _) comb useg bseg) -> + case comb of + LamI ua ba uf bf entry + | ck || ua <= uac && ba <= bac -> do + ustk <- ensure ustk uf + bstk <- ensure bstk bf + (ustk, bstk) <- moveArgs ustk bstk args + ustk <- dumpSeg ustk useg A + bstk <- dumpSeg bstk bseg A + ustk <- acceptArgs ustk ua + bstk <- acceptArgs bstk ba + eval env denv activeThreads ustk bstk k combRef entry + | otherwise -> do + (useg, bseg) <- closeArgs C ustk bstk useg bseg args + ustk <- discardFrame =<< frameArgs ustk + bstk <- discardFrame =<< frameArgs bstk + bstk <- bump bstk + poke bstk $ PAp cix comb useg bseg + yield env denv activeThreads ustk bstk k + where + uac = asize ustk + ucount args + uscount useg + bac = asize bstk + bcount args + bscount bseg + clo -> zeroArgClosure clo + where + zeroArgClosure clo + | ZArgs <- args, + asize ustk == 0, + asize bstk == 0 = do + ustk <- discardFrame ustk + bstk <- discardFrame bstk bstk <- bump bstk - poke bstk $ PAp comb useg bseg + poke bstk clo yield env denv activeThreads ustk bstk k - where - uac = asize ustk + ucount args + uscount useg - bac = asize bstk + bcount args + bscount bseg -apply !env !denv !activeThreads !ustk !bstk !k !_ !args clo - | ZArgs <- args, - asize ustk == 0, - asize bstk == 0 = do - ustk <- discardFrame ustk - bstk <- discardFrame bstk - bstk <- bump bstk - poke bstk clo - yield env denv activeThreads ustk bstk k - | otherwise = die $ "applying non-function: " ++ show clo + | otherwise = die $ "applying non-function: " ++ show clo {-# INLINE apply #-} jump :: @@ -794,8 +859,8 @@ jump !env !denv !activeThreads !ustk !bstk !k !args clo = case clo of -- pending, and the result stacks need to be adjusted. Hence the 3 results. adjust (Mark ua ba rs denv k) = (0, 0, Mark (ua + asize ustk) (ba + asize bstk) rs denv k) - adjust (Push un bn ua ba cix k) = - (0, 0, Push un bn (ua + asize ustk) (ba + asize bstk) cix k) + adjust (Push un bn ua ba cix uf bf rsect k) = + (0, 0, Push un bn (ua + asize ustk) (ba + asize bstk) cix uf bf rsect k) adjust k = (asize ustk, asize bstk, k) {-# INLINE jump #-} @@ -815,8 +880,8 @@ repush !env !activeThreads !ustk !bstk = go where denv' = cs <> EC.withoutKeys denv ps cs' = EC.restrictKeys denv ps - go !denv (Push un bn ua ba nx sk) !k = - go denv sk $ Push un bn ua ba nx k + go !denv (Push un bn ua ba cix uf bf rsect sk) !k = + go denv sk $ Push un bn ua ba cix uf bf rsect k go !_ (CB _) !_ = die "repush: impossible" {-# INLINE repush #-} @@ -1776,23 +1841,22 @@ yield !env !denv !activeThreads !ustk !bstk !k = leap denv k ustk <- adjustArgs ustk ua bstk <- adjustArgs bstk ba apply env denv activeThreads ustk bstk k False (BArg1 0) clo - leap !denv (Push ufsz bfsz uasz basz rComb k) = do - let Lam _ _ uf bf nx = unRComb rComb + leap !denv (Push ufsz bfsz uasz basz (CIx ref _ _) uf bf nx k) = do ustk <- restoreFrame ustk ufsz uasz bstk <- restoreFrame bstk bfsz basz ustk <- ensure ustk uf bstk <- ensure bstk bf - eval env denv activeThreads ustk bstk k (rCombRef rComb) nx + eval env denv activeThreads ustk bstk k ref nx leap _ (CB (Hook f)) = f ustk bstk leap _ KE = pure () {-# INLINE yield #-} selectTextBranch :: - Util.Text.Text -> RSection -> M.Map Util.Text.Text RSection -> RSection + Util.Text.Text -> MSection -> M.Map Util.Text.Text MSection -> MSection selectTextBranch t df cs = M.findWithDefault df t cs {-# INLINE selectTextBranch #-} -selectBranch :: Tag -> RBranch -> RSection +selectBranch :: Tag -> MBranch -> MSection selectBranch t (Test1 u y n) | t == u = y | otherwise = n @@ -1838,8 +1902,13 @@ splitCont !denv !ustk !bstk !k !p = where denv' = cs <> EC.withoutKeys denv ps cs' = EC.restrictKeys denv ps - walk !denv !usz !bsz !ck (Push un bn ua ba br k) = - walk denv (usz + un + ua) (bsz + bn + ba) (Push un bn ua ba br ck) k + walk !denv !usz !bsz !ck (Push un bn ua ba br up bp brSect k) = + walk + denv + (usz + un + ua) + (bsz + bn + ba) + (Push un bn ua ba br up bp brSect ck) + k finish !denv !usz !bsz !ua !ba !ck !k = do (useg, ustk) <- grab ustk usz @@ -1861,8 +1930,8 @@ discardCont denv ustk bstk k p = <&> \(_, denv, ustk, bstk, k) -> (denv, ustk, bstk, k) {-# INLINE discardCont #-} -resolve :: CCache -> DEnv -> Stack 'BX -> RRef -> IO Closure -resolve _ _ _ (Env rComb) = pure $ PAp rComb unull bnull +resolve :: CCache -> DEnv -> Stack 'BX -> MRef -> IO Closure +resolve _ _ _ (Env cix mcomb) = pure $ mCombClosure cix mcomb resolve _ _ bstk (Stk i) = peekOff bstk i resolve env denv _ (Dyn i) = case EC.lookup i denv of Just clo -> pure clo @@ -1876,15 +1945,15 @@ unhandledErr fname env i = where bomb sh = die $ fname ++ ": unhandled ability request: " ++ sh -rCombSection :: EnumMap Word64 RCombs -> CombIx -> RComb -rCombSection combs cix@(CIx r n i) = +rCombSection :: EnumMap Word64 MCombs -> CombIx -> MComb +rCombSection combs (CIx r n i) = case EC.lookup n combs of Just cmbs -> case EC.lookup i cmbs of - Just cmb -> RComb cix cmb + Just cmb -> RComb cmb Nothing -> error $ "unknown section `" ++ show i ++ "` of combinator `" ++ show n ++ "`. Reference: " ++ show r Nothing -> error $ "unknown combinator `" ++ show n ++ "`. Reference: " ++ show r -resolveSection :: CCache -> Section -> IO RSection +resolveSection :: CCache -> Section -> IO MSection resolveSection cc section = do rcombs <- readTVarIO (combs cc) pure $ rCombSection rcombs <$> section @@ -1901,9 +1970,6 @@ updateMap new0 r = do stateTVar r $ \old -> let total = new <> old in (total, total) -modifyMap :: TVar s -> (s -> s) -> STM s -modifyMap r f = stateTVar r $ \old -> let new = f old in (new, new) - refLookup :: String -> M.Map Reference Word64 -> Reference -> Word64 refLookup s m r | Just w <- M.lookup r m = w @@ -1911,7 +1977,7 @@ refLookup s m r error $ "refLookup:" ++ s ++ ": unknown reference: " ++ show r decodeCacheArgument :: - Sq.Seq Closure -> IO [(Reference, SuperGroup Symbol)] + Sq.Seq Closure -> IO [(Reference, Code)] decodeCacheArgument s = for (toList s) $ \case DataB2 _ _ (Foreign x) (DataB2 _ _ (Foreign y) _) -> case unwrapForeign x of @@ -2038,32 +2104,77 @@ evaluateSTM x = unsafeIOToSTM (evaluate x) cacheAdd0 :: S.Set Reference -> - [(Reference, SuperGroup Symbol)] -> + [(Reference, Code)] -> [(Reference, Set Reference)] -> CCache -> IO () -cacheAdd0 ntys0 tml sands cc = atomically $ do - have <- readTVar (intermed cc) - let new = M.difference toAdd have - sz = fromIntegral $ M.size new - rgs = M.toList new - rs = fst <$> rgs - int <- writeTVar (intermed cc) (have <> new) - rty <- addRefs (freshTy cc) (refTy cc) (tagRefs cc) ntys0 - ntm <- stateTVar (freshTm cc) $ \i -> (i, i + sz) - rtm <- updateMap (M.fromList $ zip rs [ntm ..]) (refTm cc) - -- check for missing references - let rns = RN (refLookup "ty" rty) (refLookup "tm" rtm) - combinate :: Word64 -> (Reference, SuperGroup Symbol) -> (Word64, EnumMap Word64 Comb) - combinate n (r, g) = (n, emitCombs rns r n g) - nrs <- updateMap (mapFromList $ zip [ntm ..] rs) (combRefs cc) - ncs <- modifyMap (combs cc) \oldCombs -> - let newCombs = resolveCombs (Just oldCombs) . mapFromList $ zipWith combinate [ntm ..] rgs - in newCombs <> oldCombs - nsn <- updateMap (M.fromList sands) (sandbox cc) - pure $ int `seq` rtm `seq` nrs `seq` ncs `seq` nsn `seq` () - where - toAdd = M.fromList tml +cacheAdd0 ntys0 termSuperGroups sands cc = do + let toAdd = M.fromList (termSuperGroups <&> second codeGroup) + (unresolvedCacheableCombs, unresolvedNonCacheableCombs) <- atomically $ do + have <- readTVar (intermed cc) + let new = M.difference toAdd have + let sz = fromIntegral $ M.size new + let rgs = M.toList new + let rs = fst <$> rgs + int <- writeTVar (intermed cc) (have <> new) + rty <- addRefs (freshTy cc) (refTy cc) (tagRefs cc) ntys0 + ntm <- stateTVar (freshTm cc) $ \i -> (i, i + sz) + rtm <- updateMap (M.fromList $ zip rs [ntm ..]) (refTm cc) + -- check for missing references + let rns = RN (refLookup "ty" rty) (refLookup "tm" rtm) + combinate :: Word64 -> (Reference, SuperGroup Symbol) -> (Word64, EnumMap Word64 Comb) + combinate n (r, g) = (n, emitCombs rns r n g) + let combRefUpdates = (mapFromList $ zip [ntm ..] rs) + let combIdFromRefMap = (M.fromList $ zip rs [ntm ..]) + let newCacheableCombs = + termSuperGroups + & mapMaybe + ( \case + (ref, CodeRep _ Cacheable) -> + M.lookup ref combIdFromRefMap + _ -> Nothing + ) + & EC.setFromList + newCombRefs <- updateMap combRefUpdates (combRefs cc) + (unresolvedNewCombs, unresolvedCacheableCombs, unresolvedNonCacheableCombs, updatedCombs) <- stateTVar (combs cc) \oldCombs -> + let unresolvedNewCombs :: EnumMap Word64 (GCombs any CombIx) + unresolvedNewCombs = absurdCombs . mapFromList $ zipWith combinate [ntm ..] rgs + (unresolvedCacheableCombs, unresolvedNonCacheableCombs) = + EC.mapToList unresolvedNewCombs & foldMap \(w, gcombs) -> + if EC.member w newCacheableCombs + then (EC.mapSingleton w gcombs, mempty) + else (mempty, EC.mapSingleton w gcombs) + newCombs :: EnumMap Word64 MCombs + newCombs = resolveCombs (Just oldCombs) $ unresolvedNewCombs + updatedCombs = newCombs <> oldCombs + in ((unresolvedNewCombs, unresolvedCacheableCombs, unresolvedNonCacheableCombs, updatedCombs), updatedCombs) + nsc <- updateMap unresolvedNewCombs (srcCombs cc) + nsn <- updateMap (M.fromList sands) (sandbox cc) + ncc <- updateMap newCacheableCombs (cacheableCombs cc) + -- Now that the code cache is primed with everything we need, + -- we can pre-evaluate the top-level constants. + pure $ int `seq` rtm `seq` newCombRefs `seq` updatedCombs `seq` nsn `seq` ncc `seq` nsc `seq` (unresolvedCacheableCombs, unresolvedNonCacheableCombs) + preEvalTopLevelConstants unresolvedCacheableCombs unresolvedNonCacheableCombs cc + +preEvalTopLevelConstants :: (EnumMap Word64 (GCombs Closure CombIx)) -> (EnumMap Word64 (GCombs Closure CombIx)) -> CCache -> IO () +preEvalTopLevelConstants cacheableCombs newCombs cc = do + activeThreads <- Just <$> UnliftIO.newIORef mempty + evaluatedCacheableCombsVar <- newTVarIO mempty + for_ (EC.mapToList cacheableCombs) \(w, _) -> do + Debug.debugM Debug.Temp "Evaluating " w + let hook _ustk bstk = do + clos <- peek bstk + Debug.debugM Debug.Temp "Evaluated" ("Evaluated " ++ show w ++ " to " ++ show clos) + atomically $ do + modifyTVar evaluatedCacheableCombsVar $ EC.mapInsert w (EC.mapSingleton 0 $ CachedClosure w clos) + apply0 (Just hook) cc activeThreads w + + evaluatedCacheableCombs <- readTVarIO evaluatedCacheableCombsVar + Debug.debugLogM Debug.Temp "Done pre-caching" + let allNew = evaluatedCacheableCombs <> newCombs + -- Rewrite all the inlined combinator references to point to the + -- new cached versions. + atomically $ modifyTVar (combs cc) (\existingCombs -> (resolveCombs (Just $ EC.mapDifference existingCombs allNew) allNew) <> existingCombs) expandSandbox :: Map Reference (Set Reference) -> @@ -2086,22 +2197,24 @@ expandSandbox sand0 groups = fixed mempty extra' = M.fromList new cacheAdd :: - [(Reference, SuperGroup Symbol)] -> + [(Reference, Code)] -> CCache -> IO [Reference] cacheAdd l cc = do rtm <- readTVarIO (refTm cc) rty <- readTVarIO (refTy cc) sand <- readTVarIO (sandbox cc) - let known = M.keysSet rtm <> S.fromList (fst <$> l) + let known = M.keysSet rtm <> S.fromList (view _1 <$> l) f b r | not b, S.notMember r known = Const (S.singleton r, mempty) | b, M.notMember r rty = Const (mempty, S.singleton r) | otherwise = Const (mempty, mempty) - (missing, tys) = getConst $ (foldMap . foldMap) (foldGroupLinks f) l - l' = filter (\(r, _) -> M.notMember r rtm) l + (missing, tys) = + getConst $ (foldMap . foldMap . foldGroup) (foldGroupLinks f) l + l'' = filter (\(r, _) -> M.notMember r rtm) l + l' = map (second codeGroup) l'' if S.null missing - then [] <$ cacheAdd0 tys l' (expandSandbox sand l') cc + then [] <$ cacheAdd0 tys l'' (expandSandbox sand l') cc else pure $ S.toList missing reflectValue :: EnumMap Word64 Reference -> Closure -> IO ANF.Value @@ -2115,8 +2228,8 @@ reflectValue rty = goV goIx (CIx r _ i) = ANF.GR r i - goV (PApV rComb ua ba) = - ANF.Partial (goIx $ rCombIx rComb) (fromIntegral <$> ua) <$> traverse goV ba + goV (PApV cix _rComb ua ba) = + ANF.Partial (goIx cix) (fromIntegral <$> ua) <$> traverse goV ba goV (DataC _ t [w] []) = ANF.BLit <$> reflectUData t w goV (DataC r t us bs) = ANF.Data r (maskTags t) (fromIntegral <$> us) <$> traverse goV bs @@ -2131,13 +2244,13 @@ reflectValue rty = goV ps <- traverse refTy (EC.setToList ps) de <- traverse (\(k, v) -> (,) <$> refTy k <*> goV v) (mapToList de) ANF.Mark (fromIntegral ua) (fromIntegral ba) ps (M.fromList de) <$> goK k - goK (Push uf bf ua ba rComb k) = + goK (Push uf bf ua ba cix _ _ _rsect k) = ANF.Push (fromIntegral uf) (fromIntegral bf) (fromIntegral ua) (fromIntegral ba) - (goIx $ rCombIx rComb) + (goIx cix) <$> goK k goF f @@ -2170,7 +2283,7 @@ reflectValue rty = goV | t == floatTag = pure $ ANF.Float (intToDouble v) | otherwise = die . err $ "unboxed data: " <> show (t, v) -reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] RClosure) +reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] Closure) reifyValue cc val = do erc <- atomically $ do @@ -2188,7 +2301,7 @@ reifyValue cc val = do (tyLinks, tmLinks) = valueLinks f val reifyValue0 :: - (EnumMap Word64 RCombs, M.Map Reference Word64, M.Map Reference Word64) -> + (EnumMap Word64 MCombs, M.Map Reference Word64, M.Map Reference Word64) -> ANF.Value -> IO Closure reifyValue0 (combs, rty, rtm) = goV @@ -2200,15 +2313,22 @@ reifyValue0 (combs, rty, rtm) = goV refTm r | Just w <- M.lookup r rtm = pure w | otherwise = die . err $ "unknown term reference: " ++ show r - goIx :: ANF.GroupRef -> IO RComb + goIx :: ANF.GroupRef -> IO (CombIx, MComb) goIx (ANF.GR r i) = refTm r <&> \n -> - rCombSection combs (CIx r n i) + let cix = (CIx r n i) + in (cix, rCombSection combs cix) goV (ANF.Partial gr ua ba) = - pap <$> (goIx gr) <*> traverse goV ba - where - pap i = PApV i (fromIntegral <$> ua) + goIx gr >>= \case + (cix, RComb (Comb rcomb)) -> pap cix rcomb <$> traverse goV ba + where + pap cix i = PApV cix i (fromIntegral <$> ua) + (_, RComb (CachedClosure _ clo)) + | [] <- ua, [] <- ba -> pure clo + | otherwise -> die . err $ msg + where + msg = "reifyValue0: non-trivial partial application to cached value" goV (ANF.Data r t0 us bs) = do t <- flip packTags (fromIntegral t0) . fromIntegral <$> refTy r DataC r t (fromIntegral <$> us) <$> traverse goV bs @@ -2231,13 +2351,22 @@ reifyValue0 (combs, rty, rtm) = goV mrk ps de k = Mark (fromIntegral ua) (fromIntegral ba) (setFromList ps) (mapFromList de) k goK (ANF.Push uf bf ua ba gr k) = - Push - (fromIntegral uf) - (fromIntegral bf) - (fromIntegral ua) - (fromIntegral ba) - <$> (goIx gr) - <*> goK k + goIx gr >>= \case + (cix, RComb (Lam _ _ un bx sect)) -> + Push + (fromIntegral uf) + (fromIntegral bf) + (fromIntegral ua) + (fromIntegral ba) + cix + un + bx + sect + <$> goK k + (CIx r _ _, _) -> + die . err $ + "tried to reify a continuation with a cached value resumption" + ++ show r goL (ANF.Text t) = pure . Foreign $ Wrap Rf.textRef t goL (ANF.List l) = Foreign . Wrap Rf.listRef <$> traverse goV l @@ -2285,8 +2414,8 @@ universalEq frn = eqc ct1 == ct2 && eql (==) us1 us2 && eql eqc bs1 bs2 - eqc (PApV i1 us1 bs1) (PApV i2 us2 bs2) = - i1 == i2 + eqc (PApV cix1 _ us1 bs1) (PApV cix2 _ us2 bs2) = + cix1 == cix2 && eql (==) us1 us2 && eql eqc bs1 bs2 eqc (CapV k1 ua1 ba1 us1 bs1) (CapV k2 ua2 ba2 us2 bs2) = @@ -2424,8 +2553,8 @@ universalCompare frn = cmpc False -- when comparing corresponding `Any` values, which have -- existentials inside check that type references match <> cmpl (cmpc $ tyEq || rf1 == Rf.anyRef) bs1 bs2 - cmpc tyEq (PApV i1 us1 bs1) (PApV i2 us2 bs2) = - compare i1 i2 + cmpc tyEq (PApV cix1 _ us1 bs1) (PApV cix2 _ us2 bs2) = + compare cix1 cix2 <> cmpl compare us1 us2 <> cmpl (cmpc tyEq) bs1 bs2 cmpc _ (CapV k1 ua1 ba1 us1 bs1) (CapV k2 ua2 ba2 us2 bs2) = diff --git a/unison-runtime/src/Unison/Runtime/Serialize.hs b/unison-runtime/src/Unison/Runtime/Serialize.hs index 064200cd55..394b846a0b 100644 --- a/unison-runtime/src/Unison/Runtime/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/Serialize.hs @@ -201,6 +201,12 @@ getByteArray = PA.byteArrayFromList <$> getList getWord8 putByteArray :: (MonadPut m) => PA.ByteArray -> m () putByteArray a = putFoldable putWord8 (IL.toList a) +getArray :: (MonadGet m) => m a -> m (PA.Array a) +getArray getThing = PA.arrayFromList <$> getList getThing + +putArray :: (MonadPut m) => (a -> m ()) -> PA.Array a -> m () +putArray putThing a = putFoldable putThing (IL.toList a) + getBlock :: (MonadGet m) => m Bytes.Chunk getBlock = getLength >>= fmap Bytes.byteStringToChunk . getByteString diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index b85707b1b3..f916a12166 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -8,9 +8,24 @@ module Unison.Runtime.Stack ( K (..), - GClosure (.., DataC, PApV, CapV), - Closure, - RClosure, + GClosure (..), + Closure + ( .., + DataC, + PApV, + CapV, + PAp, + Enum, + DataU1, + DataU2, + DataB1, + DataB2, + DataUB, + DataG, + Captured, + Foreign, + BlackHole + ), IxClosure, Callback (..), Augment (..), @@ -50,6 +65,7 @@ where import Control.Monad (when) import Control.Monad.Primitive import Data.Foldable as F (for_) +import Data.Functor (($>)) import Data.Kind qualified as Kind import Data.Sequence (Seq) import Data.Word @@ -80,7 +96,7 @@ data K !Int -- pending unboxed args !Int -- pending boxed args !(EnumSet Word64) - !(EnumMap Word64 RClosure) + !(EnumMap Word64 Closure) !K | -- save information about a frame for later resumption Push @@ -88,53 +104,114 @@ data K !Int -- boxed frame size !Int -- pending unboxed args !Int -- pending boxed args - !RComb -- local continuation reference + !CombIx -- resumption section reference + !Int -- unboxed stack guard + !Int -- boxed stack guard + !(RSection Closure) -- resumption section !K - deriving (Eq, Ord) -type RClosure = GClosure RComb +instance Eq K where + KE == KE = True + (CB cb) == (CB cb') = cb == cb' + (Mark ua ba ps m k) == (Mark ua' ba' ps' m' k') = + ua == ua' && ba == ba' && ps == ps' && m == m' && k == k' + (Push uf bf ua ba ci _ _ _sect k) == (Push uf' bf' ua' ba' ci' _ _ _sect' k') = + uf == uf' && bf == bf' && ua == ua' && ba == ba' && ci == ci' && k == k' + _ == _ = False + +instance Ord K where + compare KE KE = EQ + compare (CB cb) (CB cb') = compare cb cb' + compare (Mark ua ba ps m k) (Mark ua' ba' ps' m' k') = + compare (ua, ba, ps, m, k) (ua', ba', ps', m', k') + compare (Push uf bf ua ba ci _ _ _sect k) (Push uf' bf' ua' ba' ci' _ _ _sect' k') = + compare (uf, bf, ua, ba, ci, k) (uf', bf', ua', ba', ci', k') + compare KE _ = LT + compare _ KE = GT + compare (CB _) _ = LT + compare _ (CB _) = GT + compare (Mark _ _ _ _ _) _ = LT + compare _ (Mark _ _ _ _ _) = GT + +newtype Closure = Closure {unClosure :: (GClosure (RComb Closure))} + deriving stock (Show, Eq, Ord) type IxClosure = GClosure CombIx -type Closure = GClosure RComb - data GClosure comb - = PAp - !comb + = GPAp + !CombIx + {-# UNPACK #-} !(GCombInfo comb) {-# UNPACK #-} !(Seg 'UN) -- unboxed args {- unpack -} !(Seg 'BX) -- boxed args - | Enum !Reference !Word64 - | DataU1 !Reference !Word64 !Int - | DataU2 !Reference !Word64 !Int !Int - | DataB1 !Reference !Word64 !(GClosure comb) - | DataB2 !Reference !Word64 !(GClosure comb) !(GClosure comb) - | DataUB !Reference !Word64 !Int !(GClosure comb) - | DataG !Reference !Word64 !(Seg 'UN) !(Seg 'BX) + | GEnum !Reference !Word64 + | GDataU1 !Reference !Word64 !Int + | GDataU2 !Reference !Word64 !Int !Int + | GDataB1 !Reference !Word64 !(GClosure comb) + | GDataB2 !Reference !Word64 !(GClosure comb) !(GClosure comb) + | GDataUB !Reference !Word64 !Int !(GClosure comb) + | GDataG !Reference !Word64 !(Seg 'UN) !(Seg 'BX) | -- code cont, u/b arg size, u/b data stacks - Captured !K !Int !Int {-# UNPACK #-} !(Seg 'UN) !(Seg 'BX) - | Foreign !Foreign - | BlackHole - deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) + GCaptured !K !Int !Int {-# UNPACK #-} !(Seg 'UN) !(Seg 'BX) + | GForeign !Foreign + | GBlackHole + deriving stock (Show, Functor, Foldable, Traversable) + +instance Eq (GClosure comb) where + -- This is safe because the embedded CombIx will break disputes + a == b = (a $> ()) == (b $> ()) + +instance Ord (GClosure comb) where + compare a b = compare (a $> ()) (b $> ()) + +pattern PAp cix comb segUn segBx = Closure (GPAp cix comb segUn segBx) + +pattern Enum r t = Closure (GEnum r t) + +pattern DataU1 r t i = Closure (GDataU1 r t i) + +pattern DataU2 r t i j = Closure (GDataU2 r t i j) + +pattern DataB1 r t x <- Closure (GDataB1 r t (Closure -> x)) + where + DataB1 r t x = Closure (GDataB1 r t (unClosure x)) + +pattern DataB2 r t x y <- Closure (GDataB2 r t (Closure -> x) (Closure -> y)) + where + DataB2 r t x y = Closure (GDataB2 r t (unClosure x) (unClosure y)) + +pattern DataUB r t i y <- Closure (GDataUB r t i (Closure -> y)) + where + DataUB r t i y = Closure (GDataUB r t i (unClosure y)) + +pattern DataG r t us bs = Closure (GDataG r t us bs) + +pattern Captured k ua ba us bs = Closure (GCaptured k ua ba us bs) + +pattern Foreign x = Closure (GForeign x) + +pattern BlackHole = Closure GBlackHole traceK :: Reference -> K -> [(Reference, Int)] traceK begin = dedup (begin, 1) where dedup p (Mark _ _ _ _ k) = dedup p k - dedup p@(cur, n) (Push _ _ _ _ (RComb (CIx r _ _) _) k) + dedup p@(cur, n) (Push _ _ _ _ (CIx r _ _) _ _ _ k) | cur == r = dedup (cur, 1 + n) k | otherwise = p : dedup (r, 1) k dedup p _ = [p] -splitData :: RClosure -> Maybe (Reference, Word64, [Int], [RClosure]) -splitData (Enum r t) = Just (r, t, [], []) -splitData (DataU1 r t i) = Just (r, t, [i], []) -splitData (DataU2 r t i j) = Just (r, t, [i, j], []) -splitData (DataB1 r t x) = Just (r, t, [], [x]) -splitData (DataB2 r t x y) = Just (r, t, [], [x, y]) -splitData (DataUB r t i y) = Just (r, t, [i], [y]) -splitData (DataG r t us bs) = Just (r, t, ints us, bsegToList bs) -splitData _ = Nothing +splitData :: Closure -> Maybe (Reference, Word64, [Int], [Closure]) +splitData = \case + (Enum r t) -> Just (r, t, [], []) + (DataU1 r t i) -> Just (r, t, [i], []) + (DataU2 r t i j) -> Just (r, t, [i, j], []) + (DataB1 r t x) -> Just (r, t, [], [x]) + (DataB2 r t x y) -> Just (r, t, [], [x, y]) + (DataUB r t i y) -> Just (r, t, [i], [y]) + (DataG r t us bs) -> Just (r, t, ints us, bsegToList bs) + _ -> Nothing -- | Converts an unboxed segment to a list of integers for a more interchangeable -- representation. The segments are stored in backwards order, so this reverses @@ -153,15 +230,15 @@ useg ws = case L.fromList $ reverse ws of -- | Converts a boxed segment to a list of closures. The segments are stored -- backwards, so this reverses the contents. -bsegToList :: Seg 'BX -> [RClosure] +bsegToList :: Seg 'BX -> [Closure] bsegToList = reverse . L.toList -- | Converts a list of closures back to a boxed segment. Segments are stored -- backwards, so this reverses the contents. -bseg :: [RClosure] -> Seg 'BX +bseg :: [Closure] -> Seg 'BX bseg = L.fromList . reverse -formData :: Reference -> Word64 -> [Int] -> [RClosure] -> RClosure +formData :: Reference -> Word64 -> [Int] -> [Closure] -> Closure formData r t [] [] = Enum r t formData r t [i] [] = DataU1 r t i formData r t [i, j] [] = DataU2 r t i j @@ -176,21 +253,23 @@ frameDataSize = go 0 0 go usz bsz KE = (usz, bsz) go usz bsz (CB _) = (usz, bsz) go usz bsz (Mark ua ba _ _ k) = go (usz + ua) (bsz + ba) k - go usz bsz (Push uf bf ua ba _ k) = go (usz + uf + ua) (bsz + bf + ba) k + go usz bsz (Push uf bf ua ba _ _ _ _ k) = + go (usz + uf + ua) (bsz + bf + ba) k -pattern DataC :: Reference -> Word64 -> [Int] -> [RClosure] -> RClosure +pattern DataC :: Reference -> Word64 -> [Int] -> [Closure] -> Closure pattern DataC rf ct us bs <- (splitData -> Just (rf, ct, us, bs)) where DataC rf ct us bs = formData rf ct us bs -pattern PApV :: RComb -> [Int] -> [RClosure] -> RClosure -pattern PApV ic us bs <- - PAp ic (ints -> us) (bsegToList -> bs) +pattern PApV :: + CombIx -> RCombInfo Closure -> [Int] -> [Closure] -> Closure +pattern PApV cix rcomb us bs <- + PAp cix rcomb (ints -> us) (bsegToList -> bs) where - PApV ic us bs = PAp ic (useg us) (bseg bs) + PApV cix rcomb us bs = PAp cix rcomb (useg us) (bseg bs) -pattern CapV :: K -> Int -> Int -> [Int] -> [RClosure] -> RClosure +pattern CapV :: K -> Int -> Int -> [Int] -> [Closure] -> Closure pattern CapV k ua ba us bs <- Captured k ua ba (ints -> us) (bsegToList -> bs) where @@ -202,7 +281,7 @@ pattern CapV k ua ba us bs <- {-# COMPLETE DataC, PApV, CapV, Foreign, BlackHole #-} -marshalToForeign :: (HasCallStack) => RClosure -> Foreign +marshalToForeign :: (HasCallStack) => Closure -> Foreign marshalToForeign (Foreign x) = x marshalToForeign c = error $ "marshalToForeign: unhandled closure: " ++ show c @@ -215,7 +294,7 @@ type FP = Int type UA = MutableByteArray (PrimState IO) -type BA = MutableArray (PrimState IO) RClosure +type BA = MutableArray (PrimState IO) Closure words :: Int -> Int words n = n `div` 8 @@ -283,7 +362,7 @@ bargOnto stk sp cop cp0 (Arg2 i j) = do bargOnto stk sp cop cp0 (ArgN v) = do buf <- if overwrite - then newArray sz BlackHole + then newArray sz $ BlackHole else pure cop let loop i | i < 0 = return () @@ -527,16 +606,16 @@ peekOffBi :: (BuiltinForeign b) => Stack 'BX -> Int -> IO b peekOffBi bstk i = unwrapForeign . marshalToForeign <$> peekOff bstk i {-# INLINE peekOffBi #-} -peekOffS :: Stack 'BX -> Int -> IO (Seq RClosure) +peekOffS :: Stack 'BX -> Int -> IO (Seq Closure) peekOffS bstk i = unwrapForeign . marshalToForeign <$> peekOff bstk i {-# INLINE peekOffS #-} -pokeS :: Stack 'BX -> Seq RClosure -> IO () +pokeS :: Stack 'BX -> Seq Closure -> IO () pokeS bstk s = poke bstk (Foreign $ Wrap Ty.listRef s) {-# INLINE pokeS #-} -pokeOffS :: Stack 'BX -> Int -> Seq RClosure -> IO () +pokeOffS :: Stack 'BX -> Int -> Seq Closure -> IO () pokeOffS bstk i s = pokeOff bstk i (Foreign $ Wrap Ty.listRef s) {-# INLINE pokeOffS #-} @@ -559,7 +638,7 @@ instance Show K where where go _ KE = "]" go _ (CB _) = "]" - go com (Push uf bf ua ba ci k) = + go com (Push uf bf ua ba ci _un _bx _rsect k) = com ++ show (uf, bf, ua, ba, ci) ++ go "," k go com (Mark ua ba ps _ k) = com ++ "M " ++ show ua ++ " " ++ show ba ++ " " ++ show ps ++ go "," k @@ -569,10 +648,10 @@ instance MEM 'BX where { bap :: !Int, bfp :: !Int, bsp :: !Int, - bstk :: {-# UNPACK #-} !(MutableArray (PrimState IO) RClosure) + bstk :: {-# UNPACK #-} !(MutableArray (PrimState IO) Closure) } - type Elem 'BX = RClosure - type Seg 'BX = Array RClosure + type Elem 'BX = Closure + type Seg 'BX = Array Closure alloc = BS (-1) (-1) (-1) <$> newArray 512 BlackHole {-# INLINE alloc #-} @@ -711,24 +790,25 @@ uscount seg = words $ sizeofByteArray seg bscount :: Seg 'BX -> Int bscount seg = sizeofArray seg -closureTermRefs :: (Monoid m) => (Reference -> m) -> (RClosure -> m) -closureTermRefs f (PAp (RComb (CIx r _ _) _) _ cs) = - f r <> foldMap (closureTermRefs f) cs -closureTermRefs f (DataB1 _ _ c) = closureTermRefs f c -closureTermRefs f (DataB2 _ _ c1 c2) = - closureTermRefs f c1 <> closureTermRefs f c2 -closureTermRefs f (DataUB _ _ _ c) = - closureTermRefs f c -closureTermRefs f (Captured k _ _ _ cs) = - contTermRefs f k <> foldMap (closureTermRefs f) cs -closureTermRefs f (Foreign fo) - | Just (cs :: Seq RClosure) <- maybeUnwrapForeign Ty.listRef fo = - foldMap (closureTermRefs f) cs -closureTermRefs _ _ = mempty +closureTermRefs :: (Monoid m) => (Reference -> m) -> (Closure -> m) +closureTermRefs f = \case + PAp (CIx r _ _) _ _ cs -> + f r <> foldMap (closureTermRefs f) cs + (DataB1 _ _ c) -> closureTermRefs f c + (DataB2 _ _ c1 c2) -> + closureTermRefs f c1 <> closureTermRefs f c2 + (DataUB _ _ _ c) -> + closureTermRefs f c + (Captured k _ _ _ cs) -> + contTermRefs f k <> foldMap (closureTermRefs f) cs + (Foreign fo) + | Just (cs :: Seq Closure) <- maybeUnwrapForeign Ty.listRef fo -> + foldMap (closureTermRefs f) cs + _ -> mempty contTermRefs :: (Monoid m) => (Reference -> m) -> K -> m contTermRefs f (Mark _ _ _ m k) = foldMap (closureTermRefs f) m <> contTermRefs f k -contTermRefs f (Push _ _ _ _ (RComb (CIx r _ _) _) k) = +contTermRefs f (Push _ _ _ _ (CIx r _ _) _ _ _ k) = f r <> contTermRefs f k contTermRefs _ _ = mempty diff --git a/unison-runtime/tests/Unison/Test/Runtime/MCode.hs b/unison-runtime/tests/Unison/Test/Runtime/MCode.hs index 58118cf120..daaf61ea69 100644 --- a/unison-runtime/tests/Unison/Test/Runtime/MCode.hs +++ b/unison-runtime/tests/Unison/Test/Runtime/MCode.hs @@ -10,7 +10,9 @@ import Data.Map.Strict qualified as Map import EasyTest import Unison.Reference (Reference, Reference' (Builtin)) import Unison.Runtime.ANF - ( SuperGroup (..), + ( Cacheability (..), + Code (..), + SuperGroup (..), lamLift, superNormalize, ) @@ -38,11 +40,12 @@ testEval0 :: [(Reference, SuperGroup Symbol)] -> SuperGroup Symbol -> Test () testEval0 env main = ok << io do cc <- baseCCache False - _ <- cacheAdd ((mainRef, main) : env) cc + _ <- cacheAdd ((fmap . fmap) uncacheable $ (mainRef, main) : env) cc rtm <- readTVarIO (refTm cc) apply0 Nothing cc Nothing (rtm Map.! mainRef) where (<<) = flip (>>) + uncacheable sg = CodeRep sg Uncacheable multRec :: String multRec = diff --git a/unison-runtime/unison-runtime.cabal b/unison-runtime/unison-runtime.cabal index ea54c20b6a..33650d1944 100644 --- a/unison-runtime/unison-runtime.cabal +++ b/unison-runtime/unison-runtime.cabal @@ -133,6 +133,7 @@ library , unison-pretty-printer , unison-syntax , unison-util-bytes + , unison-util-recursion , unliftio , vector default-language: Haskell2010 diff --git a/unison-src/builtin-tests/interpreter-tests.sh b/unison-src/builtin-tests/interpreter-tests.sh index e1f3e5c05e..94c0aeea4b 100755 --- a/unison-src/builtin-tests/interpreter-tests.sh +++ b/unison-src/builtin-tests/interpreter-tests.sh @@ -4,7 +4,7 @@ set -ex ucm=$(stack exec -- which unison) echo "$ucm" -runtime_tests_version="@unison/runtime-tests/releases/0.0.1" +runtime_tests_version="@unison/runtime-tests/releases/0.0.2" echo $runtime_tests_version codebase=${XDG_CACHE_HOME:-"$HOME/.cache"}/unisonlanguage/runtime-tests.unison diff --git a/unison-src/builtin-tests/jit-tests.sh b/unison-src/builtin-tests/jit-tests.sh index 1cba258c06..bd3464b4ab 100755 --- a/unison-src/builtin-tests/jit-tests.sh +++ b/unison-src/builtin-tests/jit-tests.sh @@ -8,7 +8,7 @@ if [ -z "$1" ]; then exit 1 fi -runtime_tests_version="@unison/runtime-tests/releases/0.0.1" +runtime_tests_version="@unison/runtime-tests/releases/0.0.2" echo $runtime_tests_version codebase=${XDG_CACHE_HOME:-"$HOME/.cache"}/unisonlanguage/runtime-tests.unison diff --git a/unison-src/transcripts-manual/gen-racket-libs.md b/unison-src/transcripts-manual/gen-racket-libs.md index d1e3818a26..b3137a636d 100644 --- a/unison-src/transcripts-manual/gen-racket-libs.md +++ b/unison-src/transcripts-manual/gen-racket-libs.md @@ -4,7 +4,7 @@ When we start out, `./scheme-libs/racket` contains a bunch of library files that Next, we'll download the jit project and generate a few Racket files from it. ```ucm -jit-setup/main> lib.install @unison/internal/releases/0.0.20 +jit-setup/main> lib.install @unison/internal/releases/0.0.21 ``` ```unison diff --git a/unison-src/transcripts-manual/gen-racket-libs.output.md b/unison-src/transcripts-manual/gen-racket-libs.output.md index 3def8b4636..9586cc8d72 100644 --- a/unison-src/transcripts-manual/gen-racket-libs.output.md +++ b/unison-src/transcripts-manual/gen-racket-libs.output.md @@ -3,12 +3,12 @@ When we start out, `./scheme-libs/racket` contains a bunch of library files that Next, we'll download the jit project and generate a few Racket files from it. ``` ucm -jit-setup/main> lib.install @unison/internal/releases/0.0.20 +jit-setup/main> lib.install @unison/internal/releases/0.0.21 - Downloaded 14935 entities. + Downloaded 14985 entities. - I installed @unison/internal/releases/0.0.20 as - unison_internal_0_0_20. + I installed @unison/internal/releases/0.0.21 as + unison_internal_0_0_21. ``` ``` unison diff --git a/unison-src/transcripts-using-base/random-deserial.md b/unison-src/transcripts-using-base/random-deserial.md index 2c6ff77de5..5ceb2900d4 100644 --- a/unison-src/transcripts-using-base/random-deserial.md +++ b/unison-src/transcripts-using-base/random-deserial.md @@ -25,15 +25,20 @@ shuffle = runTestCase : Text ->{Exception,IO} (Text, Test.Result) runTestCase name = - sfile = directory ++ name ++ ".v4.ser" - lsfile = directory ++ name ++ ".v3.ser" + sfile = directory ++ name ++ ".v5.ser" + ls3file = directory ++ name ++ ".v3.ser" + ls4file = directory ++ name ++ ".v4.ser" ofile = directory ++ name ++ ".out" - hfile = directory ++ name ++ ".v4.hash" + hfile = directory ++ name ++ ".v5.hash" p@(f, i) = loadSelfContained sfile - pl@(fl, il) = - if fileExists lsfile - then loadSelfContained lsfile + pl3@(fl3, il3) = + if fileExists ls3file + then loadSelfContained ls3file + else p + pl4@(fl4, il4) = + if fileExists ls4file + then loadSelfContained ls4file else p o = fromUtf8 (readFile ofile) h = readFile hfile @@ -43,8 +48,10 @@ runTestCase name = then Fail (name ++ " output mismatch") else if not (toBase32 (crypto.hash Sha3_512 p) == h) then Fail (name ++ " hash mismatch") - else if not (fl il == f i) - then Fail (name ++ " legacy mismatch") + else if not (fl3 il3 == f i) + then Fail (name ++ " legacy v3 mismatch") + else if not (fl4 il4 == f i) + then Fail (name ++ " legacy v4 mismatch") else Ok name (name, result) diff --git a/unison-src/transcripts-using-base/random-deserial.output.md b/unison-src/transcripts-using-base/random-deserial.output.md index 6c68e978ec..316132ed4d 100644 --- a/unison-src/transcripts-using-base/random-deserial.output.md +++ b/unison-src/transcripts-using-base/random-deserial.output.md @@ -25,15 +25,20 @@ shuffle = runTestCase : Text ->{Exception,IO} (Text, Test.Result) runTestCase name = - sfile = directory ++ name ++ ".v4.ser" - lsfile = directory ++ name ++ ".v3.ser" + sfile = directory ++ name ++ ".v5.ser" + ls3file = directory ++ name ++ ".v3.ser" + ls4file = directory ++ name ++ ".v4.ser" ofile = directory ++ name ++ ".out" - hfile = directory ++ name ++ ".v4.hash" + hfile = directory ++ name ++ ".v5.hash" p@(f, i) = loadSelfContained sfile - pl@(fl, il) = - if fileExists lsfile - then loadSelfContained lsfile + pl3@(fl3, il3) = + if fileExists ls3file + then loadSelfContained ls3file + else p + pl4@(fl4, il4) = + if fileExists ls4file + then loadSelfContained ls4file else p o = fromUtf8 (readFile ofile) h = readFile hfile @@ -43,8 +48,10 @@ runTestCase name = then Fail (name ++ " output mismatch") else if not (toBase32 (crypto.hash Sha3_512 p) == h) then Fail (name ++ " hash mismatch") - else if not (fl il == f i) - then Fail (name ++ " legacy mismatch") + else if not (fl3 il3 == f i) + then Fail (name ++ " legacy v3 mismatch") + else if not (fl4 il4 == f i) + then Fail (name ++ " legacy v4 mismatch") else Ok name (name, result) diff --git a/unison-src/transcripts-using-base/serial-test-00.md b/unison-src/transcripts-using-base/serial-test-00.md index 21860243e3..d1a0b8e282 100644 --- a/unison-src/transcripts-using-base/serial-test-00.md +++ b/unison-src/transcripts-using-base/serial-test-00.md @@ -64,7 +64,7 @@ mkTestCase = do f = evaluate balancedSum catenate tup = (tree0, tree1, tree2, tree3) - saveTestCase "case-00" "v4" f tup + saveTestCase "case-00" "v5" f tup ``` ```ucm diff --git a/unison-src/transcripts-using-base/serial-test-00.output.md b/unison-src/transcripts-using-base/serial-test-00.output.md index ce996f93ba..4483682980 100644 --- a/unison-src/transcripts-using-base/serial-test-00.output.md +++ b/unison-src/transcripts-using-base/serial-test-00.output.md @@ -64,7 +64,7 @@ mkTestCase = do f = evaluate balancedSum catenate tup = (tree0, tree1, tree2, tree3) - saveTestCase "case-00" "v4" f tup + saveTestCase "case-00" "v5" f tup ``` ``` ucm diff --git a/unison-src/transcripts-using-base/serial-test-01.md b/unison-src/transcripts-using-base/serial-test-01.md index bc5f84af0d..7d5f1ffa07 100644 --- a/unison-src/transcripts-using-base/serial-test-01.md +++ b/unison-src/transcripts-using-base/serial-test-01.md @@ -12,7 +12,7 @@ combines = cases "(" ++ toText rx ++ ", " ++ toText ry ++ ", \"" ++ rz ++ "\")" mkTestCase = do - saveTestCase "case-01" "v4" combines (l1, l2, l3) + saveTestCase "case-01" "v5" combines (l1, l2, l3) ``` ```ucm diff --git a/unison-src/transcripts-using-base/serial-test-01.output.md b/unison-src/transcripts-using-base/serial-test-01.output.md index a6654a2547..f2734eb118 100644 --- a/unison-src/transcripts-using-base/serial-test-01.output.md +++ b/unison-src/transcripts-using-base/serial-test-01.output.md @@ -12,7 +12,7 @@ combines = cases "(" ++ toText rx ++ ", " ++ toText ry ++ ", \"" ++ rz ++ "\")" mkTestCase = do - saveTestCase "case-01" "v4" combines (l1, l2, l3) + saveTestCase "case-01" "v5" combines (l1, l2, l3) ``` ``` ucm diff --git a/unison-src/transcripts-using-base/serial-test-02.md b/unison-src/transcripts-using-base/serial-test-02.md index 15518165a0..06a6d255f1 100644 --- a/unison-src/transcripts-using-base/serial-test-02.md +++ b/unison-src/transcripts-using-base/serial-test-02.md @@ -25,7 +25,7 @@ products = cases (x, y, z) -> "(" ++ toText px ++ ", " ++ toText py ++ ", \"" ++ toText pz ++ "\")" mkTestCase = do - saveTestCase "case-02" "v4" products (l1, l2, l3) + saveTestCase "case-02" "v5" products (l1, l2, l3) ``` diff --git a/unison-src/transcripts-using-base/serial-test-02.output.md b/unison-src/transcripts-using-base/serial-test-02.output.md index 102fea092b..08339ffd0f 100644 --- a/unison-src/transcripts-using-base/serial-test-02.output.md +++ b/unison-src/transcripts-using-base/serial-test-02.output.md @@ -25,7 +25,7 @@ products = cases (x, y, z) -> "(" ++ toText px ++ ", " ++ toText py ++ ", \"" ++ toText pz ++ "\")" mkTestCase = do - saveTestCase "case-02" "v4" products (l1, l2, l3) + saveTestCase "case-02" "v5" products (l1, l2, l3) ``` diff --git a/unison-src/transcripts-using-base/serial-test-03.md b/unison-src/transcripts-using-base/serial-test-03.md index 2e66f687d9..c7b514de72 100644 --- a/unison-src/transcripts-using-base/serial-test-03.md +++ b/unison-src/transcripts-using-base/serial-test-03.md @@ -40,7 +40,7 @@ finish = cases (x, y, z) -> mkTestCase = do trip = (suspSum l1, suspSum l2, suspSum l3) - saveTestCase "case-03" "v4" finish trip + saveTestCase "case-03" "v5" finish trip ``` ```ucm diff --git a/unison-src/transcripts-using-base/serial-test-03.output.md b/unison-src/transcripts-using-base/serial-test-03.output.md index a20eafe7f6..824cab1a39 100644 --- a/unison-src/transcripts-using-base/serial-test-03.output.md +++ b/unison-src/transcripts-using-base/serial-test-03.output.md @@ -40,7 +40,7 @@ finish = cases (x, y, z) -> mkTestCase = do trip = (suspSum l1, suspSum l2, suspSum l3) - saveTestCase "case-03" "v4" finish trip + saveTestCase "case-03" "v5" finish trip ``` ``` ucm diff --git a/unison-src/transcripts-using-base/serial-test-04.md b/unison-src/transcripts-using-base/serial-test-04.md index 212b59c9e0..210b42796a 100644 --- a/unison-src/transcripts-using-base/serial-test-04.md +++ b/unison-src/transcripts-using-base/serial-test-04.md @@ -10,7 +10,7 @@ mutual1 n = mutual0 n mkTestCase = do - saveTestCase "case-04" "v4" mutual1 5 + saveTestCase "case-04" "v5" mutual1 5 ``` ```ucm diff --git a/unison-src/transcripts-using-base/serial-test-04.output.md b/unison-src/transcripts-using-base/serial-test-04.output.md index 0c045e097d..bb6a6c5fa0 100644 --- a/unison-src/transcripts-using-base/serial-test-04.output.md +++ b/unison-src/transcripts-using-base/serial-test-04.output.md @@ -10,7 +10,7 @@ mutual1 n = mutual0 n mkTestCase = do - saveTestCase "case-04" "v4" mutual1 5 + saveTestCase "case-04" "v5" mutual1 5 ``` ``` ucm diff --git a/unison-src/transcripts-using-base/serialized-cases/case-00.v5.hash b/unison-src/transcripts-using-base/serialized-cases/case-00.v5.hash new file mode 100644 index 0000000000..181c564dc3 --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-00.v5.hash @@ -0,0 +1 @@ +Z6EW6IDZJXHDMNGTVSKYLMZVG47ORYF4O6JDQXQGQFJP476SLM75FXFOYI27OJHMIX5OIHKQ6LXWLYQ5LDGEYWEXK6GQPP6JKH6SVMI= \ No newline at end of file diff --git a/unison-src/transcripts-using-base/serialized-cases/case-00.v5.ser b/unison-src/transcripts-using-base/serialized-cases/case-00.v5.ser new file mode 100644 index 0000000000..afdd5055e3 --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-00.v5.ser @@ -0,0 +1 @@ +AAAAABIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQCAYBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQEAABEEACITAXWMOCQYHP2S67NQK5TVVWHTWRHFIEUOIEFN74DGYKE2OBEPAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGBQAAQAQCAIBAYAAIAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAIAAAAIBAEBQCAIBBMAACAIBAMAQCIIAERGBPMY4FBQO7VF563AV3HLLMPHNCOKQJI4QIK37YGNQUJU4CI6AABAGAUCAECYAAIAQCAYAA4AQECYAAMAQCAYBAEQQAJCMC6ZRYKDA57KL35WBLWOWWY6O2E4VASRZAQVX7QM3BITJYER4AACAQBYGAIFQABABAEBQACACAEAAGAAJAIBQAAAAAEAUAABP6FJQWQ7SCDU3JWOKBXLTS6QCY2USLMHUBPFRDGDT7LHPHKJWHDVXD7SD5OFSIBT3BJDDZO4PDQZQ2SBWHU3L5YTB5F7CPGHUZUBAAAAAAAAAAAAAAAAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDAIAACIIAHDXRRIMB4F6FH4J44EBLP3BIFABO6BS5DLJQ4I7Z27OHFVQB5AUQAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMDAAAIBAEAAAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGAQAAEQQBCLQUZTNWT6XVBNC7BA7RZ2HQDESXNE6HF6TC7W2SFPNUPVZUMHAAAAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYGAABQCAIBAYAAIAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAEAAEAIBAYAAIAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAEAAEAIBAYAAIAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAEAAEAIBAYAAIAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAEAAEAIBAYAAIAKAAAX7CUYLIPZBB2NU3HFA3VZZPIBMNKJFWD2AXSYRTBZ7VTXTVE3DR23R7ZB6XCZEAZ5QURR4XOHRYMYNJA3D2NV64JQ6S7RHTD2M2AQAAEAAACYABYAQCAYABIAQOCYABUAQCAYABMAQMCYABQAQCAYABQAQKCYABMAQCAYABQAQICQBAEDQGAJIBMAACAIBAMAQACSOMF2C45DPKRSXQ5ABAQFQAAQBAEBQCAAHKRSXQ5BOFMVQEAIABIAQCBYDAIWCACYAAMAQCAYBAADVIZLYOQXCWKYCAEAAWAAEAEAQGAIABJHGC5BOORXVIZLYOQAQOCYAAUAQCAYBAADVIZLYOQXCWKYCAEAAUAIBA4BQELBABMAAMAIBAMAQAB2UMV4HILRLFMBACAALAADQCAIDAEAAUTTBOQXHI32UMV4HIAIKBMAAQAIBAMAQAB2UMV4HILRLFMBACAAKAEAQOAYCFQQAWAAJAEAQGAIAA5KGK6DUFYVSWAQBAAFQACQBAEBQCAAHKRSXQ5BOFMVQEAANBIAQCBYDAEUQGAIAA5KGK6DUFYVSWAQBAAAAAAAAAAAACAKAAAX7CUYLIPZBB2NU3HFA3VZZPIBMNKJFWD2AXSYRTBZ7VTXTVE3DR23R7ZB6XCZEAZ5QURR4XOHRYMYNJA3D2NV64JQ6S7RHTD2M2AQAAAAAAAAAAAAAAAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQKAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAAASCAEJOCTGNW2P26UFUL4ED6HHI6AMSK5UTY4X2ML63KIV5WR6XGRQ4AAAAAAAAAAAAAAAAIAACIIAERGBPMY4FBQO7VF563AV3HLLMPHNCOKQJI4QIK37YGNQUJU4CI6AAAAAAAAAAAAAAABQAAJBAA4O6GFBQHQXYU7RHTQQFN7MFAUAF3YGLUNNGDRD7HL5Y4WWAHUCSAAAAAAAAAAAAAAAAAAAAVHGC5BOFMAAAAAAAAAAAAAAAMEAAAABEEACITAXWMOCQYHP2S67NQK5TVVWHTWRHFIEUOIEFN74DGYKE2OBEPAAAAAAAAAAAAAAAAYAAEQQAOHPDCQYDYL4KPYTZYICW7WCQKAC54DF2GWTBYR7TV64OLLAD2BJAAAAAAAAAAAAAAAAAAAAOVDFPB2C4KZLAAAAAAAAAAAAAAADAAAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAQGAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAIDAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAAAAGCACAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAAAAGCABAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAEBQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAAAAADBABQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAACAYBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAAAAABQQBABAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAAAAAAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAIDAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAEBQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAACAYBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAAAAABQQAQBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAAAAABQQAIBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAABAMAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAAAAYIAMAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAQGAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEAIAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEAAAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAIDAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAEBQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAACAYBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAAAAABQQBYBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAAAAABQQBQBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAABAMAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAAAAYIBAAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAQGAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEASAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEAKAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABACAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAACAYBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAABAMAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAQGAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEAEAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEACAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAIDAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAAAAGCADAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAEBQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAAAAADBACACAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAAAAADBAFACAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAACAYBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAABAMAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAQGAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEAEAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEACAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAIDAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAAAAGCADAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAEBQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAAAAADBACACAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAAAAADBAAACAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAACAYBAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAABAMAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAQGAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEAOAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAAAAMEAMAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAIDAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAAAAGCAIAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAEBQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAAAAADBAEQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAAAAADBACQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAAAAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAQGAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAIDAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAAAAGAAFNBSWY3DPAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAAAAGAABEAAQCQFLNOASV6MR5HG6P3HFFKN2IW7E4DK75AL4PFVOBRGHLB55BOHFMRTBHEHGBWKEQOK5SZZZ7AXGFJUNVTX7PRKUK2DUMTL4ERO7HQAPYAAAAAAAAAAAAAAQGAIBICVWXAJK7GI6TTPH5TSSVG5ELPSOBVP6QF6HS2XAYTDVQ66QXDSWIZQTSDTA3FCIHFOZM447QLTCU2G2Z37XYVKFNB2GJV6CIXPTYAH4AAAAAAAAAAAAAAIDAEAUBK3LQEVPTEPJZXT6ZZJKTOSFXZHA2X7IC7DZNLQMJR2YPPILRZLEMYJZBZQNSREDSXMWOOPYFZRKNDNM5734KVCWQ5DE27BELXZ4AD6AAAAAAAAAAAAAAAAAGAAEM5XW6ZABAFAKW24BFL4ZD2ON47WOKKU3URN6JYGV72AXY6LK4DCMOWD32C4OKZDGCOIOMDMUJA4V3FTTT6BOMKTI3LHP67CVIVUHIZGXYJC56PAA7QAAAAAAAAAAAAAAAABQAA3CPFSQCAKAVNVYCKXZSHU43Z7M4UVJXJC34TQNL7UBPR4WVYGEY5MHXUFY4VSGME4Q4YGZISBZLWLHHH4C4YVGRWWO756FKRLIORSNPQSF346AB7AAAAAAAAAAAAAAAAABAFAAAL7RKMFUH4QQ5G2NTSQN244XUAWGVES3B5ALZMIZQ472Z3Z2SNRY5NY74Q7LRMSAM6YKIY6LXDY4GMGUQNR5G27OEYPJPYTZR5GNAIAAAAAAAAAAAAAAAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAA \ No newline at end of file diff --git a/unison-src/transcripts-using-base/serialized-cases/case-01.v5.hash b/unison-src/transcripts-using-base/serialized-cases/case-01.v5.hash new file mode 100644 index 0000000000..d576afd225 --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-01.v5.hash @@ -0,0 +1 @@ +F5QWFLMAWQDYCMOPDCCTYLWJ2HOBGUG2G5YLWHSAFGDXSHGYQIWDSN6PVWC2RJXIGB7ZBSZVIJ6OENKGWAEZIV3CLQ2AWL3WKITPDXA= \ No newline at end of file diff --git a/unison-src/transcripts-using-base/serialized-cases/case-01.v5.ser b/unison-src/transcripts-using-base/serialized-cases/case-01.v5.ser new file mode 100644 index 0000000000..071ca615cb --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-01.v5.ser @@ -0,0 +1 @@ +AAAAABIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQCBABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQEAABEEAFG5MMPCUOP3IIQXASYKKG2MIJ2XJ3B7MGFL6E44DZUAQUNLQVKHIAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGBQAAMAQCAIKAEAQYAIAAAAAAAAAAAAAGAIBEEAO7KOJ7HCZGJXDGV7GZE7OLVCVEIO5QE4Y6TLY67FZSQS6DUK2SVYAAQAQGAQAAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMBAAAJBACAVWVMCTIBA5P5JFQIRMCJBBMWMLBPXDOTQRHHF76XEAPI46LZWWAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQMAABAEDAABABIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAQAAQBAEDAABABIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAQAAQBAEDAABABIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAQAAQBAEDAABABIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAQAAALAAAQCAIDAEAAORTMN5QXILRLAAFACAIMAIAAAAAAAAAAAAALAAGQCAIDAEASCACTOWGHRKHH5UEILQJMFFDNGEE5LU5Q7WDCV7COOB42AIKGVYKVDUAAGAIAA4FQAAQBAEBQCAAFJFXHILRLAAFACAIMAAAAAAAAAAAAAAALAAGACAIDAEASCACTOWGHRKHH5UEILQJMFFDNGEE5LU5Q7WDCV7COOB42AIKGVYKVDUAAGAIABAFQAAYBAEBQCAJBACKBUK5CBIZUMPZQELVRT4XZEUX7KCXBOZMJE7YZOIMHLEHMX4UEEAAABIAQCBYDAAFQACYBAEBQCAJBABJXLDDYVDT62CEFYEWCSRWTCCOV2OYP3BRK7RHHA6NAEFDK4FKR2AADAEAASCQBAEDQGAJIBMAAIAIBAMAQADCGNRXWC5BOORXVIZLYOQAQOCYAAUAQCAYBAADVIZLYOQXCWKYCAEAAUAIBA4BQELBABMAAMAIBAMAQAB2UMV4HILRLFMBACAALAADQCAIDAEAAUSLOOQXHI32UMV4HIAIIBMAAQAIBAMAQAB2UMV4HILRLFMBACAAKAEAQOAYDFQQCECYABEAQCAYBAADVIZLYOQXCWKYCAEAAWAAKAEAQGAIAA5KGK6DUFYVSWAQABEFACAIHAMBCEKIDAEAAOVDFPB2C4KZLAIAQAAAAAAAAAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGAQAAEQQBFA2FORAUM2GH4YCF2YZ6L4SKL7VBLQXMWESP4MXEGDVSDWL6KCCAAAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYGAABACAILAAAQCAIDAEAAWQ3IMFZC45DPKRSXQ5ABAABQCAAHKRSXQ5BOFMVQEAQAAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMBAAAJBADX2TSPZYWJSNYZVPZWJH3S5IVJCDXMBHGHU26HXZOMUEXQ5CWUVOAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQMAAEAEAQCAILAABQCAIDAEAAOTDJON2C4YLUAIAAGBQAAQAUBPFXSLRYBUMTQI4D4TSH2NNNUNKNR3L447EHJZMO3DMA3FE3H7JJBKRQSX7O7KXGBYVP5635Y6GI6DVXFPYHJ2YVBLSZV6TR5NYFZLZAAAQAAEAQWAABAEAQGAAEAIBQACQBAEGACAAAAAAAAAAAAEFQAAQBAEBQCAAFJZQXILRLAICAAAYBAEQQB35JZH44LEZG4M2X43ET5ZOUKURB3WATTD2NPD34XGKCLYORLKKXAACAQBYCAAAQAAICAAAACAKAAAX7CUYLIPZBB2NU3HFA3VZZPIBMNKJFWD2AXSYRTBZ7VTXTVE3DR23R7ZB6XCZEAZ5QURR4XOHRYMYNJA3D2NV64JQ6S7RHTD2M2AQAAAAAAAAAAAAAAAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQKAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAAASCAEBLNKYFGQCB272SLARCYESCCZMYWC7OG5HBCOOL75OIA6RZ4XTNMAAAAAAAAAAAAAAAAAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMAQGAYLH7YAAAAAAAAAAAYLIAAAAAAAAAAAAAYLIAEAAAAAAAAAAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMAQGAYIAEBQQAQDBABQCAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDAEBQGCTBAMFGEAYKMMAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAAAEAUAABP6FJQWQ7SCDU3JWOKBXLTS6QCY2USLMHUBPFRDGDT7LHPHKJWHDVXD7SD5OFSIBT3BJDDZO4PDQZQ2SBWHU3L5YTB5F7CPGHUZUBAAAAAAAAAAAAAAAAA==== \ No newline at end of file diff --git a/unison-src/transcripts-using-base/serialized-cases/case-02.v5.hash b/unison-src/transcripts-using-base/serialized-cases/case-02.v5.hash new file mode 100644 index 0000000000..f7f6926bc2 --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-02.v5.hash @@ -0,0 +1 @@ +OKXJPQQY4QXSCGDHM2LSUTSIKWE7W5PS6CSYCKBOEOBTRKHOKWTH6QZP7HEVWPEJC5CWGWB54ZPI7YB36F37MXN7ISPCP5JGX26NRBQ= \ No newline at end of file diff --git a/unison-src/transcripts-using-base/serialized-cases/case-02.v5.ser b/unison-src/transcripts-using-base/serialized-cases/case-02.v5.ser new file mode 100644 index 0000000000..0257e72254 --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-02.v5.ser @@ -0,0 +1 @@ +AAAAABIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQCBIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQEAABEEAAYIUEFZ4JEHYKKJOYXA3U4QEFR2C7BDWZX43W26BCDHYJLM2O2UYAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGBQAAIAQCCYAAIAQCAYBAAFEY2LTOQXHM2LFO5WACAAGAACACQBXUUCXAJCWUDKCCPAAZUOSPHG5OAQWM7RAIACNQG5HLXLG25SJ6V4VM43AO7YPRRQOZDZQ6GRWPWODX4EPCCQUPWP5K4RWURF7N2IYQAACAABACAIGAEDAAA2OMF2ACAAAAAAAAAAAAAFACAIMAEAAAAAAAAAAAAADAQAUAMY65NCSULNIGUIJ26OXZM426I623Z65KBOZEJNZZYM7LU57JG7EVXPBXX6OFMJZQKWUPCI3PXACLDTU7NZUWCBSXG2XRNZ7IM23NWTQAAABAAAQWAABAEAQGAIAAVHGC5BOFIBAIAIDAEASCAAMEKCC46ESD4FFEXMLQN2OICCY5BPQR3M36N3NPARBT4EVWNHNKMAAEAABAEAACAQAAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMBAAAJBAAQQUM3BJ2CBV2DRYDFJVT73O4QXWQ2FFGAQ65UETP5ZKJGMQUOPIAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQMAABAEDAABABIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAQAAQBAEDAABABIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAQAAQBAEDAABABIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAQAAQBAEDAABABIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAQAAALAAFQCAIDAEASCAHMBCFOX4WLK3FQIFDLLBB3ZZQPJHUEKONSUX2NJGCJJSHMAWVAHQAACBILAAFACAIDAEASCAHMBCFOX4WLK3FQIFDLLBB3ZZQPJHUEKONSUX2NJGCJJSHMAWVAHQAACBALAAEQCAIDAEASCAHMBCFOX4WLK3FQIFDLLBB3ZZQPJHUEKONSUX2NJGCJJSHMAWVAHQAACAYKAEAQOAYBFAFQAAIBAEBQCAAKJZQXILTUN5KGK6DUAEBQWAACAEAQGAIAA5KGK6DUFYVSWAQBAAFACAIHAMBCYIALAABQCAIDAEAAOVDFPB2C4KZLAIAQACYAAQAQCAYBAAFE4YLUFZ2G6VDFPB2ACBQLAACQCAIDAEAAOVDFPB2C4KZLAIAQACQBAEDQGAZMEARAWAAGAEAQGAIAA5KGK6DUFYVSWAQBAAFQABYBAEBQCAAKJZQXILTUN5KGK6DUAEEQWAAIAEAQGAIAA5KGK6DUFYVSWAQBAAFACAIHAMBCEKIDAEAAOVDFPB2C4KZLAIAQAAAAAAAAAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGAQAAEQQAZBETA2YKUQSP2CMAM3N7CPNDHRXDY2J6ZCJ4PQFN3I32GWQGMJTAAAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYGAEAQCBQAAIAQCQBTD3VUKKRNVA2RBHLZ27FTTLZD3LPH3VIF3ERFXHHBT5OTX5E34SW54G67ZYVRHGBK2R4JDN64AJMOOT5XGSYIGK43K6FXH5BTLNW2OAABAAAQCBIBIAZR522FFIW2QNIQTV45PSZZV4R5VXT52UC5SIS3TTQZ6XJ36SN6JLO6DPP44KYTTAVNI6ERW7OAEWHHJ63TJMEDFONVPC3T6QZVW3NHAAEAACDKOVWXAQ3PNZ2ACAABAIAQAAIBBEAQABABAFADGHXLIUVC3KBVCCOXTV6LHGXSHWW6PXKQLWJCLOOODH25HP2JXZFN3YN57TRLCOMCVVDYSG35YASY45H3ONFQQMVZWV4LOP2DGW3NU4AAAAQBAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMBAAAJBABTRHHJSOELTLHBAUQWOZQU2H5SUAC5SDOJNUSQDJ2NEYRSZ4RBDQAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQMAABAEFACAIMAEAAAAAAAAAAAAADAEASCAAMEKCC46ESD4FFEXMLQN2OICCY5BPQR3M36N3NPARBT4EVWNHNKMAAEAABAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMBAAAJBADWARCXL6LFVNSYECRVVQQ544YHUT2CFHGZKL5GUTBEUZDWALKQDYAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQMAABAEFQAAIBAEBQCAJBABSCJGBVQVJBE7UEYAZW36E62GPDOHRUT5SETY7AK3WRXUNNAMYTGAAABAASCADHCOOTE4IXGWOCBJBM5TBJUP3FIAF3EG4S3JFAGTU2JRDFTZCCHAAACAIDAAAQCAAAAEAUAABP6FJQWQ7SCDU3JWOKBXLTS6QCY2USLMHUBPFRDGDT7LHPHKJWHDVXD7SD5OFSIBT3BJDDZO4PDQZQ2SBWHU3L5YTB5F7CPGHUZUBAAAAAAAAAAAAAAAAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDAUAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAABEEACCCRTMFHIIGXIOHAMVGWP7N3SC62DIUUYCD3WQSN7XFJEZSCRZ5AAAAAAAAAAAAAAAAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYBAUBQQAIDBABQGCAFAMEAOAYIBEAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYBBEBQQAIDBABAGCAAAMEAGAYIAQBQQBIDBADAGCAHAMEAQAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMAQQAYIAEBQQAQDBACAGCAIAMEBAAYIAMBQQBIDBADACAKAAAX7CUYLIPZBB2NU3HFA3VZZPIBMNKJFWD2AXSYRTBZ7VTXTVE3DR23R7ZB6XCZEAZ5QURR4XOHRYMYNJA3D2NV64JQ6S7RHTD2M2AQAAAAAAAAAAAAAAAABAFAAAL7RKMFUH4QQ5G2NTSQN244XUAWGVES3B5ALZMIZQ472Z3Z2SNRY5NY74Q7LRMSAM6YKIY6LXDY4GMGUQNR5G27OEYPJPYTZR5GNAIAAAAAAAAAAAAAAAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAA=== \ No newline at end of file diff --git a/unison-src/transcripts-using-base/serialized-cases/case-03.v5.hash b/unison-src/transcripts-using-base/serialized-cases/case-03.v5.hash new file mode 100644 index 0000000000..3b39c4aee9 --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-03.v5.hash @@ -0,0 +1 @@ +DLSO2TFPG5363MWC7FDSUW55VYA7P7CI4DBRFLWGPSUTF6YR45QPIPBSJPANZH44MGVYRSSMTPXODLDUFCO6JF43V3IPU4DRDU7JKII= \ No newline at end of file diff --git a/unison-src/transcripts-using-base/serialized-cases/case-03.v5.ser b/unison-src/transcripts-using-base/serialized-cases/case-03.v5.ser new file mode 100644 index 0000000000..f0188e6737 --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-03.v5.ser @@ -0,0 +1 @@ +AAAAABIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQCCIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQEAABEEAAOT2MXCZHSMGAQPMEZKCLBK4QHW54TGGJGIN2ZSOFWF4ATCCIDMQAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGBQBAEAQMAACAEAUAN3GIMROJ5IWBPMSHX64WVGJX6EVR6NCKICJCW2N4SPLQXPT6PXCXZDZJLMCA6CDITYETZT5R2CPBEKIKXQMMHVEFHUWQ6BSLO5APT5AAAIAAEAQKAKAG5TEGIXE6ULAXWJD37OLKTE37CKY7GRFEBERLNG6JHVYLXZ7H3RL4R4UVWBAPBBUJ4CJ4Z6Y5BHQSFEFLYGGD2SCT2LIPAZFXOQHZ6QABAAAQ2TVNVYEG33OOQAQACYAAEAQCAYBAEQQAB2PJS4LE6JQYCB5QTFIJMFLSA63XSMYZEZBXLGJYWYXQCMIJANSAEAQAAYAAMAQAAIAAEAQSAIAAQAQCQBXMZBSFZHVCYF5SI673S2UZG7YSWHZUJJAJEK3JXSJ5OC56PZ64K7EPFFNQIDYINCPASPGPWHIJ4ERJBK6BRQ6UQU6S2DYGJN3UB6PUAAAAIAQAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGAQAAEQQAB2PJS4LE6JQYCB5QTFIJMFLSA63XSMYZEZBXLGJYWYXQCMIJANSAEAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYGAABACAILAAAQCAIDAEASCAAHJ5GLRMTZGDAIHWCMVBFQVOID3O6JTDETEG5MZHC3C6AJRBEBWIAAACABEEANR5YMZ4O453FLTU6EFVRUUPWHXYW6TUZGJMG5CJVPJJYYAJA5VZIAAIBACAYAAEAQAAABAFAAAL7RKMFUH4QQ5G2NTSQN244XUAWGVES3B5ALZMIZQ472Z3Z2SNRY5NY74Q7LRMSAM6YKIY6LXDY4GMGUQNR5G27OEYPJPYTZR5GNAIAAAAAAAAAAAAAAAAAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYCAAASCABD4J3OKKBTZLPQBBAFHIQYPQADAQXNC3RHA5YKBV72ZGYDNKNQSIAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDAYAAEAIBBMAAKAIBAMAQACSMNFZXILTWNFSXO3ABAADAABABIA32KBLQERLKBVBBHQAM2HJHTTOXAILGPYQEABGYDOTV3VTNOZE7K6KWONQHP4HYYYHMR4YPDI3H3HB36CHRBIKH3H6VOI3KIS7W5EMIAABAAAQBAEFACAIMAEAAAAAAAAAAAAALAACACAIDAEAAYVLONF3GK4TTMFWC4PJ5AIBAABQAAQAAOQTPN5WGKYLOAEAAACYAAEAQCAYBAACU4YLUFYVQEBQDAMAQCIIAEPRHNZJIGPFN6AEEAU5CDB6AAMCC5ULOE4DXBIGX7LE3ANVJWCJAAAQAAMAQWAACAEAQGAIBEEAC2JSHAGH3K5IHP2I4HDLNULFR2E4EAVMRCBBNP4YWVWQTSB7RT7IAAEDAWAADAEAQGBABIA3WMQZC4T2RMC6ZEPP5ZNKMTP4JLD42EUQESFNU3ZE6XBO7H47OFPSHSSWYEB4EGRHQJHTH3DUE6CIUQVPAYYPKIKPJNB4DEW52A7H2AAAACAADAEASCABD4J3OKKBTZLPQBBAFHIQYPQADAQXNC3RHA5YKBV72ZGYDNKNQSIAAEAAEAEAACAQAAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMBAAAJBAAWSMRYBR62XKB36SHBY23NCZMORHBAFLEIQILL7GFVNUE4QP4M72AABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQMAACAEAQWAABAEAQGAIBEEALXH4JMVTQID2LYZDNY3BE27ZGPCN3RF5B7BBRYHCBOA6XAK6MCPAAAIAQAAYDAFAELKAEKPNPXNQI6W6YSDGGZGXWUNYSTAHMSM6JVRCZOWLR4AATVNPYCLZDPEOQXITARNPEUEFDJ3J63DOWUMUEQ22II25H2OTZMS7VLYAACAIAAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMBAAAJBAA253RUJNETZ3VLBDFSP6O3WXO2GIFWYC5R4RFOHVEID6ZKI2ZOCIAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQMAACAEAQMAAEAFAELKAEKPNPXNQI6W6YSDGGZGXWUNYSTAHMSM6JVRCZOWLR4AATVNPYCLZDPEOQXITARNPEUEFDJ3J63DOWUMUEQ22II25H2OTZMS7VLYAAEAABAEAQAAIBAEFQAAIBAEBQAAABAIBQCAJBAA253RUJNETZ3VLBDFSP6O3WXO2GIFWYC5R4RFOHVEID6ZKI2ZOCIAACAMAAAAABAFAAAL7RKMFUH4QQ5G2NTSQN244XUAWGVES3B5ALZMIZQ472Z3Z2SNRY5NY74Q7LRMSAM6YKIY6LXDY4GMGUQNR5G27OEYPJPYTZR5GNAIAAAAAAAAAAAAAAAAAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYCAAASCAC23KGP4O2QVLBIVRGK3KNMAXLIWJNNACUZJTSDXUCUCGLJWAODNUAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDAYAACAIGAACACQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAABAABACAIGAACACQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAABAABACAIGAACACQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAABAABACAIGAACACQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAABAAAAUAIBBQAQAAAAAAAAAAACBMAAWAIBAMAQCIIAGXO4NCLJE6O5KYIZMT7TW5V3WRSBNWAXMPEJLR5JCA7WKSGWLQSAAAQAAYFACAIMAEAAAAAAAAAAAAQLAAFACAIDAEASCABV3XDIS2JHTXKWCGLE745XNO5UMQLNQF3DZCK4PKIQH5SURVS4EQAAEAAGBIAQCDABAAAAAAAAAAAAECYABEAQCAYBAEQQANO5Y2EWSJ452VQRSZH7HN3LXNDEC3MBOY6ISXD2SEB7MVENMXBEAABAABQKAEAQOAYBFAFQAAIBAEBQCAAKJZQXILTUN5KGK6DUAECQWAACAEAQGAIAA5KGK6DUFYVSWAQBAAFACAIHAMBCYIALAABQCAIDAEAAOVDFPB2C4KZLAIAQACYAAQAQCAYBAAFE4YLUFZ2G6VDFPB2ACBYLAACQCAIDAEAAOVDFPB2C4KZLAIAQACQBAEDQGAZMEARAWAAGAEAQGAIAA5KGK6DUFYVSWAQBAAFQABYBAEBQCAAKJZQXILTUN5KGK6DUAEEQWAAIAEAQGAIAA5KGK6DUFYVSWAQBAAFACAIHAMBCEKIDAEAAOVDFPB2C4KZLAIAQAAAAAAAAAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGAQAAEQQBO47RFSWOBAPJPDENXDMETL7EZ4JXOEXUH4EGHA4IFYD24BLZQJ4AAAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYGAABQCAIBBMAACAIBAMAQABKOMF2C4KYCAIAAGAACAEAAAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGAQAAEQQBWHXBTHR3TXMVOOTYQWWGSR6Y67C32OTEZFQ3UJGV5FHDABEDWXFAAAQCQAVMBCUJUWZXIISNQY3J4HHF4UCTG2VI2OTKVWAQFVZWYX3T5MXS6LWV44LU2USLVE3FHYGV7SNVPQ5CN26L4NIXDELTBDOENZ644M7KAAAAAAAAAAAAAAAEAYGAABACAIDAAAQCAAAAEAUAABP6FJQWQ7SCDU3JWOKBXLTS6QCY2USLMHUBPFRDGDT7LHPHKJWHDVXD7SD5OFSIBT3BJDDZO4PDQZQ2SBWHU3L5YTB5F7CPGHUZUBAAAAAAAAAAAAAAAAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDAIAACIIA56Y5WAMUIZRITDKODUPJXHBCZSTKHCBX3KEPA7VOBOBEFIG6PEJQAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMDAAAQBAEFACAIMAEAAAAAAAAAAAAALAAAQCAIDAEASCABD4J3OKKBTZLPQBBAFHIQYPQADAQXNC3RHA5YKBV72ZGYDNKNQSIAAEAACAMBQCQCFVACFHWX3WYEPLPMJBTDMTL3KG4JJQDWJGPE2YRMXLFY6AAJ2WX4BF4RXSHILUJQIWXSKCCRU5U7NRXLKGKCINNEENOT5HJ4WJP2V4AAAAEAAAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGBIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIAACIIALLNIZ7R3KCVMFCWEZLNJVQC5NCZFVUAKTFGOIO6QKQIZNGYBYNWQAAAAAAAAAAAAAAAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIAQCQCFVACFHWX3WYEPLPMJBTDMTL3KG4JJQDWJGPE2YRMXLFY6AAJ2WX4BF4RXSHILUJQIWXSKCCRU5U7NRXLKGKCINNEENOT5HJ4WJP2V4AAAAAAAAAAAAAAQCAABEEALXH4JMVTQID2LYZDNY3BE27ZGPCN3RF5B7BBRYHCBOA6XAK6MCPAAAAAAAAAAAAAAAAQDBABQAAJBAADU6TFYWJ4TBQED3BGKQSYKXEB5XPEZRSJSDOWMTRNRPAEYQSA3EAIAAAAAAAAAAAAACAAABBVHK3LQINXW45AAAAAAAAAAAAAACAQLAAASCABNEZDQDD5VOUDX5EODRVW2FSY5COCAKWIRAQWX6MLK3IJZA7YZ7UAAAAAAAAAAAAAAAEBQQAYBAADUE33PNRSWC3QAAAAAAAAAAAAQAAYIAABQQAADAEEAGCADAMEAIAYIAABQQBIDBADAGCAAAMEAOAYIBAAQCQBXUUCXAJCWUDKCCPAAZUOSPHG5OAQWM7RAIACNQG5HLXLG25SJ6V4VM43AO7YPRRQOZDZQ6GRWPWODX4EPCCQUPWP5K4RWURF7N2IYQAAAAAAAAAAAAAAAEAYIAABQCCADBABQGCAEAMEAAAYIAUBQQBQDBAAAGCAHAMEAQAYIAMBQCCIDBAAAGCADAMEAIAYIAABQQBIDBADAGCAAAMEAOAYIBABQQAADAEFQGCABAMEAEAYIAABQQAYDBACAGCAAAMEAKAYIAYBQQAADBADQGCAIAEAUAABP6FJQWQ7SCDU3JWOKBXLTS6QCY2USLMHUBPFRDGDT7LHPHKJWHDVXD7SD5OFSIBT3BJDDZO4PDQZQ2SBWHU3L5YTB5F7CPGHUZUBAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAMAAAAAAAAAAAAABEEAO7MO3AGKEMYUJRVHB2HU3TQRMZJVDRA35VCHQP2XAXASCUDPHSEYAAAAAAAAAAAAACAQAAAAAAAAAAAEAAAAAAAAAAAAAAEQQAI7CO3SSQM6K34AIIBJ2EGD4AAYEF3IW4JYHOCQNP6WJWA3KTMESAAAAAAAAAAAAAAYAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABACAKAIWUAIU627O3AR5N5REGMNSNPNI3RFGAOZEZ4TLCFS5MXDYABHK27QEXSG6I5BORGBC26JIIKGTWT5WG5NIZIJBVUQRV2PU5HSZF7KXQAAAAAAAAAAAAACAIAAEQQBO47RFSWOBAPJPDENXDMETL7EZ4JXOEXUH4EGHA4IFYD24BLZQJ4AAAAAAAAAAAAAAACAMEAEAABEEAAOT2MXCZHSMGAQPMEZKCLBK4QHW54TGGJGIN2ZSOFWF4ATCCIDMQBAAAAAAAAAAAAAAIAAAEGU5LNOBBW63TUAAAAAAAAAAAAAAICBMAACIIAFUTEOAMPWV2QO7URYOGW3IWLDUJYIBKZCECC27ZRNLNBHED7DH6QAAAAAAAAAAAAAAAQGCACAEAAOQTPN5WGKYLOAAAAAAAAAAAACAADBAAAGCAAAMAQSAYIAMBQQAADBAAQGCAAAMEAKAYIAABQQBADBAAAGCAGAEAUAN5FAVYCIVVA2QQTYAGNDUTZZXLQEFTH4ICAATMBXJ252ZWXMSPVPFLHGYDX6D4MMDWI6MHRUNT5TQ57BDYQUFD5T7KXENVEJP3OSGEAAAAAAAAAAAAAAABAGCAAAMAQSAYIAMBQQAADBAAQGCAAAMEAKAYIAABQQBADBAAAGCAGAMEAEAYBBIBQQAADBABQGCAAAMEACAYIAABQQBIDBAAAGCAEAMEAAAYIAYBQQAADAEFQGCACAMEAAAYIAMBQQAADBAAQGCAAAMEAKAYIAABQQBADBAAAGCAGAEAUAABP6FJQWQ7SCDU3JWOKBXLTS6QCY2USLMHUBPFRDGDT7LHPHKJWHDVXD7SD5OFSIBT3BJDDZO4PDQZQ2SBWHU3L5YTB5F7CPGHUZUBAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAMAAAAAAAAAAAAABEEAO7MO3AGKEMYUJRVHB2HU3TQRMZJVDRA35VCHQP2XAXASCUDPHSEYAAAAAAAAAAAAACAQAAAAAAAAAAAEAAAAAAAAAAAAAAEQQAI7CO3SSQM6K34AIIBJ2EGD4AAYEF3IW4JYHOCQNP6WJWA3KTMESAAAAAAAAAAAAAAYAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABACAKAIWUAIU627O3AR5N5REGMNSNPNI3RFGAOZEZ4TLCFS5MXDYABHK27QEXSG6I5BORGBC26JIIKGTWT5WG5NIZIJBVUQRV2PU5HSZF7KXQAAAAAAAAAAAAAAAIDBAWQCAKAAAX7CUYLIPZBB2NU3HFA3VZZPIBMNKJFWD2AXSYRTBZ7VTXTVE3DR23R7ZB6XCZEAZ5QURR4XOHRYMYNJA3D2NV64JQ6S7RHTD2M2AQAAAAAAAAAAAAAAAABAFAAAL7RKMFUH4QQ5G2NTSQN244XUAWGVES3B5ALZMIZQ472Z3Z2SNRY5NY74Q7LRMSAM6YKIY6LXDY4GMGUQNR5G27OEYPJPYTZR5GNAIAAAAAAAAAAAAAAAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAA=== \ No newline at end of file diff --git a/unison-src/transcripts-using-base/serialized-cases/case-04.v5.hash b/unison-src/transcripts-using-base/serialized-cases/case-04.v5.hash new file mode 100644 index 0000000000..acb9258d45 --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-04.v5.hash @@ -0,0 +1 @@ +EXAQLMU6IKGAY7DNOHND5VUQQAQPIJN3IVCF5DISOOEVLRQZ3Q2CZOYEVDMY7MYQX2CG6CJFH2HQD6XOMKHQNK5JUZB3G7RZQNREQRQ= \ No newline at end of file diff --git a/unison-src/transcripts-using-base/serialized-cases/case-04.v5.ser b/unison-src/transcripts-using-base/serialized-cases/case-04.v5.ser new file mode 100644 index 0000000000..bcced67760 --- /dev/null +++ b/unison-src/transcripts-using-base/serialized-cases/case-04.v5.ser @@ -0,0 +1 @@ +AAAAABIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQCBIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQEAABEEADVNOCW62AVOZXJ6CMCXMWMTBLF4FFUTLGYPNRXF3BZCNXIDIOZNIAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGBQAAEAQMAAGAABU4YLUAEAAAAAAAAAAAAAHAMCG623BPEAQWAACAEAQGAIBEEAG57PICSIFU224UOLFTG2BAWCL4E7NVW2SJJUAWDIJO7R3YJCNHYQAAAFACAIMAEAAAAAAAAAAAAILAAAQCAIDAEAAQTTBOQXGI4TPOABAEAADAEASCAB2WXBLPNAKXM3U7BGBLWLGJQVS6CS2JVTMHWY3S5Q4RG3UBUHMWUAQCAAAAEAUAABP6FJQWQ7SCDU3JWOKBXLTS6QCY2USLMHUBPFRDGDT7LHPHKJWHDVXD7SD5OFSIBT3BJDDZO4PDQZQ2SBWHU3L5YTB5F7CPGHUZUBAAAAAAAAAAAAAAAAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDAIAACIIAHK24FN5UBK5TOT4EYFOZMZGCWLYKLJGWNQ63DOLWDSE3OQGQ5S2QCAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMDAAAIBAMAQCIIAHK24FN5UBK5TOT4EYFOZMZGCWLYKLJGWNQ63DOLWDSE3OQGQ5S2QAAIAAAAQCQAAF7YVGC2D6IIOTNGZZIG5OOL2ALDKSJNQ6QF4WEMYOP5M545JGY4OW4P6IPVYWJAGPMFEMPF3R4ODGDKIGY6TNPXCMHUX4J4Y6TGQEAAAAAAAAAAAAAAAAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMBAAAJBABXP32AUSBNGWXFDSZMZWQIFQS7BH3NNWUSKNAFQ2CLX4O6CITJ6EAABAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIBQMAAABMAACAIBAMAQCIIA74Z3E7TZQYDVD277KYVK5NAJDGFSKNDJXTUKC63K45WJSDPTGK4QAAALAABACAIDAEABGSKPFZXXAZLOIZUWYZJONFWXA3BOOYZQAAYBAEQQB3YGQKCYHD3UZXVHZGINUEURDHPZAHALBT23ILWELMAMPRQ2D7NPAABACAAAAEAUAABP6FJQWQ7SCDU3JWOKBXLTS6QCY2USLMHUBPFRDGDT7LHPHKJWHDVXD7SD5OFSIBT3BJDDZO4PDQZQ2SBWHU3L5YTB5F7CPGHUZUBAAAAAAAAAAAAAAAAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDAIAACIIA54DIFBMDR52M32T4TEG2CKIRTX4QDQFQZ5NUF3CFWAGHYYNB7WXQAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMDAABABAEAQCCYAAEAQCAYAAIBACAADAACACAAAAEAUAABP6FJQWQ7SCDU3JWOKBXLTS6QCY2USLMHUBPFRDGDT7LHPHKJWHDVXD7SD5OFSIBT3BJDDZO4PDQZQ2SBWHU3L5YTB5F7CPGHUZUBAAAAAAAAAAAAAAAAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDAIAACIIA74Z3E7TZQYDVD277KYVK5NAJDGFSKNDJXTUKC63K45WJSDPTGK4QAAIBIAKWARKE2LM3UEJGYMNU6DTS6KBJTNKUNHJVK3AIC243ML5Z6WLZPF3K6OF2NKJF2SNST4DK7ZG2XYORG5PF6GULRSFZQRXCG47OOGPVAAAAAAAAAAAAAAACAMDAAAIBAYAAIAKAAYHWPACBPYWKJKM2NKSLWVRBTSNVST2AI6PHPF4OJ5445524FEGZP6XTZUG4DBW2Y2I4CYBXK5ONOIRUUGROEFVJFPSLQVSNSU5EE7IAAIAACAIBAAAQCAIDAQAUAJOA7BYABDTZGHSVVPMSW7MJOX2SYXXFOHDKQRESSFMT3HFUDFIO5UOEVZ4JCZAQQL53EGN2XPGLX432KM4VDDP52DPQXQ7AQNTICXPAAAABAAAAAAIBIAAC74KTBNB7EEHJWTM4UDOXHF5AFRVJEWYPIC6LCGMHH6WO6OUTMOHLOH7EH24LEQDHWCSGHS5Y6HBTBVEDMPJWX3RGD2L6E6MPJTICAAAAAAAAAAAAAAAAAEAUAFLAIVCNFWN2CETMGG2PBZZPFAUZWVKGTU2VNQEBNONWF647LF4XS5VPHC5GVES5JGZJ6BVP4TNL4HITOXS7DKFYZC4YI3RDOPXHDH2QAAAAAAAAAAAAAABAGBIBAFABKYCFITJNTOQRE3BRWTYOOLZIFGNVKRU5GVLMBALLTNRPXH2ZPF4XNLZYXJVJEXKJWKPQNL7E3K7B2E3V4XY2ROGIXGCG4I3T5ZYZ6UAAAAAAAAAAAAAAAIAACIIAHK24FN5UBK5TOT4EYFOZMZGCWLYKLJGWNQ63DOLWDSE3OQGQ5S2QCAAAAAAAAAAAAAAACAKACVQEKRGS3G5BCJWDDNHQ44XSQKM3KVDJ2NKWYCAWXG3C7OPVS6LZO2XTROTKSJOUTMU7A2X6JWV6DUJXLZPRVC4MROMENYRXH3TRT5IAAAAAAAAAAAAAAAQDBACQCAKAAAX7CUYLIPZBB2NU3HFA3VZZPIBMNKJFWD2AXSYRTBZ7VTXTVE3DR23R7ZB6XCZEAZ5QURR4XOHRYMYNJA3D2NV64JQ6S7RHTD2M2AQAAAAAAAAAAAAAAAABAFAAAL7RKMFUH4QQ5G2NTSQN244XUAWGVES3B5ALZMIZQ472Z3Z2SNRY5NY74Q7LRMSAM6YKIY6LXDY4GMGUQNR5G27OEYPJPYTZR5GNAIAAAAAAAAAAAAAAAA====== \ No newline at end of file