diff options
author | Simon Marlow <marlowsd@gmail.com> | 2016-06-23 09:22:32 +0100 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2016-06-24 11:29:33 +0100 |
commit | eb732195f6c005c769232a79e5d17e3d768603d1 (patch) | |
tree | af50965f6f74f524d0552c66140cb5982a6dcfd6 /libraries/ghci | |
parent | bdb0d24be9c83b08fd3f4b870a17f6be31a24b1b (diff) | |
download | haskell-eb732195f6c005c769232a79e5d17e3d768603d1.tar.gz |
Remote GHCi: comments only
Summary: Add more Notes and signposts across the codebase to help navigation.
Test Plan: validate
Reviewers: goldfire, simonpj, austin, ezyang, hvr, bgamari, erikd
Subscribers: thomie
Differential Revision: https://phabricator.haskell.org/D2358
Diffstat (limited to 'libraries/ghci')
-rw-r--r-- | libraries/ghci/GHCi/CreateBCO.hs | 1 | ||||
-rw-r--r-- | libraries/ghci/GHCi/Message.hs | 17 | ||||
-rw-r--r-- | libraries/ghci/GHCi/RemoteTypes.hs | 8 | ||||
-rw-r--r-- | libraries/ghci/GHCi/Run.hs | 5 | ||||
-rw-r--r-- | libraries/ghci/GHCi/TH.hs | 98 |
5 files changed, 125 insertions, 4 deletions
diff --git a/libraries/ghci/GHCi/CreateBCO.hs b/libraries/ghci/GHCi/CreateBCO.hs index 9501b5f0a7..f42c975cd7 100644 --- a/libraries/ghci/GHCi/CreateBCO.hs +++ b/libraries/ghci/GHCi/CreateBCO.hs @@ -10,6 +10,7 @@ -- (c) The University of Glasgow 2002-2006 -- +-- | Create real byte-code objects from 'ResolvedBCO's. module GHCi.CreateBCO (createBCOs) where import GHCi.ResolvedBCO diff --git a/libraries/ghci/GHCi/Message.hs b/libraries/ghci/GHCi/Message.hs index b46030f7ea..b14fca4f2d 100644 --- a/libraries/ghci/GHCi/Message.hs +++ b/libraries/ghci/GHCi/Message.hs @@ -2,6 +2,12 @@ GeneralizedNewtypeDeriving, ExistentialQuantification, RecordWildCards #-} {-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-orphans #-} +-- | +-- Remote GHCi message types and serialization. +-- +-- For details on Remote GHCi, see Note [Remote GHCi] in +-- compiler/ghci/GHCi.hs. +-- module GHCi.Message ( Message(..), Msg(..) , THMessage(..), THMsg(..) @@ -44,7 +50,8 @@ import System.IO.Error -- ----------------------------------------------------------------------------- -- The RPC protocol between GHC and the interactive server --- | A @Message a@ is a message that returns a value of type @a@ +-- | A @Message a@ is a message that returns a value of type @a@. +-- These are requests sent from GHC to the server. data Message a where -- | Exit the iserv process Shutdown :: Message () @@ -159,6 +166,8 @@ data Message a where -> Message (Maybe HValueRef) -- Template Haskell ------------------------------------------- + -- For more details on how TH works with Remote GHCi, see + -- Note [Remote Template Haskell] in libraries/ghci/GHCi/TH.hs. -- | Start a new TH module, return a state token that should be StartTH :: Message (RemoteRef (IORef QState)) @@ -198,7 +207,8 @@ instance Binary a => Binary (QResult a) -- | Messages sent back to GHC from GHCi.TH, to implement the methods --- of 'Quasi'. +-- of 'Quasi'. For an overview of how TH works with Remote GHCi, see +-- Note [Remote Template Haskell] in GHCi.TH. data THMessage a where NewName :: String -> THMessage (THResult TH.Name) Report :: Bool -> String -> THMessage (THResult ()) @@ -352,6 +362,9 @@ data THResultType = THExp | THPat | THType | THDec | THAnnWrapper instance Binary THResultType +-- | The server-side Template Haskell state. This is created by the +-- StartTH message. A new one is created per module that GHC +-- typechecks. data QState = QState { qsMap :: Map TypeRep Dynamic -- ^ persistent data between splices in a module diff --git a/libraries/ghci/GHCi/RemoteTypes.hs b/libraries/ghci/GHCi/RemoteTypes.hs index ea91f19a2b..5bc0136113 100644 --- a/libraries/ghci/GHCi/RemoteTypes.hs +++ b/libraries/ghci/GHCi/RemoteTypes.hs @@ -1,4 +1,12 @@ {-# LANGUAGE CPP, StandaloneDeriving, GeneralizedNewtypeDeriving #-} + +-- | +-- Types for referring to remote objects in Remote GHCi. For more +-- details, see Note [External GHCi pointers] in compiler/ghci/GHCi.hs +-- +-- For details on Remote GHCi, see Note [Remote GHCi] in +-- compiler/ghci/GHCi.hs. +-- module GHCi.RemoteTypes ( RemotePtr(..), toRemotePtr, fromRemotePtr, castRemotePtr , HValue(..) diff --git a/libraries/ghci/GHCi/Run.hs b/libraries/ghci/GHCi/Run.hs index a2ea4e203c..542fe551cd 100644 --- a/libraries/ghci/GHCi/Run.hs +++ b/libraries/ghci/GHCi/Run.hs @@ -3,7 +3,10 @@ {-# OPTIONS_GHC -fno-warn-name-shadowing #-} -- | --- Execute GHCi messages +-- Execute GHCi messages. +-- +-- For details on Remote GHCi, see Note [Remote GHCi] in +-- compiler/ghci/GHCi.hs. -- module GHCi.Run ( run, redirectInterrupts diff --git a/libraries/ghci/GHCi/TH.hs b/libraries/ghci/GHCi/TH.hs index 6d6158ffdb..3495162a12 100644 --- a/libraries/ghci/GHCi/TH.hs +++ b/libraries/ghci/GHCi/TH.hs @@ -7,6 +7,85 @@ -- module GHCi.TH (startTH, finishTH, runTH, GHCiQException(..)) where +{- Note [Remote Template Haskell] + +Here is an overview of how TH works with -fexternal-interpreter. + +Initialisation +~~~~~~~~~~~~~~ + +GHC sends a StartTH message to the server (see TcSplice.getTHState): + + StartTH :: Message (RemoteRef (IORef QState)) + +The server creates an initial QState object, makes an IORef to it, and +returns a RemoteRef to this to GHC. (see GHCi.TH.startTH below). + +This happens once per module, the first time we need to run a TH +splice. The reference that GHC gets back is kept in +tcg_th_remote_state in the TcGblEnv, and passed to each RunTH call +that follows. + + +For each splice +~~~~~~~~~~~~~~~ + +1. GHC compiles a splice to byte code, and sends it to the server: in + a CreateBCOs message: + + CreateBCOs :: [LB.ByteString] -> Message [HValueRef] + +2. The server creates the real byte-code objects in its heap, and + returns HValueRefs to GHC. HValueRef is the same as RemoteRef + HValue. + +3. GHC sends a RunTH message to the server: + + RunTH + :: RemoteRef (IORef QState) + -- The state returned by StartTH in step1 + -> HValueRef + -- The HValueRef we got in step 4, points to the code for the splice + -> THResultType + -- Tells us what kind of splice this is (decl, expr, type, etc.) + -> Maybe TH.Loc + -- Source location + -> Message (QResult ByteString) + -- Eventually it will return a QResult back to GHC. The + -- ByteString here is the (encoded) result of the splice. + +4. The server runs the splice code. + +5. Each time the splice code calls a method of the Quasi class, such + as qReify, a message is sent from the server to GHC. These + messages are defined by the THMessage type. GHC responds with the + result of the request, e.g. in the case of qReify it would be the + TH.Info for the requested entity. + +6. When the splice has been fully evaluated, the server sends + RunTHDone back to GHC. This tells GHC that the server has finished + sending THMessages and will send the QResult next. + +8. The server then sends a QResult back to GHC, which is notionally + the response to the original RunTH message. The QResult indicates + whether the splice succeeded, failed, or threw an exception. + + +After typechecking +~~~~~~~~~~~~~~~~~~ + +GHC sends a FinishTH message to the server (see TcSplice.finishTH). +The server runs any finalizers that were added by addModuleFinalizer. + + +Other Notes on TH / Remote GHCi + + * Note [Remote GHCi] in compiler/ghci/GHCi.hs + * Note [External GHCi pointers] in compiler/ghci/GHCi.hs + * Note [TH recover with -fexternal-interpreter] in + compiler/typecheck/TcSplice.hs +-} + import GHCi.Message import GHCi.RemoteTypes import GHC.Serialized @@ -29,6 +108,7 @@ import qualified Language.Haskell.TH as TH import qualified Language.Haskell.TH.Syntax as TH import Unsafe.Coerce +-- | Create a new instance of 'QState' initQState :: Pipe -> QState initQState p = QState M.empty [] Nothing p @@ -39,8 +119,10 @@ runModFinalizers = go =<< getState putState (s { qsFinalizers = ff}) >> TH.runQ f >> getState >>= go go _ = return () +-- | The monad in which we run TH computations on the server newtype GHCiQ a = GHCiQ { runGHCiQ :: QState -> IO (a, QState) } +-- | The exception thrown by "fail" in the GHCiQ monad data GHCiQException = GHCiQException QState String deriving Show @@ -75,6 +157,7 @@ putState s = GHCiQ $ \_ -> return ((),s) noLoc :: TH.Loc noLoc = TH.Loc "<no file>" "<no package>" "<no module>" (0,0) (0,0) +-- | Send a 'THMessage' to GHC and return the result. ghcCmd :: Binary a => THMessage (THResult a) -> GHCiQ a ghcCmd m = GHCiQ $ \s -> do r <- remoteTHCall (qsPipe s) m @@ -126,11 +209,14 @@ instance TH.Quasi GHCiQ where qIsExtEnabled x = ghcCmd (IsExtEnabled x) qExtsEnabled = ghcCmd ExtsEnabled +-- | The implementation of the 'StartTH' message: create +-- a new IORef QState, and return a RemoteRef to it. startTH :: IO (RemoteRef (IORef QState)) startTH = do r <- newIORef (initQState (error "startTH: no pipe")) mkRemoteRef r +-- | The implementation of the 'FinishTH' message. finishTH :: Pipe -> RemoteRef (IORef QState) -> IO () finishTH pipe rstate = do qstateref <- localRef rstate @@ -138,11 +224,20 @@ finishTH pipe rstate = do _ <- runGHCiQ runModFinalizers qstate { qsPipe = pipe } return () +-- | The implementation of the 'RunTH' message runTH - :: Pipe -> RemoteRef (IORef QState) -> HValueRef + :: Pipe + -> RemoteRef (IORef QState) + -- ^ The TH state, created by 'startTH' + -> HValueRef + -- ^ The splice to run -> THResultType + -- ^ What kind of splice it is -> Maybe TH.Loc + -- ^ The source location -> IO ByteString + -- ^ Returns an (encoded) result that depends on the THResultType + runTH pipe rstate rhv ty mb_loc = do hv <- localRef rhv case ty of @@ -156,6 +251,7 @@ runTH pipe rstate rhv ty mb_loc = do AnnotationWrapper thing -> return $! LB.toStrict (runPut (put (toSerialized serializeWithData thing))) +-- | Run a Q computation. runTHQ :: Binary a => Pipe -> RemoteRef (IORef QState) -> Maybe TH.Loc -> TH.Q a -> IO ByteString |