PageRenderTime 56ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Gen2/Generator.hs

http://github.com/ghcjs/ghcjs
Haskell | 2380 lines | 1969 code | 202 blank | 209 comment | 141 complexity | 53ba0ea6b8d11c785bf0808556563920 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. {-# LANGUAGE CPP,
  2. QuasiQuotes,
  3. TupleSections,
  4. OverloadedStrings,
  5. LambdaCase,
  6. MultiWayIf,
  7. TemplateHaskell,
  8. ViewPatterns,
  9. BangPatterns
  10. #-}
  11. {-
  12. Main generator module
  13. -}
  14. module Gen2.Generator (generate) where
  15. import Fingerprint
  16. import ForeignCall
  17. import CostCentre
  18. import FastString
  19. import TysWiredIn
  20. import BasicTypes
  21. import ListSetOps
  22. import PrelNames
  23. import DynFlags
  24. import Encoding
  25. import UniqSet
  26. import Literal
  27. import DataCon
  28. import CoreSyn
  29. import IdInfo
  30. import TcType
  31. import UniqFM
  32. import Unique
  33. import StgSyn
  34. import PrimOp
  35. import Module
  36. import VarSet
  37. import Panic
  38. import TyCon
  39. import Util
  40. import Type hiding (typeSize)
  41. import RepType
  42. import TysPrim
  43. import Name
  44. import GHC
  45. import Id
  46. import HscTypes
  47. import Control.Applicative
  48. import Control.DeepSeq
  49. import Control.Lens hiding ((||=))
  50. import Control.Monad.State.Strict
  51. import Data.Array
  52. import Data.Bits
  53. ((.|.), shiftL, shiftR, (.&.), testBit, xor, complement)
  54. import Data.ByteString (ByteString)
  55. import qualified Data.ByteString as B
  56. import qualified Data.ByteString.Lazy as BL
  57. import Data.Char (ord, chr, isDigit)
  58. import Data.Either (partitionEithers)
  59. import Data.Function (on)
  60. import Data.Generics.Aliases (mkT)
  61. import Data.Generics.Schemes (everywhere)
  62. import Data.Int
  63. import Data.IntMap.Strict (IntMap)
  64. import qualified Data.IntMap.Strict as IM
  65. import qualified Data.IntSet as IS
  66. import Data.Maybe
  67. (isJust, isNothing, catMaybes, fromMaybe, maybeToList, listToMaybe)
  68. import Data.Map (Map)
  69. import qualified Data.Map as M
  70. import Data.Set (Set)
  71. import qualified Data.Set as S
  72. import Data.List
  73. (partition, intercalate, sort, sortBy, foldl', scanl')
  74. import qualified Data.List as L
  75. import qualified Data.Text as T
  76. import qualified Data.Text.Encoding as T
  77. import Data.Text (Text)
  78. import Compiler.JMacro
  79. import qualified Text.Parsec as P
  80. import Compiler.Compat
  81. import Compiler.Settings
  82. import Gen2.Base
  83. import Gen2.Deps
  84. import Gen2.Utils
  85. import Gen2.Prim
  86. import Gen2.Rts
  87. import Gen2.RtsTypes
  88. import Gen2.StgAst
  89. import Gen2.RtsAlloc
  90. import Gen2.RtsApply
  91. import qualified Gen2.Linker as Linker
  92. import Gen2.ClosureInfo
  93. import qualified Gen2.Optimizer as O
  94. import qualified Gen2.Object as Object
  95. import Gen2.Sinker
  96. import Gen2.Profiling
  97. import qualified Gen2.Compactor as Compactor
  98. import GHC.Float
  99. -- debug
  100. import Gen2.Printer (pretty)
  101. import qualified Data.Text.Lazy as TL
  102. import Text.PrettyPrint.Leijen.Text (displayT, renderPretty)
  103. import qualified Debug.Trace
  104. data DependencyDataCache = DDC
  105. { _ddcModule :: !(IntMap Object.Package) -- ^ Unique Module -> Object.Package
  106. , _ddcId :: !(IntMap Object.Fun) -- ^ Unique Id -> Object.Fun (only to other modules)
  107. , _ddcOther :: !(Map OtherSymb Object.Fun)
  108. }
  109. makeLenses ''DependencyDataCache
  110. type StgPgm = [StgBinding]
  111. data ExprCtx = ExprCtx
  112. { _ctxTop :: Id
  113. , _ctxTarget :: [(PrimRep,[JExpr])]
  114. , _ctxEval :: UniqSet Id
  115. , _ctxLne :: UniqSet Id -- ^ all lne-bound things
  116. , _ctxLneFrameBs :: UniqFM Int -- ^ binds in current lne frame (defined at size)
  117. , _ctxLneFrame :: [(Id,Int)] -- ^ contents of current lne frame
  118. , _ctxSrcSpan :: Maybe RealSrcSpan
  119. }
  120. makeLenses ''ExprCtx
  121. instance Show ExprCtx where
  122. show (ExprCtx top tgt eval lne _lnefbs lnef _mbSpan) =
  123. "ExprCtx\n" ++ unlines [show top, show tgt, sus eval, sus lne, show lnef]
  124. where
  125. sus = show . nonDetEltsUniqSet
  126. clearCtxStack :: ExprCtx -> ExprCtx
  127. clearCtxStack ctx = ctx & ctxLneFrameBs .~ emptyUFM
  128. & ctxLneFrame .~ []
  129. adjustCtxStack :: Int -> ExprCtx -> ExprCtx
  130. adjustCtxStack n ctx
  131. | l < n = panic $ "adjustCtxStack: let-no-escape stack too short: " ++
  132. show l ++ " < " ++ show n
  133. | otherwise = ctx & ctxLneFrame %~ take n
  134. where
  135. l = ctx ^. ctxLneFrame . to length
  136. addEval :: Id -> ExprCtx -> ExprCtx
  137. addEval i = over ctxEval (flip addOneToUniqSet i)
  138. generate :: GhcjsSettings
  139. -> DynFlags
  140. -> Module
  141. -> [StgTopBinding] -- StgPgm
  142. -> [SptEntry]
  143. -> CollectedCCs
  144. -> ByteString -- ^ binary data for the .js_o object file
  145. generate settings df m s spt_entries cccs =
  146. let (uf, s') = sinkPgm m s
  147. in trace' ("generate\n" ++ intercalate "\n\n" (map showIndent s)) $
  148. flip evalState (initState df m uf) $ do
  149. ifProfiling' $ initCostCentres cccs
  150. (st, lus) <- genUnits df m s' spt_entries
  151. -- (exported symbol names, javascript statements) for each linkable unit
  152. p <- forM lus $ \u ->
  153. mapM (fmap (\(TxtI i) -> i) . jsIdI) (luIdExports u) >>=
  154. \ts -> return (ts ++ luOtherExports u, luStat u)
  155. let (st', dbg) = dumpAst st settings df s'
  156. deps <- genDependencyData df m lus
  157. -- p first, so numbering of linkable units lines up
  158. pure . BL.toStrict $
  159. Object.object' st' deps (p ++ dbg)
  160. {- |
  161. Generate an extra linkable unit for the object file if -debug is active.
  162. this unit is never actually linked, but it contains the optimized STG AST
  163. so it can be easily reviewed using ghcjs --print-obj to aid in solving
  164. code generator problems.
  165. -}
  166. dumpAst :: Object.SymbolTable
  167. -> GhcjsSettings
  168. -> DynFlags
  169. -> [StgTopBinding]
  170. -> (Object.SymbolTable, [([Text], BL.ByteString)])
  171. dumpAst st _settings dflags s
  172. | buildingDebug dflags = (st', [(["h$debug", "h$dumpAst"], bs)])
  173. | otherwise = (st, [])
  174. where
  175. (st', bs) = Object.serializeStat st [] [] [j| h$dumpAst = `x` |] [] []
  176. x = T.intercalate "\n\n" (map (T.pack . showIndent) s)
  177. -- | variable prefix for the nth block in module
  178. modulePrefix :: Module -> Int -> Text
  179. modulePrefix m n =
  180. let encMod = zEncodeString . moduleNameString . moduleName $ m
  181. in T.pack $ "h$" ++ encMod ++ "_id_" ++ show n
  182. -- | data used to generate one ObjUnit in our object file
  183. data LinkableUnit = LinkableUnit
  184. { luStat :: BL.ByteString -- ^ serialized JS AST
  185. , luIdExports :: [Id] -- ^ exported names from haskell identifiers
  186. , luOtherExports :: [Text] -- ^ other exports
  187. , luIdDeps :: [Id] -- ^ identifiers this unit depends on
  188. , luOtherDeps :: [OtherSymb] -- ^ symbols not from a haskell id that this unit depends on
  189. , luRequired :: Bool -- ^ always link this unit
  190. , luForeignRefs :: [ForeignRef]
  191. } deriving (Eq, Ord, Show)
  192. -- | Generate the ingredients for the linkable units for this module
  193. genUnits :: HasDebugCallStack
  194. => DynFlags
  195. -> Module
  196. -> [StgTopBinding] -- StgPgm
  197. -> [SptEntry]
  198. -> G (Object.SymbolTable, [LinkableUnit]) -- ^ the final symbol table and the linkable units
  199. genUnits dflags m ss spt_entries = generateGlobalBlock =<< go 2 Object.emptySymbolTable ss
  200. where
  201. -- ss' = [l | StgTopLifted l <- ss]
  202. go :: HasDebugCallStack
  203. => Int -- ^ the block we're generating (block 0 is the global unit for the module)
  204. -> Object.SymbolTable -- ^ the shared symbol table
  205. -> [StgTopBinding]
  206. -> G (Object.SymbolTable, [LinkableUnit])
  207. go n st (x:xs) = do
  208. (st', mlu) <- generateBlock st x n
  209. (st'', lus) <- go (n+1) st' xs
  210. return (st'', maybe lus (:lus) mlu)
  211. go _ st [] = return (st, [])
  212. -- | Generate the global unit that all other blocks in the module depend on
  213. -- used for cost centres and static initializers
  214. -- the global unit has no dependencies, exports the moduleGlobalSymbol
  215. generateGlobalBlock :: HasDebugCallStack
  216. => (Object.SymbolTable, [LinkableUnit])
  217. -> G (Object.SymbolTable, [LinkableUnit])
  218. generateGlobalBlock (st, lus) = do
  219. glbl <- use gsGlobal
  220. staticInit <-
  221. initStaticPtrs spt_entries
  222. (st', _, bs) <- serializeLinkableUnit m st [] [] []
  223. ( O.optimize
  224. . jsSaturate (Just $ modulePrefix m 1)
  225. $ mconcat (reverse glbl) <> staticInit) [] []
  226. return ( st'
  227. , LinkableUnit bs
  228. []
  229. [moduleGlobalSymbol dflags m]
  230. []
  231. []
  232. False
  233. []
  234. : lus
  235. )
  236. -- | Generate the linkable unit for one binding or group of
  237. -- mutually recursive bindings
  238. generateBlock :: HasDebugCallStack
  239. => Object.SymbolTable
  240. -> StgTopBinding
  241. -> Int
  242. -> G (Object.SymbolTable, Maybe LinkableUnit)
  243. generateBlock st (StgTopStringLit bnd str) n = do
  244. bids <- genIdsI bnd
  245. case bids of
  246. [b1@(TxtI b1t),b2@(TxtI b2t)] -> do
  247. -- [e1,e2] <- genLit (MachStr str)
  248. emitStatic b1t (StaticUnboxed (StaticUnboxedString str)) Nothing
  249. emitStatic b2t (StaticUnboxed (StaticUnboxedStringOffset str)) Nothing
  250. extraTl <- use (gsGroup . ggsToplevelStats)
  251. si <- use (gsGroup . ggsStatic)
  252. let stat = mempty -- mconcat (reverse extraTl) <> b1 ||= e1 <> b2 ||= e2
  253. (st', _ss, bs) <- serializeLinkableUnit m st [bnd] [] si
  254. (jsSaturate (Just $ modulePrefix m n) stat) [] []
  255. pure (st', Just $ LinkableUnit bs [bnd] [] [] [] False [])
  256. _ -> panic "generateBlock: invalid size"
  257. generateBlock st (StgTopLifted decl) n =
  258. trace' ("generateBlock:\n" ++ showIndent decl) $
  259. do
  260. tl <- genToplevel decl
  261. extraTl <- use (gsGroup . ggsToplevelStats)
  262. ci <- use (gsGroup . ggsClosureInfo)
  263. si <- use (gsGroup . ggsStatic)
  264. unf <- use gsUnfloated
  265. extraDeps <- use (gsGroup . ggsExtraDeps)
  266. fRefs <- use (gsGroup . ggsForeignRefs)
  267. resetGroup
  268. let allDeps = collectIds unf decl
  269. topDeps = collectTopIds decl
  270. required = hasExport decl
  271. stat = O.optimize
  272. . jsSaturate (Just $ modulePrefix m n)
  273. $ mconcat (reverse extraTl) <> tl
  274. (st', _ss, bs) <- serializeLinkableUnit m st topDeps ci si stat [] fRefs
  275. return $! seqList topDeps `seq` seqList allDeps `seq` st' `seq`
  276. (st', Just $ LinkableUnit bs topDeps [] allDeps (S.toList extraDeps) required fRefs)
  277. initStaticPtrs :: [SptEntry] -> C
  278. initStaticPtrs ptrs = mconcat <$> mapM initStatic ptrs
  279. where
  280. initStatic (SptEntry sp_id (Fingerprint w1 w2)) = do
  281. i <- jsId sp_id
  282. fpa <- concat <$> mapM (genLit . mkMachWord64 . fromIntegral) [w1,w2]
  283. let sptInsert = ApplExpr (ValExpr (JVar (TxtI "h$hs_spt_insert")))
  284. (fpa ++ [i])
  285. return [j| h$initStatic.push(function() {
  286. `sptInsert`;
  287. })
  288. |]
  289. hasExport :: StgBinding -> Bool
  290. hasExport bnd =
  291. case bnd of
  292. StgNonRec b e -> isExportedBind b e
  293. StgRec bs -> any (uncurry isExportedBind) bs
  294. where
  295. isExportedBind _i (StgRhsCon _cc con _) =
  296. getUnique con == staticPtrDataConKey
  297. isExportedBind _ _ = False
  298. {- |
  299. serialize the payload of a linkable unit in the object file, adding
  300. strings to the SymbolTable where necessary
  301. -}
  302. serializeLinkableUnit :: HasDebugCallStack
  303. => Module
  304. -> Object.SymbolTable -- symbol table to start with
  305. -> [Id] -- id's exported by unit
  306. -> [ClosureInfo]
  307. -> [StaticInfo]
  308. -> JStat -- generated code for the unit
  309. -> [Object.ExpFun]
  310. -> [Object.ForeignRef]
  311. -> G (Object.SymbolTable, [Text], BL.ByteString)
  312. serializeLinkableUnit _m st i ci si stat fe fi = do
  313. i' <- mapM idStr i
  314. let (st', o) = Object.serializeStat st ci si stat fe fi
  315. rnf i' `seq` rnf o `seq` return (st', i', o)
  316. where
  317. idStr i = itxt <$> jsIdI i
  318. collectTopIds :: StgBinding -> [Id]
  319. collectTopIds (StgNonRec b _) = [b]
  320. collectTopIds (StgRec bs) = let xs = map (zapFragileIdInfo . fst) bs
  321. in seqList xs `seq` xs
  322. collectIds :: UniqFM StgExpr -> StgBinding -> [Id]
  323. collectIds unfloated b =
  324. let xs = map zapFragileIdInfo .
  325. filter acceptId $ S.toList (bindingRefs unfloated b)
  326. in seqList xs `seq` xs
  327. where
  328. acceptId i = all ($ i) [not . isForbidden] -- fixme test this: [isExported[isGlobalId, not.isForbidden]
  329. -- the GHC.Prim module has no js source file
  330. isForbidden i
  331. | Just m <- nameModule_maybe (getName i) =
  332. moduleNameText m == T.pack "GHC.Prim" &&
  333. modulePackageKey m == primPackageKey
  334. | otherwise = False
  335. {- |
  336. generate the object's dependy data, taking care that package and module names
  337. are only stored once
  338. -}
  339. genDependencyData :: HasDebugCallStack
  340. => DynFlags
  341. -> Module
  342. -> [LinkableUnit]
  343. -> G Object.Deps
  344. genDependencyData dflags mod units = do
  345. -- [(blockindex, blockdeps, required, exported)]
  346. ds <- evalStateT (sequence (map (uncurry oneDep) blocks))
  347. (DDC IM.empty IM.empty M.empty)
  348. return $ Object.Deps (Linker.mkPackage $
  349. toInstalledUnitId (moduleUnitId mod))
  350. (moduleNameText mod)
  351. (IS.fromList [ n | (n, _, True, _) <- ds ])
  352. (M.fromList $ (\(n,_,_,es) -> map (,n) es) =<< ds)
  353. (listArray (0, length blocks-1) (ds ^.. traverse . _2))
  354. where
  355. -- Id -> Block
  356. unitIdExports :: UniqFM Int
  357. unitIdExports = listToUFM $
  358. concatMap (\(u,n) -> map (,n) (luIdExports u)) blocks
  359. -- OtherSymb -> Block
  360. unitOtherExports :: Map OtherSymb Int
  361. unitOtherExports = M.fromList $
  362. concatMap (\(u,n) -> map (,n)
  363. (map (OtherSymb mod)
  364. (luOtherExports u)))
  365. blocks
  366. blocks :: [(LinkableUnit, Int)]
  367. blocks = zip units [0..]
  368. -- generate the list of exports and set of dependencies for one unit
  369. oneDep :: LinkableUnit
  370. -> Int
  371. -> StateT DependencyDataCache G (Int, Object.BlockDeps, Bool, [Object.Fun])
  372. oneDep (LinkableUnit _ idExports otherExports idDeps otherDeps req frefs) n = do
  373. (edi, bdi) <- partitionEithers <$> mapM (lookupIdFun n) idDeps
  374. (edo, bdo) <- partitionEithers <$> mapM lookupOtherFun otherDeps
  375. expi <- mapM lookupExportedId (filter isExportedId idExports)
  376. expo <- mapM lookupExportedOther otherExports
  377. -- fixme thin deps, remove all transitive dependencies!
  378. let bdeps = Object.BlockDeps
  379. (IS.toList . IS.fromList . filter (/=n) $ bdi++bdo)
  380. (S.toList . S.fromList $ edi++edo)
  381. -- [] -- fixme support foreign exported
  382. -- frefs
  383. return (n, bdeps, req, expi++expo)
  384. idModule :: Id -> Maybe Module
  385. idModule i = nameModule_maybe (getName i) >>= \m ->
  386. guard (m /= mod) >> return m
  387. -- get the function for an Id from the cache, add it if necessary
  388. -- result: Left Object.Fun if function refers to another module
  389. -- Right blockNumber if function refers to current module
  390. --
  391. -- assumes function is internal to the current block if it's
  392. -- from teh current module and not in the unitIdExports map.
  393. lookupIdFun :: Int -> Id
  394. -> StateT DependencyDataCache G (Either Object.Fun Int)
  395. lookupIdFun n i = case lookupUFM unitIdExports i of
  396. Just k -> return (Right k)
  397. Nothing -> case idModule i of
  398. Nothing -> return (Right n)
  399. Just m ->
  400. let k = getKey . getUnique $ i
  401. addEntry :: StateT DependencyDataCache G Object.Fun
  402. addEntry = do
  403. (TxtI idTxt) <- lift (jsIdI i)
  404. lookupExternalFun (Just k) (OtherSymb m idTxt)
  405. in if m == mod
  406. then panic ("local id not found: " ++ show m)
  407. else Left <$> (maybe addEntry return =<<
  408. use (ddcId . to (IM.lookup k)))
  409. -- get the function for an OtherSymb from the cache, add it if necessary
  410. lookupOtherFun :: OtherSymb
  411. -> StateT DependencyDataCache G (Either Object.Fun Int)
  412. lookupOtherFun od@(OtherSymb m idTxt) =
  413. case M.lookup od unitOtherExports of
  414. Just n -> return (Right n)
  415. Nothing | m == mod -> panic ("genDependencyData.lookupOtherFun: unknown local other id: " ++ T.unpack idTxt)
  416. Nothing -> Left <$> (maybe (lookupExternalFun Nothing od) return =<<
  417. use (ddcOther . to (M.lookup od)))
  418. lookupExportedId :: Id -> StateT DependencyDataCache G Object.Fun
  419. lookupExportedId i = do
  420. (TxtI idTxt) <- lift (jsIdI i)
  421. lookupExternalFun (Just . getKey . getUnique $ i) (OtherSymb mod idTxt)
  422. lookupExportedOther :: Text -> StateT DependencyDataCache G Object.Fun
  423. lookupExportedOther = lookupExternalFun Nothing . OtherSymb mod
  424. -- lookup a dependency to another module, add to the id cache if there's
  425. -- an id key, otherwise add to other cache
  426. lookupExternalFun :: Maybe Int
  427. -> OtherSymb -> StateT DependencyDataCache G Object.Fun
  428. lookupExternalFun mbIdKey od@(OtherSymb m idTxt) = do
  429. let mk = getKey . getUnique $ m
  430. mpk = Linker.mkPackage (toInstalledUnitId (moduleUnitId m))
  431. inCache p = Object.Fun p (moduleNameText m) idTxt
  432. addCache = do
  433. let cache' = IM.insert mk mpk
  434. ddcModule %= cache'
  435. cache' `seq` return (Object.Fun mpk (moduleNameText m) idTxt)
  436. f <- maybe addCache (return . inCache) =<<
  437. use (ddcModule . to (IM.lookup mk))
  438. maybe (ddcOther %= M.insert od f) (\k -> ddcId %= IM.insert k f) mbIdKey
  439. return f
  440. moduleNameText :: Module -> Text
  441. moduleNameText m
  442. | xs == ":Main" = T.pack "Main"
  443. | otherwise = T.pack xs
  444. where xs = moduleNameString . moduleName $ m
  445. genToplevel :: StgBinding -> C
  446. genToplevel (StgNonRec bndr rhs) = genToplevelDecl bndr rhs
  447. genToplevel (StgRec bs) =
  448. mconcat $ map (\(bndr, rhs) -> genToplevelDecl bndr rhs) bs
  449. -- entry function of the worker
  450. enterDataCon :: DataCon -> G JExpr
  451. enterDataCon d = jsDcEntryId (dataConWorkId d)
  452. enterDataConI :: DataCon -> G Ident
  453. enterDataConI d = jsDcEntryIdI (dataConWorkId d)
  454. genToplevelDecl :: Id -> StgRhs -> C
  455. genToplevelDecl i rhs = do
  456. s1 <- resetSlots (genToplevelConEntry i rhs)
  457. s2 <- resetSlots (genToplevelRhs i rhs)
  458. return (s1 <> s2)
  459. genToplevelConEntry :: Id -> StgRhs -> C
  460. genToplevelConEntry i rhs@(StgRhsCon _cc con _args)
  461. | i `elem` [ i' | AnId i' <- dataConImplicitTyThings con ]
  462. = genSetConInfo i con (stgRhsLive rhs) -- NoSRT
  463. genToplevelConEntry i rhs@(StgRhsClosure _cc _bi [] _upd_flag
  464. _args (removeTick -> StgConApp dc _cargs _))
  465. | i `elem` [ i' | AnId i' <- dataConImplicitTyThings dc ]
  466. = genSetConInfo i dc (stgRhsLive rhs) -- srt
  467. genToplevelConEntry _ _ = mempty
  468. removeTick :: StgExpr -> StgExpr
  469. removeTick (StgTick _ e) = e
  470. removeTick e = e
  471. genStaticRefsRhs :: StgRhs -> G CIStatic
  472. genStaticRefsRhs lv = genStaticRefs (stgRhsLive lv)
  473. -- fixme, update to new way to compute static refs dynamically
  474. genStaticRefs :: LiveVars -> G CIStatic
  475. genStaticRefs lv
  476. | isEmptyDVarSet sv = return noStatic
  477. | otherwise = do
  478. unfloated <- use gsUnfloated
  479. let xs = filter (\x -> not (elemUFM x unfloated ||
  480. isLiftedType_maybe (idType x) == Just False))
  481. (dVarSetElems sv)
  482. CIStaticRefs . catMaybes <$> mapM getStaticRef xs
  483. where
  484. sv = liveStatic lv
  485. getStaticRef :: Id -> G (Maybe Text)
  486. getStaticRef = fmap (fmap itxt . listToMaybe) . genIdsI
  487. genToplevelRhs :: Id
  488. -> StgRhs
  489. -> C
  490. genToplevelRhs i rhs@(StgRhsClosure cc _bi _ upd args body)
  491. -- foreign exports
  492. | (StgOpApp (StgFCallOp (CCall (CCallSpec (StaticTarget _ t _ _) _ _)) _)
  493. [StgLitArg _ {- (MachInt _is_js_conv) -}, StgLitArg (MachStr _js_name), StgVarArg _tgt] _) <- body,
  494. t == fsLit "__mkExport" = return mempty -- fixme error "export not implemented"
  495. -- general cases:
  496. genToplevelRhs i (StgRhsCon cc con args) = do
  497. ii <- jsIdI i
  498. allocConStatic ii cc con args
  499. return mempty
  500. genToplevelRhs i rhs@(StgRhsClosure cc _bi [] _upd_flag {- srt -} args body) = do
  501. eid@(TxtI eidt) <- jsEnIdI i
  502. (TxtI idt) <- jsIdI i
  503. -- pushGlobalRefs
  504. body <- genBody (ExprCtx i [] emptyUniqSet emptyUniqSet emptyUFM [] Nothing) i R2 args body
  505. (lidents, lids) <- unzip <$> liftToGlobal (jsSaturate (Just . T.pack $ "ghcjs_tmp_sat_") body)
  506. let lidents' = map (\(TxtI t) -> t) lidents
  507. -- li
  508. -- refs <- popGlobalRefs
  509. CIStaticRefs sr0 <- genStaticRefsRhs rhs
  510. let sri = filter (`notElem` lidents') sr0
  511. sr = CIStaticRefs sri
  512. -- emitToplevel $ AssignStat (ValExpr (JVar $ TxtI ("h$globalRefs_" <> idt)))
  513. -- (ValExpr (JList $ map (ValExpr . JVar) lidents ++ [jnull] ++ map (ValExpr . JVar . TxtI) sri))
  514. et <- genEntryType args
  515. ll <- loadLiveFun lids
  516. (static, regs, upd) <-
  517. if et == CIThunk
  518. then (StaticThunk (Just (eidt, map StaticObjArg lidents')), CIRegs 0 [PtrV],) <$> updateThunk
  519. else return (StaticFun eidt (map StaticObjArg lidents'),
  520. (if null lidents then CIRegs 1 (concatMap idVt args)
  521. else CIRegs 0 (PtrV : concatMap idVt args))
  522. , mempty)
  523. setcc <- ifProfiling $
  524. if et == CIThunk
  525. then enterCostCentreThunk
  526. else enterCostCentreFun cc
  527. emitClosureInfo (ClosureInfo eidt
  528. regs
  529. idt
  530. (fixedLayout $ map (uTypeVt . idType) lids) -- (CILayoutFixed 0 [])
  531. et
  532. sr)
  533. ccId <- costCentreStackLbl cc
  534. emitStatic idt static ccId
  535. return $ eid ||= JFunc [] (ll <> upd <> setcc <> body)
  536. genToplevelRhs _ _ = panic "genToplevelRhs: top-level values cannot have live variables"
  537. dumpGlobalIdCache :: Text -> G ()
  538. dumpGlobalIdCache itxt = do
  539. GlobalIdCache gidc <- use globalIdCache
  540. let i = TxtI ("h$globalIdCache_" <> itxt)
  541. vs = M.keys
  542. emitToplevel [j| `i` = `M.keys gidc`; |]
  543. {- emitToplevel $ [j|
  544. AssignStat (ValExpr (JVar . TxtI $ "h$globalIdCache_" <> idt))
  545. (ValExpr (JList
  546. -}
  547. liftToGlobal :: JStat -> G [(Ident, Id)]
  548. liftToGlobal jst = do
  549. GlobalIdCache gidc <- use globalIdCache
  550. let sids = filter (`M.member` gidc) (jst ^.. Compactor.identsS)
  551. cnt = M.fromListWith (+) (map (,1) sids)
  552. sids' = sortBy (compare `on` (cnt M.!)) (nub' sids)
  553. pure $ map (\s -> (s, snd $ gidc M.! s)) sids'
  554. nub' :: (Ord a, Eq a) => [a] -> [a]
  555. nub' xs = go S.empty xs
  556. where
  557. go _ [] = []
  558. go s xxs@(x:xs) | S.member x s = go s xs
  559. | otherwise = x : go (S.insert x s) xs
  560. -- ids = filter M.member gidc
  561. {-
  562. algorithm:
  563. - collect all Id refs that are in the cache, count usage
  564. - order by increasing use
  565. - prepend loading lives var to body: body can stay the same
  566. -}
  567. {-
  568. todo for stack frames:
  569. - change calling convention?
  570. - return stack[sp] -> return stack[sp].f ?
  571. -> no we miss the continuation object then
  572. -> set h$rS
  573. -> return h$rs(); instead
  574. -}
  575. loadLiveFun :: [Id] -> C
  576. loadLiveFun l = do
  577. l' <- concat <$> mapM genIdsI l
  578. case l' of
  579. [] -> return mempty
  580. [v] -> return (decl' v [je| `R1`.d1 |])
  581. [v1,v2] -> return (decl' v1 [je| `R1`.d1 |] <> decl' v2 [je| `R1`.d2 |])
  582. (v:vs) -> do
  583. d <- makeIdent
  584. let l'' = mconcat . zipWith (loadLiveVar $ toJExpr d) [(1::Int)..] $ vs
  585. return (decl' v [je| `R1`.d1 |] <> [j| `decl d`; `d` = `R1`.d2 |] <> l'')
  586. where
  587. loadLiveVar d n v = let ident = dataFields ! n
  588. in decl' v (SelExpr d ident)
  589. dataFields :: Array Int Ident
  590. dataFields = listArray (1,16384) (map (TxtI . T.pack . ('d':) . show) [(1::Int)..16384])
  591. genBody :: HasDebugCallStack => ExprCtx -> Id -> StgReg -> [Id] -> StgExpr -> C
  592. genBody ctx i startReg args e =
  593. -- trace' ("genBody: " ++ show args)
  594. (genBody0 ctx i startReg args e)
  595. genBody0 :: HasDebugCallStack
  596. => ExprCtx
  597. -> Id
  598. -> StgReg
  599. -> [Id]
  600. -> StgExpr
  601. -> C
  602. genBody0 ctx i startReg args e = do
  603. la <- loadArgs startReg args
  604. lav <- verifyRuntimeReps args
  605. let ids :: [(PrimRep, [JExpr])]
  606. ids = -- take (resultSize args $ idType i) (map toJExpr $ enumFrom R1)
  607. reverse . fst $
  608. foldl' (\(rs, vs) (rep, size) ->
  609. let (vs0, vs1) = splitAt size vs
  610. in ((rep, vs0):rs,vs1))
  611. ([], map toJExpr $ enumFrom R1)
  612. (resultSize args $ idType i)
  613. (e, _r) <- trace' ("genBody0 ids:\n" ++ show ids) (genExpr (ctx & ctxTarget .~ ids) e)
  614. return $ la <> lav <> e <> returnStack -- [j| return `Stack`[`Sp`]; |]
  615. -- find the result type after applying the function to the arguments
  616. resultSize :: HasDebugCallStack => [Id] -> Type -> [(PrimRep, Int)]
  617. resultSize xs t = trace' ("resultSize\n" ++ show xs ++ "\n" ++ show t)
  618. (let r = resultSize0 xs t
  619. in trace' ("resultSize -> " ++ show r) r
  620. )
  621. resultSize0 :: HasDebugCallStack
  622. => [Id]
  623. -> Type
  624. -> [(PrimRep, Int)] -- Int
  625. resultSize0 xxs@(x:xs) t
  626. -- - | isUnboxedTupleType
  627. -- - | t' <- piResultTys t (map idType xxs) = resultSize0 [] t'
  628. -- - | MultiRep _ <- {- trace' "resultSize0 ubx" -} (repType (idType x)) = panic "genBody: unboxed tuple argument"
  629. -- - | otherwise = {- trace' "resultSize0 not" $ -}
  630. | t' <- unwrapType t
  631. , Just (fa, fr) <- splitFunTy_maybe t' -- isFunTy t' =
  632. , Just (tc, ys) <- splitTyConApp_maybe fa
  633. , isUnboxedTupleTyCon tc =
  634. resultSize0 xxs (mkFunTys (dropRuntimeRepArgs ys) fr)
  635. | t' <- unwrapType t
  636. , Just (fa, fr) <- splitFunTy_maybe t' = -- isFunTy t' =
  637. resultSize0 xs fr
  638. -- let (fa, fr) = splitFunTy t'
  639. -- let t'' = mkFunTys (map primRepToType . typePrimRep $ unwrapType fa) fr
  640. -- in resultSize0 xs (maybe fr snd . splitFunTy_maybe $ t'')
  641. | otherwise = [(LiftedRep, 1)] -- possibly newtype family, must be boxed
  642. -- case typePrimRep (unwrapType t) of -- repType t of
  643. -- (UnaryRep t' | isFunTy t' ->
  644. -- let (fa,fr) = splitFunTy t'
  645. -- t'' = mkFunTys (map slotTyToType . repTypeSlots $ repType fa) fr
  646. -- in {- trace' ("resultSize0 fun: " ++ show (fa, fr)) $ -}
  647. -- resultSize0 xs (snd . splitFunTy $ t'')
  648. -- _ -> 1 -- possibly newtype family, must be boxed
  649. resultSize0 [] t
  650. | isRuntimeRepKindedTy t' = []
  651. | isRuntimeRepTy t' = []
  652. | Nothing <- isLiftedType_maybe t' = [(LiftedRep, 1)]
  653. | otherwise = typeTarget t
  654. where
  655. t' = unwrapType t
  656. -- map (\t -> (t, varSize (primRepVt t))) $ typePrimRep (unwrapType t)
  657. {- trace' "resultSize0 eol" $ -}
  658. -- case repType t of
  659. -- UnaryRep t' -> {- trace' ("resultSize0 eol2: " ++ show t') $ -} typeSize t'
  660. -- MultiRep tys -> {- trace' ("resultSize0 eol3: " ++ show tys) $ -} sum (map (typeSize . slotTyToType) tys)
  661. loadArgs :: HasDebugCallStack => StgReg -> [Id] -> C
  662. loadArgs start args = do
  663. args' <- concatMapM genIdArgI args
  664. return (mconcat $ zipWith (||=) args' [start..])
  665. data ExprResult = ExprCont
  666. | ExprInline (Maybe [JExpr])
  667. deriving (Eq, Ord, Show)
  668. data ExprValData = ExprValData [JExpr]
  669. deriving (Eq, Ord, Show)
  670. -- not a Monoid
  671. branchResult :: HasDebugCallStack => [ExprResult] -> ExprResult
  672. branchResult [] = panic "branchResult: empty list"
  673. branchResult [e] = e
  674. branchResult (ExprCont:_) = ExprCont
  675. branchResult (_:es)
  676. | any (==ExprCont) es = ExprCont
  677. | otherwise = ExprInline Nothing
  678. genExpr :: HasDebugCallStack => ExprCtx -> StgExpr -> G (JStat, ExprResult)
  679. genExpr top e = trace' ("genExpr\n" ++ showIndent e)
  680. (genExpr0 top e)
  681. genExpr0 :: HasDebugCallStack
  682. => ExprCtx
  683. -> StgExpr
  684. -> G (JStat, ExprResult)
  685. genExpr0 top (StgApp f args) = genApp top f args
  686. genExpr0 top (StgLit l) =
  687. -- fixme check primRep here?
  688. (,ExprInline Nothing) .
  689. assignAllCh ("genExpr StgLit " ++ show (top ^. ctxTarget))
  690. (concatMap snd $ top ^. ctxTarget)
  691. <$> genLit l
  692. genExpr0 top (StgConApp con args _) = do
  693. as <- concatMapM genArg args
  694. c <- genCon top con as
  695. return (c, ExprInline (Just as))
  696. genExpr0 top (StgOpApp (StgFCallOp f _) args t) =
  697. genForeignCall top f t (concatMap snd $ top ^. ctxTarget) args
  698. genExpr0 top (StgOpApp (StgPrimOp op) args t) = genPrimOp top op args t
  699. genExpr0 top (StgOpApp (StgPrimCallOp c) args t) = genPrimCall top c args t
  700. genExpr0 _ (StgLam{}) = panic "genExpr: StgLam"
  701. genExpr0 top stg@(StgCase e b at alts) =
  702. genCase top b e at alts (liveVars $ stgExprLive False stg)
  703. genExpr0 top (StgLet b e) = do
  704. (b',top') <- genBind top b
  705. (s,r) <- genExpr top' e
  706. return (b' <> s, r)
  707. genExpr0 top (StgLetNoEscape b e) = do
  708. (b', top') <- genBindLne top b
  709. (s, r) <- genExpr top' e
  710. return (b' <> s, r)
  711. genExpr0 top (StgTick (ProfNote cc count scope) e) = do
  712. setSCCstats <- ifProfilingM $ setCC cc count scope
  713. (stats, result) <- genExpr top e
  714. return (setSCCstats <> stats, result)
  715. genExpr0 top (StgTick (SourceNote span _sname) e) =
  716. genExpr (top & ctxSrcSpan .~ Just span) e
  717. genExpr0 top (StgTick _m e) = genExpr top e
  718. might_be_a_function :: HasDebugCallStack => Type -> Bool
  719. -- Return False only if we are *sure* it's a data type
  720. -- Look through newtypes etc as much as poss
  721. might_be_a_function ty
  722. | [LiftedRep] <- typePrimRep ty
  723. , Just tc <- tyConAppTyCon_maybe (unwrapType ty)
  724. , isDataTyCon tc
  725. = False
  726. | otherwise
  727. = True
  728. matchVarName :: String -> FastString -> FastString -> Id -> Bool
  729. matchVarName pkg modu occ (idName -> n)
  730. | Just m <- nameModule_maybe n =
  731. occ == occNameFS (nameOccName n) &&
  732. modu == moduleNameFS (moduleName m) &&
  733. pkg `L.isPrefixOf` (unitIdString (moduleUnitId m))
  734. | otherwise = False
  735. genApp :: HasDebugCallStack
  736. => ExprCtx
  737. -> Id
  738. -> [StgArg]
  739. -> G (JStat, ExprResult)
  740. -- special cases for JSString literals
  741. -- we could handle unpackNBytes# here, but that's probably not common
  742. -- enough to warrant a special case
  743. genApp ctx i [StgVarArg v]
  744. | [top] <- concatMap snd (ctx ^. ctxTarget)
  745. -- , Just (Lit (MachStr bs)) <- expandUnfolding_maybe (idUnfolding v)
  746. -- , Just t <- decodeModifiedUTF8 bs -- unpackFS fs -- Just t <- decodeModifiedUTF8 bs
  747. , matchVarName "ghcjs-prim" "GHCJS.Prim" "unsafeUnpackJSStringUtf8##" i =
  748. (,ExprInline Nothing) . assignj top . ApplExpr (ValExpr (JVar (TxtI "h$decodeUtf8z")))
  749. <$> genIds v
  750. genApp ctx i [StgLitArg (MachStr bs), x]
  751. | [top] <- concatMap snd (ctx ^. ctxTarget), getUnique i == unpackCStringAppendIdKey, Just d <- decodeModifiedUTF8 bs = do
  752. -- fixme breaks assumption in codegen if bs doesn't decode
  753. prof <- csProf <$> use gsSettings
  754. let profArg = if prof then [jCafCCS] else []
  755. a <- genArg x
  756. return ([j| `top` = `ApplExpr (jsv "h$appendToHsStringA") $ [toJExpr d, toJExpr a] ++ profArg`; |]
  757. ,ExprInline Nothing)
  758. genApp top i a
  759. | Just n <- top ^. ctxLneFrameBs . to (flip lookupUFM i) = do -- let-no-escape
  760. as' <- concatMapM genArg a
  761. ei <- jsEntryId i
  762. let ra = mconcat . reverse $
  763. zipWith (\r a -> [j| `r` = `a`; |]) [R1 ..] as'
  764. p <- pushLneFrame n top
  765. a <- adjSp 1 -- for the header (which will only be written when the thread is suspended)
  766. return (ra <> p <> a <> [j| return `ei`; |], ExprCont)
  767. | n == 0 && (isUnboxedTupleType (idType i) || isStrictType (idType i)) = do
  768. a <- assignAllCh1 "genApp" (top ^. ctxTarget) .
  769. (alignTarget (idTarget i)) <$> genIds i
  770. return (a, ExprInline Nothing)
  771. | [vt] <- idVt i, isUnboxable vt && n == 0 && i `elementOfUniqSet` (top ^. ctxEval) = do
  772. let [c] = concatMap snd $ top ^. ctxTarget
  773. is <- genIds i
  774. case is of
  775. [i'] ->
  776. return ([j| `c` = (typeof `i'` === 'object') ? `i'`.d1 : `i'`; |]
  777. ,ExprInline Nothing)
  778. _ -> panic "genApp: invalid size"
  779. | n == 0 && (i `elementOfUniqSet` (top ^. ctxEval) || isStrictId i) = do
  780. a <- assignAllCh1 ("genApp:" ++ show i ++ " " ++ show (idFunRepArity i, idVt i))
  781. (top ^. ctxTarget) .
  782. (alignTarget (idTarget i))
  783. <$> genIds i
  784. settings <- use gsSettings
  785. let ww = case concatMap snd (top ^. ctxTarget) of
  786. [t] | csAssertRts settings ->
  787. [j| if(typeof `t` === 'object' && `isThunk t`)
  788. throw "unexpected thunk";
  789. |]
  790. _ -> mempty
  791. return (a <> ww, ExprInline Nothing)
  792. | DataConWrapId dc <- idDetails i, isNewTyCon (dataConTyCon dc) = do
  793. as <- concatMapM genArg a
  794. case as of
  795. [ai] -> do
  796. let [t] = concatMap snd (top ^. ctxTarget)
  797. [StgVarArg a'] = a
  798. if isStrictId a' || a' `elementOfUniqSet` (top ^. ctxEval)
  799. then return ([j| `t` = `ai`; |], ExprInline Nothing)
  800. else return ([j| return h$e(`ai`); |], ExprCont)
  801. _ -> panic "genApp: invalid size"
  802. | idFunRepArity i == 0 && n == 0 && not (might_be_a_function (idType i)) = do
  803. ii <- enterId
  804. return ([j| return h$e(`ii`) |], ExprCont)
  805. | idFunRepArity i == n && not (isLocalId i) && isStrictId i && n /= 0 = do
  806. as' <- concatMapM genArg a
  807. jmp <- jumpToII i as' =<< r1
  808. return (jmp, ExprCont)
  809. | idFunRepArity i < n && isStrictId i && idFunRepArity i > 0 =
  810. let (reg,over) = splitAt (idFunRepArity i) a
  811. in do
  812. reg' <- concatMapM genArg reg
  813. pc <- pushCont over
  814. jmp <- jumpToII i reg' =<< r1
  815. return (pc <> jmp, ExprCont)
  816. | otherwise = do
  817. jmp <- jumpToFast a =<< r1
  818. return (jmp, ExprCont)
  819. where
  820. enterId :: G JExpr
  821. enterId = genArg (StgVarArg i) >>=
  822. \case
  823. [x] -> return x
  824. xs -> panic $ "genApp: unexpected multi-var argument (" ++ show (length xs) ++ ")\n" ++ showIndent i
  825. r1 :: C
  826. r1 = do
  827. ids <- genIds i
  828. return $ mconcat $ zipWith (\r u -> [j| `r`=`u`; |]) (enumFrom R1) ids
  829. n = length a
  830. pushCont :: HasDebugCallStack
  831. => [StgArg]
  832. -> C
  833. pushCont as = do
  834. as' <- concatMapM genArg as
  835. (app, spec) <- selectApply False (as,as')
  836. if spec
  837. then push $ reverse $ app : as'
  838. else push $ reverse $ app : mkTag as' as : as'
  839. where
  840. mkTag rs ns = toJExpr ((length rs `shiftL` 8) .|. length ns)
  841. -- regular let binding: allocate heap object
  842. genBind :: HasDebugCallStack
  843. => ExprCtx
  844. -> StgBinding
  845. -> G (JStat, ExprCtx)
  846. genBind ctx bndr =
  847. case bndr of
  848. StgNonRec b r -> do
  849. j <- assign b r >>= \case
  850. Just ja -> return ja
  851. Nothing -> allocCls Nothing [(b,r)]
  852. return (j, addEvalRhs ctx [(b,r)])
  853. StgRec bs -> do
  854. jas <- mapM (uncurry assign) bs -- fixme these might depend on parts initialized by allocCls
  855. let m = if null jas then Nothing else Just (mconcat $ catMaybes jas)
  856. j <- allocCls m . map snd . filter (isNothing . fst) $ zip jas bs
  857. return (j, addEvalRhs ctx bs)
  858. where
  859. ctx' = clearCtxStack ctx
  860. assign :: Id -> StgRhs -> G (Maybe JStat)
  861. assign b (StgRhsClosure _ccs _bi [the_fv] _upd [] expr)
  862. | let strip = snd . stripStgTicksTop (not . tickishIsCode)
  863. , StgCase (StgApp scrutinee []) _ (AlgAlt _) [(DataAlt _, params, sel_expr)] <- strip expr
  864. , StgApp selectee [] <- strip sel_expr
  865. , let params_w_offsets = zip params (scanl' (+) 1 $ map (typeSize . idType) params)
  866. , let total_size = sum (map (typeSize . idType) params)
  867. , the_fv == scrutinee
  868. , Just the_offset <- assocMaybe params_w_offsets selectee
  869. , the_offset <= 16 -- fixme make this some configurable constant
  870. = do
  871. let sel_tag | the_offset == 2 = if total_size == 2 then "2a"
  872. else "2b"
  873. | otherwise = show the_offset
  874. tgts <- genIdsI b
  875. the_fvjs <- genIds the_fv
  876. case (tgts, the_fvjs) of
  877. ([tgt], [the_fvj]) -> return $ Just
  878. (tgt ||= ApplExpr (ValExpr (JVar (TxtI ("h$c_sel_" <> T.pack sel_tag))))
  879. [the_fvj])
  880. _ -> panic "genBind.assign: invalid size"
  881. assign b (StgRhsClosure _ccs _bi _free _upd [] expr)
  882. | snd (isInlineExpr (ctx ^. ctxEval) expr) = do
  883. d <- declIds b
  884. tgt <- genIds b
  885. (j, _) <- genExpr (ctx & ctxTarget .~ alignTarget (idTarget b) tgt) expr
  886. return (Just (d <> j))
  887. assign b (StgRhsCon{}) = return Nothing
  888. assign b r = genEntry ctx' b r >> return Nothing
  889. addEvalRhs c [] = c
  890. addEvalRhs c ((b,r):xs)
  891. | (StgRhsCon{}) <- r = addEvalRhs (addEval b c) xs
  892. | (StgRhsClosure _ _ _ ReEntrant _ _) <- r = addEvalRhs (addEval b c) xs
  893. | otherwise = addEvalRhs c xs
  894. genBindLne :: HasDebugCallStack
  895. => ExprCtx
  896. -> StgBinding
  897. -> G (JStat, ExprCtx)
  898. genBindLne ctx bndr =
  899. trace' ("genBindLne\n" ++ showIndent bndr)
  900. (genBindLne0 ctx bndr)
  901. genBindLne0 :: HasDebugCallStack
  902. => ExprCtx
  903. -> StgBinding
  904. -> G (JStat, ExprCtx)
  905. genBindLne0 ctx bndr = do
  906. vis <- map (\(x,y,_) -> (x,y)) <$>
  907. optimizeFree oldFrameSize (newLvs++map fst updBinds)
  908. declUpds <- mconcat <$> mapM (fmap (||= jnull) . jsIdI . fst) updBinds
  909. let newFrameSize = oldFrameSize + length vis
  910. ctx' = ctx & ctxLne %~ flip addListToUniqSet bound
  911. & ctxLneFrameBs %~ flip addListToUFM (map (,newFrameSize) bound)
  912. & ctxLneFrame %~ (++vis)
  913. mapM_ (uncurry $ genEntryLne ctx') binds
  914. return (declUpds, ctx')
  915. where
  916. oldFrame = ctx ^. ctxLneFrame
  917. oldFrameSize = length oldFrame
  918. isOldLv i = i `elementOfUniqSet` (ctx ^. ctxLne) ||
  919. i `elem` (map fst oldFrame)
  920. live = liveVars $ mkDVarSet $ stgLneLive' bndr
  921. newLvs = filter (not . isOldLv) (dVarSetElems live)
  922. binds = case bndr of
  923. StgNonRec b e -> [(b,e)]
  924. StgRec bs -> bs
  925. bound = map fst binds
  926. (updBinds, _nonUpdBinds) = partition (isUpdatableRhs . snd) binds
  927. stgLneLive' :: StgBinding -> [Id]
  928. stgLneLive' b = filter (`notElem` bindees b) (stgLneLive b)
  929. stgLneLive :: StgBinding -> [Id]
  930. stgLneLive (StgNonRec _b e) = stgLneLiveExpr e
  931. stgLneLive (StgRec bs) = L.nub $ concatMap (stgLneLiveExpr . snd) bs
  932. stgLneLiveExpr :: StgRhs -> [Id]
  933. stgLneLiveExpr (StgRhsClosure _ _ l _ _ _) = l
  934. stgLneLiveExpr (StgRhsCon {}) = []
  935. isUpdatableRhs :: StgRhs -> Bool
  936. isUpdatableRhs (StgRhsClosure _ _ _ u _ _) = isUpdatable u
  937. isUpdatableRhs _ = False
  938. {-
  939. Let-no-escape entries live on the stack. There is no heap object associated with them.
  940. A let-no-escape entry is called like a normal stack frame, although as an optimization,
  941. `Stack`[`Sp`] is not set when making the call. This done later if the thread needs to
  942. be suspended.
  943. Updatable let-no-escape binders have one 'private' slot in the stack frame. This slot
  944. is initially set to null, changed to h$blackhole when the thunk is being evaluated.
  945. -}
  946. genEntryLne :: HasDebugCallStack => ExprCtx -> Id -> StgRhs -> G ()
  947. genEntryLne ctx i rhs@(StgRhsClosure _cc _bi _live2 update args body) =
  948. resetSlots $ do
  949. let payloadSize = length frame
  950. frame = ctx ^. ctxLneFrame
  951. myOffset =
  952. maybe (panic "genEntryLne: updatable binder not found in let-no-escape frame")
  953. ((payloadSize-) . fst)
  954. (listToMaybe $ filter ((==i).fst.snd) (zip [0..] frame))
  955. bh | isUpdatable update =
  956. [j| var x = h$bh_lne(`Sp`-`myOffset`, `payloadSize+1`);
  957. if(x) return(x);
  958. |]
  959. | otherwise = mempty
  960. lvs <- popLneFrame True payloadSize ctx
  961. body <- genBody ctx i R1 args body
  962. ei <- jsEntryIdI i
  963. sr <- genStaticRefsRhs rhs
  964. let f = JFunc [] (bh <> lvs <> body)
  965. emitClosureInfo $
  966. ClosureInfo (itxt ei)
  967. (CIRegs 0 $ concatMap idVt args)
  968. (itxt ei <> ", " <> T.pack (show i))
  969. (fixedLayout . reverse $
  970. map (stackSlotType . fst) (ctx ^. ctxLneFrame))
  971. CIStackFrame
  972. sr
  973. emitToplevel (ei ||= f)
  974. genEntryLne ctx i (StgRhsCon cc con args) = resetSlots $ do
  975. let payloadSize = length (ctx ^. ctxLneFrame)
  976. ei <- jsEntryIdI i
  977. di <- enterDataCon con
  978. ii <- makeIdent
  979. p <- popLneFrame True payloadSize ctx
  980. args' <- concatMapM genArg args
  981. ac <- allocCon ii con cc args'
  982. emitToplevel $ ei ||= JFunc []
  983. (decl ii <> p <> ac <> [j| `R1` = `ii`; |] <> returnStack)
  984. -- generate the entry function for a local closure
  985. genEntry :: HasDebugCallStack => ExprCtx -> Id -> StgRhs -> G ()
  986. genEntry _ _i (StgRhsCon _cc _con _args) = return () -- mempty -- error "local data entry"
  987. genEntry ctx i rhs@(StgRhsClosure cc _bi live upd_flag args body) = resetSlots $ do
  988. ll <- loadLiveFun live
  989. llv <- verifyRuntimeReps live
  990. upd <- genUpdFrame upd_flag i
  991. body <- genBody entryCtx i R2 args body
  992. ei <- jsEntryIdI i
  993. et <- genEntryType args
  994. setcc <- ifProfiling $
  995. if et == CIThunk
  996. then enterCostCentreThunk
  997. else enterCostCentreFun cc
  998. sr <- genStaticRefsRhs rhs
  999. emitClosureInfo $ ClosureInfo (itxt ei)
  1000. (CIRegs 0 $ PtrV : concatMap idVt args)
  1001. (itxt ei <> ", " <> T.pack (show i))
  1002. (fixedLayout $ map (uTypeVt . idType) live)
  1003. et
  1004. sr
  1005. emitToplevel (ei ||= JFunc [] (ll <> llv <> upd <> setcc <> body))
  1006. where
  1007. entryCtx = ExprCtx i [] (ctx ^. ctxEval) (ctx ^. ctxLne) emptyUFM [] (ctx ^. ctxSrcSpan)
  1008. genEntryType :: HasDebugCallStack => [Id] -> G CIType
  1009. genEntryType [] = return CIThunk
  1010. genEntryType args0 = {- trace' "genEntryType" $ -} do
  1011. args' <- mapM genIdArg args
  1012. return $ CIFun (length args) (length $ concat args')
  1013. where
  1014. args = filter (not . isRuntimeRepKindedTy . idType) args0
  1015. genSetConInfo :: HasDebugCallStack => Id -> DataCon -> LiveVars -> C
  1016. genSetConInfo i d l {- srt -} = do
  1017. ei <- jsDcEntryIdI i
  1018. sr <- genStaticRefs l
  1019. emitClosureInfo $ ClosureInfo (itxt ei)
  1020. (CIRegs 0 [PtrV])
  1021. (T.pack $ show d)
  1022. (fixedLayout $ map uTypeVt fields)
  1023. (CICon $ dataConTag d)
  1024. sr
  1025. return (ei ||= mkDataEntry)
  1026. where
  1027. -- dataConRepArgTys sometimes returns unboxed tuples. is that a bug?
  1028. fields = concatMap (map primRepToType . typePrimRep . unwrapType)
  1029. (dataConRepArgTys d)
  1030. -- concatMap (map slotTyToType . repTypeSlots . repType) (dataConRepArgTys d)
  1031. mkDataEntry :: JExpr
  1032. mkDataEntry = ValExpr $ JFunc [] returnStack
  1033. genUpdFrame :: UpdateFlag -> Id -> C
  1034. genUpdFrame u i
  1035. | isReEntrant u = mempty
  1036. | isOneShotBndr i = maybeBh
  1037. | isUpdatable u = updateThunk
  1038. | otherwise = maybeBh
  1039. where
  1040. isReEntrant ReEntrant = True
  1041. isReEntrant _ = False
  1042. maybeBh = do
  1043. settings <- use gsSettings
  1044. assertRtsStat (return $ bhSingleEntry settings)
  1045. -- allocate local closures
  1046. allocCls :: Maybe JStat -> [(Id, StgRhs)] -> C
  1047. allocCls dynMiddle xs = do
  1048. (stat, dyn) <- partitionEithers <$> mapM toCl xs
  1049. cs <- use gsSettings
  1050. return (mconcat stat) <> allocDynAll cs True dynMiddle dyn
  1051. where
  1052. -- left = static, right = dynamic
  1053. toCl :: (Id, StgRhs)
  1054. -> G (Either JStat (Ident,JExpr,[JExpr],CostCentreStack))
  1055. -- statics
  1056. {- making zero-arg constructors static is problematic, see #646
  1057. proper candidates for this optimization should have been floated
  1058. already
  1059. toCl (i, StgRhsCon cc con []) = do
  1060. ii <- jsIdI i
  1061. Left <$> (return (decl ii) <> allocCon ii con cc []) -}
  1062. toCl (i, StgRhsCon cc con [a]) | isUnboxableCon con = do
  1063. ii <- jsIdI i
  1064. Left <$> (return (decl ii) <> (allocCon ii con cc =<< genArg a))
  1065. -- dynamics
  1066. toCl (i, StgRhsCon cc con ar) =
  1067. -- fixme do we need to handle unboxed?
  1068. Right <$> ((,,,) <$> jsIdI i
  1069. <*> enterDataCon con
  1070. <*> concatMapM genArg ar
  1071. <*> pure cc)
  1072. toCl (i, StgRhsClosure cc _bi live _upd_flag _args _body) =
  1073. Right <$> ((,,,) <$> jsIdI i
  1074. <*> jsEntryId i
  1075. <*> concatMapM genIds live
  1076. <*> pure cc)
  1077. genCase :: HasDebugCallStack
  1078. => ExprCtx
  1079. -> Id
  1080. -> StgExpr
  1081. -> AltType
  1082. -> [StgAlt]
  1083. -> LiveVars
  1084. -> G (JStat, ExprResult)
  1085. genCase top bnd e at alts l =
  1086. trace' ("genCase\n" ++ showIndent e ++ "\n" ++ unlines (map showIndent alts))
  1087. (genCase0 top bnd e at alts l)
  1088. -- fixme CgCase has a reps_compatible check here
  1089. genCase0 :: HasDebugCallStack
  1090. => ExprCtx
  1091. -> Id
  1092. -> StgExpr
  1093. -> AltType
  1094. -> [StgAlt]
  1095. -> LiveVars
  1096. -> G (JStat, ExprResult)
  1097. genCase0 top bnd e at alts l
  1098. | snd (isInlineExpr (top ^. ctxEval) e) = withNewIdent $ \ccsVar -> do
  1099. bndi <- genIdsI bnd
  1100. (ej, r) <- genExpr (top & ctxTop .~ bnd
  1101. & ctxTarget .~ alignTarget (idTarget bnd)
  1102. (map toJExpr bndi)) e
  1103. -- ExprCtx bnd (map toJExpr bndi) (top ^. ctxEval) (top ^. ctxLneV) (top ^. ctxLneB) (top ^. ctxLne)) e
  1104. let d = case r of
  1105. ExprInline d0 -> d0
  1106. ExprCont -> panic $ "genCase: expression was not inline:\n" ++
  1107. showIndent e ++ "\n" ++
  1108. (TL.unpack . (<>"\n") . displayT . renderPretty 0.8 150 . pretty . jsSaturate (Just "debug") $ ej)
  1109. ww = mempty -- if snd (isInlineExpr emptyUniqSet e) then mempty else [j| h$log('danger will robinson'); |]
  1110. (aj, ar) <- genAlts (addEval bnd top) bnd at d alts
  1111. saveCCS <- ifProfiling $ ccsVar |= jCurrentCCS
  1112. restoreCCS <- ifProfiling $ [j| `jCurrentCCS` = `ccsVar`; |]
  1113. return ( decl ccsVar <>
  1114. mconcat (map decl bndi) <>
  1115. saveCCS <>
  1116. ww <>
  1117. ej <>
  1118. restoreCCS <>
  1119. aj
  1120. , ar
  1121. )
  1122. | otherwise = do
  1123. rj <- genRet (addEval bnd top) bnd at alts l
  1124. (ej, _r) <- genExpr (top & ctxTop .~ bnd
  1125. & ctxTarget .~ alignTarget (idTarget bnd)
  1126. (map toJExpr [R1 ..])) e
  1127. return (rj <> ej, ExprCont)
  1128. alignTarget :: [(PrimRep, Int)] -> [a] -> [(PrimRep, [a])]
  1129. alignTarget [] _ = []
  1130. alignTarget ((rep, size):xs) vs
  1131. | length vs0 == size = (rep, vs0) : alignTarget xs vs1
  1132. | otherwise = panic "alignTarget: target size insufficient"
  1133. where (vs0, vs1) = splitAt size vs
  1134. idTarget :: Id -> [(PrimRep, Int)]
  1135. idTarget = typeTarget . idType
  1136. typeTarget :

Large files files are truncated, but you can click here to view the full file