diff options
| author | Nick Barnes | 2001-10-31 14:40:56 +0000 |
|---|---|---|
| committer | Nick Barnes | 2001-10-31 14:40:56 +0000 |
| commit | 7acfca905d76140f4cc0b09c9a12de237de364cd (patch) | |
| tree | 3ed8babfa3a73d30f29e08ca5d5adcda4ca4e826 /mps/code/root.c | |
| parent | b7ce4893f9902d57cd67ac9a92fa6c3d5a8fc833 (diff) | |
| download | emacs-7acfca905d76140f4cc0b09c9a12de237de364cd.tar.gz emacs-7acfca905d76140f4cc0b09c9a12de237de364cd.zip | |
Branch imports for masters.
Copied from Perforce
Change: 23678
ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code/root.c')
| -rw-r--r-- | mps/code/root.c | 669 |
1 files changed, 669 insertions, 0 deletions
diff --git a/mps/code/root.c b/mps/code/root.c new file mode 100644 index 00000000000..2643f70785d --- /dev/null +++ b/mps/code/root.c | |||
| @@ -0,0 +1,669 @@ | |||
| 1 | /* impl.c.root: ROOT IMPLEMENTATION | ||
| 2 | * | ||
| 3 | * $HopeName: MMsrc!root.c(trunk.34) $ | ||
| 4 | * Copyright (C) 2001 Harlequin Limited. All rights reserved. | ||
| 5 | * | ||
| 6 | * .purpose: This is the implementation of the root datatype. | ||
| 7 | * | ||
| 8 | * .design: For design, see design.mps.root and | ||
| 9 | * design.mps.root-interface. */ | ||
| 10 | |||
| 11 | #include "mpm.h" | ||
| 12 | |||
| 13 | SRCID(root, "$HopeName: MMsrc!root.c(trunk.34) $"); | ||
| 14 | |||
| 15 | |||
| 16 | /* RootStruct -- tracing root structure */ | ||
| 17 | |||
| 18 | #define RootSig ((Sig)0x51960029) /* SIGnature ROOT */ | ||
| 19 | |||
| 20 | typedef struct RootStruct { | ||
| 21 | Sig sig; | ||
| 22 | Serial serial; /* from arena->rootSerial */ | ||
| 23 | Arena arena; /* owning arena */ | ||
| 24 | RingStruct arenaRing; /* attachment to arena */ | ||
| 25 | Rank rank; /* rank of references in this root */ | ||
| 26 | TraceSet grey; /* traces for which root is grey */ | ||
| 27 | RefSet summary; /* summary of references in root */ | ||
| 28 | RootMode mode; /* mode */ | ||
| 29 | Bool protectable; /* Can protect root? */ | ||
| 30 | Addr protBase; /* base of protectable area */ | ||
| 31 | Addr protLimit; /* limit of protectable area */ | ||
| 32 | AccessSet pm; /* Protection Mode */ | ||
| 33 | RootVar var; /* union discriminator */ | ||
| 34 | union RootUnion { | ||
| 35 | struct { | ||
| 36 | RootScanMethod scan; /* the function which does the scanning */ | ||
| 37 | void *p; /* environment for scan */ | ||
| 38 | size_t s; /* environment for scan */ | ||
| 39 | } fun; | ||
| 40 | struct { | ||
| 41 | Addr *base; /* beginning of table */ | ||
| 42 | Addr *limit; /* one off end of table */ | ||
| 43 | } table; | ||
| 44 | struct { | ||
| 45 | Addr *base; /* beginning of table */ | ||
| 46 | Addr *limit; /* one off end of table */ | ||
| 47 | Word mask; /* tag mask for scanning */ | ||
| 48 | } tableMasked; | ||
| 49 | struct { | ||
| 50 | RootScanRegMethod scan; /* function for scanning registers */ | ||
| 51 | Thread thread; /* passed to scan */ | ||
| 52 | void *p; /* passed to scan */ | ||
| 53 | size_t s; /* passed to scan */ | ||
| 54 | } reg; | ||
| 55 | struct { | ||
| 56 | FormatScanMethod scan; /* format-like scanner */ | ||
| 57 | Addr base, limit; /* passed to scan */ | ||
| 58 | } fmt; | ||
| 59 | } the; | ||
| 60 | } RootStruct; | ||
| 61 | |||
| 62 | |||
| 63 | /* RootVarCheck -- check a Root union discriminator | ||
| 64 | * | ||
| 65 | * .rootvarcheck: Synchronize with impl.h.mpmtypes.rootvar */ | ||
| 66 | |||
| 67 | Bool RootVarCheck(RootVar rootVar) | ||
| 68 | { | ||
| 69 | CHECKL(rootVar == RootTABLE || rootVar == RootTABLE_MASKED | ||
| 70 | || rootVar == RootFUN || rootVar == RootFMT || rootVar == RootREG); | ||
| 71 | UNUSED(rootVar); | ||
| 72 | return TRUE; | ||
| 73 | } | ||
| 74 | |||
| 75 | |||
| 76 | /* RootModeCheck */ | ||
| 77 | |||
| 78 | Bool RootModeCheck(RootMode mode) | ||
| 79 | { | ||
| 80 | CHECKL((mode & (RootModeCONSTANT | RootModePROTECTABLE | ||
| 81 | | RootModePROTECTABLE_INNER)) | ||
| 82 | == mode); | ||
| 83 | /* RootModePROTECTABLE_INNER implies RootModePROTECTABLE */ | ||
| 84 | CHECKL((mode & RootModePROTECTABLE_INNER) == 0 | ||
| 85 | || (mode & RootModePROTECTABLE)); | ||
| 86 | UNUSED(mode); | ||
| 87 | |||
| 88 | return TRUE; | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | /* RootCheck -- check the consistency of a root structure | ||
| 93 | * | ||
| 94 | * .rootcheck: Keep synchonized with impl.h.mpmst.root. */ | ||
| 95 | |||
| 96 | Bool RootCheck(Root root) | ||
| 97 | { | ||
| 98 | CHECKS(Root, root); | ||
| 99 | CHECKU(Arena, root->arena); | ||
| 100 | CHECKL(root->serial < ArenaGlobals(root->arena)->rootSerial); | ||
| 101 | CHECKL(RingCheck(&root->arenaRing)); | ||
| 102 | CHECKL(RankCheck(root->rank)); | ||
| 103 | CHECKL(TraceSetCheck(root->grey)); | ||
| 104 | /* Don't need to check var here, because of the switch below */ | ||
| 105 | switch(root->var) | ||
| 106 | { | ||
| 107 | case RootTABLE: | ||
| 108 | CHECKL(root->the.table.base != 0); | ||
| 109 | CHECKL(root->the.table.base < root->the.table.limit); | ||
| 110 | break; | ||
| 111 | |||
| 112 | case RootTABLE_MASKED: | ||
| 113 | CHECKL(root->the.tableMasked.base != 0); | ||
| 114 | CHECKL(root->the.tableMasked.base < root->the.tableMasked.limit); | ||
| 115 | /* Can't check anything about the mask. */ | ||
| 116 | break; | ||
| 117 | |||
| 118 | case RootFUN: | ||
| 119 | CHECKL(root->the.fun.scan != NULL); | ||
| 120 | break; | ||
| 121 | |||
| 122 | case RootREG: | ||
| 123 | CHECKL(root->the.reg.scan != NULL); | ||
| 124 | CHECKL(ThreadCheck(root->the.reg.thread)); | ||
| 125 | break; | ||
| 126 | |||
| 127 | case RootFMT: | ||
| 128 | CHECKL(root->the.fmt.scan != NULL); | ||
| 129 | CHECKL(root->the.fmt.base != 0); | ||
| 130 | CHECKL(root->the.fmt.base < root->the.fmt.limit); | ||
| 131 | break; | ||
| 132 | |||
| 133 | default: | ||
| 134 | NOTREACHED; | ||
| 135 | } | ||
| 136 | CHECKL(RootModeCheck(root->mode)); | ||
| 137 | CHECKL(BoolCheck(root->protectable)); | ||
| 138 | if (root->protectable) { | ||
| 139 | CHECKL(root->protBase != (Addr)0); | ||
| 140 | CHECKL(root->protLimit != (Addr)0); | ||
| 141 | CHECKL(root->protBase < root->protLimit); | ||
| 142 | /* there is no AccessSetCheck */ | ||
| 143 | } else { | ||
| 144 | CHECKL(root->protBase == (Addr)0); | ||
| 145 | CHECKL(root->protLimit == (Addr)0); | ||
| 146 | CHECKL(root->pm == (AccessSet)0); | ||
| 147 | } | ||
| 148 | return TRUE; | ||
| 149 | } | ||
| 150 | |||
| 151 | |||
| 152 | /* rootCreate, RootCreateTable, RootCreateReg, RootCreateFmt, RootCreateFun | ||
| 153 | * | ||
| 154 | * RootCreate* set up the appropriate union member, and call the generic | ||
| 155 | * create function to do the actual creation | ||
| 156 | * | ||
| 157 | * See design.mps.root.init for initial value. */ | ||
| 158 | |||
| 159 | static Res rootCreate(Root *rootReturn, Arena arena, | ||
| 160 | Rank rank, RootMode mode, RootVar type, | ||
| 161 | union RootUnion *theUnionP) | ||
| 162 | { | ||
| 163 | Root root; | ||
| 164 | Res res; | ||
| 165 | void *p; | ||
| 166 | Globals globals; | ||
| 167 | |||
| 168 | AVER(rootReturn != NULL); | ||
| 169 | AVERT(Arena, arena); | ||
| 170 | AVERT(Rank, rank); | ||
| 171 | AVERT(RootVar, type); | ||
| 172 | globals = ArenaGlobals(arena); | ||
| 173 | |||
| 174 | res = ControlAlloc(&p, arena, sizeof(RootStruct), FALSE); | ||
| 175 | if (res != ResOK) | ||
| 176 | return res; | ||
| 177 | root = (Root)p; /* Avoid pun */ | ||
| 178 | |||
| 179 | root->arena = arena; | ||
| 180 | root->rank = rank; | ||
| 181 | root->var = type; | ||
| 182 | root->the = *theUnionP; | ||
| 183 | root->grey = TraceSetEMPTY; | ||
| 184 | root->summary = RefSetUNIV; | ||
| 185 | root->mode = mode; | ||
| 186 | root->pm = AccessSetEMPTY; | ||
| 187 | root->protectable = FALSE; | ||
| 188 | root->protBase = (Addr)0; | ||
| 189 | root->protLimit = (Addr)0; | ||
| 190 | |||
| 191 | /* See design.mps.arena.root-ring */ | ||
| 192 | RingInit(&root->arenaRing); | ||
| 193 | |||
| 194 | root->serial = globals->rootSerial; | ||
| 195 | ++globals->rootSerial; | ||
| 196 | root->sig = RootSig; | ||
| 197 | |||
| 198 | AVERT(Root, root); | ||
| 199 | |||
| 200 | RingAppend(&globals->rootRing, &root->arenaRing); | ||
| 201 | |||
| 202 | *rootReturn = root; | ||
| 203 | return ResOK; | ||
| 204 | } | ||
| 205 | |||
| 206 | static Res rootCreateProtectable(Root *rootReturn, Arena arena, | ||
| 207 | Rank rank, RootMode mode, RootVar var, | ||
| 208 | Addr base, Addr limit, | ||
| 209 | union RootUnion *theUnion) | ||
| 210 | { | ||
| 211 | Res res; | ||
| 212 | Root root; | ||
| 213 | Ring node, next; | ||
| 214 | |||
| 215 | res = rootCreate(&root, arena, rank, mode, var, theUnion); | ||
| 216 | if (res != ResOK) | ||
| 217 | return res; | ||
| 218 | if (mode & RootModePROTECTABLE) { | ||
| 219 | root->protectable = TRUE; | ||
| 220 | if (mode & RootModePROTECTABLE_INNER) { | ||
| 221 | root->protBase = AddrAlignUp(base, ArenaAlign(arena)); | ||
| 222 | root->protLimit = AddrAlignDown(limit, ArenaAlign(arena)); | ||
| 223 | if (!(root->protBase < root->protLimit)) { | ||
| 224 | /* root had no inner pages */ | ||
| 225 | root->protectable = FALSE; | ||
| 226 | root->mode &=~ (RootModePROTECTABLE|RootModePROTECTABLE_INNER); | ||
| 227 | } | ||
| 228 | } else { | ||
| 229 | root->protBase = AddrAlignDown(base, ArenaAlign(arena)); | ||
| 230 | root->protLimit = AddrAlignUp(limit, ArenaAlign(arena)); | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | /* Check that this root doesn't intersect with any other root */ | ||
| 235 | RING_FOR(node, &ArenaGlobals(arena)->rootRing, next) { | ||
| 236 | Root trial = RING_ELT(Root, arenaRing, node); | ||
| 237 | if (trial != root) { | ||
| 238 | /* (trial->protLimit <= root->protBase */ | ||
| 239 | /* || root->protLimit <= trial->protBase) */ | ||
| 240 | /* is the "okay" state. The negation of this is: */ | ||
| 241 | if (root->protBase < trial->protLimit | ||
| 242 | && trial->protBase < root->protLimit) { | ||
| 243 | NOTREACHED; | ||
| 244 | RootDestroy(root); | ||
| 245 | return ResFAIL; | ||
| 246 | } | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | AVERT(Root, root); | ||
| 251 | |||
| 252 | *rootReturn = root; | ||
| 253 | return ResOK; | ||
| 254 | } | ||
| 255 | |||
| 256 | Res RootCreateTable(Root *rootReturn, Arena arena, | ||
| 257 | Rank rank, RootMode mode, Addr *base, Addr *limit) | ||
| 258 | { | ||
| 259 | Res res; | ||
| 260 | union RootUnion theUnion; | ||
| 261 | |||
| 262 | AVER(rootReturn != NULL); | ||
| 263 | AVERT(Arena, arena); | ||
| 264 | AVER(RankCheck(rank)); | ||
| 265 | AVER(base != 0); | ||
| 266 | AVER(base < limit); | ||
| 267 | |||
| 268 | theUnion.table.base = base; | ||
| 269 | theUnion.table.limit = limit; | ||
| 270 | |||
| 271 | res = rootCreateProtectable(rootReturn, arena, rank, mode, | ||
| 272 | RootTABLE, (Addr)base, (Addr)limit, &theUnion); | ||
| 273 | return res; | ||
| 274 | } | ||
| 275 | |||
| 276 | Res RootCreateTableMasked(Root *rootReturn, Arena arena, | ||
| 277 | Rank rank, RootMode mode, Addr *base, Addr *limit, | ||
| 278 | Word mask) | ||
| 279 | { | ||
| 280 | union RootUnion theUnion; | ||
| 281 | |||
| 282 | AVER(rootReturn != NULL); | ||
| 283 | AVERT(Arena, arena); | ||
| 284 | AVER(RankCheck(rank)); | ||
| 285 | AVER(base != 0); | ||
| 286 | AVER(base < limit); | ||
| 287 | /* Can't check anything about mask. */ | ||
| 288 | |||
| 289 | theUnion.tableMasked.base = base; | ||
| 290 | theUnion.tableMasked.limit = limit; | ||
| 291 | theUnion.tableMasked.mask = mask; | ||
| 292 | |||
| 293 | return rootCreateProtectable(rootReturn, arena, rank, mode, RootTABLE_MASKED, | ||
| 294 | (Addr)base, (Addr)limit, &theUnion); | ||
| 295 | } | ||
| 296 | |||
| 297 | Res RootCreateReg(Root *rootReturn, Arena arena, | ||
| 298 | Rank rank, Thread thread, | ||
| 299 | RootScanRegMethod scan, void *p, size_t s) | ||
| 300 | { | ||
| 301 | union RootUnion theUnion; | ||
| 302 | |||
| 303 | AVER(rootReturn != NULL); | ||
| 304 | AVERT(Arena, arena); | ||
| 305 | AVER(RankCheck(rank)); | ||
| 306 | AVERT(Thread, thread); | ||
| 307 | AVER(scan != NULL); | ||
| 308 | |||
| 309 | theUnion.reg.scan = scan; | ||
| 310 | theUnion.reg.thread = thread; | ||
| 311 | theUnion.reg.p = p; | ||
| 312 | theUnion.reg.s = s; | ||
| 313 | |||
| 314 | return rootCreate(rootReturn, arena, rank, (RootMode)0, RootREG, &theUnion); | ||
| 315 | } | ||
| 316 | |||
| 317 | Res RootCreateFmt(Root *rootReturn, Arena arena, | ||
| 318 | Rank rank, RootMode mode, FormatScanMethod scan, | ||
| 319 | Addr base, Addr limit) | ||
| 320 | { | ||
| 321 | union RootUnion theUnion; | ||
| 322 | |||
| 323 | AVER(rootReturn != NULL); | ||
| 324 | AVERT(Arena, arena); | ||
| 325 | AVER(RankCheck(rank)); | ||
| 326 | AVER(FUNCHECK(scan)); | ||
| 327 | AVER(base != 0); | ||
| 328 | AVER(base < limit); | ||
| 329 | |||
| 330 | theUnion.fmt.scan = scan; | ||
| 331 | theUnion.fmt.base = base; | ||
| 332 | theUnion.fmt.limit = limit; | ||
| 333 | |||
| 334 | return rootCreateProtectable(rootReturn, arena, rank, mode, | ||
| 335 | RootFMT, base, limit, &theUnion); | ||
| 336 | } | ||
| 337 | |||
| 338 | Res RootCreateFun(Root *rootReturn, Arena arena, Rank rank, | ||
| 339 | RootScanMethod scan, void *p, size_t s) | ||
| 340 | { | ||
| 341 | union RootUnion theUnion; | ||
| 342 | |||
| 343 | AVER(rootReturn != NULL); | ||
| 344 | AVERT(Arena, arena); | ||
| 345 | AVER(RankCheck(rank)); | ||
| 346 | AVER(FUNCHECK(scan)); | ||
| 347 | |||
| 348 | theUnion.fun.scan = scan; | ||
| 349 | theUnion.fun.p = p; | ||
| 350 | theUnion.fun.s = s; | ||
| 351 | |||
| 352 | return rootCreate(rootReturn, arena, rank, (RootMode)0, RootFUN, &theUnion); | ||
| 353 | } | ||
| 354 | |||
| 355 | |||
| 356 | /* RootDestroy -- destroy a root */ | ||
| 357 | |||
| 358 | void RootDestroy(Root root) | ||
| 359 | { | ||
| 360 | Arena arena; | ||
| 361 | |||
| 362 | AVERT(Root, root); | ||
| 363 | |||
| 364 | arena = RootArena(root); | ||
| 365 | |||
| 366 | AVERT(Arena, arena); | ||
| 367 | |||
| 368 | RingRemove(&root->arenaRing); | ||
| 369 | RingFinish(&root->arenaRing); | ||
| 370 | |||
| 371 | root->sig = SigInvalid; | ||
| 372 | |||
| 373 | ControlFree(arena, root, sizeof(RootStruct)); | ||
| 374 | } | ||
| 375 | |||
| 376 | |||
| 377 | /* RootArena -- return the rank of a root | ||
| 378 | * | ||
| 379 | * Must be thread-safe. */ | ||
| 380 | |||
| 381 | Arena RootArena(Root root) | ||
| 382 | { | ||
| 383 | AVER(CHECKT(Root, root)); | ||
| 384 | return root->arena; | ||
| 385 | } | ||
| 386 | |||
| 387 | |||
| 388 | /* RootRank -- return the rank of a root */ | ||
| 389 | |||
| 390 | Rank RootRank(Root root) | ||
| 391 | { | ||
| 392 | AVERT(Root, root); | ||
| 393 | return root->rank; | ||
| 394 | } | ||
| 395 | |||
| 396 | |||
| 397 | /* RootPM -- return the protection mode of a root */ | ||
| 398 | |||
| 399 | AccessSet RootPM(Root root) | ||
| 400 | { | ||
| 401 | AVERT(Root, root); | ||
| 402 | return root->pm; | ||
| 403 | } | ||
| 404 | |||
| 405 | |||
| 406 | /* RootSummary -- return the summary of a root */ | ||
| 407 | |||
| 408 | RefSet RootSummary(Root root) | ||
| 409 | { | ||
| 410 | AVERT(Root, root); | ||
| 411 | return root->summary; | ||
| 412 | } | ||
| 413 | |||
| 414 | |||
| 415 | /* RootGrey -- mark root grey */ | ||
| 416 | |||
| 417 | void RootGrey(Root root, Trace trace) | ||
| 418 | { | ||
| 419 | AVERT(Root, root); | ||
| 420 | AVERT(Trace, trace); | ||
| 421 | |||
| 422 | root->grey = TraceSetAdd(root->grey, trace); | ||
| 423 | } | ||
| 424 | |||
| 425 | |||
| 426 | static void rootSetSummary(Root root, RefSet summary) | ||
| 427 | { | ||
| 428 | AVERT(Root, root); | ||
| 429 | /* Can't check summary */ | ||
| 430 | if (root->protectable) { | ||
| 431 | if (summary == RefSetUNIV) { | ||
| 432 | root->summary = summary; | ||
| 433 | root->pm &= ~AccessWRITE; | ||
| 434 | } else { | ||
| 435 | root->pm |= AccessWRITE; | ||
| 436 | root->summary = summary; | ||
| 437 | } | ||
| 438 | } else | ||
| 439 | AVER(root->summary == RefSetUNIV); | ||
| 440 | } | ||
| 441 | |||
| 442 | |||
| 443 | /* RootScan -- scan root */ | ||
| 444 | |||
| 445 | Res RootScan(ScanState ss, Root root) | ||
| 446 | { | ||
| 447 | Res res; | ||
| 448 | |||
| 449 | AVERT(Root, root); | ||
| 450 | AVERT(ScanState, ss); | ||
| 451 | AVER(root->rank == ss->rank); | ||
| 452 | |||
| 453 | if (TraceSetInter(root->grey, ss->traces) == TraceSetEMPTY) | ||
| 454 | return ResOK; | ||
| 455 | |||
| 456 | AVER(ScanStateSummary(ss) == RefSetEMPTY); | ||
| 457 | |||
| 458 | if (root->pm != AccessSetEMPTY) { | ||
| 459 | ProtSet(root->protBase, root->protLimit, AccessSetEMPTY); | ||
| 460 | } | ||
| 461 | |||
| 462 | switch(root->var) { | ||
| 463 | case RootTABLE: | ||
| 464 | res = TraceScanArea(ss, root->the.table.base, root->the.table.limit); | ||
| 465 | ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit); | ||
| 466 | if (res != ResOK) | ||
| 467 | goto failScan; | ||
| 468 | break; | ||
| 469 | |||
| 470 | case RootTABLE_MASKED: | ||
| 471 | res = TraceScanAreaMasked(ss, | ||
| 472 | root->the.tableMasked.base, | ||
| 473 | root->the.tableMasked.limit, | ||
| 474 | root->the.tableMasked.mask); | ||
| 475 | ss->scannedSize += AddrOffset(root->the.table.base, root->the.table.limit); | ||
| 476 | if (res != ResOK) | ||
| 477 | goto failScan; | ||
| 478 | break; | ||
| 479 | |||
| 480 | case RootFUN: | ||
| 481 | res = (*root->the.fun.scan)(ss, root->the.fun.p, root->the.fun.s); | ||
| 482 | if (res != ResOK) | ||
| 483 | goto failScan; | ||
| 484 | break; | ||
| 485 | |||
| 486 | case RootREG: | ||
| 487 | res = (*root->the.reg.scan)(ss, root->the.reg.thread, | ||
| 488 | root->the.reg.p, root->the.reg.s); | ||
| 489 | if (res != ResOK) | ||
| 490 | goto failScan; | ||
| 491 | break; | ||
| 492 | |||
| 493 | case RootFMT: | ||
| 494 | res = (*root->the.fmt.scan)(ss, root->the.fmt.base, root->the.fmt.limit); | ||
| 495 | ss->scannedSize += AddrOffset(root->the.fmt.base, root->the.fmt.limit); | ||
| 496 | if (res != ResOK) | ||
| 497 | goto failScan; | ||
| 498 | break; | ||
| 499 | |||
| 500 | default: | ||
| 501 | NOTREACHED; | ||
| 502 | res = ResUNIMPL; | ||
| 503 | goto failScan; | ||
| 504 | } | ||
| 505 | |||
| 506 | AVER(res == ResOK); | ||
| 507 | root->grey = TraceSetDiff(root->grey, ss->traces); | ||
| 508 | rootSetSummary(root, ScanStateSummary(ss)); | ||
| 509 | EVENT_PWW(RootScan, root, ss->traces, ScanStateSummary(ss)); | ||
| 510 | |||
| 511 | failScan: | ||
| 512 | if (root->pm != AccessSetEMPTY) { | ||
| 513 | ProtSet(root->protBase, root->protLimit, root->pm); | ||
| 514 | } | ||
| 515 | |||
| 516 | return res; | ||
| 517 | } | ||
| 518 | |||
| 519 | |||
| 520 | /* RootOfAddr -- return the root at addr | ||
| 521 | * | ||
| 522 | * Returns TRUE if the addr is in a root (and returns the root in | ||
| 523 | * *rootReturn) otherwise returns FALSE. Cf. SegOfAddr. */ | ||
| 524 | |||
| 525 | Bool RootOfAddr(Root *rootReturn, Arena arena, Addr addr) | ||
| 526 | { | ||
| 527 | Ring node, next; | ||
| 528 | |||
| 529 | AVER(rootReturn != NULL); | ||
| 530 | AVERT(Arena, arena); | ||
| 531 | /* addr is arbitrary and can't be checked */ | ||
| 532 | |||
| 533 | RING_FOR(node, &ArenaGlobals(arena)->rootRing, next) { | ||
| 534 | Root root = RING_ELT(Root, arenaRing, node); | ||
| 535 | |||
| 536 | if (root->protectable && root->protBase <= addr && addr < root->protLimit) { | ||
| 537 | *rootReturn = root; | ||
| 538 | return TRUE; | ||
| 539 | } | ||
| 540 | } | ||
| 541 | |||
| 542 | return FALSE; | ||
| 543 | } | ||
| 544 | |||
| 545 | |||
| 546 | /* RootAccess -- handle barrier hit on root */ | ||
| 547 | |||
| 548 | void RootAccess(Root root, AccessSet mode) | ||
| 549 | { | ||
| 550 | AVERT(Root, root); | ||
| 551 | /* Can't AVERT mode. */ | ||
| 552 | AVER((root->pm & mode) != AccessSetEMPTY); | ||
| 553 | AVER(mode == AccessWRITE); /* only write protection supported */ | ||
| 554 | |||
| 555 | rootSetSummary(root, RefSetUNIV); | ||
| 556 | |||
| 557 | /* Access must now be allowed. */ | ||
| 558 | AVER((root->pm & mode) == AccessSetEMPTY); | ||
| 559 | ProtSet(root->protBase, root->protLimit, root->pm); | ||
| 560 | } | ||
| 561 | |||
| 562 | |||
| 563 | /* RootsIterate -- iterate over all the roots in the arena */ | ||
| 564 | |||
| 565 | Res RootsIterate(Globals arena, RootIterateFn f, void *p) | ||
| 566 | { | ||
| 567 | Res res = ResOK; | ||
| 568 | Ring node, next; | ||
| 569 | |||
| 570 | RING_FOR(node, &arena->rootRing, next) { | ||
| 571 | Root root = RING_ELT(Root, arenaRing, node); | ||
| 572 | |||
| 573 | res = (*f)(root, p); | ||
| 574 | if (res != ResOK) | ||
| 575 | return res; | ||
| 576 | } | ||
| 577 | return res; | ||
| 578 | } | ||
| 579 | |||
| 580 | |||
| 581 | /* RootDescribe -- describe a root */ | ||
| 582 | |||
| 583 | Res RootDescribe(Root root, mps_lib_FILE *stream) | ||
| 584 | { | ||
| 585 | Res res; | ||
| 586 | |||
| 587 | if (!CHECKT(Root, root)) return ResFAIL; | ||
| 588 | if (stream == NULL) return ResFAIL; | ||
| 589 | |||
| 590 | res = WriteF(stream, | ||
| 591 | "Root $P ($U) {\n", (WriteFP)root, (WriteFU)root->serial, | ||
| 592 | " arena $P ($U)\n", (WriteFP)root->arena, | ||
| 593 | (WriteFU)root->arena->serial, | ||
| 594 | " rank $U\n", (WriteFU)root->rank, | ||
| 595 | " grey $B\n", (WriteFB)root->grey, | ||
| 596 | " summary $B\n", (WriteFB)root->summary, | ||
| 597 | NULL); | ||
| 598 | if (res != ResOK) return res; | ||
| 599 | |||
| 600 | switch(root->var) { | ||
| 601 | case RootTABLE: | ||
| 602 | res = WriteF(stream, | ||
| 603 | " table base $A limit $A\n", | ||
| 604 | root->the.table.base, root->the.table.limit, | ||
| 605 | NULL); | ||
| 606 | if (res != ResOK) return res; | ||
| 607 | break; | ||
| 608 | |||
| 609 | case RootTABLE_MASKED: | ||
| 610 | res = WriteF(stream, " table base $A limit $A mask $B\n", | ||
| 611 | root->the.tableMasked.base, root->the.tableMasked.limit, | ||
| 612 | root->the.tableMasked.mask, | ||
| 613 | NULL); | ||
| 614 | if (res != ResOK) return res; | ||
| 615 | break; | ||
| 616 | |||
| 617 | case RootFUN: | ||
| 618 | res = WriteF(stream, | ||
| 619 | " scan function $F\n", (WriteFF)root->the.fun.scan, | ||
| 620 | " environment p $P s $W\n", | ||
| 621 | root->the.fun.p, (WriteFW)root->the.fun.s, | ||
| 622 | NULL); | ||
| 623 | if (res != ResOK) return res; | ||
| 624 | break; | ||
| 625 | |||
| 626 | case RootREG: | ||
| 627 | res = WriteF(stream, | ||
| 628 | " thread $P\n", (WriteFP)root->the.reg.thread, | ||
| 629 | " environment p $P", root->the.reg.p, | ||
| 630 | NULL); | ||
| 631 | if (res != ResOK) return res; | ||
| 632 | break; | ||
| 633 | |||
| 634 | case RootFMT: | ||
| 635 | res = WriteF(stream, | ||
| 636 | " scan function $F\n", (WriteFF)root->the.fmt.scan, | ||
| 637 | " format base $A limit $A\n", | ||
| 638 | root->the.fmt.base, root->the.fmt.limit, | ||
| 639 | NULL); | ||
| 640 | if (res != ResOK) return res; | ||
| 641 | break; | ||
| 642 | |||
| 643 | default: | ||
| 644 | NOTREACHED; | ||
| 645 | } | ||
| 646 | |||
| 647 | res = WriteF(stream, | ||
| 648 | "} Root $P ($U)\n", (WriteFP)root, (WriteFU)root->serial, | ||
| 649 | NULL); | ||
| 650 | if (res != ResOK) return res; | ||
| 651 | |||
| 652 | return ResOK; | ||
| 653 | } | ||
| 654 | |||
| 655 | |||
| 656 | /* RootsDescribe -- describe all roots */ | ||
| 657 | |||
| 658 | Res RootsDescribe(Globals arenaGlobals, mps_lib_FILE *stream) | ||
| 659 | { | ||
| 660 | Res res = ResOK; | ||
| 661 | Ring node, next; | ||
| 662 | |||
| 663 | RING_FOR(node, &arenaGlobals->rootRing, next) { | ||
| 664 | Root root = RING_ELT(Root, arenaRing, node); | ||
| 665 | res = RootDescribe(root, stream); /* this outputs too much */ | ||
| 666 | if (res != ResOK) return res; | ||
| 667 | } | ||
| 668 | return res; | ||
| 669 | } | ||