From bd6b519ef9d5e0d0595793041457a607fcc15b13 Mon Sep 17 00:00:00 2001
From: Patrick Palka <patrick@parcs.ath.cx>
Date: Mon, 16 Jul 2012 16:58:40 -0400
Subject: [PATCH] Consider usage files in the GHCi recompilation checker
Modules now get recompiled if their usage files have changed.
---
compiler/main/DriverPipeline.hs | 22 ++++++++++-----
compiler/main/GHC.hs | 1 +
compiler/main/GhcMake.hs | 59 +++++++++++++++++++++++++++++++--------
compiler/main/HscTypes.lhs | 2 ++
4 files changed, 66 insertions(+), 18 deletions(-)
diff --git a/compiler/main/DriverPipeline.hs b/compiler/main/DriverPipeline.hs
index 4770679..0bb3e7b 100644
|
a
|
b
|
|
| 162 | 162 | | otherwise = source_modified0 |
| 163 | 163 | object_filename = ml_obj_file location |
| 164 | 164 | |
| 165 | | let handleBatch HscNoRecomp |
| | 165 | let handleBatch _iface HscNoRecomp |
| 166 | 166 | = ASSERT (isJust maybe_old_linkable) |
| 167 | 167 | return maybe_old_linkable |
| 168 | 168 | |
| 169 | | handleBatch (HscRecomp hasStub _) |
| | 169 | handleBatch _iface (HscRecomp hasStub _) |
| 170 | 170 | | isHsBoot src_flavour |
| 171 | 171 | = do when (isObjectTarget hsc_lang) $ -- interpreted reaches here too |
| 172 | 172 | liftIO $ touchObjectFile dflags' object_filename |
| … |
… |
|
| 196 | 196 | let linkable = LM unlinked_time this_mod hs_unlinked |
| 197 | 197 | return (Just linkable) |
| 198 | 198 | |
| 199 | | handleInterpreted HscNoRecomp |
| | 199 | handleInterpreted _iface HscNoRecomp |
| 200 | 200 | = ASSERT (isJust maybe_old_linkable) |
| 201 | 201 | return maybe_old_linkable |
| 202 | | handleInterpreted (HscRecomp _hasStub Nothing) |
| | 202 | handleInterpreted _iface (HscRecomp _hasStub Nothing) |
| 203 | 203 | = ASSERT (isHsBoot src_flavour) |
| 204 | 204 | return maybe_old_linkable |
| 205 | | handleInterpreted (HscRecomp hasStub (Just (comp_bc, modBreaks))) |
| | 205 | handleInterpreted iface (HscRecomp hasStub (Just (comp_bc, modBreaks))) |
| 206 | 206 | = do stub_o <- case hasStub of |
| 207 | 207 | Nothing -> return [] |
| 208 | 208 | Just stub_c -> do |
| … |
… |
|
| 210 | 210 | return [DotO stub_o] |
| 211 | 211 | |
| 212 | 212 | let hs_unlinked = [BCOs comp_bc modBreaks] |
| 213 | | unlinked_time = ms_hs_date summary |
| | 213 | |
| | 214 | unlinked_time <- do |
| | 215 | let usage_mtimes = |
| | 216 | [mtime | UsageFile _ mtime <- mi_usages iface] |
| | 217 | return $ maximum (ms_hs_date summary : usage_mtimes) |
| 214 | 218 | -- Why do we use the timestamp of the source file here, |
| 215 | 219 | -- rather than the current time? This works better in |
| 216 | 220 | -- the case where the local clock is out of sync |
| 217 | 221 | -- with the filesystem's clock. It's just as accurate: |
| 218 | 222 | -- if the source is modified, then the linkable will |
| 219 | 223 | -- be out of date. |
| | 224 | -- However, make sure to take into account the mtimes of the |
| | 225 | -- module's usage files, too. |
| | 226 | |
| 220 | 227 | let linkable = LM unlinked_time this_mod |
| 221 | 228 | (hs_unlinked ++ stub_o) |
| 222 | 229 | return (Just linkable) |
| … |
… |
|
| 227 | 234 | = do (result, iface, details) |
| 228 | 235 | <- compiler hsc_env' summary source_modified mb_old_iface |
| 229 | 236 | (Just (mod_index, nmods)) |
| 230 | | linkable <- handle result |
| | 237 | linkable <- handle iface result |
| 231 | 238 | return (HomeModInfo{ hm_details = details, |
| 232 | 239 | hm_iface = iface, |
| 233 | 240 | hm_linkable = linkable }) |
| … |
… |
|
| 946 | 953 | ms_hspp_buf = hspp_buf, |
| 947 | 954 | ms_location = location4, |
| 948 | 955 | ms_hs_date = src_timestamp, |
| | 956 | ms_uf_date = Nothing, |
| 949 | 957 | ms_obj_date = Nothing, |
| 950 | 958 | ms_textual_imps = imps, |
| 951 | 959 | ms_srcimps = src_imps } |
diff --git a/compiler/main/GHC.hs b/compiler/main/GHC.hs
index bedb300..80efcc5 100644
|
a
|
b
|
|
| 882 | 882 | -- want. (Thus it doesn't matter what the timestamp |
| 883 | 883 | -- for the (nonexistent) source file is.) |
| 884 | 884 | ms_hs_date = currentTime, |
| | 885 | ms_uf_date = Nothing, |
| 885 | 886 | ms_obj_date = Nothing, |
| 886 | 887 | -- Only handling the single-module case for now, so no imports. |
| 887 | 888 | ms_srcimps = [], |
diff --git a/compiler/main/GhcMake.hs b/compiler/main/GhcMake.hs
index 322c631..fca9638 100644
|
a
|
b
|
|
| 502 | 502 | all stableObject (imports m) |
| 503 | 503 | && old linkable does not exist, or is == on-disk .o |
| 504 | 504 | && date(on-disk .o) > date(.hs) |
| | 505 | && date(linkableTime) > usage file dates |
| 505 | 506 | |
| 506 | 507 | stableBCO m = |
| 507 | 508 | all stable (imports m) |
| 508 | 509 | && date(BCO) > date(.hs) |
| | 510 | && date(linkableTime) > usage file dates |
| 509 | 511 | @ |
| 510 | 512 | |
| 511 | 513 | These properties embody the following ideas: |
| … |
… |
|
| 567 | 569 | where |
| 568 | 570 | same_as_prev t = case lookupUFM hpt (ms_mod_name ms) of |
| 569 | 571 | Just hmi | Just l <- hm_linkable hmi |
| 570 | | -> isObjectLinkable l && t == linkableTime l |
| | 572 | -> isObjectLinkable l && t == linkableTime l && |
| | 573 | uf_date_ok ms l |
| 571 | 574 | _other -> True |
| 572 | 575 | -- why '>=' rather than '>' above? If the filesystem stores |
| 573 | 576 | -- times to the nearset second, we may occasionally find that |
| … |
… |
|
| 584 | 587 | | otherwise = case lookupUFM hpt (ms_mod_name ms) of |
| 585 | 588 | Just hmi | Just l <- hm_linkable hmi -> |
| 586 | 589 | not (isObjectLinkable l) && |
| 587 | | linkableTime l >= ms_hs_date ms |
| | 590 | linkableTime l >= ms_hs_date ms && |
| | 591 | uf_date_ok ms l |
| 588 | 592 | _other -> False |
| 589 | 593 | |
| | 594 | uf_date_ok ms linkable = Just (linkableTime linkable) >= ms_uf_date ms |
| | 595 | |
| 590 | 596 | -- ----------------------------------------------------------------------------- |
| 591 | 597 | -- |
| 592 | 598 | -- | The upsweep |
| … |
… |
|
| 1194 | 1200 | = do |
| 1195 | 1201 | let location = ms_location old_summary |
| 1196 | 1202 | |
| | 1203 | (uf_date_ok,uf_date) <- isOkUsageFileDate hsc_env old_summary |
| 1197 | 1204 | src_timestamp <- get_src_timestamp |
| 1198 | 1205 | -- The file exists; we checked in getRootSummary above. |
| 1199 | 1206 | -- If it gets removed subsequently, then this |
| … |
… |
|
| 1201 | 1208 | -- behaviour. |
| 1202 | 1209 | |
| 1203 | 1210 | -- return the cached summary if the source didn't change |
| 1204 | | if ms_hs_date old_summary == src_timestamp |
| | 1211 | if ms_hs_date old_summary == src_timestamp && uf_date_ok |
| 1205 | 1212 | then do -- update the object-file timestamp |
| 1206 | 1213 | obj_timestamp <- |
| 1207 | 1214 | if isObjectTarget (hscTarget (hsc_dflags hsc_env)) |
| … |
… |
|
| 1210 | 1217 | else return Nothing |
| 1211 | 1218 | return old_summary{ ms_obj_date = obj_timestamp } |
| 1212 | 1219 | else |
| 1213 | | new_summary src_timestamp |
| | 1220 | new_summary src_timestamp uf_date |
| 1214 | 1221 | |
| 1215 | 1222 | | otherwise |
| 1216 | 1223 | = do src_timestamp <- get_src_timestamp |
| 1217 | | new_summary src_timestamp |
| | 1224 | new_summary src_timestamp Nothing |
| 1218 | 1225 | where |
| 1219 | 1226 | get_src_timestamp = case maybe_buf of |
| 1220 | 1227 | Just (_,t) -> return t |
| 1221 | 1228 | Nothing -> liftIO $ getModificationUTCTime file |
| 1222 | 1229 | -- getMofificationUTCTime may fail |
| 1223 | 1230 | |
| 1224 | | new_summary src_timestamp = do |
| | 1231 | new_summary src_timestamp uf_date = do |
| 1225 | 1232 | let dflags = hsc_dflags hsc_env |
| 1226 | 1233 | |
| 1227 | 1234 | (dflags', hspp_fn, buf) |
| … |
… |
|
| 1251 | 1258 | ms_hspp_buf = Just buf, |
| 1252 | 1259 | ms_srcimps = srcimps, ms_textual_imps = the_imps, |
| 1253 | 1260 | ms_hs_date = src_timestamp, |
| | 1261 | ms_uf_date = uf_date, |
| 1254 | 1262 | ms_obj_date = obj_timestamp }) |
| 1255 | 1263 | |
| 1256 | 1264 | findSummaryBySourceFile :: [ModSummary] -> FilePath -> Maybe ModSummary |
| … |
… |
|
| 1282 | 1290 | let location = ms_location old_summary |
| 1283 | 1291 | src_fn = expectJust "summariseModule" (ml_hs_file location) |
| 1284 | 1292 | |
| | 1293 | (uf_date_ok,uf_date) <- isOkUsageFileDate hsc_env old_summary |
| | 1294 | |
| 1285 | 1295 | -- check the modification time on the source file, and |
| 1286 | 1296 | -- return the cached summary if it hasn't changed. If the |
| 1287 | 1297 | -- file has disappeared, we need to call the Finder again. |
| 1288 | | case maybe_buf of |
| 1289 | | Just (_,t) -> check_timestamp old_summary location src_fn t |
| | 1298 | maybe_ms <- case maybe_buf of |
| | 1299 | Just (_,t) -> check_timestamp old_summary location src_fn t uf_date_ok |
| 1290 | 1300 | Nothing -> do |
| 1291 | 1301 | m <- tryIO (getModificationUTCTime src_fn) |
| 1292 | 1302 | case m of |
| 1293 | | Right t -> check_timestamp old_summary location src_fn t |
| | 1303 | Right t -> |
| | 1304 | check_timestamp old_summary location src_fn t uf_date_ok |
| 1294 | 1305 | Left e | isDoesNotExistError e -> find_it |
| 1295 | 1306 | | otherwise -> ioError e |
| 1296 | 1307 | |
| | 1308 | return $ case maybe_ms of |
| | 1309 | Nothing -> Nothing |
| | 1310 | Just ms -> Just ms { ms_uf_date = uf_date } |
| | 1311 | |
| 1297 | 1312 | | otherwise = find_it |
| 1298 | 1313 | where |
| 1299 | 1314 | dflags = hsc_dflags hsc_env |
| 1300 | 1315 | |
| 1301 | 1316 | hsc_src = if is_boot then HsBootFile else HsSrcFile |
| 1302 | 1317 | |
| 1303 | | check_timestamp old_summary location src_fn src_timestamp |
| 1304 | | | ms_hs_date old_summary == src_timestamp = do |
| | 1318 | check_timestamp old_summary location src_fn src_timestamp uf_date_ok |
| | 1319 | | ms_hs_date old_summary == src_timestamp, uf_date_ok = do |
| 1305 | 1320 | -- update the object-file timestamp |
| 1306 | 1321 | obj_timestamp <- |
| 1307 | 1322 | if isObjectTarget (hscTarget (hsc_dflags hsc_env)) |
| … |
… |
|
| 1377 | 1392 | ms_srcimps = srcimps, |
| 1378 | 1393 | ms_textual_imps = the_imps, |
| 1379 | 1394 | ms_hs_date = src_timestamp, |
| | 1395 | ms_uf_date = Nothing, |
| 1380 | 1396 | ms_obj_date = obj_timestamp })) |
| 1381 | 1397 | |
| 1382 | 1398 | |
| | 1399 | -- Iterate over the module's usage files, and check whether they have been |
| | 1400 | -- modified. |
| | 1401 | isOkUsageFileDate :: HscEnv -> ModSummary |
| | 1402 | -> IO (Bool, Maybe UTCTime) |
| | 1403 | -- ^ Returns whether the usage files haven't changed, and |
| | 1404 | -- the latest mtime of all the usage files. |
| | 1405 | isOkUsageFileDate hsc_env summary |
| | 1406 | | Just hmi <- lookupUFM (hsc_HPT hsc_env) (ms_mod_name summary) = do |
| | 1407 | let usages = mi_usages (hm_iface hmi) |
| | 1408 | usage_files = [file | UsageFile file _ <- usages] |
| | 1409 | old_mtimes = [mtime | UsageFile _ mtime <- usages] |
| | 1410 | |
| | 1411 | mtimes <- mapM modificationTimeIfExists usage_files |
| | 1412 | let max_mtime |
| | 1413 | | null mtimes = Nothing |
| | 1414 | | otherwise = maximum mtimes |
| | 1415 | |
| | 1416 | return (mtimes == map Just old_mtimes, max_mtime) |
| | 1417 | |
| | 1418 | | otherwise = return (False, Nothing) |
| | 1419 | |
| 1383 | 1420 | getObjTimestamp :: ModLocation -> Bool -> IO (Maybe UTCTime) |
| 1384 | 1421 | getObjTimestamp location is_boot |
| 1385 | 1422 | = if is_boot then return Nothing |
diff --git a/compiler/main/HscTypes.lhs b/compiler/main/HscTypes.lhs
index 343df00..e2a3079 100644
|
a
|
b
|
|
| 1813 | 1813 | ms_hsc_src :: HscSource, -- ^ The module source either plain Haskell, hs-boot or external core |
| 1814 | 1814 | ms_location :: ModLocation, -- ^ Location of the various files belonging to the module |
| 1815 | 1815 | ms_hs_date :: UTCTime, -- ^ Timestamp of source file |
| | 1816 | ms_uf_date :: Maybe UTCTime, -- ^ Latest timestamp of usage files |
| 1816 | 1817 | ms_obj_date :: Maybe UTCTime, -- ^ Timestamp of object, if we have one |
| 1817 | 1818 | ms_srcimps :: [Located (ImportDecl RdrName)], -- ^ Source imports of the module |
| 1818 | 1819 | ms_textual_imps :: [Located (ImportDecl RdrName)], -- ^ Non-source imports of the module from the module *text* |
| … |
… |
|
| 1865 | 1866 | ppr ms |
| 1866 | 1867 | = sep [text "ModSummary {", |
| 1867 | 1868 | nest 3 (sep [text "ms_hs_date = " <> text (show (ms_hs_date ms)), |
| | 1869 | text "ms_uf_date = " <> text (show (ms_uf_date ms)), |
| 1868 | 1870 | text "ms_mod =" <+> ppr (ms_mod ms) |
| 1869 | 1871 | <> text (hscSourceString (ms_hsc_src ms)) <> comma, |
| 1870 | 1872 | text "ms_textual_imps =" <+> ppr (ms_textual_imps ms), |