Skip to content

Commit 4d356ea

Browse files
hsyl20luite
authored andcommitted
JS: implement TH support
- Add ghc-interp.js bootstrap script for the JS interpreter - Interactively link and execute iserv code from the ghci package - Incrementally load and run JS code for splices into the running iserv Co-authored-by: Luite Stegeman <[email protected]>
1 parent 8185b1c commit 4d356ea

File tree

67 files changed

+1885
-787
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+1885
-787
lines changed

compiler/GHC.hs

+30-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE MultiWayIf #-}
12
{-# LANGUAGE CPP #-}
23
{-# LANGUAGE NondecreasingIndentation, ScopedTypeVariables #-}
34
{-# LANGUAGE TupleSections, NamedFieldPuns #-}
@@ -315,6 +316,7 @@ import GHC.Driver.Backend
315316
import GHC.Driver.Config.Finder (initFinderOpts)
316317
import GHC.Driver.Config.Parser (initParserOpts)
317318
import GHC.Driver.Config.Logger (initLogFlags)
319+
import GHC.Driver.Config.StgToJS (initStgToJSConfig)
318320
import GHC.Driver.Config.Diagnostic
319321
import GHC.Driver.Main
320322
import GHC.Driver.Make
@@ -676,8 +678,10 @@ setTopSessionDynFlags dflags = do
676678
logger <- getLogger
677679

678680
-- Interpreter
679-
interp <- if gopt Opt_ExternalInterpreter dflags
680-
then do
681+
interp <- if
682+
-- external interpreter
683+
| gopt Opt_ExternalInterpreter dflags
684+
-> do
681685
let
682686
prog = pgm_i dflags ++ flavour
683687
profiled = ways dflags `hasWay` WayProf
@@ -699,10 +703,31 @@ setTopSessionDynFlags dflags = do
699703
, iservConfHook = createIservProcessHook (hsc_hooks hsc_env)
700704
, iservConfTrace = tr
701705
}
702-
s <- liftIO $ newMVar IServPending
706+
s <- liftIO $ newMVar InterpPending
707+
loader <- liftIO Loader.uninitializedLoader
708+
return (Just (Interp (ExternalInterp (ExtIServ (ExtInterpState conf s))) loader))
709+
710+
-- JavaScript interpreter
711+
| ArchJavaScript <- platformArch (targetPlatform dflags)
712+
-> do
713+
s <- liftIO $ newMVar InterpPending
703714
loader <- liftIO Loader.uninitializedLoader
704-
return (Just (Interp (ExternalInterp conf (IServ s)) loader))
705-
else
715+
let cfg = JSInterpConfig
716+
{ jsInterpNodeConfig = defaultNodeJsSettings
717+
, jsInterpScript = topDir dflags </> "ghc-interp.js"
718+
, jsInterpTmpFs = hsc_tmpfs hsc_env
719+
, jsInterpTmpDir = tmpDir dflags
720+
, jsInterpLogger = hsc_logger hsc_env
721+
, jsInterpCodegenCfg = initStgToJSConfig dflags
722+
, jsInterpUnitEnv = hsc_unit_env hsc_env
723+
, jsInterpFinderOpts = initFinderOpts dflags
724+
, jsInterpFinderCache = hsc_FC hsc_env
725+
}
726+
return (Just (Interp (ExternalInterp (ExtJS (ExtInterpState cfg s))) loader))
727+
728+
-- Internal interpreter
729+
| otherwise
730+
->
706731
#if defined(HAVE_INTERNAL_INTERPRETER)
707732
do
708733
loader <- liftIO Loader.uninitializedLoader

compiler/GHC/Driver/Main.hs

+145-86
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,10 @@ import GHC.Driver.Hooks
140140
import GHC.Driver.GenerateCgIPEStub (generateCgIPEStub)
141141

142142
import GHC.Runtime.Context
143-
import GHC.Runtime.Interpreter ( addSptEntry )
143+
import GHC.Runtime.Interpreter
144+
import GHC.Runtime.Interpreter.JS
144145
import GHC.Runtime.Loader ( initializePlugins )
145-
import GHCi.RemoteTypes ( ForeignHValue )
146+
import GHCi.RemoteTypes
146147
import GHC.ByteCode.Types
147148

148149
import GHC.Linker.Loader
@@ -156,6 +157,9 @@ import GHC.HsToCore
156157

157158
import GHC.StgToByteCode ( byteCodeGen )
158159
import GHC.StgToJS ( stgToJS )
160+
import GHC.StgToJS.Ids
161+
import GHC.StgToJS.Types
162+
import GHC.JS.Syntax
159163

160164
import GHC.IfaceToCore ( typecheckIface, typecheckWholeCoreBindings )
161165

@@ -172,7 +176,6 @@ import GHC.Core
172176
import GHC.Core.Lint.Interactive ( interactiveInScope )
173177
import GHC.Core.Tidy ( tidyExpr )
174178
import GHC.Core.Type ( Type, Kind )
175-
import GHC.Core.Multiplicity
176179
import GHC.Core.Utils ( exprType )
177180
import GHC.Core.ConLike
178181
import GHC.Core.Opt.Pipeline
@@ -201,7 +204,6 @@ import GHC.Stg.Pipeline ( stg2stg, StgCgInfos )
201204

202205
import GHC.Builtin.Utils
203206
import GHC.Builtin.Names
204-
import GHC.Builtin.Uniques ( mkPseudoUniqueE )
205207

206208
import qualified GHC.StgToCmm as StgToCmm ( codeGen )
207209
import GHC.StgToCmm.Types (CmmCgInfos (..), ModuleLFInfos, LambdaFormInfo(..))
@@ -231,7 +233,7 @@ import GHC.Types.SourceError
231233
import GHC.Types.SafeHaskell
232234
import GHC.Types.ForeignStubs
233235
import GHC.Types.Name.Env ( mkNameEnv )
234-
import GHC.Types.Var.Env ( emptyTidyEnv )
236+
import GHC.Types.Var.Env ( mkEmptyTidyEnv )
235237
import GHC.Types.Error
236238
import GHC.Types.Fixity.Env
237239
import GHC.Types.CostCentre
@@ -245,6 +247,8 @@ import GHC.Types.Name.Ppr
245247
import GHC.Types.Name.Set (NonCaffySet)
246248
import GHC.Types.TyThing
247249
import GHC.Types.HpcInfo
250+
import GHC.Types.Unique.Supply (uniqFromMask)
251+
import GHC.Types.Unique (getKey)
248252

249253
import GHC.Utils.Fingerprint ( Fingerprint )
250254
import GHC.Utils.Panic
@@ -289,6 +293,7 @@ import System.IO.Unsafe ( unsafeInterleaveIO )
289293
import GHC.Iface.Env ( trace_if )
290294
import GHC.Stg.InferTags.TagSig (seqTagSig)
291295
import GHC.Types.Unique.FM
296+
import GHC.Types.Unique.DFM
292297

293298

294299
{- **********************************************************************
@@ -1853,7 +1858,7 @@ hscGenHardCode hsc_env cgguts location output_filename = do
18531858
c `seqList`
18541859
d `seqList`
18551860
(seqEltsUFM (seqTagSig) tag_env))
1856-
(myCoreToStg logger dflags (hsc_IC hsc_env) False this_mod location prepd_binds)
1861+
(myCoreToStg logger dflags (interactiveInScope (hsc_IC hsc_env)) False this_mod location prepd_binds)
18571862

18581863
let cost_centre_info =
18591864
(late_local_ccs ++ caf_ccs, caf_cc_stacks)
@@ -1975,7 +1980,7 @@ hscInteractive hsc_env cgguts location = do
19751980
-- omit it here
19761981
(stg_binds, _infotable_prov, _caf_ccs__caf_cc_stacks, _ignore_stg_cg_infos)
19771982
<- {-# SCC "CoreToStg" #-}
1978-
myCoreToStg logger dflags (hsc_IC hsc_env) True this_mod location prepd_binds
1983+
myCoreToStg logger dflags (interactiveInScope (hsc_IC hsc_env)) True this_mod location prepd_binds
19791984
----------------- Generate byte code ------------------
19801985
comp_bc <- byteCodeGen hsc_env this_mod stg_binds data_tycons mod_breaks
19811986
------------------ Create f-x-dynamic C-side stuff -----
@@ -2150,46 +2155,21 @@ doCodeGen hsc_env this_mod denv data_tycons
21502155

21512156
return $ Stream.mapM dump2 $ generateCgIPEStub hsc_env this_mod denv pipeline_stream
21522157

2153-
myCoreToStgExpr :: Logger -> DynFlags -> InteractiveContext
2154-
-> Bool
2155-
-> Module -> ModLocation -> CoreExpr
2156-
-> IO ( Id
2157-
, [CgStgTopBinding]
2158-
, InfoTableProvMap
2159-
, CollectedCCs
2160-
, StgCgInfos )
2161-
myCoreToStgExpr logger dflags ictxt for_bytecode this_mod ml prepd_expr = do
2162-
{- Create a temporary binding (just because myCoreToStg needs a
2163-
binding for the stg2stg step) -}
2164-
let bco_tmp_id = mkSysLocal (fsLit "BCO_toplevel")
2165-
(mkPseudoUniqueE 0)
2166-
ManyTy
2167-
(exprType prepd_expr)
2168-
(stg_binds, prov_map, collected_ccs, stg_cg_infos) <-
2169-
myCoreToStg logger
2170-
dflags
2171-
ictxt
2172-
for_bytecode
2173-
this_mod
2174-
ml
2175-
[NonRec bco_tmp_id prepd_expr]
2176-
return (bco_tmp_id, stg_binds, prov_map, collected_ccs, stg_cg_infos)
2177-
2178-
myCoreToStg :: Logger -> DynFlags -> InteractiveContext
2158+
myCoreToStg :: Logger -> DynFlags -> [Var]
21792159
-> Bool
21802160
-> Module -> ModLocation -> CoreProgram
21812161
-> IO ( [CgStgTopBinding] -- output program
21822162
, InfoTableProvMap
21832163
, CollectedCCs -- CAF cost centre info (declared and used)
21842164
, StgCgInfos )
2185-
myCoreToStg logger dflags ictxt for_bytecode this_mod ml prepd_binds = do
2165+
myCoreToStg logger dflags ic_inscope for_bytecode this_mod ml prepd_binds = do
21862166
let (stg_binds, denv, cost_centre_info)
21872167
= {-# SCC "Core2Stg" #-}
21882168
coreToStg (initCoreToStgOpts dflags) this_mod ml prepd_binds
21892169

21902170
(stg_binds_with_fvs,stg_cg_info)
21912171
<- {-# SCC "Stg2Stg" #-}
2192-
stg2stg logger (interactiveInScope ictxt) (initStgPipelineOpts dflags for_bytecode)
2172+
stg2stg logger ic_inscope (initStgPipelineOpts dflags for_bytecode)
21932173
this_mod stg_binds
21942174

21952175
putDumpFileMaybe logger Opt_D_dump_stg_cg "CodeGenInput STG:" FormatSTG
@@ -2350,7 +2330,7 @@ hscParsedDecls hsc_env decls = runInteractiveHsc hsc_env $ do
23502330
<- {-# SCC "CoreToStg" #-}
23512331
liftIO $ myCoreToStg (hsc_logger hsc_env)
23522332
(hsc_dflags hsc_env)
2353-
(hsc_IC hsc_env)
2333+
(interactiveInScope (hsc_IC hsc_env))
23542334
True
23552335
this_mod
23562336
iNTERACTIVELoc
@@ -2558,56 +2538,135 @@ hscCompileCoreExpr hsc_env loc expr =
25582538
Just h -> h hsc_env loc expr
25592539

25602540
hscCompileCoreExpr' :: HscEnv -> SrcSpan -> CoreExpr -> IO (ForeignHValue, [Linkable], PkgsLoaded)
2561-
hscCompileCoreExpr' hsc_env srcspan ds_expr
2562-
= do { {- Simplify it -}
2563-
-- Question: should we call SimpleOpt.simpleOptExpr here instead?
2564-
-- It is, well, simpler, and does less inlining etc.
2565-
let dflags = hsc_dflags hsc_env
2566-
; let logger = hsc_logger hsc_env
2567-
; let ic = hsc_IC hsc_env
2568-
; let unit_env = hsc_unit_env hsc_env
2569-
; let simplify_expr_opts = initSimplifyExprOpts dflags ic
2570-
; simpl_expr <- simplifyExpr logger (ue_eps unit_env) simplify_expr_opts ds_expr
2571-
2572-
{- Tidy it (temporary, until coreSat does cloning) -}
2573-
; let tidy_expr = tidyExpr emptyTidyEnv simpl_expr
2574-
2575-
{- Prepare for codegen -}
2576-
; cp_cfg <- initCorePrepConfig hsc_env
2577-
; prepd_expr <- corePrepExpr
2578-
logger cp_cfg
2579-
tidy_expr
2580-
2581-
{- Lint if necessary -}
2582-
; lintInteractiveExpr (text "hscCompileExpr") hsc_env prepd_expr
2583-
; let iNTERACTIVELoc = ModLocation{ ml_hs_file = Nothing,
2584-
ml_hi_file = panic "hscCompileCoreExpr':ml_hi_file",
2585-
ml_obj_file = panic "hscCompileCoreExpr':ml_obj_file",
2586-
ml_dyn_obj_file = panic "hscCompileCoreExpr': ml_obj_file",
2587-
ml_dyn_hi_file = panic "hscCompileCoreExpr': ml_dyn_hi_file",
2588-
ml_hie_file = panic "hscCompileCoreExpr':ml_hie_file" }
2589-
2590-
; let ictxt = hsc_IC hsc_env
2591-
; (binding_id, stg_expr, _, _, _stg_cg_info) <-
2592-
myCoreToStgExpr logger
2593-
dflags
2594-
ictxt
2595-
True
2596-
(icInteractiveModule ictxt)
2597-
iNTERACTIVELoc
2598-
prepd_expr
2599-
2600-
{- Convert to BCOs -}
2601-
; bcos <- byteCodeGen hsc_env
2602-
(icInteractiveModule ictxt)
2603-
stg_expr
2604-
[] Nothing
2605-
2606-
{- load it -}
2607-
; (fv_hvs, mods_needed, units_needed) <- loadDecls (hscInterp hsc_env) hsc_env srcspan bcos
2608-
{- Get the HValue for the root -}
2609-
; return (expectJust "hscCompileCoreExpr'"
2610-
$ lookup (idName binding_id) fv_hvs, mods_needed, units_needed) }
2541+
hscCompileCoreExpr' hsc_env srcspan ds_expr = do
2542+
{- Simplify it -}
2543+
-- Question: should we call SimpleOpt.simpleOptExpr here instead?
2544+
-- It is, well, simpler, and does less inlining etc.
2545+
let dflags = hsc_dflags hsc_env
2546+
let logger = hsc_logger hsc_env
2547+
let ic = hsc_IC hsc_env
2548+
let unit_env = hsc_unit_env hsc_env
2549+
let simplify_expr_opts = initSimplifyExprOpts dflags ic
2550+
2551+
simpl_expr <- simplifyExpr logger (ue_eps unit_env) simplify_expr_opts ds_expr
2552+
2553+
-- Create a unique temporary binding
2554+
--
2555+
-- The id has to be exported for the JS backend. This isn't required for the
2556+
-- byte-code interpreter but it does no harm to always do it.
2557+
u <- uniqFromMask 'I'
2558+
let binding_name = mkSystemVarName u (fsLit ("BCO_toplevel"))
2559+
let binding_id = mkExportedVanillaId binding_name (exprType simpl_expr)
2560+
2561+
{- Tidy it (temporary, until coreSat does cloning) -}
2562+
let tidy_occ_env = initTidyOccEnv [occName binding_id]
2563+
let tidy_env = mkEmptyTidyEnv tidy_occ_env
2564+
let tidy_expr = tidyExpr tidy_env simpl_expr
2565+
2566+
{- Prepare for codegen -}
2567+
cp_cfg <- initCorePrepConfig hsc_env
2568+
prepd_expr <- corePrepExpr
2569+
logger cp_cfg
2570+
tidy_expr
2571+
2572+
{- Lint if necessary -}
2573+
lintInteractiveExpr (text "hscCompileExpr") hsc_env prepd_expr
2574+
let this_loc = ModLocation{ ml_hs_file = Nothing,
2575+
ml_hi_file = panic "hscCompileCoreExpr':ml_hi_file",
2576+
ml_obj_file = panic "hscCompileCoreExpr':ml_obj_file",
2577+
ml_dyn_obj_file = panic "hscCompileCoreExpr': ml_obj_file",
2578+
ml_dyn_hi_file = panic "hscCompileCoreExpr': ml_dyn_hi_file",
2579+
ml_hie_file = panic "hscCompileCoreExpr':ml_hie_file" }
2580+
2581+
-- Ensure module uniqueness by giving it a name like "GhciNNNN".
2582+
-- This uniqueness is needed by the JS linker. Without it we break the 1-1
2583+
-- relationship between modules and object files, i.e. we get different object
2584+
-- files for the same module and the JS linker doesn't support this.
2585+
--
2586+
-- Note that we can't use icInteractiveModule because the ic_mod_index value
2587+
-- isn't bumped between invocations of hscCompileExpr, so uniqueness isn't
2588+
-- guaranteed.
2589+
--
2590+
-- We reuse the unique we obtained for the binding, but any unique would do.
2591+
let this_mod = mkInteractiveModule (getKey u)
2592+
let for_bytecode = True
2593+
2594+
(stg_binds, _prov_map, _collected_ccs, _stg_cg_infos) <-
2595+
myCoreToStg logger
2596+
dflags
2597+
(interactiveInScope (hsc_IC hsc_env))
2598+
for_bytecode
2599+
this_mod
2600+
this_loc
2601+
[NonRec binding_id prepd_expr]
2602+
2603+
let interp = hscInterp hsc_env
2604+
let tmpfs = hsc_tmpfs hsc_env
2605+
let tmp_dir = tmpDir dflags
2606+
2607+
case interp of
2608+
-- always generate JS code for the JS interpreter (no bytecode!)
2609+
Interp (ExternalInterp (ExtJS i)) _ ->
2610+
jsCodeGen logger tmpfs tmp_dir unit_env (initStgToJSConfig dflags) interp i
2611+
this_mod stg_binds binding_id
2612+
2613+
_ -> do
2614+
{- Convert to BCOs -}
2615+
bcos <- byteCodeGen hsc_env
2616+
this_mod
2617+
stg_binds
2618+
[] Nothing
2619+
2620+
{- load it -}
2621+
(fv_hvs, mods_needed, units_needed) <- loadDecls interp hsc_env srcspan bcos
2622+
{- Get the HValue for the root -}
2623+
return (expectJust "hscCompileCoreExpr'"
2624+
$ lookup (idName binding_id) fv_hvs, mods_needed, units_needed)
2625+
2626+
2627+
2628+
-- | Generate JS code for the given bindings and return the HValue for the given id
2629+
jsCodeGen
2630+
:: Logger
2631+
-> TmpFs
2632+
-> TempDir
2633+
-> UnitEnv
2634+
-> StgToJSConfig
2635+
-> Interp
2636+
-> JSInterp
2637+
-> Module
2638+
-> [CgStgTopBinding]
2639+
-> Id
2640+
-> IO (ForeignHValue, [Linkable], PkgsLoaded)
2641+
jsCodeGen logger tmpfs tmp_dir unit_env js_config interp i this_mod stg_binds binding_id = do
2642+
let foreign_stubs = NoStubs
2643+
spt_entries = mempty
2644+
cost_centre_info = mempty
2645+
2646+
-- codegen into object file whose path is in out_obj
2647+
out_obj <- newTempName logger tmpfs tmp_dir TFL_CurrentModule "o"
2648+
stgToJS logger js_config stg_binds this_mod spt_entries foreign_stubs cost_centre_info out_obj
2649+
2650+
let TxtI id_sym = makeIdentForId binding_id Nothing IdPlain this_mod
2651+
-- link code containing binding "id_sym = expr", using id_sym as root
2652+
withJSInterp i $ \inst -> do
2653+
let roots = mkExportedModFuns this_mod [id_sym]
2654+
jsLinkObject logger tmpfs tmp_dir js_config unit_env inst out_obj roots
2655+
2656+
-- look up "id_sym" closure and create a StablePtr (HValue) from it
2657+
href <- lookupClosure interp (unpackFS id_sym) >>= \case
2658+
Nothing -> pprPanic "Couldn't find just linked TH closure" (ppr id_sym)
2659+
Just r -> pure r
2660+
2661+
binding_fref <- withJSInterp i $ \inst ->
2662+
mkForeignRef href (freeReallyRemoteRef inst href)
2663+
2664+
-- FIXME (#23013): the JS linker doesn't use the LoaderState.
2665+
-- The state is only maintained in the interpreter instance (jsLinkState field) for now.
2666+
let linkables = mempty
2667+
let loaded_pkgs = emptyUDFM
2668+
2669+
return (castForeignRef binding_fref, linkables, loaded_pkgs)
26112670

26122671

26132672
{- **********************************************************************

compiler/GHC/Driver/Make.hs

+1
Original file line numberDiff line numberDiff line change
@@ -2778,6 +2778,7 @@ executeLinkNode hug kn uid deps = do
27782778
link (ghcLink dflags)
27792779
(hsc_logger hsc_env')
27802780
(hsc_tmpfs hsc_env')
2781+
(hsc_FC hsc_env')
27812782
(hsc_hooks hsc_env')
27822783
dflags
27832784
(hsc_unit_env hsc_env')

0 commit comments

Comments
 (0)