1/*
2    Title:      Multi-Threaded Garbage Collector - Data sharing phase
3
4    Copyright (c) 2012, 2017 David C. J. Matthews
5
6    This library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    This library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with this library; if not, write to the Free Software
18    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
20*/
21
22/*  GC Sharing pass.
23    This pass is invoked only if the heap sizing code detects that heap space
24    is running very short because it adds a very considerable overhead to GC.
25    It aims to reduce the size of the live data in a similar way to the data
26    sharing function PolyML.shareCommonData by merging immutable cells that
27    contain data that cannot be distinguished.
28
29    This version of the code now does a deep structure merge in a similar
30    way to the full sharing function. This code first does a full pass
31    over the heap creating lists of cells that could possibly be merged.
32    There are separate lists for byte and word objects up to a fixed
33    size.  Larger objects and other objects are not considered. Because
34    all the items in a list have the same length and type (flag bits)
35    we can use the length word to link the items in the list.  A
36    consequence of this is that positive long precision values can be
37    shared but negative values cannot.
38
39    There is a sharing function that first distributes items into a
40    hash table.  Then each hash table is sorted and as part of the
41    sorting process cells with the same contents are merged.  One
42    cell is chosen and the length words on the others are set to be
43    forwarding pointers to the chosen cell.  Hashing allows for easy
44    parallel processing.
45
46    The structure sharing code works by first sharing the byte
47    data which cannot contain pointers.  Then the word data is processed
48    to separate out "tail" cells that contain only tagged integers or
49    pointers to cells that either cannot be merged, such as mutables,
50    or those that have already been processed, such as the byte data.
51    Any pointers to shared data are updated to point to the merged cell.
52    The tail cells are then sorted and shared using the sharing function
53    and become part of the "processed" set.  This process is repeated to
54    find cells that are now tails and so on.
55
56    Compared with the full sharing code this is expensive since it
57    requires repeated scans of the list of unprocessed cells.  In
58    particular there may be cells that form loops (basically closures
59    for mutually recusive functions) and if they are present they and
60    anything that points directly or indirectly at them will never
61    be removed from the list.  We stop when it appears that we are
62    not making progress and simply do a final bit-wise share of the
63    remainder.
64*/
65#ifdef HAVE_CONFIG_H
66#include "config.h"
67#elif defined(_WIN32)
68#include "winconfig.h"
69#else
70#error "No configuration file"
71#endif
72
73#ifdef HAVE_ASSERT_H
74#include <assert.h>
75#define ASSERT(x)   assert(x)
76#else
77#define ASSERT(x)
78#endif
79
80#ifdef HAVE_STRING_H
81#include <string.h>
82#endif
83
84#ifdef HAVE_STDLIB_H
85#include <stdlib.h>
86#endif
87
88#include "globals.h"
89#include "processes.h"
90#include "gc.h"
91#include "scanaddrs.h"
92#include "bitmap.h"
93#include "memmgr.h"
94#include "diagnostics.h"
95#include "gctaskfarm.h"
96#include "heapsizing.h"
97
98class ObjEntry
99{
100public:
101    ObjEntry(): objList(0), objCount(0), shareCount(0) {}
102    PolyObject *objList;
103    POLYUNSIGNED objCount;
104    POLYUNSIGNED shareCount;
105};
106
107// There is an instance of this class for each combination of size and
108// word/byte.
109class SortVector
110{
111public:
112    SortVector(): totalCount(0), carryOver(0) {}
113
114    void AddToVector(PolyObject *obj, POLYUNSIGNED length);
115
116    void SortData(void);
117    POLYUNSIGNED TotalCount() const { return totalCount; }
118    POLYUNSIGNED CurrentCount() const { return baseObject.objCount; }
119    POLYUNSIGNED Shared() const;
120    void SetLengthWord(POLYUNSIGNED l) { lengthWord = l; }
121    POLYUNSIGNED CarryOver() const { return carryOver; }
122
123    static void hashAndSortAllTask(GCTaskId*, void *a, void *b);
124    static void sharingTask(GCTaskId*, void *a, void *b);
125    static void wordDataTask(GCTaskId*, void *a, void *b);
126
127private:
128    void sortList(PolyObject *head, POLYUNSIGNED nItems, POLYUNSIGNED &count);
129
130    ObjEntry baseObject, processObjects[256];
131    POLYUNSIGNED totalCount;
132    POLYUNSIGNED lengthWord;
133    POLYUNSIGNED carryOver;
134};
135
136POLYUNSIGNED SortVector::Shared() const
137{
138    // Add all the sharing counts
139    POLYUNSIGNED shareCount = baseObject.shareCount;
140    for (unsigned i = 0; i < 256; i++)
141        shareCount += processObjects[i].shareCount;
142    return shareCount;
143}
144
145void SortVector::AddToVector(PolyObject *obj, POLYUNSIGNED length)
146{
147    obj->SetShareChain(baseObject.objList);
148    baseObject.objList = obj;
149    baseObject.objCount++;
150    totalCount++;
151}
152
153// The number of byte and word entries.
154// Objects of up to and including this size are shared.
155// Byte objects include strings so it is more likely that
156// larger objects will share.  Word objects that share
157// are much more likely to be 2 or 3 words.
158#define NUM_BYTE_VECTORS    23
159#define NUM_WORD_VECTORS    11
160
161class GetSharing: public RecursiveScanWithStack
162{
163public:
164    GetSharing();
165    void SortData(void);
166    static void shareByteData(GCTaskId *, void *, void *);
167    static void shareWordData(GCTaskId *, void *, void *);
168    static void shareRemainingWordData(GCTaskId *, void *, void *);
169
170protected:
171    virtual bool TestForScan(PolyWord *);
172    virtual void MarkAsScanning(PolyObject *);
173    virtual void StackOverflow(void) { } // Ignore stack overflow
174    virtual void Completed(PolyObject *);
175
176private:
177    // The head of chains of cells of the same size
178    SortVector byteVectors[NUM_BYTE_VECTORS];
179    SortVector wordVectors[NUM_WORD_VECTORS];
180
181    POLYUNSIGNED largeWordCount, largeByteCount, excludedCount;
182public:
183    POLYUNSIGNED totalVisited, byteAdded, wordAdded, totalSize;
184};
185
186GetSharing::GetSharing()
187{
188    for (unsigned i = 0; i < NUM_BYTE_VECTORS; i++)
189        byteVectors[i].SetLengthWord((POLYUNSIGNED)i | _OBJ_BYTE_OBJ);
190
191    for (unsigned j = 0; j < NUM_WORD_VECTORS; j++)
192        wordVectors[j].SetLengthWord(j);
193
194    largeWordCount = largeByteCount = excludedCount = 0;
195    totalVisited = byteAdded = wordAdded = totalSize = 0;
196}
197
198bool GetSharing::TestForScan(PolyWord *pt)
199{
200    PolyWord p = *pt;
201    ASSERT(p.IsDataPtr());
202    PolyObject *obj = p.AsObjPtr();
203
204    while (obj->ContainsForwardingPtr())
205    {
206        obj = obj->GetForwardingPtr();
207        *pt = obj;
208    }
209    ASSERT(obj == (*pt).AsObjPtr());
210
211    PolyWord *lengthWord = ((PolyWord*)obj) - 1;
212
213    LocalMemSpace *space = gMem.LocalSpaceForAddress(lengthWord);
214
215    if (space == 0)
216        return false; // Ignore it if it points to a permanent area
217
218    if (space->bitmap.TestBit(space->wordNo(lengthWord)))
219        return false;
220
221    ASSERT(obj->ContainsNormalLengthWord());
222
223    totalVisited += 1;
224    totalSize += obj->Length() + 1;
225
226    return true;
227}
228
229void GetSharing::MarkAsScanning(PolyObject *obj)
230{
231    ASSERT(obj->ContainsNormalLengthWord());
232    PolyWord *lengthWord = ((PolyWord*)obj) - 1;
233    LocalMemSpace *space = gMem.LocalSpaceForAddress(lengthWord);
234    ASSERT(! space->bitmap.TestBit(space->wordNo(lengthWord)));
235    space->bitmap.SetBit(space->wordNo(lengthWord));
236}
237
238void GetSharing::Completed(PolyObject *obj)
239{
240    // We mustn't include cells in the permanent area.
241    // We scan the permanent mutable areas for local addresses
242    // but we mustn't add the cells themselves.  Normally they
243    // will be mutable so would be ignored but cells that have been
244    // locked will now be immutable.  The test in TestForScan is bypassed
245    // by ScanAddressesInRegion.
246    PolyWord *lengthWord = ((PolyWord*)obj) - 1;
247    if (gMem.LocalSpaceForAddress(lengthWord) == 0)
248        return;
249
250    POLYUNSIGNED L = obj->LengthWord();
251    // We have tables for word objects and byte objects
252    // We chain entries together using the length word so it
253    // is important that we only do this for objects that
254    // have no other bits in the header, such as the sign bit.
255    if ((L & _OBJ_PRIVATE_FLAGS_MASK) == 0)
256    {
257        POLYUNSIGNED length = obj->Length();
258        if (length < NUM_WORD_VECTORS)
259            wordVectors[length].AddToVector(obj, length);
260        else largeWordCount++;
261        wordAdded++;
262    }
263    else if ((L & _OBJ_PRIVATE_FLAGS_MASK) == _OBJ_BYTE_OBJ)
264    {
265        POLYUNSIGNED length = obj->Length();
266        if (length < NUM_BYTE_VECTORS)
267            byteVectors[length].AddToVector(obj, length);
268        else largeByteCount++;
269        byteAdded++;
270    }
271    else if (! OBJ_IS_CODE_OBJECT(L) && ! OBJ_IS_MUTABLE_OBJECT(L))
272        excludedCount++; // Code and mutables can't be shared - see what could be
273}
274
275// Quicksort the list to detect cells with the same content.  These are made
276// to share and removed from further sorting.
277void SortVector::sortList(PolyObject *head, POLYUNSIGNED nItems, POLYUNSIGNED &shareCount)
278{
279    while (nItems > 2)
280    {
281        size_t bytesToCompare = OBJ_OBJECT_LENGTH(lengthWord)*sizeof(PolyWord);
282        PolyObject *median = head;
283        head = head->GetShareChain();
284        median->SetLengthWord(lengthWord);
285        PolyObject *left = 0, *right = 0;
286        POLYUNSIGNED leftCount = 0, rightCount = 0;
287        while (head != 0)
288        {
289            PolyObject *next = head->GetShareChain();
290            int res = memcmp(median, head, bytesToCompare);
291            if (res == 0)
292            {
293                // Equal - they can share
294                head->SetForwardingPtr(median);
295                shareCount++;
296            }
297            else if (res < 0)
298            {
299                head->SetShareChain(left);
300                left = head;
301                leftCount++;
302            }
303            else
304            {
305                head->SetShareChain(right);
306                right = head;
307                rightCount++;
308            }
309            head = next;
310        }
311        // We can now drop the median and anything that shares with it.
312        // Process the smaller partition recursively and the larger by
313        // tail recursion.
314        if (leftCount < rightCount)
315        {
316            sortList(left, leftCount, shareCount);
317            head = right;
318            nItems = rightCount;
319        }
320        else
321        {
322            sortList(right, rightCount, shareCount);
323            head = left;
324            nItems = leftCount;
325        }
326    }
327    if (nItems == 1)
328        head->SetLengthWord(lengthWord);
329    else if (nItems == 2)
330    {
331        PolyObject *next = head->GetShareChain();
332        head->SetLengthWord(lengthWord);
333        if (memcmp(head, next, OBJ_OBJECT_LENGTH(lengthWord)*sizeof(PolyWord)) == 0)
334        {
335            next->SetForwardingPtr(head);
336            shareCount++;
337        }
338        else next->SetLengthWord(lengthWord);
339    }
340}
341
342void SortVector::sharingTask(GCTaskId*, void *a, void *b)
343{
344    SortVector *s = (SortVector *)a;
345    ObjEntry *o = (ObjEntry*)b;
346    s->sortList(o->objList, o->objCount, o->shareCount);
347}
348
349// Process one level of the word data.
350// N.B.  The length words are updated without any locking.  This is safe
351// because all length words are initially chain entries and a chain entry
352// can be replaced by another chain entry, a forwarding pointer or a normal
353// length word.  Forwarding pointers and normal length words are only ever
354// set once.  There is a small chance that we could lose some sharing as a
355// result of a race condition if a thread defers an object because it
356// contains a pointer with a chain entry and later sees an otherwise
357// equal object where another thread has replaced the chain with a
358// normal address, adds it to the list for immediate processing and
359// so never compares the two.
360void SortVector::wordDataTask(GCTaskId*, void *a, void *)
361{
362    SortVector *s = (SortVector*)a;
363    // Partition the objects between those that have pointers to objects that are
364    // still to be processed and those that have been processed.
365    if (s->baseObject.objList == 0)
366        return;
367    PolyObject *h = s->baseObject.objList;
368    s->baseObject.objList = 0;
369    s->baseObject.objCount = 0;
370    POLYUNSIGNED words = OBJ_OBJECT_LENGTH(s->lengthWord);
371    s->carryOver = 0;
372
373    for (unsigned i = 0; i < 256; i++)
374    {
375        // Clear the entries in the hash table but not the sharing count.
376        s->processObjects[i].objList = 0;
377        s->processObjects[i].objCount = 0;
378    }
379
380    while (h != 0)
381    {
382        PolyObject *next = h->GetShareChain();
383        bool deferred = false;
384        for (POLYUNSIGNED i = 0; i < words; i++)
385        {
386            PolyWord w = h->Get(i);
387            if (w.IsDataPtr())
388            {
389                PolyObject *p = w.AsObjPtr();
390                // Update the addresses of objects that have been merged
391                if (p->ContainsForwardingPtr())
392                {
393                    h->Set(i, p->GetForwardingPtr());
394                    s->carryOver++;
395                }
396                else if (p->ContainsShareChain())
397                {
398                    // If it is still to be shared leave it
399                    deferred = true;
400                    break;
401                }
402            }
403        }
404        if (deferred)
405        {
406            // We can't do it yet: add it back to the list
407            h->SetShareChain(s->baseObject.objList);
408            s->baseObject.objList = h;
409            s->baseObject.objCount++;
410        }
411        else
412        {
413            // Add it to the hash table.
414            unsigned char hash = 0;
415            for (POLYUNSIGNED i = 0; i < words*sizeof(PolyWord); i++)
416                hash += h->AsBytePtr()[i];
417            h->SetShareChain(s->processObjects[hash].objList);
418            s->processObjects[hash].objList = h;
419            s->processObjects[hash].objCount++;
420        }
421        h = next;
422    }
423    s->SortData();
424}
425
426// Sort the entries in the hash table.
427void SortVector::SortData()
428{
429    for (unsigned j = 0; j < 256; j++)
430    {
431        ObjEntry *oentry = &processObjects[j];
432        // Sort this entry.  If it's very small just process it now.
433        switch (oentry->objCount)
434        {
435        case 0: break; // Nothing there
436
437        case 1: // Singleton - just restore the length word
438            oentry->objList->SetLengthWord(lengthWord);
439            break;
440
441        case 2:
442            {
443                // Two items - process now
444                PolyObject *obj1 = oentry->objList;
445                PolyObject *obj2 = obj1->GetShareChain();
446                obj1->SetLengthWord(lengthWord);
447                if (memcmp(obj1, obj2, OBJ_OBJECT_LENGTH(lengthWord)*sizeof(PolyWord)) == 0)
448                {
449                    obj2->SetForwardingPtr(obj1);
450                    oentry->shareCount++;
451                }
452                else obj2->SetLengthWord(lengthWord);
453                break;
454            }
455
456        default:
457            gpTaskFarm->AddWorkOrRunNow(sharingTask, this, oentry);
458        }
459    }
460}
461
462void SortVector::hashAndSortAllTask(GCTaskId*, void *a, void *b)
463{
464    SortVector *s = (SortVector *)a;
465    // Hash the contents of the base object then sort them.
466    for (unsigned i = 0; i < 256; i++)
467    {
468        // Clear the entries in the hash table but not the sharing count.
469        s->processObjects[i].objList = 0;
470        s->processObjects[i].objCount = 0;
471    }
472    PolyObject *h = s->baseObject.objList;
473    POLYUNSIGNED bytes = OBJ_OBJECT_LENGTH(s->lengthWord)*sizeof(PolyWord);
474    while (h != 0)
475    {
476        PolyObject *next = h->GetShareChain();
477        unsigned char hash = 0;
478        for (POLYUNSIGNED j = 0; j < bytes; j++)
479            hash += h->AsBytePtr()[j];
480        h->SetShareChain(s->processObjects[hash].objList);
481        s->processObjects[hash].objList = h;
482        s->processObjects[hash].objCount++;
483        h = next;
484    }
485    s->SortData();
486}
487
488// Look for sharing between byte data.  These cannot contain pointers
489// so they can all be processed together.
490void GetSharing::shareByteData(GCTaskId *, void *a, void *)
491{
492    GetSharing *s = (GetSharing*)a;
493    for (unsigned i = 0; i < NUM_BYTE_VECTORS; i++)
494    {
495        if (s->byteVectors[i].CurrentCount() != 0)
496            gpTaskFarm->AddWorkOrRunNow(SortVector::hashAndSortAllTask, &(s->byteVectors[i]), 0);
497    }
498}
499
500// Process word data at this particular level
501void GetSharing::shareWordData(GCTaskId *, void *a, void *)
502{
503    GetSharing *s = (GetSharing*)a;
504    for (unsigned i = 0; i < NUM_WORD_VECTORS; i++)
505    {
506        if (s->wordVectors[i].CurrentCount() != 0)
507            gpTaskFarm->AddWorkOrRunNow(SortVector::wordDataTask, &(s->wordVectors[i]), 0);
508    }
509}
510
511// Share any entries left.
512void GetSharing::shareRemainingWordData(GCTaskId *, void *a, void *)
513{
514    GetSharing *s = (GetSharing*)a;
515    for (unsigned i = 0; i < NUM_WORD_VECTORS; i++)
516    {
517        if (s->wordVectors[i].CurrentCount() != 0)
518            gpTaskFarm->AddWorkOrRunNow(SortVector::hashAndSortAllTask, &(s->wordVectors[i]), 0);
519    }
520}
521
522void GetSharing::SortData()
523{
524    // First process the byte objects.  They cannot contain pointers.
525    // We create a task to do this so that we never have more threads
526    // running than given with --gcthreads.
527    gpTaskFarm->AddWorkOrRunNow(shareByteData, this, 0);
528    gpTaskFarm->WaitForCompletion();
529
530    // Word data may contain pointers to other objects.  If an object
531    // has been processed its header will contain either a normal length
532    // word or a forwarding pointer if it shares.  We can process an
533    // object if every word in it is either a tagged integer or an
534    // address we have already processed.  This works provided there
535    // are no loops so when we reach a stage where we are unable to
536    // process anything we simply run a final scan on the remainder.
537    // Loops can arise from the closures of mutually recursive functions.
538
539    // Now process the word entries until we have nothing left apart from loops.
540    POLYUNSIGNED lastCount = 0, lastShared = 0;
541    for (unsigned n = 0; n < NUM_WORD_VECTORS; n++)
542        lastCount += wordVectors[n].CurrentCount();
543
544    for(unsigned pass = 1; lastCount != 0; pass++)
545    {
546        gpTaskFarm->AddWorkOrRunNow(shareWordData, this, 0);
547        gpTaskFarm->WaitForCompletion();
548
549        // At each stage check that we have removed some items
550        // from the lists.
551        POLYUNSIGNED postCount = 0, postShared = 0, carryOver = 0;
552        for (unsigned i = 0; i < NUM_WORD_VECTORS; i++)
553        {
554            postCount += wordVectors[i].CurrentCount();
555            postShared += wordVectors[i].Shared();
556            carryOver += wordVectors[i].CarryOver();
557        }
558
559        if (debugOptions & DEBUG_GC)
560            Log("GC: Share: Pass %u: %" POLYUFMT " removed (%1.1f%%) %" POLYUFMT " shared (%1.1f%%) %" POLYUFMT " remain. %" POLYUFMT " entries updated (%1.1f%%).\n",
561                pass, lastCount-postCount, (double)(lastCount-postCount) / (double) lastCount * 100.0,
562                postShared - lastShared, (double)(postShared - lastShared) / (double) (lastCount-postCount) * 100.0,
563                postCount, carryOver, (double)carryOver / (double)(lastCount-postCount) * 100.0);
564
565        // Condition for exiting the loop.  There are some heuristics here.
566        // If we remove less than 10% in a pass it's probably not worth continuing
567        // unless the carry over is large.  The "carry over" is the number of words updated as
568        // a result of the last pass.  It represents the extra sharing we gained in this pass
569        // as a result of the last pass.  If there are deep data structures that can be shared
570        // we get better sharing with more passes.  If the data structures are shallow we will
571        // get as much sharing by just running the final pass.  The first pass only carries
572        // over any sharing from the byte objects so we need to run at least one more before
573        // checking the carry over.
574        if (pass > 1 && (lastCount - postCount) * 10 < lastCount && (carryOver*2 < (lastCount-postCount) || (lastCount - postCount) * 1000 < lastCount ))
575            break;
576
577        lastCount = postCount;
578        lastShared = postShared;
579    }
580
581    // Process any remaining entries.  There may be loops.
582    gpTaskFarm->AddWorkOrRunNow(shareRemainingWordData, this, 0);
583    gpTaskFarm->WaitForCompletion();
584
585    if (debugOptions & DEBUG_GC)
586    {
587        POLYUNSIGNED postShared = 0;
588        for (unsigned i = 0; i < NUM_WORD_VECTORS; i++)
589            postShared += wordVectors[i].Shared();
590        if (debugOptions & DEBUG_GC)
591            Log("GC: Share: Final pass %" POLYUFMT " removed %" POLYUFMT " shared (%1.1f%%).\n",
592                lastCount, postShared - lastShared,
593                (double)(postShared - lastShared) / (double) lastCount * 100.0);
594    }
595
596    // Calculate the totals.
597    POLYUNSIGNED totalSize = 0, totalShared = 0, totalRecovered = 0;
598    for (unsigned k = 0; k < NUM_BYTE_VECTORS; k++)
599    {
600        totalSize += byteVectors[k].TotalCount();
601        POLYUNSIGNED shared = byteVectors[k].Shared();
602        totalShared += shared;
603        totalRecovered += shared * (k+1); // Add 1 for the length word.
604        if (debugOptions & DEBUG_GC)
605            Log("GC: Share: Byte objects of size %u: %" POLYUFMT " objects %" POLYUFMT " shared\n",
606                k, byteVectors[k].TotalCount(), byteVectors[k].Shared());
607    }
608
609    for (unsigned l = 0; l < NUM_WORD_VECTORS; l++)
610    {
611        totalSize += wordVectors[l].TotalCount();
612        POLYUNSIGNED shared = wordVectors[l].Shared();
613        totalShared += shared;
614        totalRecovered += shared * (l+1);
615        if (debugOptions & DEBUG_GC)
616            Log("GC: Share: Word objects of size %u: %" POLYUFMT " objects %" POLYUFMT " shared\n",
617                l, wordVectors[l].TotalCount(), wordVectors[l].Shared());
618    }
619
620    if (debugOptions & DEBUG_GC)
621    {
622        Log("GC: Share: Total %" POLYUFMT " objects, %" POLYUFMT " shared (%1.0f%%).  %" POLYUFMT " words recovered.\n",
623            totalSize, totalShared, (double)totalShared / (double)totalSize * 100.0, totalRecovered);
624        Log("GC: Share: Excluding %" POLYUFMT " large word objects %" POLYUFMT " large byte objects and %" POLYUFMT " others\n",
625            largeWordCount, largeByteCount, excludedCount);
626    }
627
628    gHeapSizeParameters.RecordSharingData(totalRecovered);
629}
630
631void GCSharingPhase(void)
632{
633    mainThreadPhase = MTP_GCPHASESHARING;
634
635    GetSharing sharer;
636
637    for (std::vector<LocalMemSpace*>::iterator i = gMem.lSpaces.begin(); i < gMem.lSpaces.end(); i++)
638    {
639        LocalMemSpace *lSpace = *i;
640        lSpace->bitmap.ClearBits(0, lSpace->spaceSize());
641    }
642
643    // Scan the code areas to share any constants.  We don't share the code
644    // cells themselves.
645    for (std::vector<CodeSpace *>::iterator i = gMem.cSpaces.begin(); i < gMem.cSpaces.end(); i++)
646    {
647        CodeSpace *space = *i;
648        sharer.ScanAddressesInRegion(space->bottom, space->top);
649    }
650
651    if (debugOptions & DEBUG_GC)
652        Log("GC: Share: After scanning code: Total %" POLYUFMT " (%" POLYUFMT " words) byte %" POLYUFMT " word %" POLYUFMT ".\n",
653            sharer.totalVisited, sharer.totalSize, sharer.byteAdded, sharer.wordAdded);
654
655    // Process the permanent mutable areas and the code areas
656    for (std::vector<PermanentMemSpace*>::iterator i = gMem.pSpaces.begin(); i < gMem.pSpaces.end(); i++)
657    {
658        PermanentMemSpace *space = *i;
659        if (space->isMutable && ! space->byteOnly)
660            sharer.ScanAddressesInRegion(space->bottom, space->top);
661    }
662
663    if (debugOptions & DEBUG_GC)
664        Log("GC: Share: After scanning permanent: Total %" POLYUFMT " (%" POLYUFMT " words) byte %" POLYUFMT " word %" POLYUFMT ".\n",
665            sharer.totalVisited, sharer.totalSize, sharer.byteAdded, sharer.wordAdded);
666
667    // Process the RTS roots.
668    GCModules(&sharer);
669
670    if (debugOptions & DEBUG_GC)
671        Log("GC: Share: After scanning other roots: Total %" POLYUFMT " (%" POLYUFMT " words) byte %" POLYUFMT " word %" POLYUFMT ".\n",
672            sharer.totalVisited, sharer.totalSize, sharer.byteAdded, sharer.wordAdded);
673
674    gHeapSizeParameters.RecordGCTime(HeapSizeParameters::GCTimeIntermediate, "Table");
675
676    // Sort and merge the data.
677    sharer.SortData();
678
679    gHeapSizeParameters.RecordGCTime(HeapSizeParameters::GCTimeIntermediate, "Sort");
680}
681