From 2e185b06eb7c4cd09fc4af2ab69c2424a2e4b7e2 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 3 Sep 2024 15:20:14 -0700 Subject: [PATCH 01/20] Downgrade parser-typechecker to just O1 --- parser-typechecker/package.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser-typechecker/package.yaml b/parser-typechecker/package.yaml index 7150e81120..29ea1d3619 100644 --- a/parser-typechecker/package.yaml +++ b/parser-typechecker/package.yaml @@ -11,7 +11,7 @@ flags: when: - condition: flag(optimized) - ghc-options: -funbox-strict-fields -O2 + ghc-options: -funbox-strict-fields -O library: source-dirs: src From 485de756df5a34d421bc79e4f1c110d97e6f3be5 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 3 Sep 2024 16:00:28 -0700 Subject: [PATCH 02/20] Add RComb knot-tying code --- .../unison-parser-typechecker.cabal | 4 +- .../src/Unison/Runtime/Interface.hs | 2 +- unison-runtime/src/Unison/Runtime/MCode.hs | 105 +++++++++++++----- unison-runtime/src/Unison/Runtime/Machine.hs | 35 +++--- 4 files changed, 96 insertions(+), 50 deletions(-) diff --git a/parser-typechecker/unison-parser-typechecker.cabal b/parser-typechecker/unison-parser-typechecker.cabal index af6098f702..040b382692 100644 --- a/parser-typechecker/unison-parser-typechecker.cabal +++ b/parser-typechecker/unison-parser-typechecker.cabal @@ -257,7 +257,7 @@ library , witherable default-language: Haskell2010 if flag(optimized) - ghc-options: -funbox-strict-fields -O2 + ghc-options: -funbox-strict-fields -O test-suite parser-typechecker-tests type: exitcode-stdio-1.0 @@ -340,4 +340,4 @@ test-suite parser-typechecker-tests , unison-util-rope default-language: Haskell2010 if flag(optimized) - ghc-options: -funbox-strict-fields -O2 + ghc-options: -funbox-strict-fields -O diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 66139742bb..8c258ef5cb 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -101,9 +101,9 @@ import Unison.Runtime.Exception import Unison.Runtime.MCode ( Args (..), Combs, + GSection (..), Instr (..), RefNums (..), - Section (..), combDeps, combTypes, emitComb, diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index c3d9c837bb..79d2874f20 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -12,20 +12,27 @@ module Unison.Runtime.MCode RefNums (..), MLit (..), Instr (..), - Section (.., MatchT, MatchW), - Comb (..), + GSection (.., MatchT, MatchW), + Section, + GComb (..), + Comb, + RComb (..), + GCombs, Combs, + RCombs, CombIx (..), Ref (..), UPrim1 (..), UPrim2 (..), BPrim1 (..), BPrim2 (..), - Branch (..), + GBranch (..), + Branch, bcount, ucount, emitCombs, emitComb, + resolveCombs, emptyRNs, argsToLists, combRef, @@ -39,6 +46,7 @@ where import Data.Bifunctor (bimap, first) import Data.Bits (shiftL, shiftR, (.|.)) import Data.Coerce +import Data.Functor ((<&>)) import Data.List (partition) import Data.Map.Strict qualified as M import Data.Primitive.ByteArray @@ -504,7 +512,9 @@ data Instr TryForce !Int deriving (Show, Eq, Ord) -data Section +type Section = GSection CombIx + +data GSection comb = -- Apply a function to arguments. This is the 'slow path', and -- handles applying functions from arbitrary sources. This -- requires checks to determine what exactly should happen. @@ -529,15 +539,15 @@ data Section | -- Branch on the value in the unboxed data stack Match !Int -- index of unboxed item to match on - !Branch -- branches + !(GBranch comb) -- branches | -- Yield control to the current continuation, with arguments Yield !Args -- values to yield | -- Prefix an instruction onto a section - Ins !Instr !Section + Ins !Instr !(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 !Section !CombIx + Let !(GSection comb) !comb | -- Throw an exception with the given message Die String | -- Immediately stop a thread of interpretation. This is more of @@ -548,19 +558,19 @@ data Section DMatch !(Maybe Reference) -- expected data type !Int -- index of data item on boxed stack - !Branch -- branches + !(GBranch comb) -- branches | -- Branch on a numeric type without dumping it to the stack NMatch !(Maybe Reference) -- expected data type !Int -- index of data item on boxed stack - !Branch -- branches + !(GBranch comb) -- branches | -- Branch on a request representation without dumping the tag -- portion to the unboxed stack. RMatch !Int -- index of request item on the boxed stack - !Section -- pure case - !(EnumMap Word64 Branch) -- effect cases - deriving (Show, Eq, Ord) + !(GSection comb) -- pure case + !(EnumMap Word64 (GBranch comb)) -- effect cases + deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) data CombIx = CIx @@ -582,16 +592,25 @@ emptyRNs = RN mt mt where mt _ = internalBug "RefNums: empty" -data Comb +type Comb = GComb CombIx + +data GComb comb = Lam !Int -- Number of unboxed arguments !Int -- Number of boxed arguments !Int -- Maximum needed unboxed frame size !Int -- Maximum needed boxed frame size - !Section -- Entry - deriving (Show, Eq, Ord) + !(GSection comb) -- Entry + deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) + +type Combs = GCombs CombIx -type Combs = EnumMap Word64 Comb +type RCombs = GCombs RComb + +-- | The fixed point of a GComb where all references to a Comb are themselves Combs. +newtype RComb = RComb {unRComb :: GComb RComb} + +type GCombs comb = EnumMap Word64 (GComb comb) data Ref = Stk !Int -- stack reference to a closure @@ -601,35 +620,37 @@ data Ref | Dyn !Word64 -- dynamic scope reference to a closure deriving (Show, Eq, Ord) -data Branch +type Branch = GBranch CombIx + +data GBranch comb = -- if tag == n then t else f Test1 !Word64 - !Section - !Section + !(GSection comb) + !(GSection comb) | Test2 !Word64 - !Section -- if tag == m then ... + !(GSection comb) -- if tag == m then ... !Word64 - !Section -- else if tag == n then ... - !Section -- else ... + !(GSection comb) -- else if tag == n then ... + !(GSection comb) -- else ... | TestW - !Section - !(EnumMap Word64 Section) + !(GSection comb) + !(EnumMap Word64 (GSection comb)) | TestT - !Section - !(M.Map Text Section) - deriving (Show, Eq, Ord) + !(GSection comb) + !(M.Map Text (GSection comb)) + deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) -- Convenience patterns for matches used in the algorithms below. -pattern MatchW :: Int -> Section -> EnumMap Word64 Section -> Section +pattern MatchW :: Int -> (GSection comb) -> EnumMap Word64 (GSection comb) -> (GSection comb) pattern MatchW i d cs = Match i (TestW d cs) -pattern MatchT :: Int -> Section -> M.Map Text Section -> Section +pattern MatchT :: Int -> (GSection comb) -> M.Map Text (GSection comb) -> (GSection comb) pattern MatchT i d cs = Match i (TestT d cs) pattern NMatchW :: - Maybe Reference -> Int -> Section -> EnumMap Word64 Section -> Section + Maybe Reference -> Int -> (GSection comb) -> EnumMap Word64 (GSection comb) -> (GSection comb) pattern NMatchW r i d cs = NMatch r i (TestW d cs) -- Representation of the variable context available in the current @@ -722,6 +743,30 @@ emitCombs rns grpr grpn (Rec grp ent) = rec = M.fromList $ zip rvs ixs aux = foldMap (emitComb rns grpr grpn rec) (zip ixs cmbs) +-- | lazily replace all references to combinators with the combinators themselves, +-- tying the knot recursively when necessary. +resolveCombs :: + EnumMap Word64 Combs -> + EnumMap Word64 RCombs +resolveCombs combs = + -- Fixed point lookup; make sure all uses of Combs are non-strict + -- or we'll loop forever. + let ~resolved = + combs + <&> (fmap . fmap) \(CIx _ n i) -> + case EC.lookup n resolved of + Just cmbs -> case EC.lookup i cmbs of + Just cmb -> RComb cmb + Nothing -> + error $ + "unknown section `" + ++ show i + ++ "` of combinator `" + ++ show n + ++ "`." + Nothing -> error $ "unknown combinator `" ++ show n ++ "`." + in resolved + -- 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 diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index eecc5cc09b..6d5fa48f6c 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -23,7 +23,6 @@ import Data.Text qualified as DTx import Data.Text.IO qualified as Tx import Data.Traversable import GHC.Conc as STM (unsafeIOToSTM) -import GHC.Stack import Unison.Builtin.Decls (exceptionRef, ioFailureRef) import Unison.Builtin.Decls qualified as Rf import Unison.ConstructorReference qualified as CR @@ -85,7 +84,7 @@ data CCache = CCache { foreignFuncs :: EnumMap Word64 ForeignFunc, sandboxed :: Bool, tracer :: Bool -> Closure -> Tracer, - combs :: TVar (EnumMap Word64 Combs), + combs :: TVar (EnumMap Word64 RCombs), combRefs :: TVar (EnumMap Word64 Reference), tagRefs :: TVar (EnumMap Word64 Reference), freshTm :: TVar Word64, @@ -137,10 +136,12 @@ baseCCache sandboxed = do rns = emptyRNs {dnum = refLookup "ty" builtinTypeNumbering} - combs = + combs :: EnumMap Word64 RCombs + ~combs = mapWithKey (\k v -> let r = builtinTermBackref ! k in emitComb @Symbol rns r k mempty (0, v)) numberedTermLookup + & resolveCombs info :: (Show a) => String -> a -> IO () info ctx x = infos ctx (show x) @@ -1929,19 +1930,19 @@ unhandledErr fname env i = where bomb sh = die $ fname ++ ": unhandled ability request: " ++ sh -combSection :: (HasCallStack) => CCache -> CombIx -> IO Comb -combSection env (CIx _ n i) = - readTVarIO (combs env) >>= \cs -> case EC.lookup n cs of - Just cmbs -> case EC.lookup i cmbs of - Just cmb -> pure cmb - Nothing -> - die $ - "unknown section `" - ++ show i - ++ "` of combinator `" - ++ show n - ++ "`." - Nothing -> die $ "unknown combinator `" ++ show n ++ "`." +-- combSection :: (HasCallStack) => CCache -> CombIx -> IO Comb +-- combSection env (CIx _ n i) = +-- readTVarIO (combs env) >>= \cs -> case EC.lookup n cs of +-- Just cmbs -> case EC.lookup i cmbs of +-- Just cmb -> pure cmb +-- Nothing -> +-- die $ +-- "unknown section `" +-- ++ show i +-- ++ "` of combinator `" +-- ++ show n +-- ++ "`." +-- Nothing -> die $ "unknown combinator `" ++ show n ++ "`." dummyRef :: Reference dummyRef = Builtin (DTx.pack "dummy") @@ -2107,7 +2108,7 @@ cacheAdd0 ntys0 tml sands cc = atomically $ do let rns = RN (refLookup "ty" rty) (refLookup "tm" rtm) combinate n (r, g) = (n, emitCombs rns r n g) nrs <- updateMap (mapFromList $ zip [ntm ..] rs) (combRefs cc) - ncs <- updateMap (mapFromList $ zipWith combinate [ntm ..] rgs) (combs cc) + ncs <- updateMap ((fmap . fmap) unRComb . mapFromList $ zipWith combinate [ntm ..] rgs) (combs cc) nsn <- updateMap (M.fromList sands) (sandbox cc) pure $ int `seq` rtm `seq` nrs `seq` ncs `seq` nsn `seq` () where From 33576caae070a356fedd06344a7b857bd0c2c093 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 3 Sep 2024 16:23:24 -0700 Subject: [PATCH 03/20] Add serializers for RComb --- .../src/Unison/Runtime/Decompile.hs | 4 +- .../src/Unison/Runtime/Interface.hs | 5 +- unison-runtime/src/Unison/Runtime/MCode.hs | 25 ++-- .../src/Unison/Runtime/MCode/Serialize.hs | 113 ++++++++++-------- unison-runtime/src/Unison/Runtime/Machine.hs | 6 +- unison-runtime/src/Unison/Runtime/Stack.hs | 6 +- 6 files changed, 88 insertions(+), 71 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index 00e8c4445a..5859a1de1f 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -32,7 +32,7 @@ import Unison.Runtime.Foreign maybeUnwrapForeign, ) import Unison.Runtime.IOSource (iarrayFromListRef, ibarrayFromBytesRef) -import Unison.Runtime.MCode (CombIx (..)) +import Unison.Runtime.MCode (CombIx (..), GComb (..), RComb (..)) import Unison.Runtime.Stack ( Closure (..), pattern DataC, @@ -172,7 +172,7 @@ decompile backref topTerms (PApV (CIx rf rt k) [] bs) Just _ <- topTerms rt 0 = err (UnkLocal rf k) $ bug "" | otherwise = err (UnkComb rf) $ ref () rf -decompile _ _ (PAp (CIx rf _ _) _ _) = +decompile _ _ (PAp (RComb _cix (Lam rf _ _ _ _ _)) _ _) = err (BadPAp rf) $ bug "" decompile _ _ (DataC rf _ _ _) = err (BadData rf) $ bug "" decompile _ _ BlackHole = err Exn $ bug "" diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 8c258ef5cb..85c124bef2 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -103,6 +103,7 @@ import Unison.Runtime.MCode Combs, GSection (..), Instr (..), + RCombs, RefNums (..), combDeps, combTypes, @@ -1192,7 +1193,7 @@ runStandalone sc init = data StoredCache = SCache - (EnumMap Word64 Combs) + (EnumMap Word64 RCombs) (EnumMap Word64 Reference) (EnumMap Word64 Reference) Word64 @@ -1205,7 +1206,7 @@ data StoredCache putStoredCache :: (MonadPut m) => StoredCache -> m () putStoredCache (SCache cs crs trs ftm fty int rtm rty sbs) = do - putEnumMap putNat (putEnumMap putNat putComb) cs + putEnumMap putNat (putEnumMap putNat (putComb putRComb)) cs putEnumMap putNat putReference crs putEnumMap putNat putReference trs putNat ftm diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 79d2874f20..03b72c1d84 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -596,6 +596,7 @@ type Comb = GComb CombIx data GComb comb = Lam + !Reference -- function reference, for debugging !Int -- Number of unboxed arguments !Int -- Number of boxed arguments !Int -- Maximum needed unboxed frame size @@ -608,7 +609,15 @@ type Combs = GCombs CombIx type RCombs = GCombs RComb -- | The fixed point of a GComb where all references to a Comb are themselves Combs. -newtype RComb = RComb {unRComb :: GComb RComb} +data RComb = RComb + { rCombIx :: CombIx, + unRComb :: GComb RComb + } + deriving (Eq, Ord) + +-- | RCombs can be infinitely recursive so we can't show them. +instance Show RComb where + show _ = "" type GCombs comb = EnumMap Word64 (GComb comb) @@ -753,10 +762,10 @@ resolveCombs combs = -- or we'll loop forever. let ~resolved = combs - <&> (fmap . fmap) \(CIx _ n i) -> + <&> (fmap . fmap) \(cix@(CIx _ n i)) -> case EC.lookup n resolved of Just cmbs -> case EC.lookup i cmbs of - Just cmb -> RComb cmb + Just cmb -> RComb cix cmb Nothing -> error $ "unknown section `" @@ -803,14 +812,14 @@ 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) + in (EC.mapInsert n (Lam (error "record: Missing Ref") au ab u b s) m, C u b n) recordTop :: [v] -> Word16 -> Emit Section -> Emit () recordTop vs l (EM e) = EM $ \c -> let (m, C u b s) = e c ab = length vs n = letIndex l c - in (EC.mapInsert n (Lam 0 ab u b s) m, C u b ()) + in (EC.mapInsert n (Lam (error "recordTop: Missing Ref") 0 ab u b s) m, C u b ()) -- Counts the stack space used by a context and annotates a value -- with it. @@ -1479,10 +1488,10 @@ demuxArgs as0 = (us, bs) -> DArgN (primArrayFromList us) (primArrayFromList bs) combDeps :: Comb -> [Word64] -combDeps (Lam _ _ _ _ s) = sectionDeps s +combDeps (Lam _ _ _ _ _ s) = sectionDeps s combTypes :: Comb -> [Word64] -combTypes (Lam _ _ _ _ s) = sectionTypes s +combTypes (Lam _ _ _ _ _ s) = sectionTypes s sectionDeps :: Section -> [Word64] sectionDeps (App _ (Env w _) _) = [w] @@ -1547,7 +1556,7 @@ prettyCombs w es = (mapToList es) prettyComb :: Word64 -> Word64 -> Comb -> ShowS -prettyComb w i (Lam ua ba _ _ s) = +prettyComb w i (Lam _ref ua ba _ _ s) = shows w . showString ":" . shows i diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index 2d1cabf8d3..095109f166 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -4,7 +4,10 @@ module Unison.Runtime.MCode.Serialize ( putComb, + putRComb, getComb, + putCombIx, + getCombIx, ) where @@ -19,12 +22,16 @@ import Unison.Runtime.MCode hiding (MatchT) import Unison.Runtime.Serialize import Unison.Util.Text qualified as Util.Text -putComb :: (MonadPut m) => Comb -> m () -putComb (Lam ua ba uf bf body) = - pInt ua *> pInt ba *> pInt uf *> pInt bf *> putSection body +putComb :: (MonadPut m) => (cix -> m ()) -> GComb cix -> m () +putComb putCix (Lam rf ua ba uf bf body) = + putReference rf *> pInt ua *> pInt ba *> pInt uf *> pInt bf *> putSection putCix body -getComb :: (MonadGet m) => m Comb -getComb = Lam <$> gInt <*> gInt <*> gInt <*> gInt <*> getSection +putRComb :: (MonadPut m) => RComb -> m () +putRComb (RComb _combIx _comb) = + error "TODO: figure out how to mark recursive points and serialize RComb" + +getComb :: (MonadGet m) => m cix -> m (GComb cix) +getComb gCix = Lam <$> getReference <*> gInt <*> gInt <*> gInt <*> gInt <*> (getSection gCix) data SectionT = AppT @@ -68,51 +75,51 @@ instance Tag SectionT where word2tag 11 = pure RMatchT word2tag i = unknownTag "SectionT" i -putSection :: (MonadPut m) => Section -> m () -putSection (App b r a) = +putSection :: (MonadPut m) => (cix -> m ()) -> GSection cix -> m () +putSection _pCIx (App b r a) = putTag AppT *> serialize b *> putRef r *> putArgs a -putSection (Call b w a) = +putSection _pCIx (Call b w a) = putTag CallT *> serialize b *> pWord w *> putArgs a -putSection (Jump i a) = +putSection _pCIx (Jump i a) = putTag JumpT *> pInt i *> putArgs a -putSection (Match i b) = - putTag MatchT *> pInt i *> putBranch b -putSection (Yield a) = +putSection pCIx (Match i b) = + putTag MatchT *> pInt i *> putBranch pCIx b +putSection _pCIx (Yield a) = putTag YieldT *> putArgs a -putSection (Ins i s) = - putTag InsT *> putInstr i *> putSection s -putSection (Let s ci) = - putTag LetT *> putSection s *> putCombIx ci -putSection (Die s) = +putSection pCIx (Ins i s) = + putTag InsT *> putInstr i *> putSection pCIx s +putSection pCIx (Let s ci) = + putTag LetT *> putSection pCIx s *> pCIx ci +putSection _pCIx (Die s) = putTag DieT *> serialize s -putSection Exit = +putSection _pCIx Exit = putTag ExitT -putSection (DMatch mr i b) = - putTag DMatchT *> putMaybe mr putReference *> pInt i *> putBranch b -putSection (NMatch mr i b) = - putTag NMatchT *> putMaybe mr putReference *> pInt i *> putBranch b -putSection (RMatch i pu bs) = +putSection pCIx (DMatch mr i b) = + putTag DMatchT *> putMaybe mr putReference *> pInt i *> putBranch pCIx b +putSection pCIx (NMatch mr i b) = + putTag NMatchT *> putMaybe mr putReference *> pInt i *> putBranch pCIx b +putSection pCIx (RMatch i pu bs) = putTag RMatchT *> pInt i - *> putSection pu - *> putEnumMap pWord putBranch bs + *> putSection pCIx pu + *> putEnumMap pWord (putBranch pCIx) bs -getSection :: (MonadGet m) => m Section -getSection = +getSection :: (MonadGet m) => m cix -> m (GSection cix) +getSection gCix = getTag >>= \case AppT -> App <$> deserialize <*> getRef <*> getArgs CallT -> Call <$> deserialize <*> gWord <*> getArgs JumpT -> Jump <$> gInt <*> getArgs - MatchT -> Match <$> gInt <*> getBranch + MatchT -> Match <$> gInt <*> getBranch gCix YieldT -> Yield <$> getArgs - InsT -> Ins <$> getInstr <*> getSection - LetT -> Let <$> getSection <*> getCombIx + InsT -> Ins <$> getInstr <*> getSection gCix + LetT -> Let <$> getSection gCix <*> gCix DieT -> Die <$> deserialize ExitT -> pure Exit - DMatchT -> DMatch <$> getMaybe getReference <*> gInt <*> getBranch - NMatchT -> NMatch <$> getMaybe getReference <*> gInt <*> getBranch + DMatchT -> DMatch <$> getMaybe getReference <*> gInt <*> getBranch gCix + NMatchT -> NMatch <$> getMaybe getReference <*> gInt <*> getBranch gCix RMatchT -> - RMatch <$> gInt <*> getSection <*> getEnumMap gWord getBranch + RMatch <$> gInt <*> getSection gCix <*> getEnumMap gWord (getBranch gCix) data InstrT = UPrim1T @@ -395,34 +402,34 @@ instance Tag BranchT where word2tag 3 = pure TestTT word2tag n = unknownTag "BranchT" n -putBranch :: (MonadPut m) => Branch -> m () -putBranch (Test1 w s d) = - putTag Test1T *> pWord w *> putSection s *> putSection d -putBranch (Test2 a sa b sb d) = +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) = putTag Test2T *> pWord a - *> putSection sa + *> putSection pCix sa *> pWord b - *> 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 = + *> 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 = getTag >>= \case - Test1T -> Test1 <$> gWord <*> getSection <*> getSection + Test1T -> Test1 <$> gWord <*> getSection gCix <*> getSection gCix Test2T -> Test2 <$> gWord - <*> getSection + <*> getSection gCix <*> gWord - <*> getSection - <*> getSection - TestWT -> TestW <$> getSection <*> getEnumMap gWord getSection - TestTT -> TestT <$> getSection <*> getMap (Util.Text.fromText <$> getText) getSection + <*> getSection gCix + <*> getSection gCix + TestWT -> TestW <$> getSection gCix <*> getEnumMap gWord (getSection gCix) + TestTT -> TestT <$> getSection gCix <*> getMap (Util.Text.fromText <$> getText) (getSection gCix) 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 6d5fa48f6c..2667b72ad2 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -700,7 +700,7 @@ enter !env !denv !activeThreads !ustk !bstk !k !ck !args !comb = do -- detecting saturated calls. eval env denv activeThreads ustk bstk k dummyRef entry where - Lam ua ba uf bf entry = comb + Lam _rf ua ba uf bf entry = comb {-# INLINE enter #-} -- fast path by-name delaying @@ -728,7 +728,7 @@ apply :: IO () apply !env !denv !activeThreads !ustk !bstk !k !ck !args (PAp comb useg bseg) = combSection env comb >>= \case - Lam ua ba uf bf entry + Lam _rf ua ba uf bf entry | ck || ua <= uac && ba <= bac -> do ustk <- ensure ustk uf bstk <- ensure bstk bf @@ -1828,7 +1828,7 @@ yield !env !denv !activeThreads !ustk !bstk !k = leap denv k bstk <- adjustArgs bstk ba apply env denv activeThreads ustk bstk k False (BArg1 0) clo leap !denv (Push ufsz bfsz uasz basz cix k) = do - Lam _ _ uf bf nx <- combSection env cix + Lam _rf _ _ uf bf nx <- combSection env cix ustk <- restoreFrame ustk ufsz uasz bstk <- restoreFrame bstk bfsz basz ustk <- ensure ustk uf diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index ebfe67f85a..de60f0b178 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -91,7 +91,7 @@ data K data Closure = PAp - {-# UNPACK #-} !CombIx -- reference + RComb {- Possibly recursive comb, keep it lazy or risk blowing up! -} {-# UNPACK #-} !(Seg 'UN) -- unboxed args {- unpack -} !(Seg 'BX) -- boxed args @@ -339,8 +339,8 @@ class MEM (b :: Mem) where asize :: Stack b -> SZ instance MEM 'UN where - data Stack 'UN = - -- Note: uap <= ufp <= usp + data Stack 'UN + = -- Note: uap <= ufp <= usp US { uap :: !Int, -- arg pointer ufp :: !Int, -- frame pointer From 53332879b5f166c7d9e6d1103031d739df698338 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 3 Sep 2024 16:42:48 -0700 Subject: [PATCH 04/20] WIP replacing combix with combs --- .../src/Unison/Runtime/Interface.hs | 17 ++++++----- unison-runtime/src/Unison/Runtime/MCode.hs | 8 +++++ .../src/Unison/Runtime/MCode/Serialize.hs | 4 +++ unison-runtime/src/Unison/Runtime/Machine.hs | 30 ++++++++++++++----- 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 85c124bef2..b11d3cda0f 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -100,7 +100,6 @@ import Unison.Runtime.Decompile import Unison.Runtime.Exception import Unison.Runtime.MCode ( Args (..), - Combs, GSection (..), Instr (..), RCombs, @@ -109,6 +108,8 @@ import Unison.Runtime.MCode combTypes, emitComb, emptyRNs, + rCombIx, + resolveCombs, ) import Unison.Runtime.MCode.Serialize import Unison.Runtime.Machine @@ -1219,7 +1220,7 @@ putStoredCache (SCache cs crs trs ftm fty int rtm rty sbs) = do getStoredCache :: (MonadGet m) => m StoredCache getStoredCache = SCache - <$> getEnumMap getNat (getEnumMap getNat getComb) + <$> getEnumMap getNat (getEnumMap getNat (getComb getRComb)) <*> getEnumMap getNat getReference <*> getEnumMap getNat getReference <*> getNat @@ -1274,26 +1275,28 @@ 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 = mapWithKey (\k v -> emitComb @Symbol rns (rf k) k mempty (0, v)) numberedTermLookup + & resolveCombs traceNeeded :: Word64 -> - EnumMap Word64 Combs -> - IO (EnumMap Word64 Combs) + EnumMap Word64 RCombs -> + IO (EnumMap Word64 RCombs) 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 co) + foldlM go (mapInsert w co acc) (foldMap (combDeps . fmap rCombIx) co) | otherwise = die $ "traceNeeded: unknown combinator: " ++ show w buildSCache :: - EnumMap Word64 Combs -> + EnumMap Word64 RCombs -> EnumMap Word64 Reference -> EnumMap Word64 Reference -> Word64 -> @@ -1319,7 +1322,7 @@ buildSCache cs crsrc trsrc ftm fty intsrc rtmsrc rtysrc sndbx = crs = restrictTmW crsrc termRefs = foldMap Set.singleton crs - typeKeys = setFromList $ (foldMap . foldMap) combTypes cs + typeKeys = setFromList $ (foldMap . foldMap) (combTypes . fmap rCombIx) cs trs = restrictTyW trsrc typeRefs = foldMap Set.singleton trs diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 03b72c1d84..4c14598a39 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -17,6 +17,7 @@ module Unison.Runtime.MCode GComb (..), Comb, RComb (..), + rCombToComb, GCombs, Combs, RCombs, @@ -37,6 +38,7 @@ module Unison.Runtime.MCode argsToLists, combRef, combDeps, + rCombDeps, combTypes, prettyCombs, prettyComb, @@ -615,6 +617,9 @@ data RComb = RComb } deriving (Eq, Ord) +rCombToComb :: RComb -> Comb +rCombToComb (RComb _ix c) = rCombIx <$> c + -- | RCombs can be infinitely recursive so we can't show them. instance Show RComb where show _ = "" @@ -1487,6 +1492,9 @@ demuxArgs as0 = -- TODO: handle ranges (us, bs) -> DArgN (primArrayFromList us) (primArrayFromList bs) +rCombDeps :: RComb -> [Word64] +rCombDeps = combDeps . rCombToComb + combDeps :: Comb -> [Word64] combDeps (Lam _ _ _ _ _ s) = sectionDeps s diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index 095109f166..1d8591e481 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -6,6 +6,7 @@ module Unison.Runtime.MCode.Serialize ( putComb, putRComb, getComb, + getRComb, putCombIx, getCombIx, ) @@ -33,6 +34,9 @@ putRComb (RComb _combIx _comb) = getComb :: (MonadGet m) => m cix -> m (GComb cix) getComb gCix = Lam <$> getReference <*> gInt <*> gInt <*> gInt <*> gInt <*> (getSection gCix) +getRComb :: (MonadGet m) => m RComb +getRComb = error "TODO: figure out how to mark recursive points and serialize RComb" + data SectionT = AppT | CallT diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 2667b72ad2..cf4f7460f4 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -166,17 +166,20 @@ eval0 !env !activeThreads !co = do eval env denv activeThreads ustk bstk (k KE) dummyRef co topDEnv :: + EnumMap Word64 RCombs -> M.Map Reference Word64 -> M.Map Reference Word64 -> (DEnv, K -> K) -topDEnv rfTy rfTm +topDEnv combs rfTy rfTm | Just n <- M.lookup exceptionRef rfTy, rcrf <- Builtin (DTx.pack "raise"), Just j <- M.lookup rcrf rfTm = - ( EC.mapSingleton n (PAp (CIx rcrf j 0) unull bnull), - Mark 0 0 (EC.setSingleton n) mempty - ) -topDEnv _ _ = (mempty, id) + 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 + ) +topDEnv _ _ _ = (mempty, id) -- Entry point for evaluating a numbered combinator. -- An optional callback for the base of the stack may be supplied. @@ -193,13 +196,15 @@ apply0 !callback !env !threadTracker !i = do ustk <- alloc bstk <- alloc cmbrs <- readTVarIO $ combRefs env + cmbs <- readTVarIO $ combs env (denv, kf) <- - topDEnv <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) + topDEnv cmbs <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) 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 (CIx r i 0) unull bnull + PAp entryComb unull bnull where k0 = maybe KE (CB . Hook) callback @@ -231,8 +236,9 @@ jump0 :: jump0 !callback !env !activeThreads !clo = do ustk <- alloc bstk <- alloc + cmbs <- readTVarIO $ combs env (denv, kf) <- - topDEnv <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) + topDEnv cmbs <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) bstk <- bump bstk poke bstk (Enum Rf.unitRef unitTag) jump env denv activeThreads ustk bstk (kf k0) (BArg1 0) clo @@ -1930,6 +1936,14 @@ unhandledErr fname env i = where bomb sh = die $ fname ++ ": unhandled ability request: " ++ sh +rCombSection :: EnumMap Word64 RCombs -> CombIx -> RComb +rCombSection combs cix@(CIx _ n i) = + case EC.lookup n combs of + Just cmbs -> case EC.lookup i cmbs of + Just cmb -> RComb cix cmb + Nothing -> error $ "unknown section `" ++ show i ++ "` of combinator `" ++ show n ++ "`." + Nothing -> error $ "unknown combinator `" ++ show n ++ "`." + -- combSection :: (HasCallStack) => CCache -> CombIx -> IO Comb -- combSection env (CIx _ n i) = -- readTVarIO (combs env) >>= \cs -> case EC.lookup n cs of From 11dde8e7dee6ce3d423813c2bf93d3348d7f4427 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Tue, 3 Sep 2024 16:50:40 -0700 Subject: [PATCH 05/20] More WIP --- unison-runtime/src/Unison/Runtime/MCode.hs | 7 +++++-- unison-runtime/src/Unison/Runtime/Machine.hs | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 4c14598a39..5154b4b3bd 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -13,6 +13,7 @@ module Unison.Runtime.MCode MLit (..), Instr (..), GSection (.., MatchT, MatchW), + RSection, Section, GComb (..), Comb, @@ -516,6 +517,8 @@ data Instr type Section = GSection CombIx +type RSection = GSection RComb + data GSection comb = -- Apply a function to arguments. This is the 'slow path', and -- handles applying functions from arbitrary sources. This @@ -532,7 +535,7 @@ data GSection comb -- sufficient for where we're jumping to. Call !Bool -- skip stack check - !Word64 -- global function reference + !RComb -- global function reference !Args -- arguments | -- Jump to a captured continuation value. Jump @@ -1503,7 +1506,7 @@ combTypes (Lam _ _ _ _ _ s) = sectionTypes s sectionDeps :: Section -> [Word64] sectionDeps (App _ (Env w _) _) = [w] -sectionDeps (Call _ w _) = [w] +sectionDeps (Call _ (RComb (CIx _ w _) _) _) = [w] sectionDeps (Match _ br) = branchDeps br sectionDeps (DMatch _ _ br) = branchDeps br sectionDeps (RMatch _ pu br) = diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index cf4f7460f4..da45430e1d 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -161,8 +161,9 @@ eval0 :: CCache -> ActiveThreads -> Section -> IO () eval0 !env !activeThreads !co = do ustk <- alloc bstk <- alloc + cmbs <- readTVarIO $ combs env (denv, k) <- - topDEnv <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) + topDEnv cmbs <$> readTVarIO (refTy env) <*> readTVarIO (refTm env) eval env denv activeThreads ustk bstk (k KE) dummyRef co topDEnv :: @@ -172,6 +173,7 @@ topDEnv :: (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) @@ -595,7 +597,7 @@ eval :: Stack 'BX -> K -> Reference -> - Section -> + RSection -> IO () eval !env !denv !activeThreads !ustk !bstk !k r (Match i (TestT df cs)) = do t <- peekOffBi bstk i @@ -631,9 +633,8 @@ 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 n args) = - combSection env (CIx dummyRef n 0) - >>= enter env denv activeThreads ustk bstk k ck args +eval !env !denv !activeThreads !ustk !bstk !k _ (Call ck 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 @@ -694,9 +695,9 @@ enter :: K -> Bool -> Args -> - Comb -> + RComb -> IO () -enter !env !denv !activeThreads !ustk !bstk !k !ck !args !comb = do +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 @@ -706,7 +707,7 @@ enter !env !denv !activeThreads !ustk !bstk !k !ck !args !comb = do -- detecting saturated calls. eval env denv activeThreads ustk bstk k dummyRef entry where - Lam _rf ua ba uf bf entry = comb + (RComb _ (Lam _rf ua ba uf bf entry)) = rcomb {-# INLINE enter #-} -- fast path by-name delaying @@ -1845,7 +1846,7 @@ yield !env !denv !activeThreads !ustk !bstk !k = leap denv k {-# INLINE yield #-} selectTextBranch :: - Util.Text.Text -> Section -> M.Map Util.Text.Text Section -> Section + Util.Text.Text -> RSection -> M.Map Util.Text.Text RSection -> RSection selectTextBranch t df cs = M.findWithDefault df t cs {-# INLINE selectTextBranch #-} From 813ba9a2770a5c311ad78969b5c40a1cede2aee8 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 4 Sep 2024 11:13:48 -0700 Subject: [PATCH 06/20] Propagate more RCombs, start parameterizing Ref --- .../src/Unison/Runtime/Interface.hs | 2 +- unison-runtime/src/Unison/Runtime/MCode.hs | 65 ++++++++++++------- unison-runtime/src/Unison/Runtime/Machine.hs | 22 ++++--- unison-runtime/src/Unison/Runtime/Stack.hs | 10 +-- 4 files changed, 61 insertions(+), 38 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index b11d3cda0f..78f29b6467 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -1280,7 +1280,7 @@ restoreCache (SCache cs crs trs ftm fty int rtm rty sbs) = mapWithKey (\k v -> emitComb @Symbol rns (rf k) k mempty (0, v)) numberedTermLookup - & resolveCombs + & resolveCombs Nothing traceNeeded :: Word64 -> diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 5154b4b3bd..8f0667657d 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -30,6 +30,7 @@ module Unison.Runtime.MCode BPrim2 (..), GBranch (..), Branch, + RBranch, bcount, ucount, emitCombs, @@ -38,6 +39,7 @@ module Unison.Runtime.MCode emptyRNs, argsToLists, combRef, + rCombRef, combDeps, rCombDeps, combTypes, @@ -446,9 +448,11 @@ data MLit | MY !Reference deriving (Show, Eq, Ord) +type Instr = GInstr CombIx + -- Instructions for manipulating the data stack in the main portion of -- a block -data Instr +data GInstr comb = -- 1-argument unboxed primitive operations UPrim1 !UPrim1 -- primitive instruction @@ -483,7 +487,7 @@ data Instr -- statically known function into a closure with arguments. -- No stack is necessary, because no nested evaluation happens, -- so the instruction directly takes a follow-up. - Name !Ref !Args + Name !(GRef comb) !Args | -- Dump some debugging information about the machine state to -- the screen. Info !String -- prefix for output @@ -525,7 +529,7 @@ data GSection comb -- requires checks to determine what exactly should happen. App !Bool -- skip argument check for known calling convention - !Ref -- function to call + !(GRef comb) -- function to call !Args -- arguments | -- This is the 'fast path', for when we statically know we're -- making an exactly saturated call to a statically known @@ -548,7 +552,7 @@ data GSection comb | -- Yield control to the current continuation, with arguments Yield !Args -- values to yield | -- Prefix an instruction onto a section - Ins !Instr !(GSection comb) + Ins !(GInstr comb) !(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. @@ -587,6 +591,9 @@ 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 @@ -629,16 +636,20 @@ instance Show RComb where type GCombs comb = EnumMap Word64 (GComb comb) -data Ref +type Ref = GRef CombIx + +data GRef comb = Stk !Int -- stack reference to a closure - | Env - !Word64 -- global environment reference to a combinator - !Word64 -- section - | Dyn !Word64 -- dynamic scope reference to a closure + | Env !comb + | -- !Word64 -- global environment reference to a combinator + -- !Word64 -- section + Dyn !Word64 -- dynamic scope reference to a closure deriving (Show, Eq, Ord) type Branch = GBranch CombIx +type RBranch = GBranch RComb + data GBranch comb = -- if tag == n then t else f Test1 @@ -763,25 +774,33 @@ emitCombs rns grpr grpn (Rec grp ent) = -- | lazily replace all references to combinators with the combinators themselves, -- 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) -> + -- Combinators which need their knots tied. EnumMap Word64 Combs -> EnumMap Word64 RCombs -resolveCombs combs = +resolveCombs mayExisting combs = -- Fixed point lookup; make sure all uses of Combs are non-strict -- or we'll loop forever. let ~resolved = combs <&> (fmap . fmap) \(cix@(CIx _ n i)) -> - case EC.lookup n resolved of - Just cmbs -> case EC.lookup i cmbs of - Just cmb -> RComb cix cmb - Nothing -> - error $ - "unknown section `" - ++ show i - ++ "` of combinator `" - ++ show n - ++ "`." - Nothing -> error $ "unknown combinator `" ++ show n ++ "`." + let cmbs = case mayExisting >>= EC.lookup n of + Just cmbs -> cmbs + Nothing -> + case EC.lookup n resolved of + Just cmbs -> cmbs + Nothing -> error $ "unknown combinator `" ++ show n ++ "`." + in case EC.lookup i cmbs of + Just cmb -> RComb cix cmb + Nothing -> + error $ + "unknown section `" + ++ show i + ++ "` of combinator `" + ++ show n + ++ "`." in resolved -- Type for aggregating the necessary stack frame size. First field is @@ -1505,7 +1524,7 @@ combTypes :: Comb -> [Word64] combTypes (Lam _ _ _ _ _ s) = sectionTypes s sectionDeps :: Section -> [Word64] -sectionDeps (App _ (Env w _) _) = [w] +sectionDeps (App _ (Env (RComb (CIx _ w _) _)) _) = [w] sectionDeps (Call _ (RComb (CIx _ w _) _) _) = [w] sectionDeps (Match _ br) = branchDeps br sectionDeps (DMatch _ _ br) = branchDeps br @@ -1513,7 +1532,7 @@ sectionDeps (RMatch _ pu br) = sectionDeps pu ++ foldMap branchDeps br sectionDeps (NMatch _ _ br) = branchDeps br sectionDeps (Ins i s) - | Name (Env w _) _ <- i = w : sectionDeps s + | Name (Env (RComb (CIx _ w _) _)) _ <- i = w : sectionDeps s | otherwise = sectionDeps s sectionDeps (Let s (CIx _ w _)) = w : sectionDeps s sectionDeps _ = [] diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index da45430e1d..0e9944b43b 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -141,7 +141,7 @@ baseCCache sandboxed = do mapWithKey (\k v -> let r = builtinTermBackref ! k in emitComb @Symbol rns r k mempty (0, v)) numberedTermLookup - & resolveCombs + & resolveCombs Nothing info :: (Show a) => String -> a -> IO () info ctx x = infos ctx (show x) @@ -157,7 +157,7 @@ stk'info s@(BS _ _ sp _) = do prn sp -- Entry point for evaluating a section -eval0 :: CCache -> ActiveThreads -> Section -> IO () +eval0 :: CCache -> ActiveThreads -> RSection -> IO () eval0 !env !activeThreads !co = do ustk <- alloc bstk <- alloc @@ -734,7 +734,7 @@ apply :: Closure -> IO () apply !env !denv !activeThreads !ustk !bstk !k !ck !args (PAp comb useg bseg) = - combSection env comb >>= \case + case unRComb comb of Lam _rf ua ba uf bf entry | ck || ua <= uac && ba <= bac -> do ustk <- ensure ustk uf @@ -744,7 +744,7 @@ apply !env !denv !activeThreads !ustk !bstk !k !ck !args (PAp comb useg bseg) = bstk <- dumpSeg bstk bseg A ustk <- acceptArgs ustk ua bstk <- acceptArgs bstk ba - eval env denv activeThreads ustk bstk k (combRef comb) entry + 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 @@ -1834,13 +1834,13 @@ 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 cix k) = do - Lam _rf _ _ uf bf nx <- combSection env cix + leap !denv (Push ufsz bfsz uasz basz rComb k) = do + let Lam _rf _ _ uf bf nx = unRComb rComb 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 (combRef cix) nx + eval env denv activeThreads ustk bstk k (rCombRef rComb) nx leap _ (CB (Hook f)) = f ustk bstk leap _ KE = pure () {-# INLINE yield #-} @@ -1850,7 +1850,7 @@ selectTextBranch :: selectTextBranch t df cs = M.findWithDefault df t cs {-# INLINE selectTextBranch #-} -selectBranch :: Tag -> Branch -> Section +selectBranch :: Tag -> RBranch -> RSection selectBranch t (Test1 u y n) | t == u = y | otherwise = n @@ -1971,6 +1971,9 @@ updateMap new0 r = do stateTVar r $ \old -> let total = new <> old in (total, total) +modifyMap :: (s -> s) -> TVar s -> STM s +modifyMap f r = 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 @@ -2121,9 +2124,10 @@ cacheAdd0 ntys0 tml sands cc = atomically $ do 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 <- updateMap ((fmap . fmap) unRComb . mapFromList $ zipWith combinate [ntm ..] rgs) (combs cc) + ncs <- modifyMap (\oldCombs -> (resolveCombs (Just oldCombs) . mapFromList $ zipWith combinate [ntm ..] rgs)) (combs cc) nsn <- updateMap (M.fromList sands) (sandbox cc) pure $ int `seq` rtm `seq` nrs `seq` ncs `seq` nsn `seq` () where diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index de60f0b178..b637bcf2d2 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -85,7 +85,7 @@ data K !Int -- boxed frame size !Int -- pending unboxed args !Int -- pending boxed args - !CombIx -- local continuation reference + !RComb -- local continuation reference !K deriving (Eq, Ord) @@ -112,7 +112,7 @@ traceK :: Reference -> K -> [(Reference, Int)] traceK begin = dedup (begin, 1) where dedup p (Mark _ _ _ _ k) = dedup p k - dedup p@(cur, n) (Push _ _ _ _ (CIx r _ _) k) + dedup p@(cur, n) (Push _ _ _ _ (RComb (CIx r _ _) _) k) | cur == r = dedup (cur, 1 + n) k | otherwise = p : dedup (r, 1) k dedup p _ = [p] @@ -175,7 +175,7 @@ pattern DataC rf ct us bs <- where DataC rf ct us bs = formData rf ct us bs -pattern PApV :: CombIx -> [Int] -> [Closure] -> Closure +pattern PApV :: RComb -> [Int] -> [Closure] -> Closure pattern PApV ic us bs <- PAp ic (ints -> us) (bsegToList -> bs) where @@ -703,7 +703,7 @@ bscount :: Seg 'BX -> Int bscount seg = sizeofArray seg closureTermRefs :: (Monoid m) => (Reference -> m) -> (Closure -> m) -closureTermRefs f (PAp (CIx r _ _) _ cs) = +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) = @@ -720,6 +720,6 @@ closureTermRefs _ _ = mempty contTermRefs :: (Monoid m) => (Reference -> m) -> K -> m contTermRefs f (Mark _ _ _ m k) = foldMap (closureTermRefs f) m <> contTermRefs f k -contTermRefs f (Push _ _ _ _ (CIx r _ _) k) = +contTermRefs f (Push _ _ _ _ (RComb (CIx r _ _) _) k) = f r <> contTermRefs f k contTermRefs _ _ = mempty From 8ac174faad42aa1c154883bc7c17095dfb986636 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 4 Sep 2024 12:03:29 -0700 Subject: [PATCH 07/20] Add new serializations --- unison-runtime/src/Unison/Runtime/MCode.hs | 26 ++-- .../src/Unison/Runtime/MCode/Serialize.hs | 132 +++++++----------- 2 files changed, 70 insertions(+), 88 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 8f0667657d..8c855a46aa 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -11,19 +11,23 @@ module Unison.Runtime.MCode Args (..), RefNums (..), MLit (..), - Instr (..), + GInstr (..), + Instr, GSection (.., MatchT, MatchW), RSection, Section, GComb (..), Comb, RComb (..), + pattern RCombIx, + pattern RCombRef, rCombToComb, GCombs, Combs, RCombs, CombIx (..), - Ref (..), + GRef (..), + Ref, UPrim1 (..), UPrim2 (..), BPrim1 (..), @@ -517,7 +521,7 @@ data GInstr comb Seq !Args | -- Force a delayed expression, catching any runtime exceptions involved TryForce !Int - deriving (Show, Eq, Ord) + deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) type Section = GSection CombIx @@ -539,7 +543,7 @@ data GSection comb -- sufficient for where we're jumping to. Call !Bool -- skip stack check - !RComb -- global function reference + !comb -- global function reference !Args -- arguments | -- Jump to a captured continuation value. Jump @@ -620,6 +624,12 @@ type Combs = GCombs CombIx type RCombs = GCombs RComb +pattern RCombIx :: CombIx -> RComb +pattern RCombIx r <- (rCombIx -> r) + +pattern RCombRef :: Reference -> RComb +pattern RCombRef r <- (combRef . rCombIx -> r) + -- | The fixed point of a GComb where all references to a Comb are themselves Combs. data RComb = RComb { rCombIx :: CombIx, @@ -644,7 +654,7 @@ data GRef comb | -- !Word64 -- global environment reference to a combinator -- !Word64 -- section Dyn !Word64 -- dynamic scope reference to a closure - deriving (Show, Eq, Ord) + deriving (Show, Eq, Ord, Functor, Foldable, Traversable) type Branch = GBranch CombIx @@ -1524,15 +1534,15 @@ combTypes :: Comb -> [Word64] combTypes (Lam _ _ _ _ _ s) = sectionTypes s sectionDeps :: Section -> [Word64] -sectionDeps (App _ (Env (RComb (CIx _ w _) _)) _) = [w] -sectionDeps (Call _ (RComb (CIx _ w _) _) _) = [w] +sectionDeps (App _ (Env (CIx _ w _)) _) = [w] +sectionDeps (Call _ 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 (RComb (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 _ = [] diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index 1d8591e481..479198231d 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -80,43 +80,33 @@ instance Tag SectionT where word2tag i = unknownTag "SectionT" i putSection :: (MonadPut m) => (cix -> m ()) -> GSection cix -> m () -putSection _pCIx (App b r a) = - putTag AppT *> serialize b *> putRef r *> putArgs a -putSection _pCIx (Call b w a) = - putTag CallT *> serialize b *> pWord w *> putArgs a -putSection _pCIx (Jump i a) = - putTag JumpT *> pInt i *> putArgs a -putSection pCIx (Match i b) = - putTag MatchT *> pInt i *> putBranch pCIx b -putSection _pCIx (Yield a) = - putTag YieldT *> putArgs a -putSection pCIx (Ins i s) = - putTag InsT *> putInstr i *> putSection pCIx s -putSection pCIx (Let s ci) = - putTag LetT *> putSection pCIx s *> pCIx ci -putSection _pCIx (Die s) = - putTag DieT *> serialize s -putSection _pCIx Exit = - putTag ExitT -putSection pCIx (DMatch mr i b) = - putTag DMatchT *> putMaybe mr putReference *> pInt i *> putBranch pCIx b -putSection pCIx (NMatch mr i b) = - putTag NMatchT *> putMaybe mr putReference *> pInt i *> putBranch pCIx b -putSection pCIx (RMatch i pu bs) = - putTag RMatchT - *> pInt i - *> putSection pCIx pu - *> putEnumMap pWord (putBranch pCIx) bs +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 + Jump i a -> putTag JumpT *> pInt i *> putArgs a + Match i b -> putTag MatchT *> pInt i *> putBranch pCix 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 + 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 + RMatch i pu bs -> + putTag RMatchT + *> pInt i + *> putSection pCix pu + *> putEnumMap pWord (putBranch pCix) bs getSection :: (MonadGet m) => m cix -> m (GSection cix) getSection gCix = getTag >>= \case - AppT -> App <$> deserialize <*> getRef <*> getArgs - CallT -> Call <$> deserialize <*> gWord <*> getArgs + AppT -> App <$> deserialize <*> getRef gCix <*> getArgs + CallT -> Call <$> deserialize <*> gCix <*> getArgs JumpT -> Jump <$> gInt <*> getArgs MatchT -> Match <$> gInt <*> getBranch gCix YieldT -> Yield <$> getArgs - InsT -> Ins <$> getInstr <*> getSection gCix + InsT -> Ins <$> getInstr gCix <*> getSection gCix LetT -> Let <$> getSection gCix <*> gCix DieT -> Die <$> deserialize ExitT -> pure Exit @@ -188,48 +178,30 @@ instance Tag InstrT where word2tag 18 = pure BLitT word2tag n = unknownTag "InstrT" n -putInstr :: (MonadPut m) => Instr -> m () -putInstr (UPrim1 up i) = - putTag UPrim1T *> putTag up *> pInt i -putInstr (UPrim2 up i j) = - putTag UPrim2T *> putTag up *> pInt i *> pInt j -putInstr (BPrim1 bp i) = - putTag BPrim1T *> putTag bp *> pInt i -putInstr (BPrim2 bp i j) = - putTag BPrim2T *> putTag bp *> pInt i *> pInt j -putInstr (ForeignCall b w a) = - putTag ForeignCallT *> serialize b *> pWord w *> putArgs a -putInstr (SetDyn w i) = - putTag SetDynT *> pWord w *> pInt i -putInstr (Capture w) = - putTag CaptureT *> pWord w -putInstr (Name r a) = - putTag NameT *> putRef r *> putArgs a -putInstr (Info s) = - putTag InfoT *> serialize s -putInstr (Pack r w a) = - putTag PackT *> putReference r *> pWord w *> putArgs a -putInstr (Unpack mr i) = - putTag UnpackT *> putMaybe mr putReference *> pInt i -putInstr (Lit l) = - putTag LitT *> putLit l -putInstr (BLit r l) = - putTag BLitT *> putReference r *> putLit l -putInstr (Print i) = - putTag PrintT *> pInt i -putInstr (Reset s) = - putTag ResetT *> putEnumSet pWord s -putInstr (Fork i) = - putTag ForkT *> pInt i -putInstr (Atomically i) = - putTag AtomicallyT *> pInt i -putInstr (Seq a) = - putTag SeqT *> putArgs a -putInstr (TryForce i) = - putTag TryForceT *> pInt i - -getInstr :: (MonadGet m) => m Instr -getInstr = +putInstr :: (MonadPut m) => (cix -> m ()) -> GInstr cix -> m () +putInstr pCix = \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 + (BPrim2 bp i j) -> putTag BPrim2T *> putTag bp *> pInt i *> pInt j + (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 + (Info s) -> putTag InfoT *> serialize s + (Pack r w a) -> putTag PackT *> putReference r *> pWord w *> putArgs a + (Unpack mr i) -> putTag UnpackT *> putMaybe mr putReference *> pInt i + (Lit l) -> putTag LitT *> putLit l + (BLit r l) -> putTag BLitT *> putReference r *> putLit l + (Print i) -> putTag PrintT *> pInt i + (Reset s) -> putTag ResetT *> putEnumSet pWord s + (Fork i) -> putTag ForkT *> pInt i + (Atomically i) -> putTag AtomicallyT *> pInt i + (Seq a) -> putTag SeqT *> putArgs a + (TryForce i) -> putTag TryForceT *> pInt i + +getInstr :: (MonadGet m) => m cix -> m (GInstr cix) +getInstr gCix = getTag >>= \case UPrim1T -> UPrim1 <$> getTag <*> gInt UPrim2T -> UPrim2 <$> getTag <*> gInt <*> gInt @@ -238,7 +210,7 @@ getInstr = ForeignCallT -> ForeignCall <$> deserialize <*> gWord <*> getArgs SetDynT -> SetDyn <$> gWord <*> gInt CaptureT -> Capture <$> gWord - NameT -> Name <$> getRef <*> getArgs + NameT -> Name <$> getRef gCix <*> getArgs InfoT -> Info <$> deserialize PackT -> Pack <$> getReference <*> gWord <*> getArgs UnpackT -> Unpack <$> getMaybe getReference <*> gInt @@ -342,16 +314,16 @@ instance Tag RefT where word2tag 2 = pure DynT word2tag n = unknownTag "RefT" n -putRef :: (MonadPut m) => Ref -> m () -putRef (Stk i) = putTag StkT *> pInt i -putRef (Env i j) = putTag EnvT *> pWord i *> pWord j -putRef (Dyn i) = putTag DynT *> pWord i +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 -getRef :: (MonadGet m) => m Ref -getRef = +getRef :: (MonadGet m) => m cix -> m (GRef cix) +getRef gCix = getTag >>= \case StkT -> Stk <$> gInt - EnvT -> Env <$> gWord <*> gWord + EnvT -> Env <$> gCix DynT -> Dyn <$> gWord putCombIx :: (MonadPut m) => CombIx -> m () From 3bca08c307794d96f9aeb6421a84165c2ff7b212 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Wed, 4 Sep 2024 12:13:35 -0700 Subject: [PATCH 08/20] Finish replacing combs in Ref --- .../src/Unison/Runtime/Decompile.hs | 4 +- unison-runtime/src/Unison/Runtime/MCode.hs | 44 ++++++++++--------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index 5859a1de1f..6d43257b89 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -32,7 +32,7 @@ import Unison.Runtime.Foreign maybeUnwrapForeign, ) import Unison.Runtime.IOSource (iarrayFromListRef, ibarrayFromBytesRef) -import Unison.Runtime.MCode (CombIx (..), GComb (..), RComb (..)) +import Unison.Runtime.MCode (CombIx (..), GComb (..), RComb (..), pattern RCombIx) import Unison.Runtime.Stack ( Closure (..), pattern DataC, @@ -161,7 +161,7 @@ decompile backref topTerms (DataC rf _ [] [b]) 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 (CIx rf rt k) [] 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 diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 8c855a46aa..978e9a329a 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -902,24 +902,24 @@ emitSection rns grpr grpn rec ctx (TLets d us ms bu bo) = where ectx = pushCtx (zip us ms) ctx emitSection rns grpr grpn rec ctx (TName u (Left f) args bo) = - emitClosures grpn rec ctx args $ \ctx as -> - Ins (Name (Env (cnum rns f) 0) as) + 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 emitSection rns grpr grpn rec ctx (TName u (Right v) args bo) | Just (i, BX) <- ctxResolve ctx v = - emitClosures grpn rec ctx args $ \ctx as -> + emitClosures grpr grpn rec ctx args $ \ctx as -> Ins (Name (Stk i) as) <$> emitSection rns grpr grpn rec (Var u BX ctx) bo | Just n <- rctxResolve rec v = - emitClosures grpn rec ctx args $ \ctx as -> - Ins (Name (Env grpn n) as) + 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 | otherwise = emitSectionVErr v -emitSection _ _ grpn rec ctx (TVar 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 grpn j) ZArgs + countCtx ctx $ App False (Env (CIx grpr grpn j)) ZArgs | otherwise = emitSectionVErr v emitSection _ _ grpn _ ctx (TPrm p args) = -- 3 is a conservative estimate of how many extra stack slots @@ -939,9 +939,9 @@ emitSection _ _ grpn _ ctx (TFOp p args) = $ DArgV i j where (i, j) = countBlock ctx -emitSection rns _ grpn rec ctx (TApp f args) = - emitClosures grpn rec ctx args $ \ctx as -> - countCtx ctx $ emitFunction rns grpn rec ctx f as +emitSection rns grpr grpn rec ctx (TApp f args) = + emitClosures grpr grpn rec ctx args $ \ctx as -> + countCtx ctx $ emitFunction rns grpr grpn rec ctx f as emitSection _ _ _ _ ctx (TLit l) = c . countCtx ctx . Ins (emitLit l) . Yield $ litArg l where @@ -1036,31 +1036,32 @@ emitSection _ _ _ _ _ tm = emitFunction :: (Var v) => RefNums -> + Reference -> Word64 -> -- self combinator number RCtx v -> -- recursive binding group Ctx v -> -- local context Func v -> Args -> Section -emitFunction _ grpn rec ctx (FVar v) as +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 grpn j) as + App False (Env (CIx grpr grpn j)) as | otherwise = emitSectionVErr v -emitFunction rns _ _ _ (FComb r) as +emitFunction rns _grpr _ _ _ (FComb r) as | otherwise -- slow path = - App False (Env n 0) as + App False (Env (CIx r n 0)) as where n = cnum rns r -emitFunction rns _ _ _ (FCon r t) as = +emitFunction rns _grpr _ _ _ (FCon r t) as = Ins (Pack r (packTags rt t) as) . Yield $ BArg1 0 where rt = toEnum . fromIntegral $ dnum rns r -emitFunction rns _ _ _ (FReq r e) as = +emitFunction rns _grpr _ _ _ (FReq r e) as = -- Currently implementing packed calling convention for abilities -- TODO ct is 16 bits, but a is 48 bits. This will be a problem if we have -- more than 2^16 types. @@ -1070,11 +1071,11 @@ emitFunction rns _ _ _ (FReq r e) as = where a = dnum rns r rt = toEnum . fromIntegral $ a -emitFunction _ _ _ ctx (FCont k) as +emitFunction _ _grpr _ _ ctx (FCont k) as | Just (i, BX) <- ctxResolve ctx k = Jump i as | Nothing <- ctxResolve ctx k = emitFunctionVErr k | otherwise = internalBug $ "emitFunction: continuations are boxed" -emitFunction _ _ _ _ (FPrim _) _ = +emitFunction _ _grpr _ _ _ (FPrim _) _ = internalBug "emitFunction: impossible" countBlock :: Ctx v -> (Int, Int) @@ -1480,20 +1481,21 @@ emitBLit l = BLit (ANF.litRef l) (litToMLit l) -- provided continuation. emitClosures :: (Var v) => + Reference -> Word64 -> RCtx v -> Ctx v -> [v] -> (Ctx v -> Args -> Emit Section) -> Emit Section -emitClosures grpn rec ctx args k = +emitClosures grpr grpn rec ctx args k = allocate ctx args $ \ctx -> k ctx $ emitArgs grpn ctx args where allocate ctx [] k = k ctx allocate ctx (a : as) k | Just _ <- ctxResolve ctx a = allocate ctx as k | Just n <- rctxResolve rec a = - Ins (Name (Env grpn n) ZArgs) <$> allocate (Var a BX ctx) as k + Ins (Name (Env (CIx grpr grpn n)) ZArgs) <$> allocate (Var a BX ctx) as k | otherwise = internalBug $ "emitClosures: unknown reference: " ++ show a @@ -1535,7 +1537,7 @@ combTypes (Lam _ _ _ _ _ s) = sectionTypes s sectionDeps :: Section -> [Word64] sectionDeps (App _ (Env (CIx _ w _)) _) = [w] -sectionDeps (Call _ w _) = [w] +sectionDeps (Call _ (CIx _ w _) _) = [w] sectionDeps (Match _ br) = branchDeps br sectionDeps (DMatch _ _ br) = branchDeps br sectionDeps (RMatch _ pu br) = From fe7e36d594fde29feef1c890b182ae051c118ecc Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 5 Sep 2024 07:47:53 -0700 Subject: [PATCH 09/20] Propagate RClosure --- unison-runtime/src/Unison/Runtime/Builtin.hs | 6 +- .../src/Unison/Runtime/Decompile.hs | 3 +- .../src/Unison/Runtime/Foreign/Function.hs | 25 ++++---- .../src/Unison/Runtime/Interface.hs | 15 ++--- unison-runtime/src/Unison/Runtime/MCode.hs | 10 ++++ unison-runtime/src/Unison/Runtime/Machine.hs | 50 +++++++++------- unison-runtime/src/Unison/Runtime/Stack.hs | 57 +++++++++++-------- 7 files changed, 98 insertions(+), 68 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Builtin.hs b/unison-runtime/src/Unison/Runtime/Builtin.hs index f9c827fda9..52dcba6652 100644 --- a/unison-runtime/src/Unison/Runtime/Builtin.hs +++ b/unison-runtime/src/Unison/Runtime/Builtin.hs @@ -3156,7 +3156,7 @@ declareForeigns = do $ Right <$> PA.freezeByteArray src (fromIntegral off) (fromIntegral len) declareForeign Untracked "MutableArray.freeze" boxNatNatToExnBox . mkForeign $ - \(src, off, len) -> + \(src :: PA.MutableArray PA.RealWorld Closure.RClosure, off, len) -> if len == 0 then fmap Right . PA.unsafeFreezeArray =<< PA.newArray 0 Closure.BlackHole else @@ -3173,7 +3173,7 @@ declareForeigns = do pure . PA.sizeofByteArray declareForeign Tracked "IO.array" natToBox . mkForeign $ - \n -> PA.newArray n Closure.BlackHole + \n -> PA.newArray n (Closure.BlackHole :: Closure.RClosure) declareForeign Tracked "IO.arrayOf" boxNatToBox . mkForeign $ \(v :: Closure, n) -> PA.newArray n v declareForeign Tracked "IO.bytearray" natToBox . mkForeign $ PA.newByteArray @@ -3185,7 +3185,7 @@ declareForeigns = do pure arr declareForeign Untracked "Scope.array" natToBox . mkForeign $ - \n -> PA.newArray n Closure.BlackHole + \n -> PA.newArray n (Closure.BlackHole :: Closure.RClosure) 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 6d43257b89..fab0c95c95 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -34,7 +34,8 @@ import Unison.Runtime.Foreign import Unison.Runtime.IOSource (iarrayFromListRef, ibarrayFromBytesRef) import Unison.Runtime.MCode (CombIx (..), GComb (..), RComb (..), pattern RCombIx) import Unison.Runtime.Stack - ( Closure (..), + ( Closure, + GClosure (..), pattern DataC, pattern PApV, ) diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 3f1b93d9e2..2789c1c3bf 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -1,6 +1,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ViewPatterns #-} @@ -121,7 +122,7 @@ instance ForeignConvention Char where ustk <- bump ustk (ustk, bstk) <$ poke ustk (Char.ord ch) -instance ForeignConvention Closure where +instance (GClosure comb ~ Elem 'BX) => ForeignConvention (GClosure comb) where readForeign us (i : bs) _ bstk = (us,bs,) <$> peekOff bstk i readForeign _ [] _ _ = foreignCCError "Closure" writeForeign ustk bstk c = do @@ -436,7 +437,7 @@ instance ForeignConvention BufferMode where ustk <- bump ustk (ustk, bstk) <$ poke ustk sblock'buf -instance ForeignConvention [Closure] where +instance (GClosure comb ~ Elem 'BX) => ForeignConvention [GClosure comb] where readForeign us (i : bs) _ bstk = (us,bs,) . toList <$> peekOffS bstk i readForeign _ _ _ _ = foreignCCError "[Closure]" @@ -448,23 +449,23 @@ instance ForeignConvention [Foreign] where readForeign = readForeignAs (fmap marshalToForeign) writeForeign = writeForeignAs (fmap Foreign) -instance ForeignConvention (MVar Closure) where +instance ForeignConvention (MVar RClosure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap mvarRef) -instance ForeignConvention (TVar Closure) where +instance ForeignConvention (TVar RClosure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap tvarRef) -instance ForeignConvention (IORef Closure) where +instance ForeignConvention (IORef RClosure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap refRef) -instance ForeignConvention (Ticket Closure) where +instance ForeignConvention (Ticket RClosure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap ticketRef) -instance ForeignConvention (Promise Closure) where +instance ForeignConvention (Promise RClosure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap promiseRef) @@ -480,7 +481,7 @@ instance ForeignConvention Foreign where readForeign = readForeignAs marshalToForeign writeForeign = writeForeignAs Foreign -instance ForeignConvention (PA.MutableArray s Closure) where +instance ForeignConvention (PA.MutableArray s RClosure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap marrayRef) @@ -488,7 +489,7 @@ instance ForeignConvention (PA.MutableByteArray s) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap mbytearrayRef) -instance ForeignConvention (PA.Array Closure) where +instance ForeignConvention (PA.Array RClosure) where readForeign = readForeignAs (unwrapForeign . marshalToForeign) writeForeign = writeForeignAs (Foreign . Wrap iarrayRef) @@ -500,13 +501,13 @@ instance {-# OVERLAPPABLE #-} (BuiltinForeign b) => ForeignConvention b where readForeign = readForeignBuiltin writeForeign = writeForeignBuiltin -fromUnisonPair :: Closure -> (a, b) +fromUnisonPair :: RClosure -> (a, b) fromUnisonPair (DataC _ _ [] [x, DataC _ _ [] [y, _]]) = (unwrapForeignClosure x, unwrapForeignClosure y) fromUnisonPair _ = error "fromUnisonPair: invalid closure" toUnisonPair :: - (BuiltinForeign a, BuiltinForeign b) => (a, b) -> Closure + (BuiltinForeign a, BuiltinForeign b) => (a, b) -> RClosure toUnisonPair (x, y) = DataC Ty.pairRef @@ -517,7 +518,7 @@ toUnisonPair (x, y) = un = DataC Ty.unitRef 0 [] [] wr z = Foreign $ wrapBuiltin z -unwrapForeignClosure :: Closure -> a +unwrapForeignClosure :: RClosure -> 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 78f29b6467..6591da87bd 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -100,8 +100,9 @@ import Unison.Runtime.Decompile import Unison.Runtime.Exception import Unison.Runtime.MCode ( Args (..), + CombIx, + GInstr (..), GSection (..), - Instr (..), RCombs, RefNums (..), combDeps, @@ -127,6 +128,7 @@ import Unison.Runtime.Machine refNumsTm, refNumsTy, reifyValue, + resolveSection, ) import Unison.Runtime.Pattern import Unison.Runtime.Serialize as SER @@ -991,15 +993,13 @@ evalInContext ppe ctx activeThreads w = do pure $ finish result executeMainComb :: - Word64 -> + CombIx -> CCache -> IO (Either (Pretty ColorText) ()) executeMainComb init cc = do + rSection <- resolveSection cc $ Ins (Pack RF.unitRef 0 ZArgs) $ Call True init (BArg1 0) result <- - UnliftIO.try - . eval0 cc Nothing - . Ins (Pack RF.unitRef 0 ZArgs) - $ Call True init (BArg1 0) + UnliftIO.try . eval0 cc Nothing $ rSection case result of Left err -> Left <$> formatErr err Right () -> pure (Right ()) @@ -1129,6 +1129,7 @@ decodeStandalone b = bimap thd thd $ runGetOrFail g b (,,,) <$> deserialize <*> deserialize + -- TODO: Check where this is encoded. <*> getNat <*> getStoredCache @@ -1188,7 +1189,7 @@ tryM = hRE (PE _ e) = pure $ Just e hRE (BU _ _ _) = pure $ Just "impossible" -runStandalone :: StoredCache -> Word64 -> IO (Either (Pretty ColorText) ()) +runStandalone :: StoredCache -> CombIx -> IO (Either (Pretty ColorText) ()) runStandalone sc init = restoreCache sc >>= executeMainComb init diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 978e9a329a..b41b02b8d1 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -13,6 +13,7 @@ module Unison.Runtime.MCode MLit (..), GInstr (..), Instr, + RInstr, GSection (.., MatchT, MatchW), RSection, Section, @@ -27,6 +28,7 @@ module Unison.Runtime.MCode RCombs, CombIx (..), GRef (..), + RRef, Ref, UPrim1 (..), UPrim2 (..), @@ -454,6 +456,8 @@ data MLit type Instr = GInstr CombIx +type RInstr = GInstr RComb + -- Instructions for manipulating the data stack in the main portion of -- a block data GInstr comb @@ -627,9 +631,13 @@ type RCombs = GCombs RComb pattern RCombIx :: CombIx -> RComb pattern RCombIx r <- (rCombIx -> r) +{-# COMPLETE RCombIx #-} + pattern RCombRef :: Reference -> RComb pattern RCombRef r <- (combRef . rCombIx -> r) +{-# COMPLETE RCombRef #-} + -- | The fixed point of a GComb where all references to a Comb are themselves Combs. data RComb = RComb { rCombIx :: CombIx, @@ -648,6 +656,8 @@ type GCombs comb = EnumMap Word64 (GComb comb) type Ref = GRef CombIx +type RRef = GRef RComb + data GRef comb = Stk !Int -- stack reference to a closure | Env !comb diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 0e9944b43b..e59b320611 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -264,6 +264,7 @@ buildLit _ (MM r) = Foreign (Wrap Rf.termLinkRef r) buildLit _ (MY r) = Foreign (Wrap Rf.typeLinkRef r) buildLit _ (MD _) = error "buildLit: double" +-- | Execute an instruction exec :: CCache -> DEnv -> @@ -272,7 +273,7 @@ exec :: Stack 'BX -> K -> Reference -> - Instr -> + RInstr -> IO (DEnv, Stack 'UN, Stack 'BX, K) exec !_ !denv !_activeThreads !ustk !bstk !k _ (Info tx) = do info tx ustk @@ -589,6 +590,7 @@ numValue mr clo = ++ show clo ++ maybe "" (\r -> "\nexpected type: " ++ show r) mr +-- | Evaluate a section eval :: CCache -> DEnv -> @@ -1919,11 +1921,8 @@ discardCont denv ustk bstk k p = <&> \(_, denv, ustk, bstk, k) -> (denv, ustk, bstk, k) {-# INLINE discardCont #-} -resolve :: CCache -> DEnv -> Stack 'BX -> Ref -> IO Closure -resolve env _ _ (Env n i) = - readTVarIO (combRefs env) >>= \rs -> case EC.lookup n rs of - Just r -> pure $ PAp (CIx r n i) unull bnull - Nothing -> die $ "resolve: missing reference for comb: " ++ show n +resolve :: CCache -> DEnv -> Stack 'BX -> RRef -> IO Closure +resolve _ _ _ (Env rComb) = pure $ PAp rComb unull bnull resolve _ _ bstk (Stk i) = peekOff bstk i resolve env denv _ (Dyn i) = case EC.lookup i denv of Just clo -> pure clo @@ -1945,6 +1944,11 @@ rCombSection combs cix@(CIx _ n i) = Nothing -> error $ "unknown section `" ++ show i ++ "` of combinator `" ++ show n ++ "`." Nothing -> error $ "unknown combinator `" ++ show n ++ "`." +resolveSection :: CCache -> Section -> IO RSection +resolveSection cc section = do + rcombs <- readTVarIO (combs cc) + pure $ rCombSection rcombs <$> section + -- combSection :: (HasCallStack) => CCache -> CombIx -> IO Comb -- combSection env (CIx _ n i) = -- readTVarIO (combs env) >>= \cs -> case EC.lookup n cs of @@ -2183,8 +2187,8 @@ reflectValue rty = goV goIx (CIx r _ i) = ANF.GR r i - goV (PApV cix ua ba) = - ANF.Partial (goIx cix) (fromIntegral <$> ua) <$> traverse goV ba + goV (PApV rComb ua ba) = + ANF.Partial (goIx $ rCombIx rComb) (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 @@ -2199,13 +2203,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 cix k) = + goK (Push uf bf ua ba rComb k) = ANF.Push (fromIntegral uf) (fromIntegral bf) (fromIntegral ua) (fromIntegral ba) - (goIx cix) + (goIx $ rCombIx rComb) <$> goK k goF f @@ -2238,16 +2242,17 @@ 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] Closure) +reifyValue :: CCache -> ANF.Value -> IO (Either [Reference] RClosure) reifyValue cc val = do erc <- - atomically $ - readTVar (refTm cc) >>= \rtm -> - case S.toList $ S.filter (`M.notMember` rtm) tmLinks of - [] -> - Right . (,rtm) - <$> addRefs (freshTy cc) (refTy cc) (tagRefs cc) tyLinks - l -> pure (Left l) + atomically $ do + combs <- readTVar (combs cc) + rtm <- readTVar (refTm cc) + case S.toList $ S.filter (`M.notMember` rtm) tmLinks of + [] -> do + newTy <- addRefs (freshTy cc) (refTy cc) (tagRefs cc) tyLinks + pure . Right $ (combs, newTy, rtm) + l -> pure (Left l) traverse (\rfs -> reifyValue0 rfs val) erc where f False r = (mempty, S.singleton r) @@ -2255,10 +2260,10 @@ reifyValue cc val = do (tyLinks, tmLinks) = valueLinks f val reifyValue0 :: - (M.Map Reference Word64, M.Map Reference Word64) -> + (EnumMap Word64 RCombs, M.Map Reference Word64, M.Map Reference Word64) -> ANF.Value -> IO Closure -reifyValue0 (rty, rtm) = goV +reifyValue0 (combs, rty, rtm) = goV where err s = "reifyValue: cannot restore value: " ++ s refTy r @@ -2267,7 +2272,10 @@ reifyValue0 (rty, rtm) = goV refTm r | Just w <- M.lookup r rtm = pure w | otherwise = die . err $ "unknown term reference: " ++ show r - goIx (ANF.GR r i) = refTm r <&> \n -> CIx r n i + goIx :: ANF.GroupRef -> IO RComb + goIx (ANF.GR r i) = + refTm r <&> \n -> + rCombSection combs (CIx r n i) goV (ANF.Partial gr ua ba) = pap <$> (goIx gr) <*> traverse goV ba diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index b637bcf2d2..eb1884ed7f 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -8,7 +8,10 @@ module Unison.Runtime.Stack ( K (..), - Closure (.., DataC, PApV, CapV), + GClosure (.., DataC, PApV, CapV), + Closure, + RClosure, + IxClosure, Callback (..), Augment (..), Dump (..), @@ -77,7 +80,7 @@ data K !Int -- pending unboxed args !Int -- pending boxed args !(EnumSet Word64) - !(EnumMap Word64 Closure) + !(EnumMap Word64 RClosure) !K | -- save information about a frame for later resumption Push @@ -89,18 +92,24 @@ data K !K deriving (Eq, Ord) -data Closure +type RClosure = GClosure RComb + +type IxClosure = GClosure CombIx + +type Closure = GClosure RComb + +data GClosure comb = PAp - RComb {- Possibly recursive comb, keep it lazy or risk blowing up! -} + comb {- Possibly recursive comb, keep it lazy or risk blowing up -} {-# 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 !Closure - | DataB2 !Reference !Word64 !Closure !Closure - | DataUB !Reference !Word64 !Int !Closure + | 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) | -- code cont, u/b arg size, u/b data stacks Captured !K !Int !Int {-# UNPACK #-} !(Seg 'UN) !(Seg 'BX) @@ -117,7 +126,7 @@ traceK begin = dedup (begin, 1) | otherwise = p : dedup (r, 1) k dedup p _ = [p] -splitData :: Closure -> Maybe (Reference, Word64, [Int], [Closure]) +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], []) @@ -144,15 +153,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 -> [Closure] +bsegToList :: Seg 'BX -> [RClosure] bsegToList = reverse . L.toList -- | Converts a list of closures back to a boxed segment. Segments are stored -- backwards, so this reverses the contents. -bseg :: [Closure] -> Seg 'BX +bseg :: [RClosure] -> Seg 'BX bseg = L.fromList . reverse -formData :: Reference -> Word64 -> [Int] -> [Closure] -> Closure +formData :: Reference -> Word64 -> [Int] -> [RClosure] -> RClosure formData r t [] [] = Enum r t formData r t [i] [] = DataU1 r t i formData r t [i, j] [] = DataU2 r t i j @@ -169,19 +178,19 @@ frameDataSize = go 0 0 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 -pattern DataC :: Reference -> Word64 -> [Int] -> [Closure] -> Closure +pattern DataC :: Reference -> Word64 -> [Int] -> [RClosure] -> RClosure 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] -> [Closure] -> Closure +pattern PApV :: RComb -> [Int] -> [RClosure] -> RClosure pattern PApV ic us bs <- PAp ic (ints -> us) (bsegToList -> bs) where PApV ic us bs = PAp ic (useg us) (bseg bs) -pattern CapV :: K -> Int -> Int -> [Int] -> [Closure] -> Closure +pattern CapV :: K -> Int -> Int -> [Int] -> [RClosure] -> RClosure pattern CapV k ua ba us bs <- Captured k ua ba (ints -> us) (bsegToList -> bs) where @@ -193,7 +202,7 @@ pattern CapV k ua ba us bs <- {-# COMPLETE DataC, PApV, CapV, Foreign, BlackHole #-} -marshalToForeign :: (HasCallStack) => Closure -> Foreign +marshalToForeign :: (HasCallStack) => RClosure -> Foreign marshalToForeign (Foreign x) = x marshalToForeign c = error $ "marshalToForeign: unhandled closure: " ++ show c @@ -206,7 +215,7 @@ type FP = Int type UA = MutableByteArray (PrimState IO) -type BA = MutableArray (PrimState IO) Closure +type BA = MutableArray (PrimState IO) RClosure words :: Int -> Int words n = n `div` 8 @@ -518,16 +527,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 Closure) +peekOffS :: Stack 'BX -> Int -> IO (Seq RClosure) peekOffS bstk i = unwrapForeign . marshalToForeign <$> peekOff bstk i {-# INLINE peekOffS #-} -pokeS :: Stack 'BX -> Seq Closure -> IO () +pokeS :: Stack 'BX -> Seq RClosure -> IO () pokeS bstk s = poke bstk (Foreign $ Wrap Ty.listRef s) {-# INLINE pokeS #-} -pokeOffS :: Stack 'BX -> Int -> Seq Closure -> IO () +pokeOffS :: Stack 'BX -> Int -> Seq RClosure -> IO () pokeOffS bstk i s = pokeOff bstk i (Foreign $ Wrap Ty.listRef s) {-# INLINE pokeOffS #-} @@ -560,10 +569,10 @@ instance MEM 'BX where { bap :: !Int, bfp :: !Int, bsp :: !Int, - bstk :: {-# UNPACK #-} !(MutableArray (PrimState IO) Closure) + bstk :: {-# UNPACK #-} !(MutableArray (PrimState IO) RClosure) } - type Elem 'BX = Closure - type Seg 'BX = Array Closure + type Elem 'BX = RClosure + type Seg 'BX = Array RClosure alloc = BS (-1) (-1) (-1) <$> newArray 512 BlackHole {-# INLINE alloc #-} @@ -702,7 +711,7 @@ uscount seg = words $ sizeofByteArray seg bscount :: Seg 'BX -> Int bscount seg = sizeofArray seg -closureTermRefs :: (Monoid m) => (Reference -> m) -> (Closure -> m) +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 @@ -713,7 +722,7 @@ closureTermRefs f (DataUB _ _ _ c) = closureTermRefs f (Captured k _ _ _ cs) = contTermRefs f k <> foldMap (closureTermRefs f) cs closureTermRefs f (Foreign fo) - | Just (cs :: Seq Closure) <- maybeUnwrapForeign Ty.listRef fo = + | Just (cs :: Seq RClosure) <- maybeUnwrapForeign Ty.listRef fo = foldMap (closureTermRefs f) cs closureTermRefs _ _ = mempty From 33508bd31953f015ef2ac1bb65b2b1a3d4861e45 Mon Sep 17 00:00:00 2001 From: ChrisPenner Date: Thu, 5 Sep 2024 15:40:46 +0000 Subject: [PATCH 10/20] automatically run ormolu --- unison-runtime/src/Unison/Runtime/Stack.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index eb1884ed7f..e6473fd140 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -348,8 +348,8 @@ class MEM (b :: Mem) where asize :: Stack b -> SZ instance MEM 'UN where - data Stack 'UN - = -- Note: uap <= ufp <= usp + data Stack 'UN = + -- Note: uap <= ufp <= usp US { uap :: !Int, -- arg pointer ufp :: !Int, -- frame pointer From 8bd04c5187a9303dd10f6b0a8e9e0aa9cdcd5b12 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 5 Sep 2024 08:48:10 -0700 Subject: [PATCH 11/20] Propagate new interface outwards --- unison-cli/src/Unison/Main.hs | 4 ++-- unison-runtime/src/Unison/Runtime/Interface.hs | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/unison-cli/src/Unison/Main.hs b/unison-cli/src/Unison/Main.hs index 498f2b6218..8dcbf1fa8f 100644 --- a/unison-cli/src/Unison/Main.hs +++ b/unison-cli/src/Unison/Main.hs @@ -234,10 +234,10 @@ main version = do exitError . P.wrap . P.text $ "I was unable to parse this file as a compiled\ \ program. The parser generated an unrecognized error." - Right (Right (v, rf, w, sto)) + Right (Right (v, rf, combIx, sto)) | not vmatch -> mismatchMsg | otherwise -> - withArgs args (RTI.runStandalone sto w) >>= \case + withArgs args (RTI.runStandalone sto combIx) >>= \case Left err -> exitError err Right () -> pure () where diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 6591da87bd..c6f9aa6fe7 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -100,7 +100,7 @@ import Unison.Runtime.Decompile import Unison.Runtime.Exception import Unison.Runtime.MCode ( Args (..), - CombIx, + CombIx (..), GInstr (..), GSection (..), RCombs, @@ -663,11 +663,13 @@ interpCompile version ctxVar cl ppe rf path = tryM $ do let cc = ccache ctx lk m = flip Map.lookup m =<< baseToIntermed ctx rf Just w <- lk <$> readTVarIO (refTm cc) + -- TODO: Check with Dan that this is correct + let combIx = CIx rf w 0 sto <- standalone cc w BL.writeFile path . runPutL $ do serialize $ version serialize $ RF.showShort 8 rf - putNat w + putCombIx combIx putStoredCache sto backrefLifted :: @@ -1121,7 +1123,7 @@ catchInternalErrors sub = sub `UnliftIO.catch` hCE `UnliftIO.catch` hRE decodeStandalone :: BL.ByteString -> - Either String (Text, Text, Word64, StoredCache) + Either String (Text, Text, CombIx, StoredCache) decodeStandalone b = bimap thd thd $ runGetOrFail g b where thd (_, _, x) = x @@ -1130,7 +1132,7 @@ decodeStandalone b = bimap thd thd $ runGetOrFail g b <$> deserialize <*> deserialize -- TODO: Check where this is encoded. - <*> getNat + <*> getCombIx <*> getStoredCache -- | Whether the runtime is hosted within a persistent session or as a one-off process. From 0a0df37ece4a6fd20245d1ebead55b2609039508 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 5 Sep 2024 08:52:00 -0700 Subject: [PATCH 12/20] Remove redundant ref in Lam Comments --- unison-runtime/src/Unison/Runtime/Decompile.hs | 4 ++-- unison-runtime/src/Unison/Runtime/Foreign/Function.hs | 4 ++++ unison-runtime/src/Unison/Runtime/MCode.hs | 11 +++++------ unison-runtime/src/Unison/Runtime/MCode/Serialize.hs | 6 +++--- unison-runtime/src/Unison/Runtime/Machine.hs | 6 +++--- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Decompile.hs b/unison-runtime/src/Unison/Runtime/Decompile.hs index fab0c95c95..13084ea1dc 100644 --- a/unison-runtime/src/Unison/Runtime/Decompile.hs +++ b/unison-runtime/src/Unison/Runtime/Decompile.hs @@ -32,7 +32,7 @@ import Unison.Runtime.Foreign maybeUnwrapForeign, ) import Unison.Runtime.IOSource (iarrayFromListRef, ibarrayFromBytesRef) -import Unison.Runtime.MCode (CombIx (..), GComb (..), RComb (..), pattern RCombIx) +import Unison.Runtime.MCode (CombIx (..), pattern RCombIx, pattern RCombRef) import Unison.Runtime.Stack ( Closure, GClosure (..), @@ -173,7 +173,7 @@ decompile backref topTerms (PApV (RCombIx (CIx rf rt k)) [] bs) Just _ <- topTerms rt 0 = err (UnkLocal rf k) $ bug "" | otherwise = err (UnkComb rf) $ ref () rf -decompile _ _ (PAp (RComb _cix (Lam rf _ _ _ _ _)) _ _) = +decompile _ _ (PAp (RCombRef rf) _ _) = err (BadPAp rf) $ bug "" decompile _ _ (DataC rf _ _ _) = err (BadData rf) $ bug "" decompile _ _ BlackHole = err Exn $ bug "" diff --git a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs index 2789c1c3bf..de73cc7331 100644 --- a/unison-runtime/src/Unison/Runtime/Foreign/Function.hs +++ b/unison-runtime/src/Unison/Runtime/Foreign/Function.hs @@ -122,6 +122,8 @@ instance ForeignConvention Char where ustk <- bump ustk (ustk, bstk) <$ poke ustk (Char.ord ch) +-- 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 readForeign us (i : bs) _ bstk = (us,bs,) <$> peekOff bstk i readForeign _ [] _ _ = foreignCCError "Closure" @@ -437,6 +439,8 @@ instance ForeignConvention BufferMode where ustk <- bump ustk (ustk, bstk) <$ poke ustk sblock'buf +-- 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 readForeign us (i : bs) _ bstk = (us,bs,) . toList <$> peekOffS bstk i diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index b41b02b8d1..9da1ccd93f 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -616,7 +616,6 @@ type Comb = GComb CombIx data GComb comb = Lam - !Reference -- function reference, for debugging !Int -- Number of unboxed arguments !Int -- Number of boxed arguments !Int -- Maximum needed unboxed frame size @@ -859,14 +858,14 @@ 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 (error "record: Missing Ref") au ab u b s) m, C u b n) + in (EC.mapInsert n (Lam au ab u b s) m, C u b n) recordTop :: [v] -> Word16 -> Emit Section -> Emit () recordTop vs l (EM e) = EM $ \c -> let (m, C u b s) = e c ab = length vs n = letIndex l c - in (EC.mapInsert n (Lam (error "recordTop: Missing Ref") 0 ab u b s) m, C u b ()) + in (EC.mapInsert n (Lam 0 ab u b s) m, C u b ()) -- Counts the stack space used by a context and annotates a value -- with it. @@ -1540,10 +1539,10 @@ rCombDeps :: RComb -> [Word64] rCombDeps = combDeps . rCombToComb combDeps :: Comb -> [Word64] -combDeps (Lam _ _ _ _ _ s) = sectionDeps s +combDeps (Lam _ _ _ _ s) = sectionDeps s combTypes :: Comb -> [Word64] -combTypes (Lam _ _ _ _ _ s) = sectionTypes s +combTypes (Lam _ _ _ _ s) = sectionTypes s sectionDeps :: Section -> [Word64] sectionDeps (App _ (Env (CIx _ w _)) _) = [w] @@ -1608,7 +1607,7 @@ prettyCombs w es = (mapToList es) prettyComb :: Word64 -> Word64 -> Comb -> ShowS -prettyComb w i (Lam _ref ua ba _ _ s) = +prettyComb w i (Lam ua ba _ _ s) = shows w . showString ":" . shows i diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index 479198231d..d9ed65a010 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -24,15 +24,15 @@ import Unison.Runtime.Serialize import Unison.Util.Text qualified as Util.Text putComb :: (MonadPut m) => (cix -> m ()) -> GComb cix -> m () -putComb putCix (Lam rf ua ba uf bf body) = - putReference rf *> pInt ua *> pInt ba *> pInt uf *> pInt bf *> putSection putCix body +putComb putCix (Lam ua ba uf bf body) = + pInt ua *> pInt ba *> pInt uf *> pInt bf *> putSection putCix body putRComb :: (MonadPut m) => RComb -> m () putRComb (RComb _combIx _comb) = error "TODO: figure out how to mark recursive points and serialize RComb" getComb :: (MonadGet m) => m cix -> m (GComb cix) -getComb gCix = Lam <$> getReference <*> gInt <*> gInt <*> gInt <*> gInt <*> (getSection gCix) +getComb gCix = Lam <$> gInt <*> gInt <*> gInt <*> gInt <*> (getSection gCix) getRComb :: (MonadGet m) => m RComb getRComb = error "TODO: figure out how to mark recursive points and serialize RComb" diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index e59b320611..771ed88645 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -709,7 +709,7 @@ enter !env !denv !activeThreads !ustk !bstk !k !ck !args !rcomb = do -- detecting saturated calls. eval env denv activeThreads ustk bstk k dummyRef entry where - (RComb _ (Lam _rf ua ba uf bf entry)) = rcomb + (RComb _ (Lam ua ba uf bf entry)) = rcomb {-# INLINE enter #-} -- fast path by-name delaying @@ -737,7 +737,7 @@ apply :: IO () apply !env !denv !activeThreads !ustk !bstk !k !ck !args (PAp comb useg bseg) = case unRComb comb of - Lam _rf ua ba uf bf entry + Lam ua ba uf bf entry | ck || ua <= uac && ba <= bac -> do ustk <- ensure ustk uf bstk <- ensure bstk bf @@ -1837,7 +1837,7 @@ yield !env !denv !activeThreads !ustk !bstk !k = leap denv k 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 _rf _ _ uf bf nx = unRComb rComb + let Lam _ _ uf bf nx = unRComb rComb ustk <- restoreFrame ustk ufsz uasz bstk <- restoreFrame bstk bfsz basz ustk <- ensure ustk uf From ebb495690ffebae2f3166a57cb88f770f4ad17d7 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Thu, 5 Sep 2024 16:22:45 -0700 Subject: [PATCH 13/20] Fix error which drops old combs on update --- unison-runtime/src/Unison/Runtime/Machine.hs | 21 +++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 771ed88645..8bd82d1262 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -138,9 +138,10 @@ baseCCache sandboxed = do combs :: EnumMap Word64 RCombs ~combs = - mapWithKey - (\k v -> let r = builtinTermBackref ! k in emitComb @Symbol rns r k mempty (0, v)) - numberedTermLookup + ( mapWithKey + (\k v -> let r = builtinTermBackref ! k in emitComb @Symbol rns r k mempty (0, v)) + numberedTermLookup + ) & resolveCombs Nothing info :: (Show a) => String -> a -> IO () @@ -1937,12 +1938,12 @@ unhandledErr fname env i = bomb sh = die $ fname ++ ": unhandled ability request: " ++ sh rCombSection :: EnumMap Word64 RCombs -> CombIx -> RComb -rCombSection combs cix@(CIx _ n i) = +rCombSection combs cix@(CIx r n i) = case EC.lookup n combs of Just cmbs -> case EC.lookup i cmbs of Just cmb -> RComb cix cmb - Nothing -> error $ "unknown section `" ++ show i ++ "` of combinator `" ++ show n ++ "`." - Nothing -> error $ "unknown combinator `" ++ show n ++ "`." + 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 cc section = do @@ -1975,8 +1976,8 @@ updateMap new0 r = do stateTVar r $ \old -> let total = new <> old in (total, total) -modifyMap :: (s -> s) -> TVar s -> STM s -modifyMap f r = stateTVar r $ \old -> let new = f old in (new, new) +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 @@ -2131,7 +2132,9 @@ cacheAdd0 ntys0 tml sands cc = atomically $ do 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 (\oldCombs -> (resolveCombs (Just oldCombs) . mapFromList $ zipWith combinate [ntm ..] rgs)) (combs 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 From 74da0459396f0449154b8fa704a1f7a3a35d67f2 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 6 Sep 2024 10:18:47 -0700 Subject: [PATCH 14/20] Fix serialization of RCombs --- .../src/Unison/Runtime/Interface.hs | 28 +++++++++++-------- unison-runtime/src/Unison/Runtime/MCode.hs | 4 --- .../src/Unison/Runtime/MCode/Serialize.hs | 9 ------ 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index c6f9aa6fe7..44aa0fb571 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -101,6 +101,7 @@ import Unison.Runtime.Exception import Unison.Runtime.MCode ( Args (..), CombIx (..), + Combs, GInstr (..), GSection (..), RCombs, @@ -1131,7 +1132,6 @@ decodeStandalone b = bimap thd thd $ runGetOrFail g b (,,,) <$> deserialize <*> deserialize - -- TODO: Check where this is encoded. <*> getCombIx <*> getStoredCache @@ -1195,9 +1195,11 @@ runStandalone :: StoredCache -> CombIx -> IO (Either (Pretty ColorText) ()) runStandalone sc init = restoreCache sc >>= executeMainComb init +-- | A version of the Code Cache designed to be serialized to disk as +-- standalone bytecode. data StoredCache = SCache - (EnumMap Word64 RCombs) + (EnumMap Word64 Combs) (EnumMap Word64 Reference) (EnumMap Word64 Reference) Word64 @@ -1210,7 +1212,7 @@ data StoredCache putStoredCache :: (MonadPut m) => StoredCache -> m () putStoredCache (SCache cs crs trs ftm fty int rtm rty sbs) = do - putEnumMap putNat (putEnumMap putNat (putComb putRComb)) cs + putEnumMap putNat (putEnumMap putNat (putComb putCombIx)) cs putEnumMap putNat putReference crs putEnumMap putNat putReference trs putNat ftm @@ -1223,7 +1225,7 @@ putStoredCache (SCache cs crs trs ftm fty int rtm rty sbs) = do getStoredCache :: (MonadGet m) => m StoredCache getStoredCache = SCache - <$> getEnumMap getNat (getEnumMap getNat (getComb getRComb)) + <$> getEnumMap getNat (getEnumMap getNat (getComb getCombIx)) <*> getEnumMap getNat getReference <*> getEnumMap getNat getReference <*> getNat @@ -1253,7 +1255,7 @@ tabulateErrors errs = restoreCache :: StoredCache -> IO CCache restoreCache (SCache cs crs trs ftm fty int rtm rty sbs) = CCache builtinForeigns False debugText - <$> newTVarIO (cs <> combs) + <$> newTVarIO combs <*> newTVarIO (crs <> builtinTermBackref) <*> newTVarIO (trs <> builtinTypeBackref) <*> newTVarIO ftm @@ -1280,10 +1282,9 @@ restoreCache (SCache cs crs trs ftm fty int rtm rty sbs) = rf k = builtinTermBackref ! k combs :: EnumMap Word64 RCombs combs = - mapWithKey - (\k v -> emitComb @Symbol rns (rf k) k mempty (0, v)) - numberedTermLookup - & resolveCombs Nothing + let builtinCombs = mapWithKey (\k v -> emitComb @Symbol rns (rf k) k mempty (0, v)) numberedTermLookup + in builtinCombs <> cs + & resolveCombs Nothing traceNeeded :: Word64 -> @@ -1299,7 +1300,7 @@ traceNeeded init src = fmap (`withoutKeys` ks) $ go mempty init | otherwise = die $ "traceNeeded: unknown combinator: " ++ show w buildSCache :: - EnumMap Word64 RCombs -> + EnumMap Word64 Combs -> EnumMap Word64 Reference -> EnumMap Word64 Reference -> Word64 -> @@ -1325,7 +1326,7 @@ buildSCache cs crsrc trsrc ftm fty intsrc rtmsrc rtysrc sndbx = crs = restrictTmW crsrc termRefs = foldMap Set.singleton crs - typeKeys = setFromList $ (foldMap . foldMap) (combTypes . fmap rCombIx) cs + typeKeys = setFromList $ (foldMap . foldMap) combTypes cs trs = restrictTyW trsrc typeRefs = foldMap Set.singleton trs @@ -1339,7 +1340,7 @@ buildSCache cs crsrc trsrc ftm fty intsrc rtmsrc rtysrc sndbx = standalone :: CCache -> Word64 -> IO StoredCache standalone cc init = buildSCache - <$> (readTVarIO (combs cc) >>= traceNeeded init) + <$> (readTVarIO (combs cc) >>= traceNeeded init >>= pure . unTieRCombs) <*> readTVarIO (combRefs cc) <*> readTVarIO (tagRefs cc) <*> readTVarIO (freshTm cc) @@ -1348,3 +1349,6 @@ 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 9da1ccd93f..6b729d4cb5 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -47,7 +47,6 @@ module Unison.Runtime.MCode combRef, rCombRef, combDeps, - rCombDeps, combTypes, prettyCombs, prettyComb, @@ -1535,9 +1534,6 @@ demuxArgs as0 = -- TODO: handle ranges (us, bs) -> DArgN (primArrayFromList us) (primArrayFromList bs) -rCombDeps :: RComb -> [Word64] -rCombDeps = combDeps . rCombToComb - combDeps :: Comb -> [Word64] combDeps (Lam _ _ _ _ s) = sectionDeps s diff --git a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs index d9ed65a010..a96fdf18b2 100644 --- a/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs +++ b/unison-runtime/src/Unison/Runtime/MCode/Serialize.hs @@ -4,9 +4,7 @@ module Unison.Runtime.MCode.Serialize ( putComb, - putRComb, getComb, - getRComb, putCombIx, getCombIx, ) @@ -27,16 +25,9 @@ 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 -putRComb :: (MonadPut m) => RComb -> m () -putRComb (RComb _combIx _comb) = - error "TODO: figure out how to mark recursive points and serialize RComb" - getComb :: (MonadGet m) => m cix -> m (GComb cix) getComb gCix = Lam <$> gInt <*> gInt <*> gInt <*> gInt <*> (getSection gCix) -getRComb :: (MonadGet m) => m RComb -getRComb = error "TODO: figure out how to mark recursive points and serialize RComb" - data SectionT = AppT | CallT From 3f4df402d71ebe5c74954df74a52116ff721d271 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 6 Sep 2024 10:20:57 -0700 Subject: [PATCH 15/20] Switch so the RComb itself is lazy since that's where it makes the most sense conceptually --- unison-runtime/src/Unison/Runtime/MCode.hs | 4 ++-- unison-runtime/src/Unison/Runtime/Stack.hs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 6b729d4cb5..cf32059b0b 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -638,8 +638,8 @@ pattern RCombRef r <- (combRef . rCombIx -> r) -- | The fixed point of a GComb where all references to a Comb are themselves Combs. data RComb = RComb - { rCombIx :: CombIx, - unRComb :: GComb RComb + { rCombIx :: !CombIx, + unRComb :: (GComb RComb {- Possibly recursive comb, keep it lazy or risk blowing up -}) } deriving (Eq, Ord) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index e6473fd140..866df67ddb 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -100,7 +100,7 @@ type Closure = GClosure RComb data GClosure comb = PAp - comb {- Possibly recursive comb, keep it lazy or risk blowing up -} + !comb {-# UNPACK #-} !(Seg 'UN) -- unboxed args {- unpack -} !(Seg 'BX) -- boxed args From dbf3ccd7cd110d066a529a11637e47a48465957f Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 6 Sep 2024 10:20:57 -0700 Subject: [PATCH 16/20] Docs --- unison-runtime/src/Unison/Runtime/Interface.hs | 1 - unison-runtime/src/Unison/Runtime/MCode.hs | 17 ++++++++++------- unison-runtime/src/Unison/Runtime/Machine.hs | 16 +--------------- unison-runtime/src/Unison/Runtime/Stack.hs | 4 ++-- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Interface.hs b/unison-runtime/src/Unison/Runtime/Interface.hs index 44aa0fb571..17527e2061 100644 --- a/unison-runtime/src/Unison/Runtime/Interface.hs +++ b/unison-runtime/src/Unison/Runtime/Interface.hs @@ -664,7 +664,6 @@ interpCompile version ctxVar cl ppe rf path = tryM $ do let cc = ccache ctx lk m = flip Map.lookup m =<< baseToIntermed ctx rf Just w <- lk <$> readTVarIO (refTm cc) - -- TODO: Check with Dan that this is correct let combIx = CIx rf w 0 sto <- standalone cc w BL.writeFile path . runPutL $ do diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index cf32059b0b..1f2d54a479 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -626,11 +626,13 @@ type Combs = GCombs CombIx type RCombs = GCombs RComb +-- | Extract the CombIx from an RComb. pattern RCombIx :: CombIx -> RComb pattern RCombIx r <- (rCombIx -> r) {-# COMPLETE RCombIx #-} +-- | Extract the Reference from an RComb. pattern RCombRef :: Reference -> RComb pattern RCombRef r <- (combRef . rCombIx -> r) @@ -641,8 +643,9 @@ data RComb = RComb { rCombIx :: !CombIx, unRComb :: (GComb RComb {- Possibly recursive comb, keep it lazy or risk blowing up -}) } - deriving (Eq, Ord) + deriving stock (Eq, Ord) +-- | Convert an RComb to a Comb by forgetting the sections and keeping only the CombIx. rCombToComb :: RComb -> Comb rCombToComb (RComb _ix c) = rCombIx <$> c @@ -650,18 +653,18 @@ rCombToComb (RComb _ix c) = rCombIx <$> c instance Show RComb where show _ = "" +-- | Map of combinators, parameterized by comb reference type type GCombs comb = EnumMap Word64 (GComb comb) +-- | A reference to a combinator, parameterized by comb type Ref = GRef CombIx type RRef = GRef RComb data GRef comb = Stk !Int -- stack reference to a closure - | Env !comb - | -- !Word64 -- global environment reference to a combinator - -- !Word64 -- section - Dyn !Word64 -- dynamic scope reference to a closure + | Env !comb -- direct reference to comb, usually embedded as an RComb + | Dyn !Word64 -- dynamic scope reference to a closure deriving (Show, Eq, Ord, Functor, Foldable, Traversable) type Branch = GBranch CombIx @@ -799,8 +802,8 @@ resolveCombs :: EnumMap Word64 Combs -> EnumMap Word64 RCombs resolveCombs mayExisting combs = - -- Fixed point lookup; make sure all uses of Combs are non-strict - -- or we'll loop forever. + -- 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)) -> diff --git a/unison-runtime/src/Unison/Runtime/Machine.hs b/unison-runtime/src/Unison/Runtime/Machine.hs index 8bd82d1262..1feed1dc2c 100644 --- a/unison-runtime/src/Unison/Runtime/Machine.hs +++ b/unison-runtime/src/Unison/Runtime/Machine.hs @@ -137,7 +137,7 @@ baseCCache sandboxed = do rns = emptyRNs {dnum = refLookup "ty" builtinTypeNumbering} combs :: EnumMap Word64 RCombs - ~combs = + combs = ( mapWithKey (\k v -> let r = builtinTermBackref ! k in emitComb @Symbol rns r k mempty (0, v)) numberedTermLookup @@ -1950,20 +1950,6 @@ resolveSection cc section = do rcombs <- readTVarIO (combs cc) pure $ rCombSection rcombs <$> section --- combSection :: (HasCallStack) => CCache -> CombIx -> IO Comb --- combSection env (CIx _ n i) = --- readTVarIO (combs env) >>= \cs -> case EC.lookup n cs of --- Just cmbs -> case EC.lookup i cmbs of --- Just cmb -> pure cmb --- Nothing -> --- die $ --- "unknown section `" --- ++ show i --- ++ "` of combinator `" --- ++ show n --- ++ "`." --- Nothing -> die $ "unknown combinator `" ++ show n ++ "`." - dummyRef :: Reference dummyRef = Builtin (DTx.pack "dummy") diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 866df67ddb..b8c7d4c1bb 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -348,8 +348,8 @@ class MEM (b :: Mem) where asize :: Stack b -> SZ instance MEM 'UN where - data Stack 'UN = - -- Note: uap <= ufp <= usp + data Stack 'UN + = -- Note: uap <= ufp <= usp US { uap :: !Int, -- arg pointer ufp :: !Int, -- frame pointer From 7fc4bd23407ad6d2483772551e0e24446111a0cf Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Fri, 6 Sep 2024 10:45:30 -0700 Subject: [PATCH 17/20] Fix test builds --- unison-runtime/tests/Unison/Test/Runtime/MCode.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/unison-runtime/tests/Unison/Test/Runtime/MCode.hs b/unison-runtime/tests/Unison/Test/Runtime/MCode.hs index 0bb235f445..e277e60a02 100644 --- a/unison-runtime/tests/Unison/Test/Runtime/MCode.hs +++ b/unison-runtime/tests/Unison/Test/Runtime/MCode.hs @@ -16,9 +16,10 @@ import Unison.Runtime.ANF ) import Unison.Runtime.MCode ( Args (..), - Branch (..), - Instr (..), - Section (..), + GBranch (..), + GInstr (..), + GSection (..), + Section, ) import Unison.Runtime.Machine ( CCache (..), From e3f658f12ebd09d695bfb980c2a80d7cda6ddf0b Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 9 Sep 2024 10:27:38 -0700 Subject: [PATCH 18/20] Revert back to O2 on parser-typechecker --- parser-typechecker/package.yaml | 2 +- parser-typechecker/unison-parser-typechecker.cabal | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/parser-typechecker/package.yaml b/parser-typechecker/package.yaml index 29ea1d3619..7150e81120 100644 --- a/parser-typechecker/package.yaml +++ b/parser-typechecker/package.yaml @@ -11,7 +11,7 @@ flags: when: - condition: flag(optimized) - ghc-options: -funbox-strict-fields -O + ghc-options: -funbox-strict-fields -O2 library: source-dirs: src diff --git a/parser-typechecker/unison-parser-typechecker.cabal b/parser-typechecker/unison-parser-typechecker.cabal index 040b382692..af6098f702 100644 --- a/parser-typechecker/unison-parser-typechecker.cabal +++ b/parser-typechecker/unison-parser-typechecker.cabal @@ -257,7 +257,7 @@ library , witherable default-language: Haskell2010 if flag(optimized) - ghc-options: -funbox-strict-fields -O + ghc-options: -funbox-strict-fields -O2 test-suite parser-typechecker-tests type: exitcode-stdio-1.0 @@ -340,4 +340,4 @@ test-suite parser-typechecker-tests , unison-util-rope default-language: Haskell2010 if flag(optimized) - ghc-options: -funbox-strict-fields -O + ghc-options: -funbox-strict-fields -O2 From 5fa076a23d8810d5d074e4af496485b642b97153 Mon Sep 17 00:00:00 2001 From: Chris Penner Date: Mon, 9 Sep 2024 11:43:29 -0700 Subject: [PATCH 19/20] Fix Eq on RCombs --- unison-runtime/src/Unison/Runtime/MCode.hs | 13 ++++++++++--- unison-runtime/src/Unison/Runtime/Stack.hs | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/MCode.hs b/unison-runtime/src/Unison/Runtime/MCode.hs index 1f2d54a479..e469b90f6d 100644 --- a/unison-runtime/src/Unison/Runtime/MCode.hs +++ b/unison-runtime/src/Unison/Runtime/MCode.hs @@ -643,15 +643,22 @@ data RComb = RComb { rCombIx :: !CombIx, unRComb :: (GComb RComb {- Possibly recursive comb, keep it lazy or risk blowing up -}) } - deriving stock (Eq, Ord) + +-- 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 + +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 can't show them. +-- | RCombs can be infinitely recursive so we show the CombIx instead. instance Show RComb where - show _ = "" + show (RComb ix _) = show ix -- | Map of combinators, parameterized by comb reference type type GCombs comb = EnumMap Word64 (GComb comb) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index b8c7d4c1bb..8dd782f393 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -115,7 +115,7 @@ data GClosure comb Captured !K !Int !Int {-# UNPACK #-} !(Seg 'UN) !(Seg 'BX) | Foreign !Foreign | BlackHole - deriving (Show, Eq, Ord) + deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable) traceK :: Reference -> K -> [(Reference, Int)] traceK begin = dedup (begin, 1) From aca3e15f86f60908ce17aa89d0b2ca125dfd56cd Mon Sep 17 00:00:00 2001 From: ChrisPenner Date: Mon, 9 Sep 2024 18:45:04 +0000 Subject: [PATCH 20/20] automatically run ormolu --- unison-runtime/src/Unison/Runtime/Stack.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unison-runtime/src/Unison/Runtime/Stack.hs b/unison-runtime/src/Unison/Runtime/Stack.hs index 8dd782f393..b85707b1b3 100644 --- a/unison-runtime/src/Unison/Runtime/Stack.hs +++ b/unison-runtime/src/Unison/Runtime/Stack.hs @@ -348,8 +348,8 @@ class MEM (b :: Mem) where asize :: Stack b -> SZ instance MEM 'UN where - data Stack 'UN - = -- Note: uap <= ufp <= usp + data Stack 'UN = + -- Note: uap <= ufp <= usp US { uap :: !Int, -- arg pointer ufp :: !Int, -- frame pointer