aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code/root.c
diff options
context:
space:
mode:
authorNick Barnes2001-10-31 14:40:56 +0000
committerNick Barnes2001-10-31 14:40:56 +0000
commit7acfca905d76140f4cc0b09c9a12de237de364cd (patch)
tree3ed8babfa3a73d30f29e08ca5d5adcda4ca4e826 /mps/code/root.c
parentb7ce4893f9902d57cd67ac9a92fa6c3d5a8fc833 (diff)
downloademacs-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.c669
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
13SRCID(root, "$HopeName: MMsrc!root.c(trunk.34) $");
14
15
16/* RootStruct -- tracing root structure */
17
18#define RootSig ((Sig)0x51960029) /* SIGnature ROOT */
19
20typedef 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
67Bool 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
78Bool 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
96Bool 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
159static 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
206static 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
256Res 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
276Res 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
297Res 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
317Res 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
338Res 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
358void 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
381Arena 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
390Rank 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
399AccessSet RootPM(Root root)
400{
401 AVERT(Root, root);
402 return root->pm;
403}
404
405
406/* RootSummary -- return the summary of a root */
407
408RefSet RootSummary(Root root)
409{
410 AVERT(Root, root);
411 return root->summary;
412}
413
414
415/* RootGrey -- mark root grey */
416
417void 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
426static 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
445Res 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
511failScan:
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
525Bool 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
548void 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
565Res 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
583Res 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
658Res 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}