Skip to content

Commit ab49ee1

Browse files
committed
Make buckets of PCRs
Instead of having all PCRs in a single linked list, make a linked list of buckets of PCRs. Each element of the outer linked list has an associated SCC. Each individual bucket is just a linked list of objects, same as the PCR struct before. This new structure means you don't need to traverse a bunch of objects to insert a new PCR - you just need to go over a handful of buckets until you get to the right SCC.
1 parent c2fbdf2 commit ab49ee1

10 files changed

+605
-494
lines changed

src/main/scala/fred/Translator.scala

+62-50
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,19 @@ object Translator {
2929
|
3030
|struct PCR {
3131
| void *obj;
32-
| int scc;
3332
| void (*markGray)(void *);
3433
| void (*scan)(void *);
3534
| void (*collectWhite)(void *);
3635
| struct PCR *next;
3736
|};
3837
|
38+
|struct PCRBucket {
39+
| int scc;
40+
| struct PCR *first;
41+
| struct PCR *last;
42+
| struct PCRBucket *next;
43+
|};
44+
|
3945
|// Common object header
4046
|typedef struct {
4147
| int $RcField;
@@ -49,17 +55,9 @@ object Translator {
4955
| void (*free)(void *);
5056
|};
5157
|
52-
|struct PCR *pcrs;
58+
|struct PCRBucket *pcrBuckets = NULL;
5359
|struct $FreeCell *freeList = NULL;
5460
|
55-
|void printPCRs() {
56-
| fprintf(stderr, "[printPCRs] pcrs: ");
57-
| for (struct PCR *head = pcrs; head != NULL; head = head->next) {
58-
| fprintf(stderr, "%p, ", head);
59-
| }
60-
| fprintf(stderr, "\n");
61-
|}
62-
|
6361
|void addPCR(
6462
| Common *obj,
6563
| int scc,
@@ -69,29 +67,46 @@ object Translator {
6967
|) {
7068
| if (obj->addedPCR) return;
7169
| obj->addedPCR = 1;
72-
| struct PCR **prev = &pcrs;
73-
| while (*prev != NULL && (*prev)->scc <= scc) {
70+
|
71+
| struct PCRBucket **prev = &pcrBuckets;
72+
| while (*prev != NULL && (*prev)->scc < scc) {
7473
| // fprintf(stderr, "[addPCR] prev scc: %d\n", (*prev)->scc);
7574
| prev = &(*prev)->next;
7675
| }
76+
|
7777
| struct PCR *pcr = malloc(sizeof(struct PCR));
7878
| fprintf(stderr, "[addPCR] Added PCR %p, prev = %p, scc: %d\n", pcr, *prev, scc);
7979
| pcr->obj = obj;
80-
| pcr->scc = scc;
8180
| pcr->markGray = markGray;
8281
| pcr->scan = scan;
8382
| pcr->collectWhite = collectWhite;
84-
| pcr->next = *prev;
85-
| *prev = pcr;
86-
| printPCRs();
83+
| pcr->next = NULL;
84+
|
85+
| if (*prev == NULL || scc < (*prev)->scc) {
86+
| struct PCRBucket *newBucket = malloc(sizeof(struct PCRBucket));
87+
| newBucket->scc = scc;
88+
| newBucket->first = pcr;
89+
| newBucket->last = pcr;
90+
| newBucket->next = *prev;
91+
| *prev = newBucket;
92+
| } else {
93+
| (*prev)->last->next = pcr;
94+
| (*prev)->last = pcr;
95+
| }
8796
|}
8897
|
89-
|void removePCR(Common *obj) {
98+
|void removePCR(Common *obj, int scc) {
9099
| if (!obj->addedPCR) return;
91100
| obj->addedPCR = 0;
92-
| struct PCR *head = pcrs;
93-
| struct PCR **prev = &pcrs;
94101
| fprintf(stderr, "[removePCR] Trying to remove %p\n", obj);
102+
|
103+
| struct PCRBucket *bucket = pcrBuckets;
104+
| while (bucket->scc != scc) {
105+
| bucket = bucket->next;
106+
| }
107+
|
108+
| struct PCR *head = bucket->first;
109+
| struct PCR **prev = &bucket->first;
95110
| while (head != NULL) {
96111
| fprintf(stderr, "[removePCR] head = %p\n", head);
97112
| if (head->obj == obj) {
@@ -107,30 +122,26 @@ object Translator {
107122
| }
108123
|}
109124
|
110-
|void markGrayAllPCRs(struct PCR *head, int scc) {
111-
| if (head == NULL || head->scc != scc) return;
125+
|void markGrayAllPCRs(struct PCR *head) {
126+
| if (head == NULL) return;
112127
| struct PCR *next = head->next;
113128
| head->markGray(head->obj);
114-
| markGrayAllPCRs(next, scc);
129+
| markGrayAllPCRs(next);
115130
|}
116131
|
117-
|void scanAllPCRs(struct PCR *head, int scc) {
118-
| if (head == NULL || head->scc != scc) return;
132+
|void scanAllPCRs(struct PCR *head) {
133+
| if (head == NULL) return;
119134
| struct PCR *next = head->next;
120135
| head->scan(head->obj);
121-
| scanAllPCRs(next, scc);
136+
| scanAllPCRs(next);
122137
|}
123138
|
124-
|void collectWhiteAllPCRs(int scc) {
125-
| if (pcrs == NULL || pcrs->scc != scc) return;
126-
| fprintf(stderr, "[collectWhiteAllPCRs] pcr: %p, scc: %d\n", pcrs, scc);
127-
| printPCRs();
128-
| struct PCR *next = pcrs->next;
129-
| pcrs->collectWhite(pcrs->obj);
130-
| free(pcrs);
131-
| fprintf(stderr, "Removed a PCR %p\n", pcrs);
132-
| pcrs = next;
133-
| collectWhiteAllPCRs(scc);
139+
|void collectWhiteAllPCRs(struct PCR *head) {
140+
| if (head == NULL) return;
141+
| struct PCR *next = head->next;
142+
| head->collectWhite(head->obj);
143+
| free(head);
144+
| collectWhiteAllPCRs(next);
134145
|}
135146
|
136147
|void collectFreeList() {
@@ -143,19 +154,19 @@ object Translator {
143154
|}
144155
|
145156
|void processAllPCRs() {
146-
| if (pcrs == NULL) return;
147-
| int firstScc = pcrs->scc;
148-
| markGrayAllPCRs(pcrs, firstScc);
149-
| scanAllPCRs(pcrs, firstScc);
150-
| if (freeList != NULL) {
151-
| fprintf(stderr, "Free list should be null\n");
152-
| exit(1);
153-
| }
154-
| collectWhiteAllPCRs(firstScc);
155-
| collectFreeList();
156-
| fprintf(stderr, "firstScc: %d\n", firstScc);
157-
| if (pcrs != NULL) {
158-
| processAllPCRs();
157+
| while (pcrBuckets != NULL) {
158+
| markGrayAllPCRs(pcrBuckets->first);
159+
| scanAllPCRs(pcrBuckets->first);
160+
| if (freeList != NULL) {
161+
| fprintf(stderr, "Free list should be null\n");
162+
| exit(1);
163+
| }
164+
| collectWhiteAllPCRs(pcrBuckets->first);
165+
| collectFreeList();
166+
| fprintf(stderr, "[processAllPCRs]: Processed scc %d\n", pcrBuckets->scc);
167+
| struct PCRBucket *next = pcrBuckets->next;
168+
| free(pcrBuckets);
169+
| pcrBuckets = next;
159170
| }
160171
|}
161172
|""".stripMargin
@@ -249,16 +260,17 @@ object Translator {
249260
.mkString("\n")
250261
}
251262
}
263+
val scc = cycles.sccMap(typ)
252264

253265
raw"""|fprintf(stderr, "Decrementing ${typ.name} (%p)\n", $This);
254266
|if (--$This->$RcField == 0) {
255267
|$deleteCases
256-
| removePCR((void *) $This);
268+
| removePCR((void *) $This, $scc);
257269
| free($This);
258270
|} else {
259271
| addPCR(
260272
| (void *) $This,
261-
| ${cycles.sccMap(typ)},
273+
| $scc,
262274
| (void *) ${MarkGray.name(typ)},
263275
| (void *) ${Scan.name(typ)},
264276
| (void *) ${CollectWhite.name(typ)});

src/test/resources/snapshot/exec/basic-cycle.c

+61-50
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@ enum Color { kBlack, kGray, kWhite };
55

66
struct PCR {
77
void *obj;
8-
int scc;
98
void (*markGray)(void *);
109
void (*scan)(void *);
1110
void (*collectWhite)(void *);
1211
struct PCR *next;
1312
};
1413

14+
struct PCRBucket {
15+
int scc;
16+
struct PCR *first;
17+
struct PCR *last;
18+
struct PCRBucket *next;
19+
};
20+
1521
// Common object header
1622
typedef struct {
1723
int rc;
@@ -25,17 +31,9 @@ struct FreeCell {
2531
void (*free)(void *);
2632
};
2733

28-
struct PCR *pcrs;
34+
struct PCRBucket *pcrBuckets = NULL;
2935
struct FreeCell *freeList = NULL;
3036

31-
void printPCRs() {
32-
fprintf(stderr, "[printPCRs] pcrs: ");
33-
for (struct PCR *head = pcrs; head != NULL; head = head->next) {
34-
fprintf(stderr, "%p, ", head);
35-
}
36-
fprintf(stderr, "\n");
37-
}
38-
3937
void addPCR(
4038
Common *obj,
4139
int scc,
@@ -45,29 +43,46 @@ void addPCR(
4543
) {
4644
if (obj->addedPCR) return;
4745
obj->addedPCR = 1;
48-
struct PCR **prev = &pcrs;
49-
while (*prev != NULL && (*prev)->scc <= scc) {
46+
47+
struct PCRBucket **prev = &pcrBuckets;
48+
while (*prev != NULL && (*prev)->scc < scc) {
5049
// fprintf(stderr, "[addPCR] prev scc: %d\n", (*prev)->scc);
5150
prev = &(*prev)->next;
5251
}
52+
5353
struct PCR *pcr = malloc(sizeof(struct PCR));
5454
fprintf(stderr, "[addPCR] Added PCR %p, prev = %p, scc: %d\n", pcr, *prev, scc);
5555
pcr->obj = obj;
56-
pcr->scc = scc;
5756
pcr->markGray = markGray;
5857
pcr->scan = scan;
5958
pcr->collectWhite = collectWhite;
60-
pcr->next = *prev;
61-
*prev = pcr;
62-
printPCRs();
59+
pcr->next = NULL;
60+
61+
if (*prev == NULL || scc < (*prev)->scc) {
62+
struct PCRBucket *newBucket = malloc(sizeof(struct PCRBucket));
63+
newBucket->scc = scc;
64+
newBucket->first = pcr;
65+
newBucket->last = pcr;
66+
newBucket->next = *prev;
67+
*prev = newBucket;
68+
} else {
69+
(*prev)->last->next = pcr;
70+
(*prev)->last = pcr;
71+
}
6372
}
6473

65-
void removePCR(Common *obj) {
74+
void removePCR(Common *obj, int scc) {
6675
if (!obj->addedPCR) return;
6776
obj->addedPCR = 0;
68-
struct PCR *head = pcrs;
69-
struct PCR **prev = &pcrs;
7077
fprintf(stderr, "[removePCR] Trying to remove %p\n", obj);
78+
79+
struct PCRBucket *bucket = pcrBuckets;
80+
while (bucket->scc != scc) {
81+
bucket = bucket->next;
82+
}
83+
84+
struct PCR *head = bucket->first;
85+
struct PCR **prev = &bucket->first;
7186
while (head != NULL) {
7287
fprintf(stderr, "[removePCR] head = %p\n", head);
7388
if (head->obj == obj) {
@@ -83,30 +98,26 @@ void removePCR(Common *obj) {
8398
}
8499
}
85100

86-
void markGrayAllPCRs(struct PCR *head, int scc) {
87-
if (head == NULL || head->scc != scc) return;
101+
void markGrayAllPCRs(struct PCR *head) {
102+
if (head == NULL) return;
88103
struct PCR *next = head->next;
89104
head->markGray(head->obj);
90-
markGrayAllPCRs(next, scc);
105+
markGrayAllPCRs(next);
91106
}
92107

93-
void scanAllPCRs(struct PCR *head, int scc) {
94-
if (head == NULL || head->scc != scc) return;
108+
void scanAllPCRs(struct PCR *head) {
109+
if (head == NULL) return;
95110
struct PCR *next = head->next;
96111
head->scan(head->obj);
97-
scanAllPCRs(next, scc);
112+
scanAllPCRs(next);
98113
}
99114

100-
void collectWhiteAllPCRs(int scc) {
101-
if (pcrs == NULL || pcrs->scc != scc) return;
102-
fprintf(stderr, "[collectWhiteAllPCRs] pcr: %p, scc: %d\n", pcrs, scc);
103-
printPCRs();
104-
struct PCR *next = pcrs->next;
105-
pcrs->collectWhite(pcrs->obj);
106-
free(pcrs);
107-
fprintf(stderr, "Removed a PCR %p\n", pcrs);
108-
pcrs = next;
109-
collectWhiteAllPCRs(scc);
115+
void collectWhiteAllPCRs(struct PCR *head) {
116+
if (head == NULL) return;
117+
struct PCR *next = head->next;
118+
head->collectWhite(head->obj);
119+
free(head);
120+
collectWhiteAllPCRs(next);
110121
}
111122

112123
void collectFreeList() {
@@ -119,19 +130,19 @@ void collectFreeList() {
119130
}
120131

121132
void processAllPCRs() {
122-
if (pcrs == NULL) return;
123-
int firstScc = pcrs->scc;
124-
markGrayAllPCRs(pcrs, firstScc);
125-
scanAllPCRs(pcrs, firstScc);
126-
if (freeList != NULL) {
127-
fprintf(stderr, "Free list should be null\n");
128-
exit(1);
129-
}
130-
collectWhiteAllPCRs(firstScc);
131-
collectFreeList();
132-
fprintf(stderr, "firstScc: %d\n", firstScc);
133-
if (pcrs != NULL) {
134-
processAllPCRs();
133+
while (pcrBuckets != NULL) {
134+
markGrayAllPCRs(pcrBuckets->first);
135+
scanAllPCRs(pcrBuckets->first);
136+
if (freeList != NULL) {
137+
fprintf(stderr, "Free list should be null\n");
138+
exit(1);
139+
}
140+
collectWhiteAllPCRs(pcrBuckets->first);
141+
collectFreeList();
142+
fprintf(stderr, "[processAllPCRs]: Processed scc %d\n", pcrBuckets->scc);
143+
struct PCRBucket *next = pcrBuckets->next;
144+
free(pcrBuckets);
145+
pcrBuckets = next;
135146
}
136147
}
137148
enum Option_kind { None_tag, Some_tag };
@@ -202,7 +213,7 @@ void $decr_Option(struct Option* this) {
202213
$decr_List(this->value_Some);
203214
break;
204215
}
205-
removePCR((void *) this);
216+
removePCR((void *) this, 0);
206217
free(this);
207218
} else {
208219
addPCR(
@@ -221,7 +232,7 @@ void $decr_List(struct List* this) {
221232
$decr_Option(this->next);
222233
break;
223234
}
224-
removePCR((void *) this);
235+
removePCR((void *) this, 0);
225236
free(this);
226237
} else {
227238
addPCR(

0 commit comments

Comments
 (0)